Eth TX Encoding (#9531)

This commit is contained in:
Steven Allen 2022-10-21 03:59:09 -07:00 committed by vyzo
parent 57a515f7a8
commit aa0e6c17b9
7 changed files with 93 additions and 48 deletions

View File

@ -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 {
switch msg.Method {
case builtintypes.MethodsEAM.Create:
var create eam.CreateParams
if err := create.UnmarshalCBOR(paramsReader); err != nil {
return EthTxArgs{}, err
}
params = create2.Initcode
} else {
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
}
}
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,

View File

@ -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"

View File

@ -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

View File

@ -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)

2
go.mod
View File

@ -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

6
go.sum
View File

@ -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=

View File

@ -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 {
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
}