From 33e3497659969dbab5c0e94198646d53aa2a6c6a Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Mon, 25 Jul 2022 16:50:15 -0600 Subject: [PATCH 1/5] ethclient: add FeeHistory support --- ethclient/ethclient.go | 40 +++++++++++++++++++++++++++++++++++++ ethclient/ethclient_test.go | 23 +++++++++++++++++++++ internal/ethapi/api.go | 1 + 3 files changed, 64 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 24edd8648ef39..d71c09e20a1cd 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -505,6 +505,46 @@ func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return (*big.Int)(&hex), nil } +// FeeHistoryResult is the result of FeeHistory. +type FeeHistoryResult struct { + OldestBlock *big.Int `json:"oldestBlock"` + Reward [][]*big.Int `json:"reward,omitempty"` + BaseFee []*big.Int `json:"baseFeePerGas,omitempty"` + GasUsedRatio []float64 `json:"gasUsedRatio"` +} + +type feeHistoryResultMarshaling struct { + OldestBlock *hexutil.Big `json:"oldestBlock"` + Reward [][]*hexutil.Big `json:"reward,omitempty"` + BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"` + GasUsedRatio []float64 `json:"gasUsedRatio"` +} + +// FeeHistory retrieves the fee market history. +func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*FeeHistoryResult, error) { + var res feeHistoryResultMarshaling + if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), hexutil.Big(*lastBlock), rewardPercentiles); err != nil { + return nil, err + } + reward := make([][]*big.Int, len(res.Reward)) + for i, r := range res.Reward { + reward[i] = make([]*big.Int, len(r)) + for j, r := range r { + reward[i][j] = (*big.Int)(r) + } + } + baseFee := make([]*big.Int, len(res.BaseFee)) + for i, b := range res.BaseFee { + baseFee[i] = (*big.Int)(b) + } + return &FeeHistoryResult{ + OldestBlock: (*big.Int)(res.OldestBlock), + Reward: reward, + BaseFee: baseFee, + GasUsedRatio: res.GasUsedRatio, + }, nil +} + // EstimateGas tries to estimate the gas needed to execute a specific transaction based on // the current pending state of the backend blockchain. There is no guarantee that this is // the true gas limit requirement as other transactions may be added or removed by miners, diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 4a8727b37478e..9265d01f647ed 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -508,6 +508,29 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { if gasTipCap.Cmp(big.NewInt(234375000)) != 0 { t.Fatalf("unexpected gas tip cap: %v", gasTipCap) } + + // FeeHistory + history, err := ec.FeeHistory(context.Background(), 1, big.NewInt(2), []float64{95, 99}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + want := &FeeHistoryResult{ + OldestBlock: big.NewInt(2), + Reward: [][]*big.Int{ + { + big.NewInt(234375000), + big.NewInt(234375000), + }, + }, + BaseFee: []*big.Int{ + big.NewInt(765625000), + big.NewInt(671627818), + }, + GasUsedRatio: []float64{0.008912678667376286}, + } + if !reflect.DeepEqual(history, want) { + t.Fatalf("FeeHistory result doesn't match expected: (got: %v, want: %v)", history, want) + } } func testCallContractAtHash(t *testing.T, client *rpc.Client) { diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index a3637969e81e0..90322033b9358 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -86,6 +86,7 @@ type feeHistoryResult struct { GasUsedRatio []float64 `json:"gasUsedRatio"` } +// FeeHistory returns the fee market history. func (s *EthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) { oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles) if err != nil { From 5ce54d31106469b8149ead8738b653656b5593f7 Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Tue, 26 Jul 2022 06:22:50 -0600 Subject: [PATCH 2/5] ethclient: convert lastBlock to block number argument --- ethclient/ethclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index d71c09e20a1cd..a45a58591183b 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -523,7 +523,7 @@ type feeHistoryResultMarshaling struct { // FeeHistory retrieves the fee market history. func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*FeeHistoryResult, error) { var res feeHistoryResultMarshaling - if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), hexutil.Big(*lastBlock), rewardPercentiles); err != nil { + if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), toBlockNumArg(lastBlock), rewardPercentiles); err != nil { return nil, err } reward := make([][]*big.Int, len(res.Reward)) From 3b5f23a43119b5a9bf9a1ae666cd3ced54ca4fe5 Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Tue, 26 Jul 2022 08:29:27 -0600 Subject: [PATCH 3/5] interfaces,ethclient: add FeeHistory to top-level interfaces package --- ethclient/ethclient.go | 12 ++---------- ethclient/ethclient_test.go | 2 +- interfaces.go | 9 +++++++++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index a45a58591183b..8a001843187bb 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -505,14 +505,6 @@ func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { return (*big.Int)(&hex), nil } -// FeeHistoryResult is the result of FeeHistory. -type FeeHistoryResult struct { - OldestBlock *big.Int `json:"oldestBlock"` - Reward [][]*big.Int `json:"reward,omitempty"` - BaseFee []*big.Int `json:"baseFeePerGas,omitempty"` - GasUsedRatio []float64 `json:"gasUsedRatio"` -} - type feeHistoryResultMarshaling struct { OldestBlock *hexutil.Big `json:"oldestBlock"` Reward [][]*hexutil.Big `json:"reward,omitempty"` @@ -521,7 +513,7 @@ type feeHistoryResultMarshaling struct { } // FeeHistory retrieves the fee market history. -func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*FeeHistoryResult, error) { +func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *big.Int, rewardPercentiles []float64) (*ethereum.FeeHistory, error) { var res feeHistoryResultMarshaling if err := ec.c.CallContext(ctx, &res, "eth_feeHistory", hexutil.Uint(blockCount), toBlockNumArg(lastBlock), rewardPercentiles); err != nil { return nil, err @@ -537,7 +529,7 @@ func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock * for i, b := range res.BaseFee { baseFee[i] = (*big.Int)(b) } - return &FeeHistoryResult{ + return ðereum.FeeHistory{ OldestBlock: (*big.Int)(res.OldestBlock), Reward: reward, BaseFee: baseFee, diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index 9265d01f647ed..37add1bd36f0a 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -514,7 +514,7 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { if err != nil { t.Fatalf("unexpected error: %v", err) } - want := &FeeHistoryResult{ + want := ðereum.FeeHistory{ OldestBlock: big.NewInt(2), Reward: [][]*big.Int{ { diff --git a/interfaces.go b/interfaces.go index 76c1ef6908f25..cfb2345658b3d 100644 --- a/interfaces.go +++ b/interfaces.go @@ -201,6 +201,15 @@ type GasPricer interface { SuggestGasPrice(ctx context.Context) (*big.Int, error) } +// FeeHistory provides recent fee market data that consumers can use to determine +// a reasonable maxPriorityFeePerGas value. +type FeeHistory struct { + OldestBlock *big.Int `json:"oldestBlock"` // block coresponding to first response value + Reward [][]*big.Int `json:"reward,omitempty"` // list every txs priority fee per block + BaseFee []*big.Int `json:"baseFeePerGas,omitempty"` // list of each block's base fee + GasUsedRatio []float64 `json:"gasUsedRatio"` // ratio of gas used out of the total avaialble limit +} + // A PendingStateReader provides access to the pending state, which is the result of all // known executable transactions which have not yet been included in the blockchain. It is // commonly used to display the result of ’unconfirmed’ actions (e.g. wallet value From 813e1ba51dd7b6dbe019f62cfabd29e69e758a2c Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Wed, 27 Jul 2022 07:50:38 -0600 Subject: [PATCH 4/5] interfaces: remove json field names --- interfaces.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interfaces.go b/interfaces.go index cfb2345658b3d..9b4c1f3f429c1 100644 --- a/interfaces.go +++ b/interfaces.go @@ -204,10 +204,10 @@ type GasPricer interface { // FeeHistory provides recent fee market data that consumers can use to determine // a reasonable maxPriorityFeePerGas value. type FeeHistory struct { - OldestBlock *big.Int `json:"oldestBlock"` // block coresponding to first response value - Reward [][]*big.Int `json:"reward,omitempty"` // list every txs priority fee per block - BaseFee []*big.Int `json:"baseFeePerGas,omitempty"` // list of each block's base fee - GasUsedRatio []float64 `json:"gasUsedRatio"` // ratio of gas used out of the total avaialble limit + OldestBlock *big.Int // block coresponding to first response value + Reward [][]*big.Int // list every txs priority fee per block + BaseFee []*big.Int // list of each block's base fee + GasUsedRatio []float64 // ratio of gas used out of the total avaialble limit } // A PendingStateReader provides access to the pending state, which is the result of all From f64453394d1c6a04d751358513dd276e1cf53264 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 28 Jul 2022 12:38:49 +0200 Subject: [PATCH 5/5] fix typo --- interfaces.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interfaces.go b/interfaces.go index 9b4c1f3f429c1..e8d24a57cf7a1 100644 --- a/interfaces.go +++ b/interfaces.go @@ -207,7 +207,7 @@ type FeeHistory struct { OldestBlock *big.Int // block coresponding to first response value Reward [][]*big.Int // list every txs priority fee per block BaseFee []*big.Int // list of each block's base fee - GasUsedRatio []float64 // ratio of gas used out of the total avaialble limit + GasUsedRatio []float64 // ratio of gas used out of the total available limit } // A PendingStateReader provides access to the pending state, which is the result of all