Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal/ehtapi: add BlockOverrides to EstimateGas #28315

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions graphql/graphql.go
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,7 @@ func (b *Block) Call(ctx context.Context, args struct {
func (b *Block) EstimateGas(ctx context.Context, args struct {
Data ethapi.TransactionArgs
}) (hexutil.Uint64, error) {
return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCGasCap())
return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, nil, b.r.backend.RPCGasCap())
}

type Pending struct {
Expand Down Expand Up @@ -1276,7 +1276,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct {
Data ethapi.TransactionArgs
}) (hexutil.Uint64, error) {
latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, p.r.backend.RPCGasCap())
return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, nil, p.r.backend.RPCGasCap())
}

// Resolver is the top-level object in the GraphQL hierarchy.
Expand Down
14 changes: 7 additions & 7 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1181,9 +1181,9 @@ func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrO
// executeEstimate is a helper that executes the transaction under a given gas limit and returns
// true if the transaction fails for a reason that might be related to not enough gas. A non-nil
// error means execution failed due to reasons unrelated to the gas limit.
func executeEstimate(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, gasCap uint64, gasLimit uint64) (bool, *core.ExecutionResult, error) {
func executeEstimate(ctx context.Context, b Backend, args TransactionArgs, state *state.StateDB, header *types.Header, gasCap uint64, gasLimit uint64, blockOverrides *BlockOverrides) (bool, *core.ExecutionResult, error) {
args.Gas = (*hexutil.Uint64)(&gasLimit)
result, err := doCall(ctx, b, args, state, header, nil, nil, 0, gasCap)
result, err := doCall(ctx, b, args, state, header, nil, blockOverrides, 0, gasCap)
if err != nil {
if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit
Expand All @@ -1197,7 +1197,7 @@ func executeEstimate(ctx context.Context, b Backend, args TransactionArgs, state
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
// non-zero) and `gasCap` (if non-zero).
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) {
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, gasCap uint64) (hexutil.Uint64, error) {
// Binary search the gas limit, as it may need to be higher than the amount used
var (
lo uint64 // lowest-known gas limit where tx execution fails
Expand Down Expand Up @@ -1272,7 +1272,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr

// We first execute the transaction at the highest allowable gas limit, since if this fails we
// can return error immediately.
failed, result, err := executeEstimate(ctx, b, args, state.Copy(), header, gasCap, hi)
failed, result, err := executeEstimate(ctx, b, args, state.Copy(), header, gasCap, hi, blockOverrides)
if err != nil {
return 0, err
}
Expand Down Expand Up @@ -1300,7 +1300,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
// range here is skewed to favor the low side.
mid = lo * 2
}
failed, _, err = executeEstimate(ctx, b, args, state.Copy(), header, gasCap, mid)
failed, _, err = executeEstimate(ctx, b, args, state.Copy(), header, gasCap, mid, blockOverrides)
if err != nil {
// This should not happen under normal conditions since if we make it this far the
// transaction had run without error at least once before.
Expand All @@ -1321,12 +1321,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
// returns error if the transaction would revert or if there are unexpected failures. The returned
// value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap
// configuration (if non-zero).
func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) {
func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Uint64, error) {
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
if blockNrOrHash != nil {
bNrOrHash = *blockNrOrHash
}
return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, s.b.RPCGasCap())
return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, blockOverrides, s.b.RPCGasCap())
}

// RPCMarshalHeader converts the given header to the RPC output .
Expand Down
32 changes: 26 additions & 6 deletions internal/ethapi/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,12 +621,20 @@ func TestEstimateGas(t *testing.T) {
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key)
b.AddTx(tx)
}))

blockNumber := api.BlockNumber()
nextBlockNumber := (*hexutil.Big)(big.NewInt(int64(blockNumber + 1)))
block, _ := api.GetBlockByNumber(context.Background(), rpc.BlockNumber(blockNumber), true)
ts := block["timestamp"].(hexutil.Uint64)
timestamp := ts + 10

var testSuite = []struct {
blockNumber rpc.BlockNumber
call TransactionArgs
overrides StateOverride
expectErr error
want uint64
blockNumber rpc.BlockNumber
call TransactionArgs
overrides StateOverride
blockOverrides BlockOverrides
expectErr error
want uint64
}{
// simple transfer on latest block
{
Expand Down Expand Up @@ -678,9 +686,21 @@ func TestEstimateGas(t *testing.T) {
},
expectErr: core.ErrInsufficientFunds,
},
// with BlockOverrides
{
blockNumber: rpc.LatestBlockNumber,
call: TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
blockOverrides: BlockOverrides{Time: &timestamp, Number: nextBlockNumber},
expectErr: nil,
want: 21000,
},
}
for i, tc := range testSuite {
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
if tc.expectErr != nil {
if err == nil {
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
Expand Down
2 changes: 1 addition & 1 deletion internal/ethapi/transaction_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
AccessList: args.AccessList,
}
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, b.RPCGasCap())
estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, nil, b.RPCGasCap())
if err != nil {
return err
}
Expand Down