clean up ethtypes: rationalize ethtypes.EthAddressFromFilecoinAddress and conversion methods (#9992)

This commit is contained in:
raulk 2023-01-12 17:09:21 +00:00 committed by GitHub
parent 105a1259bc
commit 3ef32395f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 211 additions and 257 deletions

Binary file not shown.

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
mathbig "math/big" mathbig "math/big"
"strconv" "strconv"
@ -30,6 +31,8 @@ var (
EthTopic4 = "topic4" EthTopic4 = "topic4"
) )
var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")
type EthUint64 uint64 type EthUint64 uint64
func (e EthUint64) MarshalJSON() ([]byte, error) { func (e EthUint64) MarshalJSON() ([]byte, error) {
@ -249,21 +252,32 @@ func EthAddressFromPubKey(pubk []byte) ([]byte, error) {
} }
func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) { func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) {
ethAddr, ok, err := TryEthAddressFromFilecoinAddress(addr, true) switch addr.Protocol() {
if err != nil { case address.ID:
return EthAddress{}, xerrors.Errorf("failed to try converting filecoin to eth addr: %w", err) id, err := address.IDFromAddress(addr)
if err != nil {
return EthAddress{}, err
}
var ethaddr EthAddress
ethaddr[0] = 0xff
binary.BigEndian.PutUint64(ethaddr[12:], id)
return ethaddr, nil
case address.Delegated:
payload := addr.Payload()
namespace, n, err := varint.FromUvarint(payload)
if err != nil {
return EthAddress{}, xerrors.Errorf("invalid delegated address namespace in: %s", addr)
}
payload = payload[n:]
if namespace == builtintypes.EthereumAddressManagerActorID {
return CastEthAddress(payload)
}
} }
return EthAddress{}, ErrInvalidAddress
if !ok {
return EthAddress{}, xerrors.Errorf("failed to convert filecoin address %s to an equivalent eth address", addr)
}
return ethAddr, nil
} }
// ParseEthAddress parses an Ethereum address from a hex string. // ParseEthAddress parses an Ethereum address from a hex string.
func ParseEthAddress(s string) (EthAddress, error) { func ParseEthAddress(s string) (EthAddress, error) {
handlePrefix(&s)
b, err := decodeHexString(s, EthAddressLength) b, err := decodeHexString(s, EthAddressLength)
if err != nil { if err != nil {
return EthAddress{}, err return EthAddress{}, err
@ -304,9 +318,13 @@ func (ea *EthAddress) UnmarshalJSON(b []byte) error {
return nil return nil
} }
func (ea EthAddress) ToFilecoinAddress() (address.Address, error) { func (ea EthAddress) IsMaskedID() bool {
idmask := [12]byte{0xff} idmask := [12]byte{0xff}
if bytes.Equal(ea[:12], idmask[:]) { return bytes.Equal(ea[:12], idmask[:])
}
func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
if ea.IsMaskedID() {
// This is a masked ID address. // This is a masked ID address.
id := binary.BigEndian.Uint64(ea[12:]) id := binary.BigEndian.Uint64(ea[12:])
return address.NewIDAddress(id) return address.NewIDAddress(id)
@ -322,37 +340,6 @@ func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
return addr, nil return addr, nil
} }
// This API assumes that if an ID address is passed in, it doesn't have an equivalent
// delegated address
func TryEthAddressFromFilecoinAddress(addr address.Address, allowId bool) (EthAddress, bool, error) {
switch addr.Protocol() {
case address.ID:
if !allowId {
return EthAddress{}, false, nil
}
id, err := address.IDFromAddress(addr)
if err != nil {
return EthAddress{}, false, err
}
var ethaddr EthAddress
ethaddr[0] = 0xff
binary.BigEndian.PutUint64(ethaddr[12:], id)
return ethaddr, true, nil
case address.Delegated:
payload := addr.Payload()
namespace, n, err := varint.FromUvarint(payload)
if err != nil {
return EthAddress{}, false, xerrors.Errorf("invalid delegated address namespace in: %s", addr)
}
payload = payload[n:]
if namespace == builtintypes.EthereumAddressManagerActorID {
addr, err := CastEthAddress(payload)
return addr, err == nil, err
}
}
return EthAddress{}, false, nil
}
type EthHash [EthHashLength]byte type EthHash [EthHashLength]byte
func (h EthHash) MarshalJSON() ([]byte, error) { func (h EthHash) MarshalJSON() ([]byte, error) {
@ -372,25 +359,22 @@ func (h *EthHash) UnmarshalJSON(b []byte) error {
return nil return nil
} }
func handlePrefix(s *string) { func decodeHexString(s string, expectedLen int) ([]byte, error) {
if strings.HasPrefix(*s, "0x") || strings.HasPrefix(*s, "0X") { // Strip the leading 0x or 0X prefix since hex.DecodeString does not support it.
*s = (*s)[2:] if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
s = s[2:]
} }
if len(*s)%2 == 1 { // Sometimes clients will omit a leading zero in a byte; pad so we can decode correctly.
*s = "0" + *s if len(s)%2 == 1 {
s = "0" + s
}
if len(s) != expectedLen*2 {
return []byte{}, xerrors.Errorf("expected length %d, got %d", expectedLen, len(s))
} }
}
func decodeHexString(s string, length int) ([]byte, error) {
b, err := hex.DecodeString(s) b, err := hex.DecodeString(s)
if err != nil { if err != nil {
return []byte{}, xerrors.Errorf("cannot parse hash: %w", err) return []byte{}, xerrors.Errorf("cannot parse hex value: %w", err)
} }
if len(b) > length {
return []byte{}, xerrors.Errorf("length of decoded bytes is longer than %d", length)
}
return b, nil return b, nil
} }
@ -399,7 +383,6 @@ func EthHashFromCid(c cid.Cid) (EthHash, error) {
} }
func ParseEthHash(s string) (EthHash, error) { func ParseEthHash(s string) (EthHash, error) {
handlePrefix(&s)
b, err := decodeHexString(s, EthHashLength) b, err := decodeHexString(s, EthHashLength)
if err != nil { if err != nil {
return EthHash{}, err return EthHash{}, err
@ -427,30 +410,6 @@ type EthFeeHistory struct {
Reward *[][]EthBigInt `json:"reward,omitempty"` Reward *[][]EthBigInt `json:"reward,omitempty"`
} }
type BlkNumType int64
const (
BlkNumLatest BlkNumType = iota
BlkNumPending
BlkNumVal
)
func ParseBlkNumOption(str string) (typ BlkNumType, blkNum EthUint64, err error) {
switch str {
case "pending":
return BlkNumPending, 0, nil
case "latest":
return BlkNumLatest, 0, nil
default:
var num EthUint64
err := num.UnmarshalJSON([]byte(`"` + str + `"`))
if err != nil {
return BlkNumVal, 0, err
}
return BlkNumVal, num, nil
}
}
type EthFilterID EthHash type EthFilterID EthHash
// An opaque identifier generated by the Lotus node to refer to an active subscription. // An opaque identifier generated by the Lotus node to refer to an active subscription.

View File

@ -2529,26 +2529,26 @@ Inputs:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
1, 0,
35, 0,
69, 0,
103, 0,
63, 0,
37, 0,
227, 0,
9, 0,
204, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
] ]
``` ```
@ -2583,26 +2583,26 @@ Inputs:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
1, 0,
35, 0,
69, 0,
103, 0,
63, 0,
37, 0,
227, 0,
9, 0,
204, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
] ]
``` ```
@ -2857,26 +2857,26 @@ Response:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
1, 0,
35, 0,
69, 0,
103, 0,
63, 0,
37, 0,
227, 0,
9, 0,
204, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
``` ```
@ -2914,26 +2914,26 @@ Response:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
1, 0,
35, 0,
69, 0,
103, 0,
63, 0,
37, 0,
227, 0,
9, 0,
204, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
``` ```
@ -2960,26 +2960,26 @@ Response:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
1, 0,
35, 0,
69, 0,
103, 0,
63, 0,
37, 0,
227, 0,
9, 0,
204, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
``` ```
@ -3048,26 +3048,26 @@ Response:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
249, 0,
157, 0,
63, 0,
219, 0,
48, 0,
18, 0,
52, 0,
86, 0,
124, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
], ],
"result": {} "result": {}
} }
@ -3095,26 +3095,26 @@ Inputs:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
1, 0,
35, 0,
69, 0,
103, 0,
63, 0,
37, 0,
227, 0,
9, 0,
204, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
] ]
``` ```
@ -3143,26 +3143,26 @@ Inputs:
0, 0,
0, 0,
0, 0,
92, 0,
190, 0,
236, 0,
249, 0,
157, 0,
63, 0,
219, 0,
48, 0,
18, 0,
52, 0,
86, 0,
124, 0,
38, 0,
79, 0,
36, 0,
11, 0,
176, 0,
102, 0,
64, 0,
49 0
] ]
] ]
``` ```

View File

@ -1431,30 +1431,25 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
// use that ID to form the masked ID address. // use that ID to form the masked ID address.
// 4. Otherwise, we fetch the actor's ID from the state tree and form the masked ID with it. // 4. Otherwise, we fetch the actor's ID from the state tree and form the masked ID with it.
func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (ethtypes.EthAddress, error) { func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (ethtypes.EthAddress, error) {
// Attempt to convert directly. // BLOCK A: We are trying to get an actual Ethereum address from an f410 address.
if ethAddr, ok, err := ethtypes.TryEthAddressFromFilecoinAddress(addr, false); err != nil { // Attempt to convert directly, if it's an f4 address.
return ethtypes.EthAddress{}, err ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr)
} else if ok { if err == nil && !ethAddr.IsMaskedID() {
return ethAddr, nil return ethAddr, nil
} }
// Lookup on the target actor. // Lookup on the target actor and try to get an f410 address.
actor, err := sa.StateGetActor(ctx, addr, types.EmptyTSK) if actor, err := sa.StateGetActor(ctx, addr, types.EmptyTSK); err != nil {
if err != nil {
return ethtypes.EthAddress{}, err return ethtypes.EthAddress{}, err
} } else if actor.Address != nil {
if actor.Address != nil { if ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address); err == nil && !ethAddr.IsMaskedID() {
if ethAddr, ok, err := ethtypes.TryEthAddressFromFilecoinAddress(*actor.Address, false); err != nil {
return ethtypes.EthAddress{}, err
} else if ok {
return ethAddr, nil return ethAddr, nil
} }
} }
// BLOCK B: We gave up on getting an actual Ethereum address and are falling back to a Masked ID address.
// Check if we already have an ID addr, and use it if possible. // Check if we already have an ID addr, and use it if possible.
if ethAddr, ok, err := ethtypes.TryEthAddressFromFilecoinAddress(addr, true); err != nil { if err == nil && ethAddr.IsMaskedID() {
return ethtypes.EthAddress{}, err
} else if ok {
return ethAddr, nil return ethAddr, nil
} }