Merge branch 'release/v1.20.0' into iand/eth-openrpc-validate

This commit is contained in:
Ian Davis 2023-01-26 11:35:33 +00:00
commit a9cd76907e
24 changed files with 313 additions and 40 deletions

View File

@ -473,7 +473,7 @@ jobs:
- run:
name: Docker push
command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>
docker push filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>>
if [[ ! -z $CIRCLE_SHA ]]; then
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>

View File

@ -473,7 +473,7 @@ jobs:
- run:
name: Docker push
command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>
docker push filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>>
if [["[[ ! -z $CIRCLE_SHA ]]"]]; then
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>

View File

@ -836,6 +836,9 @@ type FullNode interface {
// Unsubscribe from a websocket subscription
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) //perm:write
// Returns the client version
Web3ClientVersion(ctx context.Context) (string, error) //perm:read
// CreateBackup creates node backup onder the specified file name. The
// method requires that the lotus daemon is running with the
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that

View File

@ -41,4 +41,6 @@ func CreateEthRPCAliases(as apitypes.Aliaser) {
as.AliasMethod("net_version", "Filecoin.NetVersion")
as.AliasMethod("net_listening", "Filecoin.NetListening")
as.AliasMethod("web3_clientVersion", "Filecoin.Web3ClientVersion")
}

View File

@ -4096,3 +4096,18 @@ func (mr *MockFullNodeMockRecorder) WalletVerify(arg0, arg1, arg2, arg3 interfac
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WalletVerify", reflect.TypeOf((*MockFullNode)(nil).WalletVerify), arg0, arg1, arg2, arg3)
}
// Web3ClientVersion mocks base method.
func (m *MockFullNode) Web3ClientVersion(arg0 context.Context) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Web3ClientVersion", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Web3ClientVersion indicates an expected call of Web3ClientVersion.
func (mr *MockFullNodeMockRecorder) Web3ClientVersion(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Web3ClientVersion", reflect.TypeOf((*MockFullNode)(nil).Web3ClientVersion), arg0)
}

View File

@ -582,6 +582,8 @@ type FullNodeStruct struct {
WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"`
WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"`
Web3ClientVersion func(p0 context.Context) (string, error) `perm:"read"`
}
}
@ -3936,6 +3938,17 @@ func (s *FullNodeStub) WalletVerify(p0 context.Context, p1 address.Address, p2 [
return false, ErrNotSupported
}
func (s *FullNodeStruct) Web3ClientVersion(p0 context.Context) (string, error) {
if s.Internal.Web3ClientVersion == nil {
return "", ErrNotSupported
}
return s.Internal.Web3ClientVersion(p0)
}
func (s *FullNodeStub) Web3ClientVersion(p0 context.Context) (string, error) {
return "", ErrNotSupported
}
func (s *GatewayStruct) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) {
if s.Internal.ChainGetBlockMessages == nil {
return nil, ErrNotSupported

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,13 +12,11 @@ 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"
typescrypto "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
"github.com/filecoin-project/lotus/chain/types"
)
@ -63,6 +61,7 @@ func EthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
to *EthAddress
params []byte
paramsReader = bytes.NewReader(msg.Params)
err error
)
if msg.Version != 0 {
@ -72,11 +71,10 @@ func EthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
switch msg.Method {
case builtintypes.MethodsEAM.CreateExternal:
var create abi.CborBytes
if err := create.UnmarshalCBOR(paramsReader); err != nil {
return EthTxArgs{}, err
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
if err != nil {
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
}
params = create
default:
return EthTxArgs{}, fmt.Errorf("unsupported EAM method")
}
@ -103,11 +101,6 @@ func EthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
if err != nil {
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
}
if len(params) == 0 {
// Otherwise, we don't get a guaranteed round-trip.
return EthTxArgs{}, xerrors.Errorf("cannot invoke contracts with empty parameters from an eth-account")
}
}
}
@ -115,6 +108,11 @@ func EthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
}
if len(params) == 0 && msg.Method != builtintypes.MethodSend {
// Otherwise, we don't get a guaranteed round-trip.
return EthTxArgs{}, xerrors.Errorf("msgs with empty parameters from an eth-account must be Sends (MethodNum: %d)", msg.Method)
}
return EthTxArgs{
ChainID: build.Eip155ChainId,
Nonce: int(msg.Nonce),
@ -143,12 +141,13 @@ func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, er
if len(tx.Input) == 0 {
return nil, xerrors.New("cannot call CreateExternal without params")
}
inputParams := abi.CborBytes(tx.Input)
params, err = actors.SerializeParams(&inputParams)
if err != nil {
return nil, fmt.Errorf("failed to serialize Create params: %w", err)
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 {

View File

@ -291,7 +291,10 @@ func DumpActorState(i *ActorRegistry, act *types.Actor, b []byte) (interface{},
um := actInfo.vmActor.State()
if um == nil {
// TODO::FVM @arajasek I would like to assert that we have the empty object here
if act.Code != EmptyObjectCid {
return nil, xerrors.Errorf("actor with code %s should only have empty object (%s) as its Head, instead has %s", act.Code, EmptyObjectCid, act.Head)
}
return nil, nil
}
if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil {

View File

@ -1517,6 +1517,8 @@ func GetAsks(ctx context.Context, api lapi.FullNode) ([]QueriedAsk, error) {
}
}(miner)
}
wg.Wait()
}()
loop:
@ -1590,6 +1592,8 @@ loop:
lk.Unlock()
}(miner)
}
wg.Wait()
}()
loop2:

View File

@ -291,6 +291,8 @@
* [WalletSignMessage](#WalletSignMessage)
* [WalletValidateAddress](#WalletValidateAddress)
* [WalletVerify](#WalletVerify)
* [Web3](#Web3)
* [Web3ClientVersion](#Web3ClientVersion)
##
@ -9207,3 +9209,16 @@ Inputs:
Response: `true`
## Web3
### Web3ClientVersion
Returns the client version
Perms: read
Inputs: `null`
Response: `"string value"`

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5061025b806100206000396000f3fe60806040526004361061001e5760003560e01c8063cb7786d714610023575b600080fd5b61003d60048036038101906100389190610129565b61003f565b005b600083036100d15760008111156100cc573073ffffffffffffffffffffffffffffffffffffffff1663cb7786d7838460018561007b91906101ab565b6040518463ffffffff1660e01b8152600401610099939291906101ee565b600060405180830381600087803b1580156100b357600080fd5b505af11580156100c7573d6000803e3d6000fd5b505050505b6100e9565b6100e86001846100e191906101ab565b838361003f565b5b505050565b600080fd5b6000819050919050565b610106816100f3565b811461011157600080fd5b50565b600081359050610123816100fd565b92915050565b600080600060608486031215610142576101416100ee565b5b600061015086828701610114565b935050602061016186828701610114565b925050604061017286828701610114565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006101b6826100f3565b91506101c1836100f3565b92508282039050818111156101d9576101d861017c565b5b92915050565b6101e8816100f3565b82525050565b600060608201905061020360008301866101df565b61021060208301856101df565b61021d60408301846101df565b94935050505056fea26469706673582212209a21ff59c642e2970917c07bf498271c2a6df8e3929677952c0c2d8031db15cc64736f6c63430008110033

View File

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

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b50610162806100206000396000f3fe60806040526004361061001e5760003560e01c8063c38e07dd14610023575b600080fd5b61003d6004803603810190610038919061009c565b61003f565b005b600081031561005e5761005d60018261005891906100f8565b61003f565b5b50565b600080fd5b6000819050919050565b61007981610066565b811461008457600080fd5b50565b60008135905061009681610070565b92915050565b6000602082840312156100b2576100b1610061565b5b60006100c084828501610087565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061010382610066565b915061010e83610066565b9250828203905081811115610126576101256100c9565b5b9291505056fea2646970667358221220ee8f18bfd33b1e0156cfe68e9071dd32960b370c7e63ec53c62dd48e28cb5d3b64736f6c63430008110033

View File

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

View File

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

View File

@ -2,6 +2,7 @@ package itests
import (
"context"
"encoding/binary"
"encoding/hex"
"testing"
"time"
@ -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"
@ -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
}
@ -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, ex exitcode.ExitCode) func(t *testing.T) {
return func(t *testing.T) {
inputData := make([]byte, 32)
binary.BigEndian.PutUint64(inputData[24:], uint64(n))
client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256)", inputData, ex)
}
}
t.Run("n=0", testN(0, exitcode.Ok))
t.Run("n=1", testN(1, exitcode.Ok))
t.Run("n=20", testN(20, exitcode.Ok))
t.Run("n=200", testN(200, exitcode.Ok))
t.Run("n=507", testN(507, exitcode.Ok))
t.Run("n=508", testN(508, exitcode.ExitCode(23))) // 23 means stack overflow
}
// 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)))
}

View File

@ -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"
@ -113,6 +115,7 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, 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,
}
@ -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()

View File

@ -1,6 +1,7 @@
package kit
import (
"bytes"
"context"
"fmt"
"testing"
@ -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"
@ -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

View File

@ -118,4 +118,8 @@ func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtyp
return ethtypes.EthHash{}, ErrModuleDisabled
}
func (e *EthModuleDummy) Web3ClientVersion(ctx context.Context) (string, error) {
return "", ErrModuleDisabled
}
var _ EthModuleAPI = &EthModuleDummy{}

View File

@ -64,6 +64,7 @@ type EthModuleAPI interface {
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error)
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error)
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error)
Web3ClientVersion(ctx context.Context) (string, error)
}
type EthEventAPI interface {
@ -500,18 +501,8 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
return nil, fmt.Errorf("failed to construct system sender address: %w", err)
}
// TODO super duper hack (raulk). The EVM runtime actor uses the U256 parameter type in
// GetStorageAtParams, which serializes as a hex-encoded string. It should serialize
// as bytes. We didn't get to fix in time for Iron, so for now we just pass
// through the hex-encoded value passed through the Eth JSON-RPC API, by remarshalling it.
// We don't fix this at origin (builtin-actors) because we are not updating the bundle
// for Iron.
tmp, err := position.MarshalJSON()
if err != nil {
panic(err)
}
params, err := actors.SerializeParams(&evm.GetStorageAtParams{
StorageKey: tmp[1 : len(tmp)-1], // TODO strip the JSON-encoding quotes -- yuck
StorageKey: position,
})
if err != nil {
return nil, fmt.Errorf("failed to serialize parameters: %w", err)
@ -714,6 +705,10 @@ func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.Et
return ethtypes.EthHashFromTxBytes(rawTx), nil
}
func (a *EthModule) Web3ClientVersion(ctx context.Context) (string, error) {
return build.UserVersion(), nil
}
func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.EthCall) (*types.Message, error) {
var from address.Address
if tx.From == nil || *tx.From == (ethtypes.EthAddress{}) {
@ -827,8 +822,9 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et
func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
msg, err := a.ethCallToFilecoinMessage(ctx, tx)
if err != nil {
return nil, err
return nil, xerrors.Errorf("failed to convert ethcall to filecoin message: %w", err)
}
ts, err := a.parseBlkParam(ctx, blkParam)
if err != nil {
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
@ -836,11 +832,17 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam s
invokeResult, err := a.applyMessage(ctx, msg, ts.Key())
if err != nil {
return nil, err
return nil, xerrors.Errorf("failed to apply message: %w", err)
}
if len(invokeResult.MsgRct.Return) > 0 {
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
// As far as I can tell, the Eth API always returns empty on contract deployment
return ethtypes.EthBytes{}, nil
} else if len(invokeResult.MsgRct.Return) > 0 {
return cbg.ReadByteArray(bytes.NewReader(invokeResult.MsgRct.Return), uint64(len(invokeResult.MsgRct.Return)))
}
return ethtypes.EthBytes{}, nil
}