diff --git a/CHANGELOG.md b/CHANGELOG.md index f6c923fb2..6866631d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - feat: metric: export Mpool message count ([filecoin-project/lotus#11361](https://github.com/filecoin-project/lotus/pull/11361)) - feat: sealing: load SectorsSummary from sealing SectorStats instead of calling API each time ([filecoin-project/lotus#11353](https://github.com/filecoin-project/lotus/pull/11353)) - fix: miner info: Show correct sector state counts ([filecoin-project/lotus#11456](https://github.com/filecoin-project/lotus/pull/11456)) +- feat: add support for specifying block number when calling `eth_estimateGas` ([filecoin-project/lotus#11462](https://github.com/filecoin-project/lotus/pull/11462)). ## Improvements - fix: Add time slicing to splitstore purging step during compaction to reduce lock congestion [filecoin-project/lotus#11269](https://github.com/filecoin-project/lotus/pull/11269) diff --git a/api/api_full.go b/api/api_full.go index f919bc13b..4ae2ea531 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -824,7 +824,7 @@ type FullNode interface { EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) //perm:read EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read - EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) //perm:read + EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) //perm:read EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) //perm:read EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) //perm:read diff --git a/api/api_gateway.go b/api/api_gateway.go index 27e725457..238bf43ab 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -114,7 +114,7 @@ type Gateway interface { EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) - EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 856d83813..92b719550 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1042,7 +1042,7 @@ func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call { } // EthEstimateGas mocks base method. -func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 jsonrpc.RawParams) (ethtypes.EthUint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1) ret0, _ := ret[0].(ethtypes.EthUint64) diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 2d1333495..8adcbc189 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -255,7 +255,7 @@ type FullNodeMethods struct { EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` - EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `perm:"read"` + EthEstimateGas func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) `perm:"read"` EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `perm:"read"` @@ -679,7 +679,7 @@ type GatewayMethods struct { EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `` - EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `` + EthEstimateGas func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) `` EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `` @@ -2134,14 +2134,14 @@ func (s *FullNodeStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) { if s.Internal.EthEstimateGas == nil { return *new(ethtypes.EthUint64), ErrNotSupported } return s.Internal.EthEstimateGas(p0, p1) } -func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) { return *new(ethtypes.EthUint64), ErrNotSupported } @@ -4400,14 +4400,14 @@ func (s *GatewayStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (s *GatewayStruct) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) { if s.Internal.EthEstimateGas == nil { return *new(ethtypes.EthUint64), ErrNotSupported } return s.Internal.EthEstimateGas(p0, p1) } -func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthUint64, error) { return *new(ethtypes.EthUint64), ErrNotSupported } diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 29131b824..994266492 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index cf83f9390..2a3e5c939 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index b796e6f56..b933329f4 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -799,6 +799,45 @@ func GetContractEthAddressFromCode(sender EthAddress, salt [32]byte, initcode [] return ethAddr, nil } +// EthEstimateGasParams handles raw jsonrpc params for eth_estimateGas +type EthEstimateGasParams struct { + Tx EthCall + BlkParam *EthBlockNumberOrHash +} + +func (e *EthEstimateGasParams) UnmarshalJSON(b []byte) error { + var params []json.RawMessage + err := json.Unmarshal(b, ¶ms) + if err != nil { + return err + } + + switch len(params) { + case 2: + err = json.Unmarshal(params[1], &e.BlkParam) + if err != nil { + return err + } + fallthrough + case 1: + err = json.Unmarshal(params[0], &e.Tx) + if err != nil { + return err + } + default: + return xerrors.Errorf("expected 1 or 2 params, got %d", len(params)) + } + + return nil +} + +func (e EthEstimateGasParams) MarshalJSON() ([]byte, error) { + if e.BlkParam != nil { + return json.Marshal([]interface{}{e.Tx, e.BlkParam}) + } + return json.Marshal([]interface{}{e.Tx}) +} + // EthFeeHistoryParams handles raw jsonrpc params for eth_feeHistory type EthFeeHistoryParams struct { BlkCount EthUint64 diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index 1dae12101..c2929f0f5 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -2402,14 +2402,7 @@ Perms: read Inputs: ```json [ - { - "from": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - "to": "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - "gas": "0x5", - "gasPrice": "0x0", - "value": "0x0", - "data": "0x07" - } + "Bw==" ] ``` diff --git a/gateway/node.go b/gateway/node.go index 367e645c1..f2464d274 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -131,7 +131,7 @@ type TargetAPI interface { EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) - EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index e6d433a17..13a12acfa 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -353,13 +353,19 @@ func (gw *Node) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt return gw.target.EthMaxPriorityFeePerGas(ctx) } -func (gw *Node) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (gw *Node) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) { + // validate params + _, err := jsonrpc.DecodeParams[ethtypes.EthEstimateGasParams](p) + if err != nil { + return ethtypes.EthUint64(0), xerrors.Errorf("decoding params: %w", err) + } + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return 0, err } // todo limit gas? to what? - return gw.target.EthEstimateGas(ctx, tx) + return gw.target.EthEstimateGas(ctx, p) } func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { diff --git a/itests/eth_account_abstraction_test.go b/itests/eth_account_abstraction_test.go index 8d92d0a04..5ca672674 100644 --- a/itests/eth_account_abstraction_test.go +++ b/itests/eth_account_abstraction_test.go @@ -3,6 +3,7 @@ package itests import ( "context" "encoding/hex" + "encoding/json" "os" "testing" "time" @@ -272,10 +273,13 @@ func TestEthAccountAbstractionFailsFromEvmActor(t *testing.T) { contract, err := hex.DecodeString(string(contractHex)) require.NoError(t, err) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, Data: contract, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) diff --git a/itests/eth_conformance_test.go b/itests/eth_conformance_test.go index 15b249977..9c1b2ae34 100644 --- a/itests/eth_conformance_test.go +++ b/itests/eth_conformance_test.go @@ -35,7 +35,7 @@ type ethAPIRaw struct { EthBlockNumber func(context.Context) (json.RawMessage, error) EthCall func(context.Context, ethtypes.EthCall, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) EthChainId func(context.Context) (json.RawMessage, error) - EthEstimateGas func(context.Context, ethtypes.EthCall) (json.RawMessage, error) + EthEstimateGas func(context.Context, jsonrpc.RawParams) (json.RawMessage, error) EthFeeHistory func(context.Context, ethtypes.EthUint64, string, []float64) (json.RawMessage, error) EthGasPrice func(context.Context) (json.RawMessage, error) EthGetBalance func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) @@ -182,10 +182,13 @@ func TestEthOpenRPCConformance(t *testing.T) { { method: "eth_estimateGas", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthEstimateGas(context.Background(), ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: &senderEthAddr, Data: contractBin, - }) + }}) + require.NoError(t, err) + + return ethapi.EthEstimateGas(ctx, gasParams) }, }, @@ -448,10 +451,13 @@ func TestEthOpenRPCConformance(t *testing.T) { } func createRawSignedEthTx(ctx context.Context, t *testing.T, client *kit.TestFullNode, senderEthAddr ethtypes.EthAddress, receiverEthAddr ethtypes.EthAddress, senderKey *key.Key, contractBin []byte) []byte { - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: &senderEthAddr, Data: contractBin, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index ce4c94a28..68861f98f 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -60,10 +60,13 @@ func TestDeployment(t *testing.T) { // verify the deployer address is an Placeholder. client.AssertActorType(ctx, deployer, manifest.PlaceholderKey) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, Data: contract, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) diff --git a/itests/eth_hash_lookup_test.go b/itests/eth_hash_lookup_test.go index e1474a90d..0a2c11d3c 100644 --- a/itests/eth_hash_lookup_test.go +++ b/itests/eth_hash_lookup_test.go @@ -3,6 +3,7 @@ package itests import ( "context" "encoding/hex" + "encoding/json" "os" "testing" "time" @@ -47,10 +48,13 @@ func TestTransactionHashLookup(t *testing.T) { // send some funds to the f410 address kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, Data: contract, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) @@ -350,10 +354,13 @@ func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) { // send some funds to the f410 address kit.SendFunds(ctx, t, client, deployer, types.FromFil(10)) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, Data: contract, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) diff --git a/itests/eth_transactions_test.go b/itests/eth_transactions_test.go index 1fffc6618..9e9fb7b87 100644 --- a/itests/eth_transactions_test.go +++ b/itests/eth_transactions_test.go @@ -3,6 +3,7 @@ package itests import ( "context" "encoding/hex" + "encoding/json" "os" "testing" "time" @@ -47,12 +48,19 @@ func TestValueTransferValidSignature(t *testing.T) { kit.SendFunds(ctx, t, client, deployer, types.FromFil(1000)) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ - From: ðAddr, - Data: contract, + blkParam := ethtypes.NewEthBlockNumberOrHashFromPredefined("latest") + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{ + Tx: ethtypes.EthCall{ + From: ðAddr, + Data: contract, + }, + BlkParam: &blkParam, }) require.NoError(t, err) + gaslimit, err := client.EthEstimateGas(ctx, gasParams) + require.NoError(t, err) + maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) require.NoError(t, err) @@ -234,11 +242,14 @@ func TestContractInvocation(t *testing.T) { params, err := hex.DecodeString("f8b2cb4f000000000000000000000000ff00000000000000000000000000000000000064") require.NoError(t, err) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, To: &contractAddr, Data: params, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) @@ -353,10 +364,15 @@ func TestGetBlockByNumber(t *testing.T) { } func deployContractTx(ctx context.Context, client *kit.TestFullNode, ethAddr ethtypes.EthAddress, contract []byte) (*ethtypes.EthTxArgs, error) { - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, Data: contract, - }) + }}) + if err != nil { + return nil, err + } + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) if err != nil { return nil, err } diff --git a/itests/fevm_test.go b/itests/fevm_test.go index cb69c036c..2dcb8ef1d 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -6,6 +6,7 @@ import ( "crypto/rand" "encoding/binary" "encoding/hex" + "encoding/json" "fmt" "testing" "time" @@ -657,11 +658,15 @@ func TestFEVMRecursiveActorCallEstimate(t *testing.T) { t.Logf("running with %d recursive calls", r) params := makeParams(r) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: ðAddr, To: &contractAddr, Data: params, - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) require.LessOrEqual(t, int64(gaslimit), build.BlockGasLimit) @@ -816,11 +821,14 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) { contractEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr) require.NoError(t, err) - gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ From: &accntEth, To: &contractEth, Value: ethtypes.EthBigInt(big.NewInt(100)), - }) + }}) + require.NoError(t, err) + + gaslimit, err := client.EthEstimateGas(ctx, gasParams) require.NoError(t, err) maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx) @@ -1034,10 +1042,13 @@ func TestFEVMErrorParsing(t *testing.T) { require.ErrorContains(t, err, expected) }) t.Run("EthEstimateGas", func(t *testing.T) { - _, err := e.EthEstimateGas(ctx, ethtypes.EthCall{ + gasParams, err := json.Marshal(ethtypes.EthEstimateGasParams{Tx: ethtypes.EthCall{ To: &contractAddrEth, Data: entryPoint, - }) + }}) + require.NoError(t, err) + + _, err = e.EthEstimateGas(ctx, gasParams) require.ErrorContains(t, err, expected) }) }) diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 743eadf34..11ff95a63 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -122,7 +122,7 @@ func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, e return ethtypes.EthBigIntZero, ErrModuleDisabled } -func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { +func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) { return 0, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 22f78e723..d4298492f 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -66,7 +66,7 @@ type EthModuleAPI interface { NetListening(ctx context.Context) (bool, error) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) - EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) + EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) @@ -1007,8 +1007,13 @@ func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk ty return res, nil } -func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) { - msg, err := ethCallToFilecoinMessage(ctx, tx) +func (a *EthModule) EthEstimateGas(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthUint64, error) { + params, err := jsonrpc.DecodeParams[ethtypes.EthEstimateGasParams](p) + if err != nil { + return ethtypes.EthUint64(0), xerrors.Errorf("decoding params: %w", err) + } + + msg, err := ethCallToFilecoinMessage(ctx, params.Tx) if err != nil { return ethtypes.EthUint64(0), err } @@ -1017,7 +1022,16 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et // gas estimation actually run. msg.GasLimit = 0 - ts := a.Chain.GetHeaviestTipSet() + var ts *types.TipSet + if params.BlkParam == nil { + ts = a.Chain.GetHeaviestTipSet() + } else { + ts, err = getTipsetByEthBlockNumberOrHash(ctx, a.Chain, *params.BlkParam) + if err != nil { + return ethtypes.EthUint64(0), xerrors.Errorf("failed to process block param: %v; %w", params.BlkParam, err) + } + } + gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key()) if err != nil { // On failure, GasEstimateMessageGas doesn't actually return the invocation result,