Skip to content

Commit

Permalink
eth_estimateGas: default feeCap to base fee (#10495)
Browse files Browse the repository at this point in the history
After [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) gas fee must
be greater or equal to block's base fee – otherwise `eth_estimateGas`
might fail with the fee defaulting to 0 (see
#10373 (comment)).

Also, this PR removes the `blockNrOrHash` argument from
`eth_estimateGas`. geth doesn't have it. Moreover, it was effectively
ignored by the previous code anyway with the exception of determining
gas limit.
  • Loading branch information
yperbasis authored May 27, 2024
1 parent cb9a019 commit da84730
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 54 deletions.
2 changes: 1 addition & 1 deletion turbo/jsonrpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ type EthAPI interface {

// Sending related (see ./eth_call.go)
Call(ctx context.Context, args ethapi2.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *ethapi2.StateOverrides) (hexutility.Bytes, error)
EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error)
EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs) (hexutil.Uint64, error)
SendRawTransaction(ctx context.Context, encodedTx hexutility.Bytes) (common.Hash, error)
SendTransaction(_ context.Context, txObject interface{}) (common.Hash, error)
Sign(ctx context.Context, _ common.Address, _ hexutility.Bytes) (hexutility.Bytes, error)
Expand Down
82 changes: 30 additions & 52 deletions turbo/jsonrpc/eth_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func headerByNumberOrHash(ctx context.Context, tx kv.Tx, blockNrOrHash rpc.Block
}

// EstimateGas implements eth_estimateGas. Returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain.
func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) {
func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs) (hexutil.Uint64, error) {
var args ethapi2.CallArgs
// if we actually get CallArgs here, we use them
if argsOrNil != nil {
Expand All @@ -135,36 +135,39 @@ func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs
args.From = new(libcommon.Address)
}

bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
chainConfig, err := api.chainConfig(ctx, dbtx)
if err != nil {
return 0, err
}

// Determine the highest gas limit can be used during the estimation.
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
// Retrieve the block to act as the gas ceiling
h, err := headerByNumberOrHash(ctx, dbtx, bNrOrHash, api)
latestCanBlockNumber, latestCanHash, isLatest, err := rpchelper.GetCanonicalBlockNumber(latestNumOrHash, dbtx, api.filters) // DoCall cannot be executed on non-canonical blocks
if err != nil {
return 0, err
}

// try and get the block from the lru cache first then try DB before failing
block := api.tryBlockFromLru(latestCanHash)
if block == nil {
block, err = api.blockWithSenders(ctx, dbtx, latestCanHash, latestCanBlockNumber)
if err != nil {
return 0, err
}
if h == nil {
// if a block number was supplied and there is no header return 0
if blockNrOrHash != nil {
return 0, nil
}
}
if block == nil {
return 0, fmt.Errorf("could not find latest block in cache or db")
}

// block number not supplied, so we haven't found a pending block, read the latest block instead
h, err = headerByNumberOrHash(ctx, dbtx, latestNumOrHash, api)
if err != nil {
return 0, err
}
if h == nil {
return 0, nil
}
}
hi = h.GasLimit
stateReader, err := rpchelper.CreateStateReaderFromBlockNumber(ctx, dbtx, latestCanBlockNumber, isLatest, 0, api.stateCache, chainConfig.ChainName)
if err != nil {
return 0, err
}
header := block.HeaderNoCopy()

// Determine the highest gas limit can be used during the estimation.
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
hi = uint64(*args.Gas)
} else {
hi = header.GasLimit
}

var feeCap *big.Int
Expand All @@ -174,6 +177,8 @@ func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs
feeCap = args.GasPrice.ToInt()
} else if args.MaxFeePerGas != nil {
feeCap = args.MaxFeePerGas.ToInt()
} else if header.BaseFee != nil {
feeCap = new(big.Int).Set(header.BaseFee)
} else {
feeCap = libcommon.Big0
}
Expand Down Expand Up @@ -218,35 +223,8 @@ func (api *APIImpl) EstimateGas(ctx context.Context, argsOrNil *ethapi2.CallArgs
}
gasCap = hi

chainConfig, err := api.chainConfig(ctx, dbtx)
if err != nil {
return 0, err
}
engine := api.engine()

latestCanBlockNumber, latestCanHash, isLatest, err := rpchelper.GetCanonicalBlockNumber(latestNumOrHash, dbtx, api.filters) // DoCall cannot be executed on non-canonical blocks
if err != nil {
return 0, err
}

// try and get the block from the lru cache first then try DB before failing
block := api.tryBlockFromLru(latestCanHash)
if block == nil {
block, err = api.blockWithSenders(ctx, dbtx, latestCanHash, latestCanBlockNumber)
if err != nil {
return 0, err
}
}
if block == nil {
return 0, fmt.Errorf("could not find latest block in cache or db")
}

stateReader, err := rpchelper.CreateStateReaderFromBlockNumber(ctx, dbtx, latestCanBlockNumber, isLatest, 0, api.stateCache, chainConfig.ChainName)
if err != nil {
return 0, err
}
header := block.HeaderNoCopy()

caller, err := transactions.NewReusableCaller(engine, stateReader, nil, header, args, api.GasCap, latestNumOrHash, dbtx, api._blockReader, chainConfig, api.evmCallTimeout)
if err != nil {
return 0, err
Expand Down
2 changes: 1 addition & 1 deletion turbo/jsonrpc/eth_call_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestEstimateGas(t *testing.T) {
if _, err := api.EstimateGas(context.Background(), &ethapi.CallArgs{
From: &from,
To: &to,
}, nil); err != nil {
}); err != nil {
t.Errorf("calling EstimateGas: %v", err)
}
}
Expand Down

0 comments on commit da84730

Please sign in to comment.