From f358160cd5e1968b480c361db75592fe64dc422f Mon Sep 17 00:00:00 2001 From: Fridrik Asmundsson Date: Wed, 3 May 2023 17:24:36 +0000 Subject: [PATCH 1/3] Add EIP-1898 support needed for The Graph compatibility Fixes: #10814 This PR updates the following RPC methods according to EIP-1898 specs. The following RPC methods are affected: - eth_getBalance - eth_getStorageAt - eth_getTransactionCount - eth_getCode - eth_call Note that eth_getBlockByNumber was not included in this list in the spec although it seems it should be affected also? Currently these methods all accept a blkParam string which can be one of "latest", "earliest", "pending", or a block number (decimal or hex). The spec enables caller to additionally specify a json hash which can include the following fields: - blockNumber EthUint64: A block number (decimal or hex) which is similar to the original use of the blkParam string - blockHash EthHash: The block hash - requireCanonical bool) If true we should make sure the block is in the canonical chain Since the blkParam needs to support both being a number/string and a json hash then this to properly work we need to introduce a new struct with pointer fields to check if they exist. This is done in the EthBlockParamByNumberOrHash struct which first tries to unmarshal as a json hash (according to eip-1898) and then fallback to unmarshal as string/number. --- api/api_full.go | 52 +++++----- api/api_gateway.go | 10 +- api/docgen/docgen.go | 3 + api/mocks/mock_full.go | 10 +- api/proxy_gen.go | 60 ++++++------ build/openrpc/full.json.gz | Bin 33937 -> 34022 bytes build/openrpc/gateway.json.gz | Bin 10386 -> 10477 bytes chain/types/ethtypes/eth_types.go | 79 +++++++++++++++ cli/evm.go | 4 +- documentation/en/api-v1-unstable-methods.md | 40 +++++++- gateway/node.go | 10 +- gateway/proxy_eth.go | 56 ++++++++--- itests/eth_balance_test.go | 15 ++- itests/eth_bytecode_test.go | 16 ++-- itests/eth_conformance_test.go | 22 +++-- itests/eth_transactions_test.go | 2 +- itests/fevm_test.go | 8 +- itests/kit/evm.go | 2 +- node/impl/full/dummy.go | 10 +- node/impl/full/eth.go | 101 ++++++++++++++++---- 20 files changed, 357 insertions(+), 143 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index af62c3b0c42..cbf2b74359f 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -796,32 +796,32 @@ type FullNode interface { // EthGetBlockTransactionCountByHash returns the number of messages in the TipSet EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) //perm:read - EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read - EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read - EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read - EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read - EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read - EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read - EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read - EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) //perm:read - EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read - EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read - - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) //perm:read - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) //perm:read - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) //perm:read - EthChainId(ctx context.Context) (ethtypes.EthUint64, error) //perm:read - EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) //perm:read - NetVersion(ctx context.Context) (string, error) //perm:read - NetListening(ctx context.Context) (bool, error) //perm:read - EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) //perm:read - EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read - 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 - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) //perm:read + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read + EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read + EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read + EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) //perm:read + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read + EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) //perm:read + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read + + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) //perm:read + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) //perm:read + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) //perm:read + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) //perm:read + NetVersion(ctx context.Context) (string, error) //perm:read + NetListening(ctx context.Context) (bool, error) //perm:read + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read + 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 + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (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 97116d345f3..767918b10a0 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -94,12 +94,12 @@ type Gateway interface { EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) NetVersion(ctx context.Context) (string, error) @@ -109,7 +109,7 @@ type Gateway interface { 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) - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) diff --git a/api/docgen/docgen.go b/api/docgen/docgen.go index 5c1d4312970..01862960076 100644 --- a/api/docgen/docgen.go +++ b/api/docgen/docgen.go @@ -480,6 +480,9 @@ func ExampleValue(method string, t, parent reflect.Type) interface{} { es := exampleStruct(method, t.Elem(), t) ExampleValues[t] = es return es + } else if t.Elem().Kind() == reflect.String { + str := "string value" + return &str } case reflect.Interface: return struct{}{} diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 0b0e3ca4cd7..62ba66ccf2f 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1012,7 +1012,7 @@ func (mr *MockFullNodeMockRecorder) EthBlockNumber(arg0 interface{}) *gomock.Cal } // EthCall mocks base method. -func (m *MockFullNode) EthCall(arg0 context.Context, arg1 ethtypes.EthCall, arg2 string) (ethtypes.EthBytes, error) { +func (m *MockFullNode) EthCall(arg0 context.Context, arg1 ethtypes.EthCall, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthCall", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthBytes) @@ -1087,7 +1087,7 @@ func (mr *MockFullNodeMockRecorder) EthGasPrice(arg0 interface{}) *gomock.Call { } // EthGetBalance mocks base method. -func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthBigInt, error) { +func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetBalance", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthBigInt) @@ -1162,7 +1162,7 @@ func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByNumber(arg0, ar } // EthGetCode mocks base method. -func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthBytes, error) { +func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetCode", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthBytes) @@ -1237,7 +1237,7 @@ func (mr *MockFullNodeMockRecorder) EthGetMessageCidByTransactionHash(arg0, arg1 } // EthGetStorageAt mocks base method. -func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) { +func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetStorageAt", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(ethtypes.EthBytes) @@ -1312,7 +1312,7 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionByHashLimited(arg0, arg1, a } // EthGetTransactionCount mocks base method. -func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthUint64, error) { +func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetTransactionCount", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthUint64) diff --git a/api/proxy_gen.go b/api/proxy_gen.go index f2caab2669f..0f6c38b56f4 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -252,7 +252,7 @@ type FullNodeMethods struct { EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` - EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `perm:"read"` + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` @@ -262,7 +262,7 @@ type FullNodeMethods struct { EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"` - EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) `perm:"read"` + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) `perm:"read"` EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `perm:"read"` @@ -272,7 +272,7 @@ type FullNodeMethods struct { EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `perm:"read"` - EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) `perm:"read"` + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `perm:"read"` @@ -282,7 +282,7 @@ type FullNodeMethods struct { EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `perm:"read"` - EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"` + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"` @@ -292,7 +292,7 @@ type FullNodeMethods struct { EthGetTransactionByHashLimited func(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) `perm:"read"` - EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"` + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) `perm:"read"` EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"` @@ -668,7 +668,7 @@ type GatewayMethods struct { EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `` - EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `` + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `` EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `` @@ -678,7 +678,7 @@ type GatewayMethods struct { EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `` - EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) `` + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) `` EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `` @@ -688,7 +688,7 @@ type GatewayMethods struct { EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `` - EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) `` + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `` EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `` @@ -698,13 +698,13 @@ type GatewayMethods struct { EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `` - EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `` + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `` EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `` EthGetTransactionByHashLimited func(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) `` - EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `` + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) `` EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `` @@ -2091,14 +2091,14 @@ func (s *FullNodeStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, e return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { +func (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthCall == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthCall(p0, p1, p2) } -func (s *FullNodeStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { +func (s *FullNodeStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -2146,14 +2146,14 @@ func (s *FullNodeStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, erro return *new(ethtypes.EthBigInt), ErrNotSupported } -func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { +func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { if s.Internal.EthGetBalance == nil { return *new(ethtypes.EthBigInt), ErrNotSupported } return s.Internal.EthGetBalance(p0, p1, p2) } -func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { +func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { return *new(ethtypes.EthBigInt), ErrNotSupported } @@ -2201,14 +2201,14 @@ func (s *FullNodeStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { +func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetCode == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetCode(p0, p1, p2) } -func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { +func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -2256,14 +2256,14 @@ func (s *FullNodeStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 return nil, ErrNotSupported } -func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { +func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetStorageAt == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetStorageAt(p0, p1, p2, p3) } -func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { +func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -2311,14 +2311,14 @@ func (s *FullNodeStub) EthGetTransactionByHashLimited(p0 context.Context, p1 *et return nil, ErrNotSupported } -func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { +func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { if s.Internal.EthGetTransactionCount == nil { return *new(ethtypes.EthUint64), ErrNotSupported } return s.Internal.EthGetTransactionCount(p0, p1, p2) } -func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { +func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { return *new(ethtypes.EthUint64), ErrNotSupported } @@ -4313,14 +4313,14 @@ func (s *GatewayStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, er return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { +func (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthCall == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthCall(p0, p1, p2) } -func (s *GatewayStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) { +func (s *GatewayStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -4368,14 +4368,14 @@ func (s *GatewayStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error return *new(ethtypes.EthBigInt), ErrNotSupported } -func (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { +func (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { if s.Internal.EthGetBalance == nil { return *new(ethtypes.EthBigInt), ErrNotSupported } return s.Internal.EthGetBalance(p0, p1, p2) } -func (s *GatewayStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) { +func (s *GatewayStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { return *new(ethtypes.EthBigInt), ErrNotSupported } @@ -4423,14 +4423,14 @@ func (s *GatewayStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { +func (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetCode == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetCode(p0, p1, p2) } -func (s *GatewayStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) { +func (s *GatewayStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -4478,14 +4478,14 @@ func (s *GatewayStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 * return nil, ErrNotSupported } -func (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { +func (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetStorageAt == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetStorageAt(p0, p1, p2, p3) } -func (s *GatewayStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { +func (s *GatewayStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -4511,14 +4511,14 @@ func (s *GatewayStub) EthGetTransactionByHashLimited(p0 context.Context, p1 *eth return nil, ErrNotSupported } -func (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { +func (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { if s.Internal.EthGetTransactionCount == nil { return *new(ethtypes.EthUint64), ErrNotSupported } return s.Internal.EthGetTransactionCount(p0, p1, p2) } -func (s *GatewayStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) { +func (s *GatewayStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { return *new(ethtypes.EthUint64), ErrNotSupported } diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index 57f88c609cd631277593979c36a0fc1dab41ca12..a3891144b50ecb5106ffab8f035c8fbcd4a80184 100644 GIT binary patch literal 34022 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 JZ}cEa0svt9>b(E} diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index 64f67f662e0..dcb85fffe96 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -839,3 +839,82 @@ func (e EthFeeHistoryParams) MarshalJSON() ([]byte, error) { } return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum}) } + +type EthBlockParamByNumberOrHash struct { + PredefinedBlock *string + Number *EthUint64 + + BlockNumber *EthUint64 `json:"blockNumber,omitempty"` + BlockHash *EthHash `json:"blockHash,omitempty"` + RequireCanonical bool `json:"requireCanonical,omitempty"` +} + +func NewEthBlockParamFromPredefined(predefined string) EthBlockParamByNumberOrHash { + return EthBlockParamByNumberOrHash{ + PredefinedBlock: &predefined, + Number: nil, + BlockHash: nil, + RequireCanonical: false, + } +} + +func NewEthBlockParamFromNumber(number EthUint64) EthBlockParamByNumberOrHash { + return EthBlockParamByNumberOrHash{ + PredefinedBlock: nil, + Number: &number, + BlockHash: nil, + RequireCanonical: false, + } +} + +func NewEthBlockParamFromHexString(str string) (EthBlockParamByNumberOrHash, error) { + // check if block param is a number (decimal or hex) + var num EthUint64 = 0 + err := num.UnmarshalJSON([]byte(str)) + if err != nil { + return NewEthBlockParamFromNumber(0), err + } + + return EthBlockParamByNumberOrHash{ + PredefinedBlock: nil, + Number: &num, + BlockHash: nil, + RequireCanonical: false, + }, nil +} + +func (e *EthBlockParamByNumberOrHash) UnmarshalJSON(b []byte) error { + // we first try to unmarshal into a EthBlockParamByNumberOrHash struct to check + // if the block param is a block hash or block number (see EIP-1898). We use + // a temporary struct to avoid infinite recursion. + type tmpStruct EthBlockParamByNumberOrHash + var tmp tmpStruct + if err := json.Unmarshal(b, &tmp); err == nil { + if tmp.BlockNumber != nil && tmp.BlockHash != nil { + return errors.New("cannot specify both blockNumber and blockHash") + } + + *e = EthBlockParamByNumberOrHash(tmp) + return nil + } + + // check if block param is once of the special strings + var str string + err := json.Unmarshal(b, &str) + if err != nil { + return err + } + if str == "earliest" || str == "pending" || str == "latest" { + e.PredefinedBlock = &str + return nil + } + + // check if block param is a number (decimal or hex) + var num EthUint64 + if err := num.UnmarshalJSON(b); err == nil { + e.Number = &num + return nil + } + + return errors.New("invalid block param") +} diff --git a/cli/evm.go b/cli/evm.go index 84cbf8c61f6..e3dda864760 100644 --- a/cli/evm.go +++ b/cli/evm.go @@ -130,7 +130,7 @@ var EvmCallSimulateCmd = &cli.Command{ From: &fromEthAddr, To: &toEthAddr, Data: params, - }, "") + }, ethtypes.NewEthBlockParamFromPredefined("latest")) if err != nil { fmt.Println("Eth call fails, return val: ", res) return err @@ -518,7 +518,7 @@ var EvmGetBytecode = &cli.Command{ defer closer() ctx := ReqContext(cctx) - code, err := api.EthGetCode(ctx, contractAddr, "latest") + code, err := api.EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) if err != nil { return err } diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index e3c97eecf4d..a72c57d6154 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -2375,7 +2375,13 @@ Inputs: "value": "0x0", "data": "0x07" }, - "string value" + { + "PredefinedBlock": "string value", + "Number": "0x5", + "blockNumber": "0x5", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "requireCanonical": true + } ] ``` @@ -2455,7 +2461,13 @@ Inputs: ```json [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - "string value" + { + "PredefinedBlock": "string value", + "Number": "0x5", + "blockNumber": "0x5", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "requireCanonical": true + } ] ``` @@ -2588,7 +2600,13 @@ Inputs: ```json [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - "string value" + { + "PredefinedBlock": "string value", + "Number": "0x5", + "blockNumber": "0x5", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "requireCanonical": true + } ] ``` @@ -2691,7 +2709,13 @@ Inputs: [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", "0x07", - "string value" + { + "PredefinedBlock": "string value", + "Number": "0x5", + "blockNumber": "0x5", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "requireCanonical": true + } ] ``` @@ -2861,7 +2885,13 @@ Inputs: ```json [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - "string value" + { + "PredefinedBlock": "string value", + "Number": "0x5", + "blockNumber": "0x5", + "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", + "requireCanonical": true + } ] ``` diff --git a/gateway/node.go b/gateway/node.go index 6f1dac73ad5..b8eac8d7298 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -110,13 +110,13 @@ type TargetAPI interface { EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) NetVersion(ctx context.Context) (string, error) @@ -126,7 +126,7 @@ type TargetAPI interface { 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) - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index b992c9ea9af..275baa935ab 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -80,6 +80,38 @@ func (gw *Node) checkBlkHash(ctx context.Context, blkHash ethtypes.EthHash) erro return gw.checkTipsetKey(ctx, tsk) } +func (gw *Node) checkEthBlockParamByNumberOrHash(ctx context.Context, blkParam ethtypes.EthBlockParamByNumberOrHash, lookback ethtypes.EthUint64) error { + head, err := gw.target.ChainHead(ctx) + if err != nil { + return err + } + + var num ethtypes.EthUint64 = 0 + if blkParam.PredefinedBlock != nil { + if *blkParam.PredefinedBlock == "earliest" { + return fmt.Errorf("block param \"earliest\" is not supported") + } else if *blkParam.PredefinedBlock == "pending" || *blkParam.PredefinedBlock == "latest" { + // Head is always ok. + if lookback == 0 { + return nil + } + + if lookback <= ethtypes.EthUint64(head.Height()) { + num = ethtypes.EthUint64(head.Height()) - lookback + } + } + } else if blkParam.Number != nil { + num = *blkParam.Number + } else if blkParam.BlockHash != nil || blkParam.BlockNumber != nil { + return fmt.Errorf("block hash and block number are not supported") + } else { + return fmt.Errorf("invalid block param") + } + + return gw.checkTipsetHeight(head, abi.ChainEpoch(num)) + +} + func (gw *Node) checkBlkParam(ctx context.Context, blkParam string, lookback ethtypes.EthUint64) error { if blkParam == "earliest" { // also not supported in node impl @@ -178,16 +210,16 @@ func (gw *Node) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *e return gw.target.EthGetMessageCidByTransactionHash(ctx, txHash) } -func (gw *Node) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) { +func (gw *Node) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return 0, err } - if err := gw.checkBlkParam(ctx, blkOpt, 0); err != nil { + if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { return 0, err } - return gw.target.EthGetTransactionCount(ctx, sender, blkOpt) + return gw.target.EthGetTransactionCount(ctx, sender, blkParam) } func (gw *Node) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { @@ -208,36 +240,36 @@ func (gw *Node) EthGetTransactionReceiptLimited(ctx context.Context, txHash etht return gw.target.EthGetTransactionReceiptLimited(ctx, txHash, limit) } -func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) { +func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } - if err := gw.checkBlkParam(ctx, blkOpt, 0); err != nil { + if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { return nil, err } - return gw.target.EthGetCode(ctx, address, blkOpt) + return gw.target.EthGetCode(ctx, address, blkParam) } -func (gw *Node) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { +func (gw *Node) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } - if err := gw.checkBlkParam(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { return nil, err } return gw.target.EthGetStorageAt(ctx, address, position, blkParam) } -func (gw *Node) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { +func (gw *Node) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return ethtypes.EthBigInt(big.Zero()), err } - if err := gw.checkBlkParam(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { return ethtypes.EthBigInt(big.Zero()), err } @@ -332,12 +364,12 @@ func (gw *Node) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtyp return gw.target.EthEstimateGas(ctx, tx) } -func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { +func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } - if err := gw.checkBlkParam(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { return nil, err } diff --git a/itests/eth_balance_test.go b/itests/eth_balance_test.go index 1165879026d..cd6d1558b58 100644 --- a/itests/eth_balance_test.go +++ b/itests/eth_balance_test.go @@ -2,7 +2,6 @@ package itests import ( "context" - "strconv" "testing" "time" @@ -32,7 +31,7 @@ func TestEthGetBalanceExistingF4address(t *testing.T) { // send some funds to the f410 address kit.SendFunds(ctx, t, client, deployer, fundAmount) - balance, err := client.EthGetBalance(ctx, ethAddr, "latest") + balance, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, balance, ethtypes.EthBigInt{Int: fundAmount.Int}) } @@ -47,7 +46,7 @@ func TestEthGetBalanceNonExistentF4address(t *testing.T) { _, ethAddr, _ := client.EVM().NewAccount() - balance, err := client.EthGetBalance(ctx, ethAddr, "latest") + balance, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, balance, ethtypes.EthBigIntZero) } @@ -71,7 +70,7 @@ func TestEthGetBalanceExistentIDMaskedAddr(t *testing.T) { balance, err := client.WalletBalance(ctx, fid) require.NoError(t, err) - ebal, err := client.EthGetBalance(ctx, ethAddr, "latest") + ebal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ebal, ethtypes.EthBigInt{Int: balance.Int}) } @@ -93,7 +92,7 @@ func TestEthGetBalanceBuiltinActor(t *testing.T) { ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(fid) require.NoError(t, err) - ebal, err := client.EthGetBalance(ctx, ethAddr, "latest") + ebal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthBigInt{Int: big.NewInt(10).Int}, ebal) } @@ -130,15 +129,15 @@ func TestEthBalanceCorrectLookup(t *testing.T) { inclTsParents, err := client.ChainGetTipSet(ctx, inclTs.Parents()) require.NoError(t, err) - bal, err := client.EVM().EthGetBalance(ctx, ethAddr, strconv.FormatInt(int64(inclTsParents.Height()), 10)) + bal, err := client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(inclTsParents.Height())) require.NoError(t, err) require.Equal(t, int64(0), bal.Int64()) - bal, err = client.EVM().EthGetBalance(ctx, ethAddr, strconv.FormatInt(int64(inclTs.Height()), 10)) + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(inclTs.Height())) require.NoError(t, err) require.Equal(t, val, bal.Int64()) - bal, err = client.EVM().EthGetBalance(ctx, ethAddr, strconv.FormatInt(int64(execTs.Height()), 10)) + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(execTs.Height())) require.NoError(t, err) require.Equal(t, val, bal.Int64()) } diff --git a/itests/eth_bytecode_test.go b/itests/eth_bytecode_test.go index a8a75e83f7b..86048ff9118 100644 --- a/itests/eth_bytecode_test.go +++ b/itests/eth_bytecode_test.go @@ -33,12 +33,12 @@ func TestGetCodeAndNonce(t *testing.T) { { // A random eth address should have no code. _, ethAddr, filAddr := client.EVM().NewAccount() - bytecode, err := client.EVM().EthGetCode(ctx, ethAddr, "latest") + bytecode, err := client.EVM().EthGetCode(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Empty(t, bytecode) // Nonce should also be zero - nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest") + nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Zero(t, nonce) @@ -46,12 +46,12 @@ func TestGetCodeAndNonce(t *testing.T) { kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10)) // The code should still be empty, target is now a placeholder. - bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest") + bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Empty(t, bytecode) // Nonce should still be zero. - nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest") + nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Zero(t, nonce) } @@ -68,12 +68,12 @@ func TestGetCodeAndNonce(t *testing.T) { contractFilAddr := *createReturn.RobustAddress // The newly deployed contract should not be empty. - bytecode, err := client.EVM().EthGetCode(ctx, contractAddr, "latest") + bytecode, err := client.EVM().EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.NotEmpty(t, bytecode) // Nonce should be one. - nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest") + nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthUint64(1), nonce) @@ -82,12 +82,12 @@ func TestGetCodeAndNonce(t *testing.T) { require.NoError(t, err) // The code should be empty again. - bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest") + bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Empty(t, bytecode) // Nonce should go back to zero - nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest") + nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Zero(t, nonce) } diff --git a/itests/eth_conformance_test.go b/itests/eth_conformance_test.go index 4d8f5c3ddb0..2a899e968e5 100644 --- a/itests/eth_conformance_test.go +++ b/itests/eth_conformance_test.go @@ -33,25 +33,25 @@ import ( type ethAPIRaw struct { EthAccounts func(context.Context) (json.RawMessage, error) EthBlockNumber func(context.Context) (json.RawMessage, error) - EthCall func(context.Context, ethtypes.EthCall, string) (json.RawMessage, error) + EthCall func(context.Context, ethtypes.EthCall, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) EthChainId func(context.Context) (json.RawMessage, error) EthEstimateGas func(context.Context, ethtypes.EthCall) (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, string) (json.RawMessage, error) + EthGetBalance func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) EthGetBlockByHash func(context.Context, ethtypes.EthHash, bool) (json.RawMessage, error) EthGetBlockByNumber func(context.Context, string, bool) (json.RawMessage, error) EthGetBlockTransactionCountByHash func(context.Context, ethtypes.EthHash) (json.RawMessage, error) EthGetBlockTransactionCountByNumber func(context.Context, ethtypes.EthUint64) (json.RawMessage, error) - EthGetCode func(context.Context, ethtypes.EthAddress, string) (json.RawMessage, error) + EthGetCode func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) EthGetFilterChanges func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) EthGetFilterLogs func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) EthGetLogs func(context.Context, *ethtypes.EthFilterSpec) (json.RawMessage, error) - EthGetStorageAt func(context.Context, ethtypes.EthAddress, ethtypes.EthBytes, string) (json.RawMessage, error) + EthGetStorageAt func(context.Context, ethtypes.EthAddress, ethtypes.EthBytes, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) EthGetTransactionByBlockHashAndIndex func(context.Context, ethtypes.EthHash, ethtypes.EthUint64) (json.RawMessage, error) EthGetTransactionByBlockNumberAndIndex func(context.Context, ethtypes.EthUint64, ethtypes.EthUint64) (json.RawMessage, error) EthGetTransactionByHash func(context.Context, *ethtypes.EthHash) (json.RawMessage, error) - EthGetTransactionCount func(context.Context, ethtypes.EthAddress, string) (json.RawMessage, error) + EthGetTransactionCount func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) EthGetTransactionReceipt func(context.Context, ethtypes.EthHash) (json.RawMessage, error) EthMaxPriorityFeePerGas func(context.Context) (json.RawMessage, error) EthNewBlockFilter func(context.Context) (json.RawMessage, error) @@ -168,7 +168,7 @@ func TestEthOpenRPCConformance(t *testing.T) { return ethapi.EthCall(context.Background(), ethtypes.EthCall{ From: &senderEthAddr, Data: contractBin, - }, "latest") + }, ethtypes.NewEthBlockParamFromPredefined("latest")) }, }, @@ -207,7 +207,8 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getBalance", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthGetBalance(context.Background(), contractEthAddr, "0x0") + blockParam, _ := ethtypes.NewEthBlockParamFromHexString("0x0") + return ethapi.EthGetBalance(context.Background(), contractEthAddr, blockParam) }, }, @@ -261,7 +262,7 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getCode", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthGetCode(context.Background(), contractEthAddr, blockNumberWithMessage.Hex()) + return ethapi.EthGetCode(context.Background(), contractEthAddr, ethtypes.NewEthBlockParamFromNumber(blockNumberWithMessage)) }, }, @@ -307,7 +308,8 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getStorageAt", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthGetStorageAt(context.Background(), contractEthAddr, ethtypes.EthBytes{0}, "0x0") + blockParam, _ := ethtypes.NewEthBlockParamFromHexString("0x0") + return ethapi.EthGetStorageAt(context.Background(), contractEthAddr, ethtypes.EthBytes{0}, blockParam) }, }, @@ -338,7 +340,7 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getTransactionCount", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthGetTransactionCount(context.Background(), senderEthAddr, blockNumberWithMessage.Hex()) + return ethapi.EthGetTransactionCount(context.Background(), senderEthAddr, ethtypes.NewEthBlockParamFromNumber(blockNumberWithMessage)) }, }, diff --git a/itests/eth_transactions_test.go b/itests/eth_transactions_test.go index 8d0df043351..eb900c7fb56 100644 --- a/itests/eth_transactions_test.go +++ b/itests/eth_transactions_test.go @@ -316,7 +316,7 @@ func TestGetBlockByNumber(t *testing.T) { // Fetch balance on a null round; should not fail and should return previous balance. // Should be lower than original balance. - bal, err := client.EthGetBalance(ctx, ethAddr, (ethtypes.EthUint64(afterNullHeight - 1)).Hex()) + bal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(afterNullHeight-1))) require.NoError(t, err) require.NotEqual(t, big.Zero(), bal) require.Equal(t, types.FromFil(10).Int, bal.Int) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 9b6dba92c00..7051bb0dfb9 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -268,14 +268,14 @@ func TestFEVMDelegateCall(t *testing.T) { // The implementation's storage should not have been updated. actorAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr) require.NoError(t, err) - value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, "latest") + value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthBytes(make([]byte, 32)), value) // The storage actor's storage _should_ have been updated storageAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(storageAddr) require.NoError(t, err) - value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, "latest") + value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthBytes(expectedResult), value) } @@ -881,7 +881,7 @@ func TestFEVMTestDeployOnTransfer(t *testing.T) { require.NoError(t, err) require.True(t, ret.Receipt.ExitCode.IsSuccess()) - balance, err := client.EVM().EthGetBalance(ctx, randomAddr, "latest") + balance, err := client.EVM().EthGetBalance(ctx, randomAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(t, err) require.Equal(t, value.Int, balance.Int) @@ -1030,7 +1030,7 @@ func TestFEVMErrorParsing(t *testing.T) { _, err := e.EthCall(ctx, ethtypes.EthCall{ To: &contractAddrEth, Data: entryPoint, - }, "latest") + }, ethtypes.NewEthBlockParamFromPredefined("latest")) require.ErrorContains(t, err, expected) }) t.Run("EthEstimateGas", func(t *testing.T) { diff --git a/itests/kit/evm.go b/itests/kit/evm.go index c8904ab15cb..9b929998063 100644 --- a/itests/kit/evm.go +++ b/itests/kit/evm.go @@ -199,7 +199,7 @@ func (e *EVM) AssertAddressBalanceConsistent(ctx context.Context, addr address.A ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr) require.NoError(e.t, err) - ebal, err := e.EthGetBalance(ctx, ethAddr, "latest") + ebal, err := e.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) require.NoError(e.t, err) require.Equal(e.t, fbal, types.BigInt(ebal)) diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 918e84d1081..636732416b6 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -62,7 +62,7 @@ func (e *EthModuleDummy) EthGetTransactionByHashLimited(ctx context.Context, txH return nil, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) { +func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { return 0, ErrModuleDisabled } @@ -82,15 +82,15 @@ func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Cont return ethtypes.EthTx{}, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) { +func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return nil, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { +func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return nil, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { +func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { return ethtypes.EthBigIntZero, ErrModuleDisabled } @@ -126,7 +126,7 @@ func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall return 0, ErrModuleDisabled } -func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { +func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { return nil, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index 38c3a88d1fe..cee222683ee 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -59,12 +59,12 @@ type EthModuleAPI interface { EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) @@ -73,7 +73,7 @@ type EthModuleAPI interface { EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) + EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (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) @@ -241,7 +241,76 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthH return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI) } -func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string, strict bool) (tipset *types.TipSet, err error) { +func (a *EthModule) getTipsetByEthBlockNumberOrHash(ctx context.Context, blkParam ethtypes.EthBlockParamByNumberOrHash) (*types.TipSet, error) { + head := a.Chain.GetHeaviestTipSet() + + predefined := blkParam.PredefinedBlock + if predefined != nil { + if *predefined == "earliest" { + return nil, fmt.Errorf("block param \"earliest\" is not supported") + } else if *predefined == "pending" { + return head, nil + } else if *predefined == "latest" { + parent, err := a.Chain.GetTipSetFromKey(ctx, head.Parents()) + if err != nil { + return nil, fmt.Errorf("cannot get parent tipset") + } + return parent, nil + } else { + return nil, fmt.Errorf("unknown predefined block %s", *predefined) + } + } + + // utility function to validate a tipset by height and return it + returnAndValidateTipsetFunc := func(height abi.ChainEpoch) (*types.TipSet, error) { + if height > head.Height()-1 { + return nil, fmt.Errorf("requested a future epoch (beyond 'latest')") + } + ts, err := a.ChainAPI.ChainGetTipSetByHeight(ctx, height, head.Key()) + if err != nil { + return nil, fmt.Errorf("cannot get tipset at height: %v", height) + } + return ts, nil + } + + if blkParam.Number != nil { + return returnAndValidateTipsetFunc(abi.ChainEpoch(*blkParam.Number)) + } + + if blkParam.BlockNumber != nil { + return returnAndValidateTipsetFunc(abi.ChainEpoch(*blkParam.BlockNumber)) + } + + if blkParam.BlockHash != nil { + ts, err := a.Chain.GetTipSetByCid(ctx, blkParam.BlockHash.ToCid()) + if err != nil { + return nil, fmt.Errorf("cannot get tipset by hash: %v", err) + } + + if blkParam.RequireCanonical { + // walk back the current chain (our head) until we reach targetHeight and validate the block hash + currTs := head + for { + if currTs.Equals(ts) { + return ts, nil + } else if currTs.Height() < ts.Height() { + return nil, fmt.Errorf("could not find block hash %s in canonical chain", blkParam.BlockHash.ToCid()) + } + + currTs, err = a.Chain.LoadTipSet(ctx, currTs.Parents()) + if err != nil { + return nil, fmt.Errorf("failed to load tipset: %v", err) + } + } + } + + return ts, nil + } + + return nil, errors.New("invalid block param") +} + +func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string, strict bool) (*types.TipSet, error) { if blkParam == "earliest" { return nil, fmt.Errorf("block param \"earliest\" is not supported") } @@ -382,13 +451,13 @@ func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) return &hash, err } -func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) { +func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { addr, err := sender.ToFilecoinAddress() if err != nil { return ethtypes.EthUint64(0), nil } - ts, err := a.parseBlkParam(ctx, blkParam, false) + ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { return ethtypes.EthUint64(0), xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) } @@ -470,13 +539,13 @@ func (a *EthAPI) EthGetTransactionByBlockNumberAndIndex(context.Context, ethtype } // EthGetCode returns string value of the compiled bytecode -func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam string) (ethtypes.EthBytes, error) { +func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { to, err := ethAddr.ToFilecoinAddress() if err != nil { return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) } - ts, err := a.parseBlkParam(ctx, blkParam, false) + ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) } @@ -554,8 +623,8 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, return blk.RawData(), nil } -func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) { - ts, err := a.parseBlkParam(ctx, blkParam, false) +func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { + ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) } @@ -645,13 +714,13 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd return ethtypes.EthBytes(ret), nil } -func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) { +func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { filAddr, err := address.ToFilecoinAddress() if err != nil { return ethtypes.EthBigInt{}, err } - ts, err := a.parseBlkParam(ctx, blkParam, false) + ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { return ethtypes.EthBigInt{}, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) } @@ -1112,13 +1181,13 @@ func ethGasSearch( return -1, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error) } -func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) { +func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { msg, err := a.ethCallToFilecoinMessage(ctx, tx) if err != nil { return nil, xerrors.Errorf("failed to convert ethcall to filecoin message: %w", err) } - ts, err := a.parseBlkParam(ctx, blkParam, false) + ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) } From eed38a3c21abb71b951fce2a9b7a06efe0eb2a00 Mon Sep 17 00:00:00 2001 From: Fridrik Asmundsson Date: Wed, 21 Jun 2023 15:34:39 +0000 Subject: [PATCH 2/3] Fix lint errors --- itests/eth_balance_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/itests/eth_balance_test.go b/itests/eth_balance_test.go index cd6d1558b58..3a2f5cd4b39 100644 --- a/itests/eth_balance_test.go +++ b/itests/eth_balance_test.go @@ -129,15 +129,15 @@ func TestEthBalanceCorrectLookup(t *testing.T) { inclTsParents, err := client.ChainGetTipSet(ctx, inclTs.Parents()) require.NoError(t, err) - bal, err := client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(inclTsParents.Height())) + bal, err := client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(inclTsParents.Height()))) require.NoError(t, err) require.Equal(t, int64(0), bal.Int64()) - bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(inclTs.Height())) + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(inclTs.Height()))) require.NoError(t, err) require.Equal(t, val, bal.Int64()) - bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(execTs.Height())) + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(execTs.Height()))) require.NoError(t, err) require.Equal(t, val, bal.Int64()) } From dda2d7e0235a3ff85c59f795217d227d0942fa3d Mon Sep 17 00:00:00 2001 From: Fridrik Asmundsson Date: Wed, 21 Jun 2023 17:36:04 +0000 Subject: [PATCH 3/3] Refactor EthBlockNumberOrHash and remove the number field --- api/api_full.go | 52 +++++++------- api/api_gateway.go | 10 +-- api/mocks/mock_full.go | 10 +-- api/proxy_gen.go | 60 ++++++++-------- build/openrpc/full.json.gz | Bin 34022 -> 33969 bytes build/openrpc/gateway.json.gz | Bin 10477 -> 10425 bytes chain/types/ethtypes/eth_types.go | 47 ++++++++----- cli/evm.go | 4 +- documentation/en/api-v1-unstable-methods.md | 40 ++--------- gateway/node.go | 10 +-- gateway/proxy_eth.go | 73 +++++++++++--------- itests/eth_balance_test.go | 14 ++-- itests/eth_bytecode_test.go | 16 ++--- itests/eth_conformance_test.go | 20 +++--- itests/eth_transactions_test.go | 2 +- itests/fevm_test.go | 8 +-- itests/kit/evm.go | 2 +- node/impl/full/dummy.go | 10 +-- node/impl/full/eth.go | 65 ++++++++--------- 19 files changed, 209 insertions(+), 234 deletions(-) diff --git a/api/api_full.go b/api/api_full.go index cbf2b74359f..591799b4883 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -796,32 +796,32 @@ type FullNode interface { // EthGetBlockTransactionCountByHash returns the number of messages in the TipSet EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) //perm:read - EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read - EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read - EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read - EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read - EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read - EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) //perm:read - EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read - EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) //perm:read - EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read - EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read - - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) //perm:read - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) //perm:read - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) //perm:read - EthChainId(ctx context.Context) (ethtypes.EthUint64, error) //perm:read - EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) //perm:read - NetVersion(ctx context.Context) (string, error) //perm:read - NetListening(ctx context.Context) (bool, error) //perm:read - EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) //perm:read - EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read - 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 - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) //perm:read + EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read + EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read + EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read + EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) //perm:read + EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read + EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) //perm:read + EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read + EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) //perm:read + EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read + EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read + + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) //perm:read + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) //perm:read + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) //perm:read + EthChainId(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) //perm:read + NetVersion(ctx context.Context) (string, error) //perm:read + NetListening(ctx context.Context) (bool, error) //perm:read + EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) //perm:read + EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read + 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 + 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 767918b10a0..f6740e1e067 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -94,12 +94,12 @@ type Gateway interface { EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*EthTxReceipt, error) - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) NetVersion(ctx context.Context) (string, error) @@ -109,7 +109,7 @@ type Gateway interface { 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) - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, 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) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index 62ba66ccf2f..a1e9c123015 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1012,7 +1012,7 @@ func (mr *MockFullNodeMockRecorder) EthBlockNumber(arg0 interface{}) *gomock.Cal } // EthCall mocks base method. -func (m *MockFullNode) EthCall(arg0 context.Context, arg1 ethtypes.EthCall, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (m *MockFullNode) EthCall(arg0 context.Context, arg1 ethtypes.EthCall, arg2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthCall", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthBytes) @@ -1087,7 +1087,7 @@ func (mr *MockFullNodeMockRecorder) EthGasPrice(arg0 interface{}) *gomock.Call { } // EthGetBalance mocks base method. -func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetBalance", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthBigInt) @@ -1162,7 +1162,7 @@ func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByNumber(arg0, ar } // EthGetCode mocks base method. -func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetCode", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthBytes) @@ -1237,7 +1237,7 @@ func (mr *MockFullNodeMockRecorder) EthGetMessageCidByTransactionHash(arg0, arg1 } // EthGetStorageAt mocks base method. -func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetStorageAt", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(ethtypes.EthBytes) @@ -1312,7 +1312,7 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionByHashLimited(arg0, arg1, a } // EthGetTransactionCount mocks base method. -func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "EthGetTransactionCount", arg0, arg1, arg2) ret0, _ := ret[0].(ethtypes.EthUint64) diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 0f6c38b56f4..ce4ec3d1e34 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -252,7 +252,7 @@ type FullNodeMethods struct { EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` - EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"` @@ -262,7 +262,7 @@ type FullNodeMethods struct { EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"` - EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) `perm:"read"` + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) `perm:"read"` EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `perm:"read"` @@ -272,7 +272,7 @@ type FullNodeMethods struct { EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `perm:"read"` - EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `perm:"read"` @@ -282,7 +282,7 @@ type FullNodeMethods struct { EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `perm:"read"` - EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `perm:"read"` EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"` @@ -292,7 +292,7 @@ type FullNodeMethods struct { EthGetTransactionByHashLimited func(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) `perm:"read"` - EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) `perm:"read"` + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) `perm:"read"` EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"` @@ -668,7 +668,7 @@ type GatewayMethods struct { EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `` - EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `` + EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `` EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `` @@ -678,7 +678,7 @@ type GatewayMethods struct { EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `` - EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) `` + EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) `` EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `` @@ -688,7 +688,7 @@ type GatewayMethods struct { EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `` - EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `` + EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `` EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `` @@ -698,13 +698,13 @@ type GatewayMethods struct { EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `` - EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) `` + EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) `` EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `` EthGetTransactionByHashLimited func(p0 context.Context, p1 *ethtypes.EthHash, p2 abi.ChainEpoch) (*ethtypes.EthTx, error) `` - EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) `` + EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) `` EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `` @@ -2091,14 +2091,14 @@ func (s *FullNodeStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, e return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthCall == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthCall(p0, p1, p2) } -func (s *FullNodeStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *FullNodeStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -2146,14 +2146,14 @@ func (s *FullNodeStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, erro return *new(ethtypes.EthBigInt), ErrNotSupported } -func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { if s.Internal.EthGetBalance == nil { return *new(ethtypes.EthBigInt), ErrNotSupported } return s.Internal.EthGetBalance(p0, p1, p2) } -func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { return *new(ethtypes.EthBigInt), ErrNotSupported } @@ -2201,14 +2201,14 @@ func (s *FullNodeStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetCode == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetCode(p0, p1, p2) } -func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -2256,14 +2256,14 @@ func (s *FullNodeStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 return nil, ErrNotSupported } -func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetStorageAt == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetStorageAt(p0, p1, p2, p3) } -func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -2311,14 +2311,14 @@ func (s *FullNodeStub) EthGetTransactionByHashLimited(p0 context.Context, p1 *et return nil, ErrNotSupported } -func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { if s.Internal.EthGetTransactionCount == nil { return *new(ethtypes.EthUint64), ErrNotSupported } return s.Internal.EthGetTransactionCount(p0, p1, p2) } -func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { return *new(ethtypes.EthUint64), ErrNotSupported } @@ -4313,14 +4313,14 @@ func (s *GatewayStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, er return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *GatewayStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthCall == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthCall(p0, p1, p2) } -func (s *GatewayStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *GatewayStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -4368,14 +4368,14 @@ func (s *GatewayStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error return *new(ethtypes.EthBigInt), ErrNotSupported } -func (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (s *GatewayStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { if s.Internal.EthGetBalance == nil { return *new(ethtypes.EthBigInt), ErrNotSupported } return s.Internal.EthGetBalance(p0, p1, p2) } -func (s *GatewayStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (s *GatewayStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { return *new(ethtypes.EthBigInt), ErrNotSupported } @@ -4423,14 +4423,14 @@ func (s *GatewayStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *GatewayStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetCode == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetCode(p0, p1, p2) } -func (s *GatewayStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *GatewayStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -4478,14 +4478,14 @@ func (s *GatewayStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 * return nil, ErrNotSupported } -func (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *GatewayStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if s.Internal.EthGetStorageAt == nil { return *new(ethtypes.EthBytes), ErrNotSupported } return s.Internal.EthGetStorageAt(p0, p1, p2, p3) } -func (s *GatewayStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (s *GatewayStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return *new(ethtypes.EthBytes), ErrNotSupported } @@ -4511,14 +4511,14 @@ func (s *GatewayStub) EthGetTransactionByHashLimited(p0 context.Context, p1 *eth return nil, ErrNotSupported } -func (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (s *GatewayStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { if s.Internal.EthGetTransactionCount == nil { return *new(ethtypes.EthUint64), ErrNotSupported } return s.Internal.EthGetTransactionCount(p0, p1, p2) } -func (s *GatewayStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (s *GatewayStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { return *new(ethtypes.EthUint64), ErrNotSupported } diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index a3891144b50ecb5106ffab8f035c8fbcd4a80184..6a25cd677273192c7b42c6211511056b637a1a70 100644 GIT binary patch literal 33969 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%0D3#&6j2*4z6Pgc6fO% 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 YHG`gS{(eD#fqi}LO7e;GsX~DL7XV3s00000 literal 10477 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 Wj{jHhf8NHQpZXneR0ef0kpBbqDrd+5 diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index dcb85fffe96..3e0dd872467 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -840,61 +840,72 @@ func (e EthFeeHistoryParams) MarshalJSON() ([]byte, error) { return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum}) } -type EthBlockParamByNumberOrHash struct { - PredefinedBlock *string - Number *EthUint64 +type EthBlockNumberOrHash struct { + // PredefinedBlock can be one of "earliest", "pending" or "latest". We could merge this + // field with BlockNumber if the latter could store negative numbers representing + // each predefined value (e.g. -1 for "earliest", -2 for "pending" and -3 for "latest") + PredefinedBlock *string `json:"-"` BlockNumber *EthUint64 `json:"blockNumber,omitempty"` BlockHash *EthHash `json:"blockHash,omitempty"` RequireCanonical bool `json:"requireCanonical,omitempty"` } -func NewEthBlockParamFromPredefined(predefined string) EthBlockParamByNumberOrHash { - return EthBlockParamByNumberOrHash{ +func NewEthBlockNumberOrHashFromPredefined(predefined string) EthBlockNumberOrHash { + return EthBlockNumberOrHash{ PredefinedBlock: &predefined, - Number: nil, + BlockNumber: nil, BlockHash: nil, RequireCanonical: false, } } -func NewEthBlockParamFromNumber(number EthUint64) EthBlockParamByNumberOrHash { - return EthBlockParamByNumberOrHash{ +func NewEthBlockNumberOrHashFromNumber(number EthUint64) EthBlockNumberOrHash { + return EthBlockNumberOrHash{ PredefinedBlock: nil, - Number: &number, + BlockNumber: &number, BlockHash: nil, RequireCanonical: false, } } -func NewEthBlockParamFromHexString(str string) (EthBlockParamByNumberOrHash, error) { +func NewEthBlockNumberOrHashFromHexString(str string) (EthBlockNumberOrHash, error) { // check if block param is a number (decimal or hex) var num EthUint64 = 0 err := num.UnmarshalJSON([]byte(str)) if err != nil { - return NewEthBlockParamFromNumber(0), err + return NewEthBlockNumberOrHashFromNumber(0), err } - return EthBlockParamByNumberOrHash{ + return EthBlockNumberOrHash{ PredefinedBlock: nil, - Number: &num, + BlockNumber: &num, BlockHash: nil, RequireCanonical: false, }, nil } -func (e *EthBlockParamByNumberOrHash) UnmarshalJSON(b []byte) error { - // we first try to unmarshal into a EthBlockParamByNumberOrHash struct to check +func (e EthBlockNumberOrHash) MarshalJSON() ([]byte, error) { + if e.PredefinedBlock != nil { + return json.Marshal(*e.PredefinedBlock) + } + + type tmpStruct EthBlockNumberOrHash + return json.Marshal(tmpStruct(e)) +} + +func (e *EthBlockNumberOrHash) UnmarshalJSON(b []byte) error { + // we first try to unmarshal into a EthBlockNumberOrHash struct to check // if the block param is a block hash or block number (see EIP-1898). We use // a temporary struct to avoid infinite recursion. - type tmpStruct EthBlockParamByNumberOrHash + type tmpStruct EthBlockNumberOrHash var tmp tmpStruct if err := json.Unmarshal(b, &tmp); err == nil { if tmp.BlockNumber != nil && tmp.BlockHash != nil { return errors.New("cannot specify both blockNumber and blockHash") } - *e = EthBlockParamByNumberOrHash(tmp) + *e = EthBlockNumberOrHash(tmp) return nil } @@ -912,7 +923,7 @@ func (e *EthBlockParamByNumberOrHash) UnmarshalJSON(b []byte) error { // check if block param is a number (decimal or hex) var num EthUint64 if err := num.UnmarshalJSON(b); err == nil { - e.Number = &num + e.BlockNumber = &num return nil } diff --git a/cli/evm.go b/cli/evm.go index e3dda864760..7eb36f8953b 100644 --- a/cli/evm.go +++ b/cli/evm.go @@ -130,7 +130,7 @@ var EvmCallSimulateCmd = &cli.Command{ From: &fromEthAddr, To: &toEthAddr, Data: params, - }, ethtypes.NewEthBlockParamFromPredefined("latest")) + }, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) if err != nil { fmt.Println("Eth call fails, return val: ", res) return err @@ -518,7 +518,7 @@ var EvmGetBytecode = &cli.Command{ defer closer() ctx := ReqContext(cctx) - code, err := api.EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + code, err := api.EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) if err != nil { return err } diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index a72c57d6154..e3c97eecf4d 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -2375,13 +2375,7 @@ Inputs: "value": "0x0", "data": "0x07" }, - { - "PredefinedBlock": "string value", - "Number": "0x5", - "blockNumber": "0x5", - "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", - "requireCanonical": true - } + "string value" ] ``` @@ -2461,13 +2455,7 @@ Inputs: ```json [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - { - "PredefinedBlock": "string value", - "Number": "0x5", - "blockNumber": "0x5", - "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", - "requireCanonical": true - } + "string value" ] ``` @@ -2600,13 +2588,7 @@ Inputs: ```json [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - { - "PredefinedBlock": "string value", - "Number": "0x5", - "blockNumber": "0x5", - "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", - "requireCanonical": true - } + "string value" ] ``` @@ -2709,13 +2691,7 @@ Inputs: [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", "0x07", - { - "PredefinedBlock": "string value", - "Number": "0x5", - "blockNumber": "0x5", - "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", - "requireCanonical": true - } + "string value" ] ``` @@ -2885,13 +2861,7 @@ Inputs: ```json [ "0x5cbeecf99d3fdb3f25e309cc264f240bb0664031", - { - "PredefinedBlock": "string value", - "Number": "0x5", - "blockNumber": "0x5", - "blockHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e", - "requireCanonical": true - } + "string value" ] ``` diff --git a/gateway/node.go b/gateway/node.go index b8eac8d7298..811cc79d3b5 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -110,13 +110,13 @@ type TargetAPI interface { EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) NetVersion(ctx context.Context) (string, error) @@ -126,7 +126,7 @@ type TargetAPI interface { 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) - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, 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) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index 275baa935ab..a07ead16cf3 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -80,36 +80,41 @@ func (gw *Node) checkBlkHash(ctx context.Context, blkHash ethtypes.EthHash) erro return gw.checkTipsetKey(ctx, tsk) } -func (gw *Node) checkEthBlockParamByNumberOrHash(ctx context.Context, blkParam ethtypes.EthBlockParamByNumberOrHash, lookback ethtypes.EthUint64) error { - head, err := gw.target.ChainHead(ctx) - if err != nil { - return err - } - - var num ethtypes.EthUint64 = 0 - if blkParam.PredefinedBlock != nil { - if *blkParam.PredefinedBlock == "earliest" { - return fmt.Errorf("block param \"earliest\" is not supported") - } else if *blkParam.PredefinedBlock == "pending" || *blkParam.PredefinedBlock == "latest" { - // Head is always ok. - if lookback == 0 { - return nil - } +func (gw *Node) checkEthBlockParam(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash, lookback ethtypes.EthUint64) error { + // first check if its a predefined block or a block number + if blkParam.PredefinedBlock != nil || blkParam.BlockNumber != nil { + head, err := gw.target.ChainHead(ctx) + if err != nil { + return err + } - if lookback <= ethtypes.EthUint64(head.Height()) { - num = ethtypes.EthUint64(head.Height()) - lookback + var num ethtypes.EthUint64 = 0 + if blkParam.PredefinedBlock != nil { + if *blkParam.PredefinedBlock == "earliest" { + return fmt.Errorf("block param \"earliest\" is not supported") + } else if *blkParam.PredefinedBlock == "pending" || *blkParam.PredefinedBlock == "latest" { + // Head is always ok. + if lookback == 0 { + return nil + } + + if lookback <= ethtypes.EthUint64(head.Height()) { + num = ethtypes.EthUint64(head.Height()) - lookback + } } + } else { + num = *blkParam.BlockNumber } - } else if blkParam.Number != nil { - num = *blkParam.Number - } else if blkParam.BlockHash != nil || blkParam.BlockNumber != nil { - return fmt.Errorf("block hash and block number are not supported") - } else { - return fmt.Errorf("invalid block param") + + return gw.checkTipsetHeight(head, abi.ChainEpoch(num)) } - return gw.checkTipsetHeight(head, abi.ChainEpoch(num)) + // otherwise its a block hash + if blkParam.BlockHash != nil { + return gw.checkBlkHash(ctx, *blkParam.BlockHash) + } + return fmt.Errorf("invalid block param") } func (gw *Node) checkBlkParam(ctx context.Context, blkParam string, lookback ethtypes.EthUint64) error { @@ -210,12 +215,12 @@ func (gw *Node) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *e return gw.target.EthGetMessageCidByTransactionHash(ctx, txHash) } -func (gw *Node) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (gw *Node) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return 0, err } - if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParam(ctx, blkParam, 0); err != nil { return 0, err } @@ -240,36 +245,36 @@ func (gw *Node) EthGetTransactionReceiptLimited(ctx context.Context, txHash etht return gw.target.EthGetTransactionReceiptLimited(ctx, txHash, limit) } -func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (gw *Node) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } - if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParam(ctx, blkParam, 0); err != nil { return nil, err } return gw.target.EthGetCode(ctx, address, blkParam) } -func (gw *Node) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (gw *Node) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } - if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParam(ctx, blkParam, 0); err != nil { return nil, err } return gw.target.EthGetStorageAt(ctx, address, position, blkParam) } -func (gw *Node) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (gw *Node) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return ethtypes.EthBigInt(big.Zero()), err } - if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParam(ctx, blkParam, 0); err != nil { return ethtypes.EthBigInt(big.Zero()), err } @@ -364,12 +369,12 @@ func (gw *Node) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtyp return gw.target.EthEstimateGas(ctx, tx) } -func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (gw *Node) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return nil, err } - if err := gw.checkEthBlockParamByNumberOrHash(ctx, blkParam, 0); err != nil { + if err := gw.checkEthBlockParam(ctx, blkParam, 0); err != nil { return nil, err } diff --git a/itests/eth_balance_test.go b/itests/eth_balance_test.go index 3a2f5cd4b39..d133ff6d90e 100644 --- a/itests/eth_balance_test.go +++ b/itests/eth_balance_test.go @@ -31,7 +31,7 @@ func TestEthGetBalanceExistingF4address(t *testing.T) { // send some funds to the f410 address kit.SendFunds(ctx, t, client, deployer, fundAmount) - balance, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + balance, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, balance, ethtypes.EthBigInt{Int: fundAmount.Int}) } @@ -46,7 +46,7 @@ func TestEthGetBalanceNonExistentF4address(t *testing.T) { _, ethAddr, _ := client.EVM().NewAccount() - balance, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + balance, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, balance, ethtypes.EthBigIntZero) } @@ -70,7 +70,7 @@ func TestEthGetBalanceExistentIDMaskedAddr(t *testing.T) { balance, err := client.WalletBalance(ctx, fid) require.NoError(t, err) - ebal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + ebal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ebal, ethtypes.EthBigInt{Int: balance.Int}) } @@ -92,7 +92,7 @@ func TestEthGetBalanceBuiltinActor(t *testing.T) { ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(fid) require.NoError(t, err) - ebal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + ebal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthBigInt{Int: big.NewInt(10).Int}, ebal) } @@ -129,15 +129,15 @@ func TestEthBalanceCorrectLookup(t *testing.T) { inclTsParents, err := client.ChainGetTipSet(ctx, inclTs.Parents()) require.NoError(t, err) - bal, err := client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(inclTsParents.Height()))) + bal, err := client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromNumber(ethtypes.EthUint64(inclTsParents.Height()))) require.NoError(t, err) require.Equal(t, int64(0), bal.Int64()) - bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(inclTs.Height()))) + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromNumber(ethtypes.EthUint64(inclTs.Height()))) require.NoError(t, err) require.Equal(t, val, bal.Int64()) - bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(execTs.Height()))) + bal, err = client.EVM().EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromNumber(ethtypes.EthUint64(execTs.Height()))) require.NoError(t, err) require.Equal(t, val, bal.Int64()) } diff --git a/itests/eth_bytecode_test.go b/itests/eth_bytecode_test.go index 86048ff9118..bc232142ab6 100644 --- a/itests/eth_bytecode_test.go +++ b/itests/eth_bytecode_test.go @@ -33,12 +33,12 @@ func TestGetCodeAndNonce(t *testing.T) { { // A random eth address should have no code. _, ethAddr, filAddr := client.EVM().NewAccount() - bytecode, err := client.EVM().EthGetCode(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + bytecode, err := client.EVM().EthGetCode(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Empty(t, bytecode) // Nonce should also be zero - nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Zero(t, nonce) @@ -46,12 +46,12 @@ func TestGetCodeAndNonce(t *testing.T) { kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10)) // The code should still be empty, target is now a placeholder. - bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Empty(t, bytecode) // Nonce should still be zero. - nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Zero(t, nonce) } @@ -68,12 +68,12 @@ func TestGetCodeAndNonce(t *testing.T) { contractFilAddr := *createReturn.RobustAddress // The newly deployed contract should not be empty. - bytecode, err := client.EVM().EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + bytecode, err := client.EVM().EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.NotEmpty(t, bytecode) // Nonce should be one. - nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthUint64(1), nonce) @@ -82,12 +82,12 @@ func TestGetCodeAndNonce(t *testing.T) { require.NoError(t, err) // The code should be empty again. - bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Empty(t, bytecode) // Nonce should go back to zero - nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Zero(t, nonce) } diff --git a/itests/eth_conformance_test.go b/itests/eth_conformance_test.go index 2a899e968e5..15b24997719 100644 --- a/itests/eth_conformance_test.go +++ b/itests/eth_conformance_test.go @@ -33,25 +33,25 @@ import ( type ethAPIRaw struct { EthAccounts func(context.Context) (json.RawMessage, error) EthBlockNumber func(context.Context) (json.RawMessage, error) - EthCall func(context.Context, ethtypes.EthCall, ethtypes.EthBlockParamByNumberOrHash) (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) 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.EthBlockParamByNumberOrHash) (json.RawMessage, error) + EthGetBalance func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) EthGetBlockByHash func(context.Context, ethtypes.EthHash, bool) (json.RawMessage, error) EthGetBlockByNumber func(context.Context, string, bool) (json.RawMessage, error) EthGetBlockTransactionCountByHash func(context.Context, ethtypes.EthHash) (json.RawMessage, error) EthGetBlockTransactionCountByNumber func(context.Context, ethtypes.EthUint64) (json.RawMessage, error) - EthGetCode func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) + EthGetCode func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) EthGetFilterChanges func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) EthGetFilterLogs func(context.Context, ethtypes.EthFilterID) (json.RawMessage, error) EthGetLogs func(context.Context, *ethtypes.EthFilterSpec) (json.RawMessage, error) - EthGetStorageAt func(context.Context, ethtypes.EthAddress, ethtypes.EthBytes, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) + EthGetStorageAt func(context.Context, ethtypes.EthAddress, ethtypes.EthBytes, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) EthGetTransactionByBlockHashAndIndex func(context.Context, ethtypes.EthHash, ethtypes.EthUint64) (json.RawMessage, error) EthGetTransactionByBlockNumberAndIndex func(context.Context, ethtypes.EthUint64, ethtypes.EthUint64) (json.RawMessage, error) EthGetTransactionByHash func(context.Context, *ethtypes.EthHash) (json.RawMessage, error) - EthGetTransactionCount func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockParamByNumberOrHash) (json.RawMessage, error) + EthGetTransactionCount func(context.Context, ethtypes.EthAddress, ethtypes.EthBlockNumberOrHash) (json.RawMessage, error) EthGetTransactionReceipt func(context.Context, ethtypes.EthHash) (json.RawMessage, error) EthMaxPriorityFeePerGas func(context.Context) (json.RawMessage, error) EthNewBlockFilter func(context.Context) (json.RawMessage, error) @@ -168,7 +168,7 @@ func TestEthOpenRPCConformance(t *testing.T) { return ethapi.EthCall(context.Background(), ethtypes.EthCall{ From: &senderEthAddr, Data: contractBin, - }, ethtypes.NewEthBlockParamFromPredefined("latest")) + }, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) }, }, @@ -207,7 +207,7 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getBalance", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - blockParam, _ := ethtypes.NewEthBlockParamFromHexString("0x0") + blockParam, _ := ethtypes.NewEthBlockNumberOrHashFromHexString("0x0") return ethapi.EthGetBalance(context.Background(), contractEthAddr, blockParam) }, }, @@ -262,7 +262,7 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getCode", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthGetCode(context.Background(), contractEthAddr, ethtypes.NewEthBlockParamFromNumber(blockNumberWithMessage)) + return ethapi.EthGetCode(context.Background(), contractEthAddr, ethtypes.NewEthBlockNumberOrHashFromNumber(blockNumberWithMessage)) }, }, @@ -308,7 +308,7 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getStorageAt", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - blockParam, _ := ethtypes.NewEthBlockParamFromHexString("0x0") + blockParam, _ := ethtypes.NewEthBlockNumberOrHashFromHexString("0x0") return ethapi.EthGetStorageAt(context.Background(), contractEthAddr, ethtypes.EthBytes{0}, blockParam) }, }, @@ -340,7 +340,7 @@ func TestEthOpenRPCConformance(t *testing.T) { method: "eth_getTransactionCount", variant: "blocknumber", call: func(a *ethAPIRaw) (json.RawMessage, error) { - return ethapi.EthGetTransactionCount(context.Background(), senderEthAddr, ethtypes.NewEthBlockParamFromNumber(blockNumberWithMessage)) + return ethapi.EthGetTransactionCount(context.Background(), senderEthAddr, ethtypes.NewEthBlockNumberOrHashFromNumber(blockNumberWithMessage)) }, }, diff --git a/itests/eth_transactions_test.go b/itests/eth_transactions_test.go index eb900c7fb56..8d836573da9 100644 --- a/itests/eth_transactions_test.go +++ b/itests/eth_transactions_test.go @@ -316,7 +316,7 @@ func TestGetBlockByNumber(t *testing.T) { // Fetch balance on a null round; should not fail and should return previous balance. // Should be lower than original balance. - bal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromNumber(ethtypes.EthUint64(afterNullHeight-1))) + bal, err := client.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromNumber(ethtypes.EthUint64(afterNullHeight-1))) require.NoError(t, err) require.NotEqual(t, big.Zero(), bal) require.Equal(t, types.FromFil(10).Int, bal.Int) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 7051bb0dfb9..1512c3277fa 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -268,14 +268,14 @@ func TestFEVMDelegateCall(t *testing.T) { // The implementation's storage should not have been updated. actorAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr) require.NoError(t, err) - value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, ethtypes.NewEthBlockParamFromPredefined("latest")) + value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthBytes(make([]byte, 32)), value) // The storage actor's storage _should_ have been updated storageAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(storageAddr) require.NoError(t, err) - value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, ethtypes.NewEthBlockParamFromPredefined("latest")) + value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, ethtypes.EthBytes(expectedResult), value) } @@ -881,7 +881,7 @@ func TestFEVMTestDeployOnTransfer(t *testing.T) { require.NoError(t, err) require.True(t, ret.Receipt.ExitCode.IsSuccess()) - balance, err := client.EVM().EthGetBalance(ctx, randomAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + balance, err := client.EVM().EthGetBalance(ctx, randomAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(t, err) require.Equal(t, value.Int, balance.Int) @@ -1030,7 +1030,7 @@ func TestFEVMErrorParsing(t *testing.T) { _, err := e.EthCall(ctx, ethtypes.EthCall{ To: &contractAddrEth, Data: entryPoint, - }, ethtypes.NewEthBlockParamFromPredefined("latest")) + }, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.ErrorContains(t, err, expected) }) t.Run("EthEstimateGas", func(t *testing.T) { diff --git a/itests/kit/evm.go b/itests/kit/evm.go index 9b929998063..99844ca3097 100644 --- a/itests/kit/evm.go +++ b/itests/kit/evm.go @@ -199,7 +199,7 @@ func (e *EVM) AssertAddressBalanceConsistent(ctx context.Context, addr address.A ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(addr) require.NoError(e.t, err) - ebal, err := e.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockParamFromPredefined("latest")) + ebal, err := e.EthGetBalance(ctx, ethAddr, ethtypes.NewEthBlockNumberOrHashFromPredefined("latest")) require.NoError(e.t, err) require.Equal(e.t, fbal, types.BigInt(ebal)) diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 636732416b6..c4bda6428da 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -62,7 +62,7 @@ func (e *EthModuleDummy) EthGetTransactionByHashLimited(ctx context.Context, txH return nil, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { return 0, ErrModuleDisabled } @@ -82,15 +82,15 @@ func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Cont return ethtypes.EthTx{}, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return nil, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return nil, ErrModuleDisabled } -func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { return ethtypes.EthBigIntZero, ErrModuleDisabled } @@ -126,7 +126,7 @@ func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall return 0, ErrModuleDisabled } -func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { return nil, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index cee222683ee..424756f8140 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -59,12 +59,12 @@ type EthModuleAPI interface { EthGetTransactionByHashLimited(ctx context.Context, txHash *ethtypes.EthHash, limit abi.ChainEpoch) (*ethtypes.EthTx, error) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) - EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) + EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) EthGetTransactionReceiptLimited(ctx context.Context, txHash ethtypes.EthHash, limit abi.ChainEpoch) (*api.EthTxReceipt, error) - EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) - EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) - EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) + EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) + EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) + EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) EthSyncing(ctx context.Context) (ethtypes.EthSyncingResult, error) @@ -73,7 +73,7 @@ type EthModuleAPI interface { EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) - EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, 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) Web3ClientVersion(ctx context.Context) (string, error) @@ -241,7 +241,7 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthH return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI) } -func (a *EthModule) getTipsetByEthBlockNumberOrHash(ctx context.Context, blkParam ethtypes.EthBlockParamByNumberOrHash) (*types.TipSet, error) { +func (a *EthModule) getTipsetByEthBlockNumberOrHash(ctx context.Context, blkParam ethtypes.EthBlockNumberOrHash) (*types.TipSet, error) { head := a.Chain.GetHeaviestTipSet() predefined := blkParam.PredefinedBlock @@ -261,8 +261,8 @@ func (a *EthModule) getTipsetByEthBlockNumberOrHash(ctx context.Context, blkPara } } - // utility function to validate a tipset by height and return it - returnAndValidateTipsetFunc := func(height abi.ChainEpoch) (*types.TipSet, error) { + if blkParam.BlockNumber != nil { + height := abi.ChainEpoch(*blkParam.BlockNumber) if height > head.Height()-1 { return nil, fmt.Errorf("requested a future epoch (beyond 'latest')") } @@ -273,34 +273,23 @@ func (a *EthModule) getTipsetByEthBlockNumberOrHash(ctx context.Context, blkPara return ts, nil } - if blkParam.Number != nil { - return returnAndValidateTipsetFunc(abi.ChainEpoch(*blkParam.Number)) - } - - if blkParam.BlockNumber != nil { - return returnAndValidateTipsetFunc(abi.ChainEpoch(*blkParam.BlockNumber)) - } - if blkParam.BlockHash != nil { ts, err := a.Chain.GetTipSetByCid(ctx, blkParam.BlockHash.ToCid()) if err != nil { return nil, fmt.Errorf("cannot get tipset by hash: %v", err) } + // verify that the tipset is in the canonical chain if blkParam.RequireCanonical { - // walk back the current chain (our head) until we reach targetHeight and validate the block hash - currTs := head - for { - if currTs.Equals(ts) { - return ts, nil - } else if currTs.Height() < ts.Height() { - return nil, fmt.Errorf("could not find block hash %s in canonical chain", blkParam.BlockHash.ToCid()) - } + // walk up the current chain (our head) until we reach ts.Height() + walkTs, err := a.ChainAPI.ChainGetTipSetByHeight(ctx, ts.Height(), head.Key()) + if err != nil { + return nil, fmt.Errorf("cannot get tipset at height: %v", ts.Height()) + } - currTs, err = a.Chain.LoadTipSet(ctx, currTs.Parents()) - if err != nil { - return nil, fmt.Errorf("failed to load tipset: %v", err) - } + // verify that it equals the expected tipset + if !walkTs.Equals(ts) { + return nil, fmt.Errorf("tipset is not canonical") } } @@ -451,7 +440,7 @@ func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) return &hash, err } -func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthUint64, error) { +func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthUint64, error) { addr, err := sender.ToFilecoinAddress() if err != nil { return ethtypes.EthUint64(0), nil @@ -459,7 +448,7 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes. ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { - return ethtypes.EthUint64(0), xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) + return ethtypes.EthUint64(0), xerrors.Errorf("failed to process block param: %v; %w", blkParam, err) } // First, handle the case where the "sender" is an EVM actor. @@ -539,7 +528,7 @@ func (a *EthAPI) EthGetTransactionByBlockNumberAndIndex(context.Context, ethtype } // EthGetCode returns string value of the compiled bytecode -func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { to, err := ethAddr.ToFilecoinAddress() if err != nil { return nil, xerrors.Errorf("cannot get Filecoin address: %w", err) @@ -547,7 +536,7 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { - return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) + return nil, xerrors.Errorf("failed to process block param: %v; %w", blkParam, err) } // StateManager.Call will panic if there is no parent @@ -623,10 +612,10 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress, return blk.RawData(), nil } -func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { - return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) + return nil, xerrors.Errorf("failed to process block param: %v; %w", blkParam, err) } l := len(position) @@ -714,7 +703,7 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd return ethtypes.EthBytes(ret), nil } -func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBigInt, error) { +func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBigInt, error) { filAddr, err := address.ToFilecoinAddress() if err != nil { return ethtypes.EthBigInt{}, err @@ -722,7 +711,7 @@ func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddre ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { - return ethtypes.EthBigInt{}, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) + return ethtypes.EthBigInt{}, xerrors.Errorf("failed to process block param: %v; %w", blkParam, err) } st, _, err := a.StateManager.TipSetState(ctx, ts) @@ -1181,7 +1170,7 @@ func ethGasSearch( return -1, xerrors.Errorf("message execution failed: exit %s, reason: %s", res.MsgRct.ExitCode, res.Error) } -func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockParamByNumberOrHash) (ethtypes.EthBytes, error) { +func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam ethtypes.EthBlockNumberOrHash) (ethtypes.EthBytes, error) { msg, err := a.ethCallToFilecoinMessage(ctx, tx) if err != nil { return nil, xerrors.Errorf("failed to convert ethcall to filecoin message: %w", err) @@ -1189,7 +1178,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam e ts, err := a.getTipsetByEthBlockNumberOrHash(ctx, blkParam) if err != nil { - return nil, xerrors.Errorf("failed to process block param: %s; %w", blkParam, err) + return nil, xerrors.Errorf("failed to process block param: %v; %w", blkParam, err) } invokeResult, err := a.applyMessage(ctx, msg, ts.Key())