add BlockOverrides to EstimateGas

This commit is contained in:
bnovil 2023-10-11 16:28:42 +08:00
parent 8976a0c97a
commit 15fb389ec7
4 changed files with 36 additions and 16 deletions

View file

@ -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.

View file

@ -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 .

View file

@ -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: &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)

View file

@ -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
}