eth/gasprice/feehistory: support finalized block (#25442)

This commit is contained in:
lightclient 2022-08-01 10:13:30 -07:00 committed by GitHub
parent 1b34ed2ed6
commit a0b88ce869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 28 deletions

View File

@ -137,44 +137,68 @@ 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
}
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 {
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.SafeBlockNumber:
resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.SafeBlockNumber)
case rpc.FinalizedBlockNumber:
resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
case rpc.EarliestBlockNumber:
resolved, err = oracle.backend.HeaderByNumber(ctx, rpc.EarliestBlockNumber)
}
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.

View File

@ -50,6 +50,8 @@ 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.FinalizedBlockNumber, []float64{0, 10}, 24, 2, nil},
{false, 1000, 1000, 2, rpc.SafeBlockNumber, []float64{0, 10}, 24, 2, nil},
}
for i, c := range cases {
config := Config{

View File

@ -45,6 +45,15 @@ 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.FinalizedBlockNumber {
return b.chain.CurrentFinalizedBlock().Header(), nil
}
if number == rpc.SafeBlockNumber {
return b.chain.CurrentSafeBlock().Header(), nil
}
if number == rpc.LatestBlockNumber {
number = testHead
}
@ -62,6 +71,15 @@ 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.FinalizedBlockNumber {
return b.chain.CurrentFinalizedBlock(), nil
}
if number == rpc.SafeBlockNumber {
return b.chain.CurrentSafeBlock(), nil
}
if number == rpc.LatestBlockNumber {
number = testHead
}
@ -109,6 +127,7 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke
config.LondonBlock = londonBlock
config.ArrowGlacierBlock = londonBlock
config.GrayGlacierBlock = londonBlock
config.TerminalTotalDifficulty = common.Big0
engine := ethash.NewFaker()
db := rawdb.NewMemoryDatabase()
genesis, err := gspec.Commit(db)
@ -150,6 +169,8 @@ func newTestBackend(t *testing.T, londonBlock *big.Int, pending bool) *testBacke
t.Fatalf("Failed to create local chain, %v", err)
}
chain.InsertChain(blocks)
chain.SetFinalized(chain.GetBlockByNumber(25))
chain.SetSafe(chain.GetBlockByNumber(25))
return &testBackend{chain: chain, pending: pending}
}