mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
internal/ethapi, eth/gasestimator: honor block overrides in estimate gas
Apply block overrides consistently for eth_estimateGas by deriving an overridden header in DoEstimateGas and using it for estimator setup. Since header does not carry blobBaseFee, plumb BlobBaseFee explicitly into gasestimator options and apply it to the EVM block context during execution. Also add regression coverage for: - gasLimit override bounding estimation allowance - blobBaseFee override triggering ErrBlobFeeCapTooLow when BlobFeeCap is too low
This commit is contained in:
parent
fc43170cdd
commit
5dc734c150
3 changed files with 46 additions and 28 deletions
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi/override"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
|
@ -38,11 +37,12 @@ import (
|
|||
// these together, it would be excessively hard to test. Splitting the parts out
|
||||
// allows testing without needing a proper live chain.
|
||||
type Options struct {
|
||||
Config *params.ChainConfig // Chain configuration for hard fork selection
|
||||
Chain core.ChainContext // Chain context to access past block hashes
|
||||
Header *types.Header // Header defining the block context to execute in
|
||||
State *state.StateDB // Pre-state on top of which to estimate the gas
|
||||
BlockOverrides *override.BlockOverrides // Block overrides to apply during the estimation
|
||||
Config *params.ChainConfig // Chain configuration for hard fork selection
|
||||
Chain core.ChainContext // Chain context to access past block hashes
|
||||
Header *types.Header // Header defining the block context to execute in
|
||||
State *state.StateDB // Pre-state on top of which to estimate the gas
|
||||
|
||||
BlobBaseFee *big.Int // BlobBaseFee optionally overrides the blob base fee in the execution context.
|
||||
|
||||
ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination
|
||||
}
|
||||
|
|
@ -64,16 +64,7 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
|||
|
||||
// Cap the maximum gas allowance according to EIP-7825 if the estimation targets Osaka
|
||||
if hi > params.MaxTxGas {
|
||||
blockNumber, blockTime := opts.Header.Number, opts.Header.Time
|
||||
if opts.BlockOverrides != nil {
|
||||
if opts.BlockOverrides.Number != nil {
|
||||
blockNumber = opts.BlockOverrides.Number.ToInt()
|
||||
}
|
||||
if opts.BlockOverrides.Time != nil {
|
||||
blockTime = uint64(*opts.BlockOverrides.Time)
|
||||
}
|
||||
}
|
||||
if opts.Config.IsOsaka(blockNumber, blockTime) {
|
||||
if opts.Config.IsOsaka(opts.Header.Number, opts.Header.Time) {
|
||||
hi = params.MaxTxGas
|
||||
}
|
||||
}
|
||||
|
|
@ -241,10 +232,8 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio
|
|||
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
|
||||
dirtyState = opts.State.Copy()
|
||||
)
|
||||
if opts.BlockOverrides != nil {
|
||||
if err := opts.BlockOverrides.Apply(&evmContext); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if opts.BlobBaseFee != nil {
|
||||
evmContext.BlobBaseFee = new(big.Int).Set(opts.BlobBaseFee)
|
||||
}
|
||||
// Lower the basefee to 0 to avoid breaking EVM
|
||||
// invariants (basefee < feecap).
|
||||
|
|
|
|||
|
|
@ -897,6 +897,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||
if err := blockOverrides.Apply(&blockCtx); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
header = blockOverrides.MakeHeader(header)
|
||||
}
|
||||
rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time)
|
||||
precompiles := vm.ActivePrecompiledContracts(rules)
|
||||
|
|
@ -904,13 +905,17 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||
return 0, err
|
||||
}
|
||||
// Construct the gas estimator option from the user input
|
||||
var blobBaseFee *big.Int
|
||||
if blockOverrides != nil && blockOverrides.BlobBaseFee != nil {
|
||||
blobBaseFee = blockOverrides.BlobBaseFee.ToInt()
|
||||
}
|
||||
opts := &gasestimator.Options{
|
||||
Config: b.ChainConfig(),
|
||||
Chain: NewChainContext(ctx, b),
|
||||
Header: header,
|
||||
BlockOverrides: blockOverrides,
|
||||
State: state,
|
||||
ErrorRatio: estimateGasErrorRatio,
|
||||
Config: b.ChainConfig(),
|
||||
Chain: NewChainContext(ctx, b),
|
||||
Header: header,
|
||||
State: state,
|
||||
BlobBaseFee: blobBaseFee,
|
||||
ErrorRatio: estimateGasErrorRatio,
|
||||
}
|
||||
// Set any required transaction default, but make sure the gas cap itself is not messed with
|
||||
// if it was not specified in the original argument list.
|
||||
|
|
|
|||
|
|
@ -780,6 +780,17 @@ func TestEstimateGas(t *testing.T) {
|
|||
expectErr: core.ErrInsufficientFunds,
|
||||
want: 21000,
|
||||
},
|
||||
// block override gas limit should bound estimation search space.
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
Input: hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
|
||||
Gas: func() *hexutil.Uint64 { v := hexutil.Uint64(0); return &v }(),
|
||||
},
|
||||
blockOverrides: override.BlockOverrides{GasLimit: func() *hexutil.Uint64 { v := hexutil.Uint64(50000); return &v }()},
|
||||
expectErr: errors.New("gas required exceeds allowance (50000)"),
|
||||
},
|
||||
// empty create
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
|
|
@ -861,6 +872,19 @@ func TestEstimateGas(t *testing.T) {
|
|||
},
|
||||
want: 21000,
|
||||
},
|
||||
// blob base fee block override should be applied during estimation.
|
||||
{
|
||||
blockNumber: rpc.LatestBlockNumber,
|
||||
call: TransactionArgs{
|
||||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1)),
|
||||
BlobHashes: []common.Hash{{0x01, 0x22}},
|
||||
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
||||
},
|
||||
blockOverrides: override.BlockOverrides{BlobBaseFee: (*hexutil.Big)(big.NewInt(2))},
|
||||
expectErr: core.ErrBlobFeeCapTooLow,
|
||||
},
|
||||
// // SPDX-License-Identifier: GPL-3.0
|
||||
//pragma solidity >=0.8.2 <0.9.0;
|
||||
//
|
||||
|
|
@ -1014,7 +1038,7 @@ func TestCall(t *testing.T) {
|
|||
Balance: big.NewInt(params.Ether),
|
||||
Nonce: 1,
|
||||
Storage: map[common.Hash]common.Hash{
|
||||
common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"),
|
||||
{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -3795,7 +3819,7 @@ func TestCreateAccessListWithStateOverrides(t *testing.T) {
|
|||
Balance: (*hexutil.Big)(big.NewInt(1000000000000000000)),
|
||||
Nonce: &nonce,
|
||||
State: map[common.Hash]common.Hash{
|
||||
common.Hash{}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"),
|
||||
{}: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000002a"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue