Skip to content

Commit

Permalink
eth/gasprice/feehistory: support finalized block (ethereum#25442)
Browse files Browse the repository at this point in the history
  • Loading branch information
gzliudan committed Jun 13, 2024
1 parent 7a687ad commit 781b7d8
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 28 deletions.
78 changes: 50 additions & 28 deletions eth/gasprice/feehistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
reward, _ := tx.EffectiveGasTip(bf.block.BaseFee())
sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward}
}
sort.Sort(sorter)
sort.Stable(sorter)

var txIndex int
sumGasUsed := sorter[0].gasUsed
Expand All @@ -137,44 +137,66 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
// also returned if requested and available.
// Note: an error is only returned if retrieving the head header has failed. If there are no
// retrievable blocks in the specified range then zero block count is returned with no error.
func (oracle *Oracle) resolveBlockRange(ctx context.Context, lastBlock rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) {
func (oracle *Oracle) resolveBlockRange(ctx context.Context, reqEnd rpc.BlockNumber, blocks int) (*types.Block, []*types.Receipt, uint64, int, error) {
var (
headBlock rpc.BlockNumber
headBlock *types.Header
pendingBlock *types.Block
pendingReceipts types.Receipts
err error
)
// query either pending block or head header and set headBlock
if lastBlock == rpc.PendingBlockNumber {
if pendingBlock, pendingReceipts = oracle.backend.PendingBlockAndReceipts(); pendingBlock != nil {
lastBlock = rpc.BlockNumber(pendingBlock.NumberU64())
headBlock = lastBlock - 1
} else {
// pending block not supported by backend, process until latest block
lastBlock = rpc.LatestBlockNumber
blocks--
if blocks == 0 {
return nil, nil, 0, 0, nil

// Get the chain's current head.
if headBlock, err = oracle.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber); err != nil {
return nil, nil, 0, 0, err
}
head := rpc.BlockNumber(headBlock.Number.Uint64())

// Fail if request block is beyond the chain's current head.
if head < reqEnd {
return nil, nil, 0, 0, fmt.Errorf("%w: requested %d, head %d", errRequestBeyondHead, reqEnd, head)
}

// Resolve block tag.
if reqEnd < 0 {
var (
resolved *types.Header
err error
)
switch reqEnd {
case rpc.PendingBlockNumber:
if pendingBlock, pendingReceipts = oracle.backend.PendingBlockAndReceipts(); pendingBlock != nil {
resolved = pendingBlock.Header()
} else {
// Pending block not supported by backend, process only until latest block.
resolved = headBlock

// Update total blocks to return to account for this.
blocks--
}
case rpc.LatestBlockNumber:
// Retrieved above.
resolved = headBlock
case rpc.CommittedBlockNumber:
resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.CommittedBlockNumber)
case rpc.EarliestBlockNumber:
resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.EarliestBlockNumber)
}
}
if pendingBlock == nil {
// if pending block is not fetched then we retrieve the head header to get the head block number
if latestHeader, err := oracle.backend.HeaderByNumber(ctx, rpc.LatestBlockNumber); err == nil {
headBlock = rpc.BlockNumber(latestHeader.Number.Uint64())
} else {
if resolved == nil || err != nil {
return nil, nil, 0, 0, err
}
// Absolute number resolved.
reqEnd = rpc.BlockNumber(resolved.Number.Uint64())
}
if lastBlock == rpc.LatestBlockNumber {
lastBlock = headBlock
} else if pendingBlock == nil && lastBlock > headBlock {
return nil, nil, 0, 0, fmt.Errorf("%w: requested %d, head %d", errRequestBeyondHead, lastBlock, headBlock)

// If there are no blocks to return, short circuit.
if blocks == 0 {
return nil, nil, 0, 0, nil
}
// ensure not trying to retrieve before genesis
if rpc.BlockNumber(blocks) > lastBlock+1 {
blocks = int(lastBlock + 1)
// Ensure not trying to retrieve before genesis.
if int(reqEnd+1) < blocks {
blocks = int(reqEnd + 1)
}
return pendingBlock, pendingReceipts, uint64(lastBlock), blocks, nil
return pendingBlock, pendingReceipts, uint64(reqEnd), blocks, nil
}

// FeeHistory returns data relevant for fee estimation based on the specified range of blocks.
Expand Down
1 change: 1 addition & 0 deletions eth/gasprice/feehistory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func TestFeeHistory(t *testing.T) {
{false, 1000, 1000, 2, rpc.PendingBlockNumber, nil, 32, 1, nil},
{true, 1000, 1000, 2, rpc.PendingBlockNumber, nil, 32, 2, nil},
{true, 1000, 1000, 2, rpc.PendingBlockNumber, []float64{0, 10}, 32, 2, nil},
{false, 1000, 1000, 2, rpc.CommittedBlockNumber, []float64{0, 10}, 32, 1, nil},
}
for i, c := range cases {
config := Config{
Expand Down
12 changes: 12 additions & 0 deletions eth/gasprice/gasprice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber
if number > testHead {
return nil, nil
}
if number == rpc.EarliestBlockNumber {
number = 0
}
if number == rpc.CommittedBlockNumber {
return b.chain.CurrentBlock().Header(), nil
}
if number == rpc.LatestBlockNumber {
number = testHead
}
Expand All @@ -62,6 +68,12 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber)
if number > testHead {
return nil, nil
}
if number == rpc.EarliestBlockNumber {
number = 0
}
if number == rpc.CommittedBlockNumber {
return b.chain.CurrentBlock(), nil
}
if number == rpc.LatestBlockNumber {
number = testHead
}
Expand Down

0 comments on commit 781b7d8

Please sign in to comment.