Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

itests: Test EAM interactions from accounts #10068

Merged
merged 2 commits into from
Jan 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions itests/contracts/RecCall.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
608060405234801561001057600080fd5b5061025b806100206000396000f3fe60806040526004361061001e5760003560e01c8063cb7786d714610023575b600080fd5b61003d60048036038101906100389190610129565b61003f565b005b600083036100d15760008111156100cc573073ffffffffffffffffffffffffffffffffffffffff1663cb7786d7838460018561007b91906101ab565b6040518463ffffffff1660e01b8152600401610099939291906101ee565b600060405180830381600087803b1580156100b357600080fd5b505af11580156100c7573d6000803e3d6000fd5b505050505b6100e9565b6100e86001846100e191906101ab565b838361003f565b5b505050565b600080fd5b6000819050919050565b610106816100f3565b811461011157600080fd5b50565b600081359050610123816100fd565b92915050565b600080600060608486031215610142576101416100ee565b5b600061015086828701610114565b935050602061016186828701610114565b925050604061017286828701610114565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006101b6826100f3565b91506101c1836100f3565b92508282039050818111156101d9576101d861017c565b5b92915050565b6101e8816100f3565b82525050565b600060608201905061020360008301866101df565b61021060208301856101df565b61021d60408301846101df565b94935050505056fea26469706673582212209a21ff59c642e2970917c07bf498271c2a6df8e3929677952c0c2d8031db15cc64736f6c63430008110033
16 changes: 16 additions & 0 deletions itests/contracts/RecCall.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract StackRecCall {
function exec1(uint256 n, uint256 m, uint256 r) public payable {
if(n == 0) {
if(r > 0) {
StackRecCall(address(this)).exec1(m, m, r-1);
}

return;
}

exec1(n-1, m, r);
}
}
1 change: 1 addition & 0 deletions itests/contracts/StackFunc.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001e5760003560e01c8063c38e07dd14610023575b600080fd5b61003d6004803603810190610038919061009c565b61003f565b005b600081031561005e5761005d60018261005891906100f8565b61003f565b5b50565b600080fd5b6000819050919050565b61007981610066565b811461008457600080fd5b50565b60008135905061009681610070565b92915050565b6000602082840312156100b2576100b1610061565b5b60006100c084828501610087565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061010382610066565b915061010e83610066565b9250828203905081811115610126576101256100c9565b5b9291505056fea2646970667358221220ee8f18bfd33b1e0156cfe68e9071dd32960b370c7e63ec53c62dd48e28cb5d3b64736f6c63430008110033
12 changes: 12 additions & 0 deletions itests/contracts/StackFunc.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

contract StackSelf {
function exec1(uint256 n) public payable {
if(n == 0) {
return;
}

exec1(n-1);
}
}
50 changes: 50 additions & 0 deletions itests/eth_account_abstraction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (

"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
builtin2 "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
"github.com/filecoin-project/go-state-types/exitcode"

"github.com/filecoin-project/lotus/api"
Expand Down Expand Up @@ -313,3 +315,51 @@ func TestEthAccountAbstractionFailsFromEvmActor(t *testing.T) {
require.Error(t, err, "expected gas estimation to fail")
require.Contains(t, err.Error(), "SysErrSenderInvalid")
}

func TestEthAccountManagerPermissions(t *testing.T) {
kit.QuietMiningLogs()

client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(10 * time.Millisecond)

ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

// setup f1/f3/f4 accounts

wsp, err := client.WalletNew(ctx, types.KTSecp256k1)
require.NoError(t, err)

wbl, err := client.WalletNew(ctx, types.KTBLS)
require.NoError(t, err)

wdl, err := client.WalletNew(ctx, types.KTDelegated)
require.NoError(t, err)

def := client.DefaultKey.Address

// send some funds
client.ExpectSend(ctx, def, wsp, types.FromFil(10), "")
client.ExpectSend(ctx, def, wbl, types.FromFil(10), "")
client.ExpectSend(ctx, def, wdl, types.FromFil(10), "")
require.NoError(t, err)

// make sure that EAM only allows CreateExternal to be called by accounts
client.ExpectSend(ctx, wsp, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create, &eam.CreateParams{Nonce: 0}))
client.ExpectSend(ctx, wbl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create, &eam.CreateParams{Nonce: 0}))
client.ExpectSend(ctx, wdl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create, &eam.CreateParams{Nonce: 0}))

client.ExpectSend(ctx, wsp, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create2, &eam.Create2Params{}))
client.ExpectSend(ctx, wbl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create2, &eam.Create2Params{}))
client.ExpectSend(ctx, wdl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "not one of supported (18)", client.MakeSendCall(builtin2.MethodsEAM.Create2, &eam.Create2Params{}))

contractHex, err := os.ReadFile("contracts/SimpleCoin.hex")
require.NoError(t, err)
contract, err := hex.DecodeString(string(contractHex))
require.NoError(t, err)
contractParams := abi.CborBytes(contract)

client.ExpectSend(ctx, wsp, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "", client.MakeSendCall(builtin2.MethodsEAM.CreateExternal, &contractParams))
client.ExpectSend(ctx, wbl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "", client.MakeSendCall(builtin2.MethodsEAM.CreateExternal, &contractParams))
client.ExpectSend(ctx, wdl, builtin2.EthereumAddressManagerActorAddr, big.Zero(), "", client.MakeSendCall(builtin2.MethodsEAM.CreateExternal, &contractParams))
}
81 changes: 79 additions & 2 deletions itests/fevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package itests

import (
"context"
"encoding/binary"
"encoding/hex"
"testing"
"time"
Expand All @@ -10,6 +11,7 @@ import (

"github.com/filecoin-project/go-address"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/go-state-types/manifest"

"github.com/filecoin-project/lotus/chain/types"
Expand Down Expand Up @@ -38,9 +40,9 @@ func inputDataFromFrom(ctx context.Context, t *testing.T, client *kit.TestFullNo

func setupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *kit.TestFullNode) {
kit.QuietMiningLogs()
blockTime := 100 * time.Millisecond
blockTime := 5 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ens.InterconnectAll().BeginMiningMustPost(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
return ctx, cancel, client
}
Expand Down Expand Up @@ -139,3 +141,78 @@ func TestEVMRpcDisable(t *testing.T) {
_, err := client.EthBlockNumber(context.Background())
require.ErrorContains(t, err, "module disabled, enable with Fevm.EnableEthRPC")
}

// TestFEVMRecursiveFuncCall deploys a contract and makes a recursive function calls
func TestFEVMRecursiveFuncCall(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
defer cancel()

//install contract Actor
filenameActor := "contracts/StackFunc.hex"
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)

testN := func(n int) func(t *testing.T) {
return func(t *testing.T) {
inputData := make([]byte, 32)
binary.BigEndian.PutUint64(inputData[24:], uint64(n))

result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "exec1(uint256)", inputData)
require.Equal(t, result, []byte{})
}
}

t.Run("n=0", testN(0))
t.Run("n=1", testN(1))
t.Run("n=20", testN(20))
t.Run("n=200", testN(200))
t.Run("n=293", testN(293))
}

// TestFEVMRecursiveActorCall deploys a contract and makes a recursive actor calls
func TestFEVMRecursiveActorCall(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
defer cancel()

//install contract Actor
filenameActor := "contracts/RecCall.hex"
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)

testN := func(n, r int, ex exitcode.ExitCode) func(t *testing.T) {
return func(t *testing.T) {
inputData := make([]byte, 32*3)
binary.BigEndian.PutUint64(inputData[24:], uint64(n))
binary.BigEndian.PutUint64(inputData[32+24:], uint64(n))
binary.BigEndian.PutUint64(inputData[32+32+24:], uint64(r))

client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256,uint256,uint256)", inputData, ex)
}
}

t.Run("n=0,r=1", testN(0, 1, exitcode.Ok))
t.Run("n=1,r=1", testN(1, 1, exitcode.Ok))
t.Run("n=20,r=1", testN(20, 1, exitcode.Ok))
t.Run("n=200,r=1", testN(200, 1, exitcode.Ok))
t.Run("n=251,r=1", testN(251, 1, exitcode.Ok))

t.Run("n=252,r=1-fails", testN(252, 1, exitcode.ExitCode(23))) // 23 means stack overflow

t.Run("n=0,r=10", testN(0, 10, exitcode.Ok))
t.Run("n=1,r=10", testN(1, 10, exitcode.Ok))
t.Run("n=20,r=10", testN(20, 10, exitcode.Ok))
t.Run("n=200,r=10", testN(200, 10, exitcode.Ok))
t.Run("n=251,r=10", testN(251, 10, exitcode.Ok))

t.Run("n=252,r=10-fails", testN(252, 10, exitcode.ExitCode(23)))

t.Run("n=0,r=32", testN(0, 32, exitcode.Ok))
t.Run("n=1,r=32", testN(1, 32, exitcode.Ok))
t.Run("n=20,r=32", testN(20, 32, exitcode.Ok))
t.Run("n=200,r=32", testN(200, 32, exitcode.Ok))
t.Run("n=251,r=32", testN(251, 32, exitcode.Ok))

t.Run("n=0,r=254", testN(0, 254, exitcode.Ok))
t.Run("n=251,r=170", testN(251, 170, exitcode.Ok))

t.Run("n=0,r=255-fails", testN(0, 255, exitcode.ExitCode(33))) // 33 means transaction reverted
t.Run("n=251,r=171-fails", testN(251, 171, exitcode.ExitCode(33)))
}
21 changes: 15 additions & 6 deletions itests/kit/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ import (
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/go-state-types/exitcode"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
Expand Down Expand Up @@ -109,11 +111,12 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target
params = buffer.Bytes()

msg := &types.Message{
To: target,
From: sender,
Value: big.Zero(),
Method: builtintypes.MethodsEVM.InvokeContract,
Params: params,
To: target,
From: sender,
Value: big.Zero(),
Method: builtintypes.MethodsEVM.InvokeContract,
GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041
Params: params,
}

e.t.Log("sending invoke message")
Expand Down Expand Up @@ -237,12 +240,18 @@ func (e *EVM) ComputeContractAddress(deployer ethtypes.EthAddress, nonce uint64)
func (e *EVM) InvokeContractByFuncName(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte) []byte {
entryPoint := CalcFuncSignature(funcSignature)
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.True(e.t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed")
require.True(e.t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed: %d", wait.Receipt.ExitCode)
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
require.NoError(e.t, err)
return result
}

func (e *EVM) InvokeContractByFuncNameExpectExit(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte, exit exitcode.ExitCode) {
entryPoint := CalcFuncSignature(funcSignature)
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.Equal(e.t, exit, wait.Receipt.ExitCode)
}

// function signatures are the first 4 bytes of the hash of the function name and types
func CalcFuncSignature(funcName string) []byte {
hasher := sha3.NewLegacyKeccak256()
Expand Down
47 changes: 47 additions & 0 deletions itests/kit/node_full.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package kit

import (
"bytes"
"context"
"fmt"
"testing"
Expand All @@ -10,9 +11,11 @@ import (
"github.com/libp2p/go-libp2p/core/peer"
"github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"
cbg "github.com/whyrusleeping/cbor-gen"

"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/exitcode"

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/api/v1api"
Expand Down Expand Up @@ -124,6 +127,50 @@ func (f *TestFullNode) AssignPrivKey(pkey *Libp2p) {
f.Pkey = pkey
}

type SendCall struct {
Method abi.MethodNum
Params []byte
}

func (f *TestFullNode) MakeSendCall(m abi.MethodNum, params cbg.CBORMarshaler) SendCall {
var b bytes.Buffer
err := params.MarshalCBOR(&b)
require.NoError(f.t, err)
return SendCall{
Method: m,
Params: b.Bytes(),
}
}

func (f *TestFullNode) ExpectSend(ctx context.Context, from, to address.Address, value types.BigInt, errContains string, sc ...SendCall) *types.SignedMessage {
msg := &types.Message{From: from, To: to, Value: value}

if len(sc) == 1 {
msg.Method = sc[0].Method
msg.Params = sc[0].Params
}

_, err := f.GasEstimateMessageGas(ctx, msg, nil, types.EmptyTSK)
if errContains != "" {
require.ErrorContains(f.t, err, errContains)
return nil
}
require.NoError(f.t, err)

if errContains == "" {
m, err := f.MpoolPushMessage(ctx, msg, nil)
require.NoError(f.t, err)

r, err := f.StateWaitMsg(ctx, m.Cid(), 1, api.LookbackNoLimit, true)
require.NoError(f.t, err)

require.Equal(f.t, exitcode.Ok, r.Receipt.ExitCode)
return m
}

return nil
}

// ChainPredicate encapsulates a chain condition.
type ChainPredicate func(set *types.TipSet) bool

Expand Down