Skip to content

Commit

Permalink
clean up ethtypes: rationalize ethtypes.EthAddressFromFilecoinAddress…
Browse files Browse the repository at this point in the history
… and conversion methods (#9992)
  • Loading branch information
raulk authored Jan 12, 2023
1 parent 105a125 commit 3ef3239
Show file tree
Hide file tree
Showing 4 changed files with 211 additions and 257 deletions.
Binary file modified build/openrpc/full.json.gz
Binary file not shown.
123 changes: 41 additions & 82 deletions chain/types/ethtypes/eth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/binary"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
mathbig "math/big"
"strconv"
Expand All @@ -30,6 +31,8 @@ var (
EthTopic4 = "topic4"
)

var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")

type EthUint64 uint64

func (e EthUint64) MarshalJSON() ([]byte, error) {
Expand Down Expand Up @@ -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)
}

if !ok {
return EthAddress{}, xerrors.Errorf("failed to convert filecoin address %s to an equivalent eth address", addr)
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)
}
}

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
Expand Down Expand Up @@ -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)
Expand All @@ -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) {
Expand All @@ -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)
}

if len(b) > length {
return []byte{}, xerrors.Errorf("length of decoded bytes is longer than %d", length)
return []byte{}, xerrors.Errorf("cannot parse hex value: %w", err)
}

return b, nil
}

Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 3ef3239

Please sign in to comment.