fix: eth: correctly convert filecoin message <-> eth txn (#10257)

1. We do allow deploying with empty initcode.
2. Make sure that the encoded "code" is non-empty, if specified.

Basically, this makes everything consistent (and it's how I specified it
in the FIP).
This commit is contained in:
Steven Allen 2023-02-13 10:33:59 -08:00 committed by GitHub
parent 03fd703db5
commit f427c2b566
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 57 deletions

View File

@ -12,6 +12,7 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
gocrypto "github.com/filecoin-project/go-crypto" gocrypto "github.com/filecoin-project/go-crypto"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big" "github.com/filecoin-project/go-state-types/big"
builtintypes "github.com/filecoin-project/go-state-types/builtin" builtintypes "github.com/filecoin-project/go-state-types/builtin"
typescrypto "github.com/filecoin-project/go-state-types/crypto" typescrypto "github.com/filecoin-project/go-state-types/crypto"
@ -99,7 +100,6 @@ func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
var ( var (
to *EthAddress to *EthAddress
params []byte params []byte
paramsReader = bytes.NewReader(msg.Params)
err error err error
) )
@ -107,14 +107,22 @@ func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version) return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version)
} }
if msg.To == builtintypes.EthereumAddressManagerActorAddr { if len(msg.Params) > 0 {
switch msg.Method { paramsReader := bytes.NewReader(msg.Params)
case builtintypes.MethodsEAM.CreateExternal:
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params))) params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
if err != nil { if err != nil {
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err) return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
} }
default: if paramsReader.Len() != 0 {
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
}
if len(params) == 0 {
return EthTxArgs{}, xerrors.Errorf("non-empty params encode empty byte array")
}
}
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
if msg.Method != builtintypes.MethodsEAM.CreateExternal {
return EthTxArgs{}, fmt.Errorf("unsupported EAM method") return EthTxArgs{}, fmt.Errorf("unsupported EAM method")
} }
} else if msg.Method == builtintypes.MethodsEVM.InvokeContract { } else if msg.Method == builtintypes.MethodsEVM.InvokeContract {
@ -123,23 +131,12 @@ func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
return EthTxArgs{}, err return EthTxArgs{}, err
} }
to = &addr to = &addr
if len(msg.Params) > 0 {
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
if err != nil {
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
}
}
} else { } else {
return EthTxArgs{}, return EthTxArgs{},
xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)", xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)",
msg.Method, builtintypes.MethodsEVM.InvokeContract) msg.Method, builtintypes.MethodsEVM.InvokeContract)
} }
if paramsReader.Len() != 0 {
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
}
return EthTxArgs{ return EthTxArgs{
ChainID: build.Eip155ChainId, ChainID: build.Eip155ChainId,
Nonce: int(msg.Nonce), Nonce: int(msg.Nonce),
@ -159,27 +156,6 @@ func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, er
var err error var err error
var params []byte var params []byte
var to address.Address
method := builtintypes.MethodsEVM.InvokeContract
// nil indicates the EAM, only CreateExternal is allowed
if tx.To == nil {
to = builtintypes.EthereumAddressManagerActorAddr
method = builtintypes.MethodsEAM.CreateExternal
if len(tx.Input) == 0 {
return nil, xerrors.New("cannot call CreateExternal without params")
}
buf := new(bytes.Buffer)
if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
return nil, xerrors.Errorf("failed to serialize Create params: %w", err)
}
params = buf.Bytes()
} else {
to, err = tx.To.ToFilecoinAddress()
if err != nil {
return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err)
}
if len(tx.Input) > 0 { if len(tx.Input) > 0 {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err = cbg.WriteByteArray(buf, tx.Input); err != nil { if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
@ -187,6 +163,19 @@ func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, er
} }
params = buf.Bytes() params = buf.Bytes()
} }
var to address.Address
var method abi.MethodNum
// nil indicates the EAM, only CreateExternal is allowed
if tx.To == nil {
method = builtintypes.MethodsEAM.CreateExternal
to = builtintypes.EthereumAddressManagerActorAddr
} else {
method = builtintypes.MethodsEVM.InvokeContract
to, err = tx.To.ToFilecoinAddress()
if err != nil {
return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err)
}
} }
return &types.Message{ return &types.Message{

View File

@ -751,18 +751,20 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
} }
var params []byte var params []byte
if len(tx.Data) > 0 {
initcode := abi.CborBytes(tx.Data)
params2, err := actors.SerializeParams(&initcode)
if err != nil {
return nil, fmt.Errorf("failed to serialize params: %w", err)
}
params = params2
}
var to address.Address var to address.Address
var method abi.MethodNum var method abi.MethodNum
if tx.To == nil { if tx.To == nil {
// this is a contract creation // this is a contract creation
to = builtintypes.EthereumAddressManagerActorAddr to = builtintypes.EthereumAddressManagerActorAddr
initcode := abi.CborBytes(tx.Data)
params2, err := actors.SerializeParams(&initcode)
if err != nil {
return nil, fmt.Errorf("failed to serialize Create params: %w", err)
}
params = params2
method = builtintypes.MethodsEAM.CreateExternal method = builtintypes.MethodsEAM.CreateExternal
} else { } else {
addr, err := tx.To.ToFilecoinAddress() addr, err := tx.To.ToFilecoinAddress()
@ -770,15 +772,6 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
} }
to = addr to = addr
if len(tx.Data) > 0 {
var buf bytes.Buffer
if err := cbg.WriteByteArray(&buf, tx.Data); err != nil {
return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string")
}
params = buf.Bytes()
}
method = builtintypes.MethodsEVM.InvokeContract method = builtintypes.MethodsEVM.InvokeContract
} }