From 15fb389ec712aae5c6f9e70a9952abc5bc6cde62 Mon Sep 17 00:00:00 2001 From: bnovil Date: Wed, 11 Oct 2023 16:28:42 +0800 Subject: [PATCH] add BlockOverrides to EstimateGas --- graphql/graphql.go | 4 ++-- internal/ethapi/api.go | 14 ++++++------- internal/ethapi/api_test.go | 32 +++++++++++++++++++++++------ internal/ethapi/transaction_args.go | 2 +- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 8304a64cf49f..00bbf94cb413 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -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 { @@ -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. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index cf1960fcf646..debc08a0eae5 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -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 @@ -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 @@ -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 } @@ -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. @@ -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 . diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 59882cd6bb54..8a428b5ed62e 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -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 { @@ -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: ×tamp, 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) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index e4cf81a3f4c8..5c956eae3fa0 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -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 }