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/hex"
"encoding/json"
"errors"
"fmt"
mathbig "math/big"
"strconv"
@ -30,6 +31,8 @@ var (
EthTopic4 = "topic4"
)
var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")
type EthUint64 uint64
func (e EthUint64) MarshalJSON() ([]byte, error) {
@ -249,21 +252,32 @@ func EthAddressFromPubKey(pubk []byte) ([]byte, error) {
}
func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) {
ethAddr, ok, err := TryEthAddressFromFilecoinAddress(addr, true)
if err != nil {
return EthAddress{}, xerrors.Errorf("failed to try converting filecoin to eth addr: %w", err)
switch addr.Protocol() {
case address.ID:
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)
}
}
if !ok {
return EthAddress{}, xerrors.Errorf("failed to convert filecoin address %s to an equivalent eth address", addr)
}
return ethAddr, nil
return EthAddress{}, ErrInvalidAddress
}
// ParseEthAddress parses an Ethereum address from a hex string.
func ParseEthAddress(s string) (EthAddress, error) {
handlePrefix(&s)
b, err := decodeHexString(s, EthAddressLength)
if err != nil {
return EthAddress{}, err
@ -304,9 +318,13 @@ func (ea *EthAddress) UnmarshalJSON(b []byte) error {
return nil
}
func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
func (ea EthAddress) IsMaskedID() bool {
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.
id := binary.BigEndian.Uint64(ea[12:])
return address.NewIDAddress(id)
@ -322,37 +340,6 @@ func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
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
func (h EthHash) MarshalJSON() ([]byte, error) {
@ -372,25 +359,22 @@ func (h *EthHash) UnmarshalJSON(b []byte) error {
return nil
}
func handlePrefix(s *string) {
if strings.HasPrefix(*s, "0x") || strings.HasPrefix(*s, "0X") {
*s = (*s)[2:]
func decodeHexString(s string, expectedLen int) ([]byte, error) {
// Strip the leading 0x or 0X prefix since hex.DecodeString does not support it.
if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
s = s[2:]
}
if len(*s)%2 == 1 {
*s = "0" + *s
// Sometimes clients will omit a leading zero in a byte; pad so we can decode correctly.
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)
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
}
@ -399,7 +383,6 @@ func EthHashFromCid(c cid.Cid) (EthHash, error) {
}
func ParseEthHash(s string) (EthHash, error) {
handlePrefix(&s)
b, err := decodeHexString(s, EthHashLength)
if err != nil {
return EthHash{}, err
@ -427,30 +410,6 @@ type EthFeeHistory struct {
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
// An opaque identifier generated by the Lotus node to refer to an active subscription.

View File

@ -2529,26 +2529,26 @@ Inputs:
0,
0,
0,
92,
190,
236,
1,
35,
69,
103,
63,
37,
227,
9,
204,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
]
```
@ -2583,26 +2583,26 @@ Inputs:
0,
0,
0,
92,
190,
236,
1,
35,
69,
103,
63,
37,
227,
9,
204,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
]
```
@ -2857,26 +2857,26 @@ Response:
0,
0,
0,
92,
190,
236,
1,
35,
69,
103,
63,
37,
227,
9,
204,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
```
@ -2914,26 +2914,26 @@ Response:
0,
0,
0,
92,
190,
236,
1,
35,
69,
103,
63,
37,
227,
9,
204,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
```
@ -2960,26 +2960,26 @@ Response:
0,
0,
0,
92,
190,
236,
1,
35,
69,
103,
63,
37,
227,
9,
204,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
```
@ -3048,26 +3048,26 @@ Response:
0,
0,
0,
92,
190,
236,
249,
157,
63,
219,
48,
18,
52,
86,
124,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"result": {}
}
@ -3095,26 +3095,26 @@ Inputs:
0,
0,
0,
92,
190,
236,
1,
35,
69,
103,
63,
37,
227,
9,
204,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
]
```
@ -3143,26 +3143,26 @@ Inputs:
0,
0,
0,
92,
190,
236,
249,
157,
63,
219,
48,
18,
52,
86,
124,
38,
79,
36,
11,
176,
102,
64,
49
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
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.
// 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) {
// Attempt to convert directly.
if ethAddr, ok, err := ethtypes.TryEthAddressFromFilecoinAddress(addr, false); err != nil {
return ethtypes.EthAddress{}, err
} else if ok {
// BLOCK A: We are trying to get an actual Ethereum address from an f410 address.
// Attempt to convert directly, if it's an f4 address.
ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr)
if err == nil && !ethAddr.IsMaskedID() {
return ethAddr, nil
}
// Lookup on the target actor.
actor, err := sa.StateGetActor(ctx, addr, types.EmptyTSK)
if err != nil {
// Lookup on the target actor and try to get an f410 address.
if actor, err := sa.StateGetActor(ctx, addr, types.EmptyTSK); err != nil {
return ethtypes.EthAddress{}, err
}
if actor.Address != nil {
if ethAddr, ok, err := ethtypes.TryEthAddressFromFilecoinAddress(*actor.Address, false); err != nil {
return ethtypes.EthAddress{}, err
} else if ok {
} else if actor.Address != nil {
if ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(*actor.Address); err == nil && !ethAddr.IsMaskedID() {
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.
if ethAddr, ok, err := ethtypes.TryEthAddressFromFilecoinAddress(addr, true); err != nil {
return ethtypes.EthAddress{}, err
} else if ok {
if err == nil && ethAddr.IsMaskedID() {
return ethAddr, nil
}