feat: use f4 eth addresses wherever possible (#9532)

Co-authored-by: Raúl Kripalani <raul@protocol.ai>
This commit is contained in:
Steven Allen 2022-10-21 04:13:16 -07:00 committed by vyzo
parent aa0e6c17b9
commit 56b238980b
4 changed files with 85 additions and 23 deletions

View File

@ -81,7 +81,7 @@ func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
}
}
if isCreate {
addr, err := EthAddressFromFilecoinIDAddress(msg.To)
addr, err := EthAddressFromFilecoinAddress(msg.To)
if err != nil {
return EthTxArgs{}, nil
}

View File

@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/go-state-types/builtin"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-multihash"
"github.com/multiformats/go-varint"
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
@ -292,15 +293,41 @@ func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
return addr, nil
}
func EthAddressFromFilecoinIDAddress(addr address.Address) (EthAddress, error) {
id, err := address.IDFromAddress(addr)
if err != nil {
return EthAddress{}, err
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 == builtin.EthereumAddressManagerActorID {
addr, err := EthAddressFromBytes(payload)
return addr, err == nil, err
}
}
var ethaddr EthAddress
ethaddr[0] = 0xff
binary.BigEndian.PutUint64(ethaddr[12:], id)
return ethaddr, nil
return EthAddress{}, false, nil
}
func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) {
ethAddr, ok, err := TryEthAddressFromFilecoinAddress(addr, true)
if !ok && err == nil {
err = xerrors.Errorf("failed to convert filecoin address %s to an equivalent eth address", addr)
}
return ethAddr, err
}
func EthAddressFromHex(s string) (EthAddress, error) {

View File

@ -119,7 +119,7 @@ func TestParseEthAddr(t *testing.T) {
addr, err := address.NewIDAddress(id)
require.Nil(t, err)
eaddr, err := EthAddressFromFilecoinIDAddress(addr)
eaddr, err := EthAddressFromFilecoinAddress(addr)
require.Nil(t, err)
faddr, err := eaddr.ToFilecoinAddress()

View File

@ -588,6 +588,50 @@ func (a *EthModule) ethBlockFromFilecoinTipSet(ctx context.Context, ts *types.Ti
return block, nil
}
// lookupEthAddress makes its best effort at finding the Ethereum address for a
// Filecoin address. It does the following:
//
// 1. If the supplied address is an f410 address, we return its payload as the EthAddress.
// 2. Otherwise (f0, f1, f2, f3), we look up the actor on the state tree. If it has a predictable address, we return it if it's f410 address.
// 3. Otherwise, we fall back to returning a masked ID Ethereum address. If the supplied address is an f0 address, we
// 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 (a *EthModule) lookupEthAddress(ctx context.Context, addr address.Address) (api.EthAddress, error) {
// Attempt to convert directly.
if ethAddr, ok, err := api.TryEthAddressFromFilecoinAddress(addr, false); err != nil {
return api.EthAddress{}, err
} else if ok {
return ethAddr, nil
}
// Lookup on the target actor.
actor, err := a.StateAPI.StateGetActor(ctx, addr, types.EmptyTSK)
if err != nil {
return api.EthAddress{}, err
}
if actor.Address != nil {
if ethAddr, ok, err := api.TryEthAddressFromFilecoinAddress(*actor.Address, false); err != nil {
return api.EthAddress{}, err
} else if ok {
return ethAddr, nil
}
}
// Check if we already have an ID addr, and use it if possible.
if ethAddr, ok, err := api.TryEthAddressFromFilecoinAddress(addr, true); err != nil {
return api.EthAddress{}, err
} else if ok {
return ethAddr, nil
}
// Otherwise, resolve the ID addr.
idAddr, err := a.StateAPI.StateLookupID(ctx, addr, types.EmptyTSK)
if err != nil {
return api.EthAddress{}, err
}
return api.EthAddressFromFilecoinAddress(idAddr)
}
func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup) (api.EthTx, error) {
if msgLookup == nil {
return api.EthTx{}, fmt.Errorf("msg does not exist")
@ -613,22 +657,12 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
return api.EthTx{}, err
}
fromFilIdAddr, err := a.StateAPI.StateLookupID(ctx, msg.From, types.EmptyTSK)
fromEthAddr, err := a.lookupEthAddress(ctx, msg.From)
if err != nil {
return api.EthTx{}, err
}
fromEthAddr, err := api.EthAddressFromFilecoinIDAddress(fromFilIdAddr)
if err != nil {
return api.EthTx{}, err
}
toFilAddr, err := a.StateAPI.StateLookupID(ctx, msg.To, types.EmptyTSK)
if err != nil {
return api.EthTx{}, err
}
toEthAddr, err := api.EthAddressFromFilecoinIDAddress(toFilAddr)
toEthAddr, err := a.lookupEthAddress(ctx, msg.To)
if err != nil {
return api.EthTx{}, err
}
@ -636,7 +670,8 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
toAddr := &toEthAddr
input := msg.Params
// Check to see if we need to decode as contract deployment.
if toFilAddr == builtintypes.EthereumAddressManagerActorAddr {
// We don't need to resolve the to address, because there's only one form (an ID).
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
switch msg.Method {
case builtintypes.MethodsEAM.Create:
toAddr = nil