Skip to content

Commit

Permalink
fix: correctly handle contract creation
Browse files Browse the repository at this point in the history
Also:

- Switch to methods from go-state-types
- Use the right method for contract creation
- Correctly handle decoding of contract creation returns
  • Loading branch information
Stebalien committed Oct 21, 2022
1 parent dae8b7e commit 92fd648
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 47 deletions.
35 changes: 24 additions & 11 deletions api/eth_transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"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"
Expand Down Expand Up @@ -58,19 +59,28 @@ type EthTxArgs struct {

func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
var to *EthAddress

paramsReader := bytes.NewReader(msg.Params)
var decodedParams []byte
var isCreate bool
paramsReader := bytes.NewReader(msg.Params)
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
to = nil

var create2 eam.Create2Params
if err := create2.UnmarshalCBOR(paramsReader); 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
}

decodedParams = create2.Initcode
} else {
}
if isCreate {
addr, err := EthAddressFromFilecoinIDAddress(msg.To)
if err != nil {
return EthTxArgs{}, nil
Expand Down Expand Up @@ -108,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
Expand All @@ -126,6 +137,7 @@ 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 {
Expand All @@ -137,14 +149,15 @@ func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) {
return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string")
}
params = buf.Bytes()
method = builtintypes.MethodsEVM.InvokeContract
}

msg := &types.Message{
Nonce: uint64(tx.Nonce),
From: from,
To: to,
Value: tx.Value,
Method: 2,
Method: method,
Params: params,
GasLimit: int64(tx.GasLimit),
GasFeeCap: tx.MaxFeePerGas,
Expand Down
4 changes: 2 additions & 2 deletions api/eth_transactions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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"
Expand Down
29 changes: 9 additions & 20 deletions api/eth_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/big"
"github.com/filecoin-project/go-state-types/builtin"
init8 "github.com/filecoin-project/go-state-types/builtin/v8/init"
"github.com/filecoin-project/go-state-types/builtin/v8/eam"

"github.com/filecoin-project/lotus/build"
)
Expand Down Expand Up @@ -206,10 +206,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() {
Expand All @@ -229,21 +233,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
Expand Down
2 changes: 1 addition & 1 deletion cli/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1811,7 +1811,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)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ require (
github.com/filecoin-project/go-legs v0.4.4
github.com/filecoin-project/go-padreader v0.0.1
github.com/filecoin-project/go-paramfetch v0.0.4
github.com/filecoin-project/go-state-types v0.1.11-0.20221020121916-001de75ef54e
github.com/filecoin-project/go-state-types v0.1.11-0.20221021072238-58379610cafe
github.com/filecoin-project/go-statemachine v1.0.2
github.com/filecoin-project/go-statestore v0.2.0
github.com/filecoin-project/go-storedcounter v0.1.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,8 @@ github.com/filecoin-project/go-state-types v0.1.5/go.mod h1:UwGVoMsULoCK+bWjEdd/
github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
github.com/filecoin-project/go-state-types v0.1.10/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-0.20220322104818-27f8fbb86dfd/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=
github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
Expand Down
41 changes: 31 additions & 10 deletions node/impl/full/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -483,7 +484,7 @@ func (a *EthModule) applyEvmMsg(ctx context.Context, tx api.EthCall) (*api.Invoc
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(),
Expand Down Expand Up @@ -633,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{
Expand All @@ -653,9 +676,7 @@ func (a *EthModule) ethTxFromFilecoinMessageLookup(ctx context.Context, msgLooku
V: api.EthBytes{},
R: api.EthBytes{},
S: api.EthBytes{},
// TODO: this will be wrong (both for contract creation, and for normal messages).
// Do we fix?
Input: msg.Params,
Input: input,
}
return tx, nil
}

0 comments on commit 92fd648

Please sign in to comment.