diff --git a/api/eth_transactions.go b/api/eth_transactions.go index cd8ca1436..73aabcf51 100644 --- a/api/eth_transactions.go +++ b/api/eth_transactions.go @@ -6,10 +6,12 @@ import ( "fmt" mathbig "math/big" + cbg "github.com/whyrusleeping/cbor-gen" "golang.org/x/crypto/sha3" "github.com/filecoin-project/go-address" gocrypto "github.com/filecoin-project/go-crypto" + "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" builtintypes "github.com/filecoin-project/go-state-types/builtin" "github.com/filecoin-project/go-state-types/builtin/v8/eam" @@ -57,23 +59,38 @@ type EthTxArgs struct { func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) { var to *EthAddress - params := msg.Params + var decodedParams []byte + var isCreate bool + paramsReader := bytes.NewReader(msg.Params) if msg.To == builtintypes.EthereumAddressManagerActorAddr { - to = nil - - var create2 eam.Create2Params - reader := bytes.NewReader(msg.Params) - if err := create2.UnmarshalCBOR(reader); err != nil { - return EthTxArgs{}, err + switch msg.Method { + case builtintypes.MethodsEAM.Create: + var create eam.CreateParams + if err := create.UnmarshalCBOR(paramsReader); err != nil { + return EthTxArgs{}, err + } + decodedParams = create.Initcode + isCreate = true + case builtintypes.MethodsEAM.Create2: + var create2 eam.Create2Params + if err := create2.UnmarshalCBOR(paramsReader); err != nil { + return EthTxArgs{}, err + } + decodedParams = create2.Initcode + isCreate = true } - - params = create2.Initcode - } else { + } + if isCreate { addr, err := EthAddressFromFilecoinIDAddress(msg.To) if err != nil { return EthTxArgs{}, nil } to = &addr + params, err := cbg.ReadByteArray(paramsReader, uint64(len(msg.Params))) + if err != nil { + return EthTxArgs{}, err + } + decodedParams = params } return EthTxArgs{ @@ -81,7 +98,7 @@ func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) { Nonce: int(msg.Nonce), To: to, Value: msg.Value, - Input: params, + Input: decodedParams, MaxFeePerGas: msg.GasFeeCap, MaxPriorityFeePerGas: msg.GasPremium, GasLimit: int(msg.GasLimit), @@ -101,6 +118,7 @@ func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) { return nil, fmt.Errorf("to and input cannot both be empty") } + var method abi.MethodNum if tx.To == nil { // TODO https://github.com/filecoin-project/ref-fvm/issues/992 // TODO unify with applyEvmMsg @@ -119,13 +137,19 @@ func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) { return nil, fmt.Errorf("failed to serialize Create2 params: %w", err) } params = params2 + method = builtintypes.MethodsEAM.Create2 } else { addr, err := tx.To.ToFilecoinAddress() if err != nil { return nil, err } to = addr - params = tx.Input + var buf bytes.Buffer + if err := cbg.WriteByteArray(&buf, tx.Input); err != nil { + return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string") + } + params = buf.Bytes() + method = builtintypes.MethodsEVM.InvokeContract } msg := &types.Message{ @@ -133,7 +157,7 @@ func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) { From: from, To: to, Value: tx.Value, - Method: 2, + Method: method, Params: params, GasLimit: int64(tx.GasLimit), GasFeeCap: tx.MaxFeePerGas, diff --git a/api/eth_transactions_test.go b/api/eth_transactions_test.go index 0da6bddcc..100656414 100644 --- a/api/eth_transactions_test.go +++ b/api/eth_transactions_test.go @@ -63,7 +63,7 @@ func TestTxArgs(t *testing.T) { func TestTransformParams(t *testing.T) { constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{ - Bytecode: mustDecodeHex("0x1122334455"), + Initcode: mustDecodeHex("0x1122334455"), }) require.Nil(t, err) @@ -86,7 +86,7 @@ func TestTransformParams(t *testing.T) { err1 = evmParams.UnmarshalCBOR(reader1) require.Nil(t, err1) - require.Equal(t, mustDecodeHex("0x1122334455"), evmParams.Bytecode) + require.Equal(t, mustDecodeHex("0x1122334455"), evmParams.Initcode) } func TestEcRecover(t *testing.T) { rHex := "0x479ff7fa64cf8bf641eb81635d1e8a698530d2f219951d234539e6d074819529" diff --git a/api/eth_types.go b/api/eth_types.go index 4d2a3b720..e23d6fa7e 100644 --- a/api/eth_types.go +++ b/api/eth_types.go @@ -17,6 +17,9 @@ import ( "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/big" + + "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v8/eam" init8 "github.com/filecoin-project/go-state-types/builtin/v8/init" "github.com/filecoin-project/lotus/build" @@ -206,10 +209,14 @@ func NewEthTxReceipt(tx EthTx, lookup *MsgLookup, replay *InvocResult) (EthTxRec Logs: []string{}, } - contractAddr, err := CheckContractCreation(lookup) - if err == nil { - receipt.To = nil - receipt.ContractAddress = contractAddr + if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() { + // Create and Create2 return the same things. + var ret eam.CreateReturn + if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil { + return EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err) + } + addr := EthAddress(ret.EthAddress) + receipt.ContractAddress = &addr } if lookup.Receipt.ExitCode.IsSuccess() { @@ -229,21 +236,6 @@ func NewEthTxReceipt(tx EthTx, lookup *MsgLookup, replay *InvocResult) (EthTxRec return receipt, nil } -func CheckContractCreation(lookup *MsgLookup) (*EthAddress, error) { - if lookup.Receipt.ExitCode.IsError() { - return nil, xerrors.Errorf("message execution was not successful") - } - var result init8.ExecReturn - ret := bytes.NewReader(lookup.Receipt.Return) - if err := result.UnmarshalCBOR(ret); err == nil { - contractAddr, err := EthAddressFromFilecoinIDAddress(result.IDAddress) - if err == nil { - return &contractAddr, nil - } - } - return nil, xerrors.Errorf("not a contract creation tx") -} - const ( EthAddressLength = 20 EthHashLength = 32 diff --git a/cli/chain.go b/cli/chain.go index 7723c24bb..8efd009ef 100644 --- a/cli/chain.go +++ b/cli/chain.go @@ -1553,7 +1553,7 @@ var ChainExecEVMCmd = &cli.Command{ } constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{ - Bytecode: contract, + Initcode: contract, }) if err != nil { return xerrors.Errorf("failed to serialize constructor params: %w", err) diff --git a/go.mod b/go.mod index 897134699..8a14726c0 100644 --- a/go.mod +++ b/go.mod @@ -133,7 +133,7 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/urfave/cli/v2 v2.8.1 github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba - github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c + github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722 github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 diff --git a/go.sum b/go.sum index 3c77ac9ee..9f0111a8e 100644 --- a/go.sum +++ b/go.sum @@ -353,6 +353,8 @@ github.com/filecoin-project/go-state-types v0.1.11-0.20220929211033-a2339f216f21 github.com/filecoin-project/go-state-types v0.1.11-0.20220929211033-a2339f216f21/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-state-types v0.1.11-0.20221020121916-001de75ef54e h1:Bl8982sk/ZAfoPNszIddnqjfezOJmvyiuzjMR+YhqOY= github.com/filecoin-project/go-state-types v0.1.11-0.20221020121916-001de75ef54e/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= +github.com/filecoin-project/go-state-types v0.1.11-0.20221021072238-58379610cafe h1:Wmo0OMEslagGjLvRhlE64wOJIZaBGW01h1w1RATr2bo= +github.com/filecoin-project/go-state-types v0.1.11-0.20221021072238-58379610cafe/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q= github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig= github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc= github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54= @@ -1755,8 +1757,8 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20210118024343-169e9d70c0c2/go.mod h1:f github.com/whyrusleeping/cbor-gen v0.0.0-20210303213153-67a261a1d291/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20220302191723-37c43cae8e14/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/cbor-gen v0.0.0-20220323183124-98fa8256a799/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= -github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c h1:6VPKXBDRt7mDUyiHx9X8ROnPYFDf3L7OfEuKCI5dZDI= -github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= +github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722 h1:0HEhvpGQJ2Gd0ngPW83aduQQuF/V9v13+3zpSrR3lrA= +github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722/go.mod h1:fgkXqYy7bV2cFeIEOkVTZS/WjXARfBqSH6Q2qHL33hQ= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E= github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8= github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 h1:EKhdznlJHPMoKr0XTrX+IlJs1LH3lyx2nfr1dOlZ79k= diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index ae5c3fe79..f144a8529 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -15,6 +15,7 @@ import ( "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/big" builtintypes "github.com/filecoin-project/go-state-types/builtin" + "github.com/filecoin-project/go-state-types/builtin/v8/eam" "github.com/filecoin-project/go-state-types/builtin/v8/evm" init8 "github.com/filecoin-project/go-state-types/builtin/v8/init" "github.com/filecoin-project/specs-actors/actors/builtin" @@ -232,7 +233,7 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr api.EthAddress) (api From: from, To: to, Value: big.Zero(), - Method: abi.MethodNum(3), // GetBytecode + Method: builtintypes.MethodsEVM.GetBytecode, Params: nil, GasLimit: build.BlockGasLimit, GasFeeCap: big.Zero(), @@ -320,7 +321,7 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr api.EthAddress, From: from, To: to, Value: big.Zero(), - Method: abi.MethodNum(4), // GetStorageAt + Method: builtintypes.MethodsEVM.GetStorageAt, Params: params, GasLimit: build.BlockGasLimit, GasFeeCap: big.Zero(), @@ -448,7 +449,7 @@ func (a *EthModule) applyEvmMsg(ctx context.Context, tx api.EthCall) (*api.Invoc // https://github.com/filecoin-project/ref-fvm/issues/992 to = builtintypes.InitActorAddr constructorParams, err := actors.SerializeParams(&evm.ConstructorParams{ - Bytecode: tx.Data, + Initcode: tx.Data, }) if err != nil { return nil, fmt.Errorf("failed to serialize constructor params: %w", err) @@ -472,14 +473,18 @@ func (a *EthModule) applyEvmMsg(ctx context.Context, tx api.EthCall) (*api.Invoc return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) } to = addr - params = tx.Data + 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() } msg := &types.Message{ From: from, To: to, Value: big.Int(tx.Value), - Method: abi.MethodNum(2), + Method: builtintypes.MethodsEVM.InvokeContract, Params: params, GasLimit: build.BlockGasLimit, GasFeeCap: big.Zero(), @@ -523,7 +528,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx api.EthCall, blkParam string return nil, err } if len(invokeResult.MsgRct.Return) > 0 { - return invokeResult.MsgRct.Return, nil + return cbg.ReadByteArray(bytes.NewReader(invokeResult.MsgRct.Return), uint64(len(invokeResult.MsgRct.Return))) } return api.EthBytes{}, nil } @@ -629,9 +634,31 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku } toAddr := &toEthAddr - _, err = api.CheckContractCreation(msgLookup) - if err == nil { - toAddr = nil + input := msg.Params + // Check to see if we need to decode as contract deployment. + if toFilAddr == builtintypes.EthereumAddressManagerActorAddr { + switch msg.Method { + case builtintypes.MethodsEAM.Create: + toAddr = nil + var params eam.CreateParams + err = params.UnmarshalCBOR(bytes.NewReader(msg.Params)) + input = params.Initcode + case builtintypes.MethodsEAM.Create2: + toAddr = nil + var params eam.Create2Params + err = params.UnmarshalCBOR(bytes.NewReader(msg.Params)) + input = params.Initcode + } + if err != nil { + return api.EthTx{}, err + } + } + // Otherwise, try to decode as a cbor byte array. + // TODO: Actually check if this is an ethereum call. This code will work for demo purposes, but is not correct. + if toAddr != nil { + if decodedParams, err := cbg.ReadByteArray(bytes.NewReader(msg.Params), uint64(len(msg.Params))); err == nil { + input = decodedParams + } } tx := api.EthTx{ @@ -649,7 +676,7 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku V: api.EthBytes{}, R: api.EthBytes{}, S: api.EthBytes{}, - Input: msg.Params, + Input: input, } return tx, nil }