diff --git a/.circleci/config.yml b/.circleci/config.yml index 88635ab2c..289cbfa23 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -643,6 +643,11 @@ workflows: suite: itest-eth_deploy target: "./itests/eth_deploy_test.go" + - test: + name: test-itest-eth_fee_history + suite: itest-eth_fee_history + target: "./itests/eth_fee_history_test.go" + - test: name: test-itest-eth_filter suite: itest-eth_filter diff --git a/api/api_full.go b/api/api_full.go index 20870adce..3bd875dc7 100644 --- a/api/api_full.go +++ b/api/api_full.go @@ -786,15 +786,15 @@ type FullNode interface { 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 - 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, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, 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 + 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 diff --git a/api/api_gateway.go b/api/api_gateway.go index 1f7cce8e3..aea6fc3d1 100644 --- a/api/api_gateway.go +++ b/api/api_gateway.go @@ -93,7 +93,7 @@ type Gateway interface { NetListening(ctx context.Context) (bool, error) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) - EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) diff --git a/api/mocks/mock_full.go b/api/mocks/mock_full.go index c944e2de1..6e4873715 100644 --- a/api/mocks/mock_full.go +++ b/api/mocks/mock_full.go @@ -1014,18 +1014,18 @@ func (mr *MockFullNodeMockRecorder) EthEstimateGas(arg0, arg1 interface{}) *gomo } // EthFeeHistory mocks base method. -func (m *MockFullNode) EthFeeHistory(arg0 context.Context, arg1 ethtypes.EthUint64, arg2 string, arg3 []float64) (ethtypes.EthFeeHistory, error) { +func (m *MockFullNode) EthFeeHistory(arg0 context.Context, arg1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EthFeeHistory", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "EthFeeHistory", arg0, arg1) ret0, _ := ret[0].(ethtypes.EthFeeHistory) ret1, _ := ret[1].(error) return ret0, ret1 } // EthFeeHistory indicates an expected call of EthFeeHistory. -func (mr *MockFullNodeMockRecorder) EthFeeHistory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockFullNodeMockRecorder) EthFeeHistory(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthFeeHistory", reflect.TypeOf((*MockFullNode)(nil).EthFeeHistory), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthFeeHistory", reflect.TypeOf((*MockFullNode)(nil).EthFeeHistory), arg0, arg1) } // EthGasPrice mocks base method. diff --git a/api/proxy_gen.go b/api/proxy_gen.go index 794456eae..2cfaa099a 100644 --- a/api/proxy_gen.go +++ b/api/proxy_gen.go @@ -252,7 +252,7 @@ type FullNodeMethods struct { EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `perm:"read"` - EthFeeHistory func(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) `perm:"read"` + EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `perm:"read"` EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"` @@ -658,7 +658,7 @@ type GatewayMethods struct { EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `` - EthFeeHistory func(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) `` + EthFeeHistory func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) `` EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `` @@ -2051,14 +2051,14 @@ func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) ( return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *FullNodeStruct) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) { +func (s *FullNodeStruct) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { if s.Internal.EthFeeHistory == nil { return *new(ethtypes.EthFeeHistory), ErrNotSupported } - return s.Internal.EthFeeHistory(p0, p1, p2, p3) + return s.Internal.EthFeeHistory(p0, p1) } -func (s *FullNodeStub) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) { +func (s *FullNodeStub) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { return *new(ethtypes.EthFeeHistory), ErrNotSupported } @@ -4218,14 +4218,14 @@ func (s *GatewayStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (e return *new(ethtypes.EthUint64), ErrNotSupported } -func (s *GatewayStruct) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) { +func (s *GatewayStruct) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { if s.Internal.EthFeeHistory == nil { return *new(ethtypes.EthFeeHistory), ErrNotSupported } - return s.Internal.EthFeeHistory(p0, p1, p2, p3) + return s.Internal.EthFeeHistory(p0, p1) } -func (s *GatewayStub) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) { +func (s *GatewayStub) EthFeeHistory(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { return *new(ethtypes.EthFeeHistory), ErrNotSupported } diff --git a/build/openrpc/full.json.gz b/build/openrpc/full.json.gz index a33ab9ab3..f5b21db04 100644 Binary files a/build/openrpc/full.json.gz and b/build/openrpc/full.json.gz differ diff --git a/build/openrpc/gateway.json.gz b/build/openrpc/gateway.json.gz index f8dc51639..f75e5a14e 100644 Binary files a/build/openrpc/gateway.json.gz and b/build/openrpc/gateway.json.gz differ diff --git a/chain/types/ethtypes/eth_types.go b/chain/types/ethtypes/eth_types.go index 4cdb2abed..c8307eed3 100644 --- a/chain/types/ethtypes/eth_types.go +++ b/chain/types/ethtypes/eth_types.go @@ -46,7 +46,11 @@ func (e EthUint64) MarshalJSON() ([]byte, error) { func (e *EthUint64) UnmarshalJSON(b []byte) error { var s string if err := json.Unmarshal(b, &s); err == nil { - parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), 16, 64) + base := 10 + if strings.HasPrefix(s, "0x") { + base = 16 + } + parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), base, 64) if err != nil { return err } @@ -732,3 +736,45 @@ func GetContractEthAddressFromCode(sender EthAddress, salt [32]byte, initcode [] return ethAddr, nil } + +// EthFeeHistoryParams handles raw jsonrpc params for eth_subscribe +type EthFeeHistoryParams struct { + BlkCount EthUint64 + NewestBlkNum string + RewardPercentiles *[]float64 +} + +func (e *EthFeeHistoryParams) UnmarshalJSON(b []byte) error { + var params []json.RawMessage + err := json.Unmarshal(b, ¶ms) + if err != nil { + return err + } + switch len(params) { + case 3: + err = json.Unmarshal(params[2], &e.RewardPercentiles) + if err != nil { + return err + } + fallthrough + case 2: + err = json.Unmarshal(params[1], &e.NewestBlkNum) + if err != nil { + return err + } + err = json.Unmarshal(params[0], &e.BlkCount) + if err != nil { + return err + } + default: + return xerrors.Errorf("expected 2 or 3 params, got %d", len(params)) + } + return nil +} + +func (e EthFeeHistoryParams) MarshalJSON() ([]byte, error) { + if e.RewardPercentiles != nil { + return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum, e.RewardPercentiles}) + } + return json.Marshal([]interface{}{e.BlkCount, e.NewestBlkNum}) +} diff --git a/chain/types/ethtypes/eth_types_test.go b/chain/types/ethtypes/eth_types_test.go index 7d49ab1b9..84eac556a 100644 --- a/chain/types/ethtypes/eth_types_test.go +++ b/chain/types/ethtypes/eth_types_test.go @@ -36,6 +36,9 @@ func TestEthIntUnmarshalJSON(t *testing.T) { {[]byte("\"0x0\""), EthUint64(0)}, {[]byte("\"0x41\""), EthUint64(65)}, {[]byte("\"0x400\""), EthUint64(1024)}, + {[]byte("\"0\""), EthUint64(0)}, + {[]byte("\"41\""), EthUint64(41)}, + {[]byte("\"400\""), EthUint64(400)}, {[]byte("0"), EthUint64(0)}, {[]byte("100"), EthUint64(100)}, {[]byte("1024"), EthUint64(1024)}, diff --git a/documentation/en/api-v1-unstable-methods.md b/documentation/en/api-v1-unstable-methods.md index b7050febd..1c0958f4c 100644 --- a/documentation/en/api-v1-unstable-methods.md +++ b/documentation/en/api-v1-unstable-methods.md @@ -2332,11 +2332,7 @@ Perms: read Inputs: ```json [ - "0x5", - "string value", - [ - 12.3 - ] + "Bw==" ] ``` diff --git a/gateway/node.go b/gateway/node.go index c41f0ceb0..778f9e6f2 100644 --- a/gateway/node.go +++ b/gateway/node.go @@ -108,7 +108,7 @@ type TargetAPI interface { NetListening(ctx context.Context) (bool, error) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) - EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) diff --git a/gateway/proxy_eth.go b/gateway/proxy_eth.go index 40b68f500..838a9ba3f 100644 --- a/gateway/proxy_eth.go +++ b/gateway/proxy_eth.go @@ -294,20 +294,25 @@ func (gw *Node) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) { var EthFeeHistoryMaxBlockCount = 128 // this seems to be expensive; todo: figure out what is a good number that works with everything -func (gw *Node) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) { +func (gw *Node) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + params, err := jsonrpc.DecodeParams[ethtypes.EthFeeHistoryParams](p) + if err != nil { + return ethtypes.EthFeeHistory{}, xerrors.Errorf("decoding params: %w", err) + } + if err := gw.limit(ctx, stateRateLimitTokens); err != nil { return ethtypes.EthFeeHistory{}, err } - if err := gw.checkBlkParam(ctx, newestBlk); err != nil { + if err := gw.checkBlkParam(ctx, params.NewestBlkNum); err != nil { return ethtypes.EthFeeHistory{}, err } - if blkCount > ethtypes.EthUint64(EthFeeHistoryMaxBlockCount) { + if params.BlkCount > ethtypes.EthUint64(EthFeeHistoryMaxBlockCount) { return ethtypes.EthFeeHistory{}, fmt.Errorf("block count too high") } - return gw.target.EthFeeHistory(ctx, blkCount, newestBlk, rewardPercentiles) + return gw.target.EthFeeHistory(ctx, p) } func (gw *Node) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) { diff --git a/itests/eth_fee_history_test.go b/itests/eth_fee_history_test.go new file mode 100644 index 000000000..9b256c527 --- /dev/null +++ b/itests/eth_fee_history_test.go @@ -0,0 +1,87 @@ +package itests + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/filecoin-project/go-jsonrpc" + + "github.com/filecoin-project/lotus/chain/types/ethtypes" + "github.com/filecoin-project/lotus/itests/kit" + "github.com/filecoin-project/lotus/lib/result" +) + +func TestEthFeeHistory(t *testing.T) { + require := require.New(t) + + kit.QuietAllLogsExcept() + + blockTime := 100 * time.Millisecond + client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) + ens.InterconnectAll().BeginMining(blockTime) + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + + // Wait for the network to create 20 blocks + <-time.After(20 * blockTime) + + history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "0x10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{"5", "0x10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{"0x10", "0x12"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(17, len(history.BaseFeePerGas)) + require.Equal(16, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(18-16+1), history.OldestBlock) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "0x10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "10"}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{5, "10", &[]float64{0.25, 0.50, 0.75}}), + ).Assert(require.NoError)) + require.NoError(err) + require.Equal(6, len(history.BaseFeePerGas)) + require.Equal(5, len(history.GasUsedRatio)) + require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock) + require.NotNil(history.Reward) + require.Equal(0, len(*history.Reward)) + + history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams]( + json.Marshal([]interface{}{1025, "10", &[]float64{0.25, 0.50, 0.75}}), + ).Assert(require.NoError)) + require.Error(err) +} diff --git a/node/impl/full/dummy.go b/node/impl/full/dummy.go index 0b4b0080c..9abe00321 100644 --- a/node/impl/full/dummy.go +++ b/node/impl/full/dummy.go @@ -80,7 +80,7 @@ func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.Eth return ethtypes.EthBigIntZero, ErrModuleDisabled } -func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) { +func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { return ethtypes.EthFeeHistory{}, ErrModuleDisabled } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index bfbd6dbda..bf1e26a43 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -57,7 +57,7 @@ type EthModuleAPI interface { 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) - EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) + EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) NetVersion(ctx context.Context) (string, error) NetListening(ctx context.Context) (bool, error) @@ -581,8 +581,12 @@ func (a *EthModule) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) return ethtypes.EthUint64(build.Eip155ChainId), nil } -func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlkNum string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) { - if blkCount > 1024 { +func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthFeeHistory, error) { + params, err := jsonrpc.DecodeParams[ethtypes.EthFeeHistoryParams](p) + if err != nil { + return ethtypes.EthFeeHistory{}, xerrors.Errorf("decoding params: %w", err) + } + if params.BlkCount > 1024 { return ethtypes.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024") } @@ -590,7 +594,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint // TODO https://github.com/filecoin-project/ref-fvm/issues/1016 var blkNum ethtypes.EthUint64 - err := blkNum.UnmarshalJSON([]byte(`"` + newestBlkNum + `"`)) + err = blkNum.UnmarshalJSON([]byte(`"` + params.NewestBlkNum + `"`)) if err == nil && uint64(blkNum) < newestBlkHeight { newestBlkHeight = uint64(blkNum) } @@ -598,8 +602,8 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint // Deal with the case that the chain is shorter than the number of // requested blocks. oldestBlkHeight := uint64(1) - if uint64(blkCount) <= newestBlkHeight { - oldestBlkHeight = newestBlkHeight - uint64(blkCount) + 1 + if uint64(params.BlkCount) <= newestBlkHeight { + oldestBlkHeight = newestBlkHeight - uint64(params.BlkCount) + 1 } ts, err := a.Chain.GetTipsetByHeight(ctx, abi.ChainEpoch(newestBlkHeight), nil, false) @@ -633,7 +637,6 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint } // Reverse the arrays; we collected them newest to oldest; the client expects oldest to newest. - for i, j := 0, len(baseFeeArray)-1; i < j; i, j = i+1, j-1 { baseFeeArray[i], baseFeeArray[j] = baseFeeArray[j], baseFeeArray[i] } @@ -641,11 +644,16 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint gasUsedRatioArray[i], gasUsedRatioArray[j] = gasUsedRatioArray[j], gasUsedRatioArray[i] } - return ethtypes.EthFeeHistory{ + ret := ethtypes.EthFeeHistory{ OldestBlock: ethtypes.EthUint64(oldestBlkHeight), BaseFeePerGas: baseFeeArray, GasUsedRatio: gasUsedRatioArray, - }, nil + } + if params.RewardPercentiles != nil { + reward := make([][]ethtypes.EthBigInt, 0) + ret.Reward = &reward + } + return ret, nil } func (a *EthModule) NetVersion(ctx context.Context) (string, error) {