From 46b95b700deb2d66e1d9c5ffcaeea52e0cb67dd7 Mon Sep 17 00:00:00 2001 From: Amin Talebi Date: Thu, 3 Aug 2023 16:41:40 +0200 Subject: [PATCH 1/6] ethapi: add state override to DoEstimateGas function signature --- internal/ethapi/api.go | 4 ++-- internal/ethapi/transaction_args.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e130d9c5070f1..9d75d12e56f0f 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1134,7 +1134,7 @@ func (s *BlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrO return result.Return(), result.Err } -func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap uint64) (hexutil.Uint64, error) { +func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) { // Binary search the gas requirement, as it may be higher than the amount used var ( lo uint64 = params.TxGas - 1 @@ -1266,7 +1266,7 @@ func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, b if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap()) + return DoEstimateGas(ctx, s.b, args, bNrOrHash, nil, s.b.RPCGasCap()) // TODO: add state overrides } // RPCMarshalHeader converts the given header to the RPC output . diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 6e2690e095d9b..3dfbf688c20fa 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, b.RPCGasCap()) + estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, b.RPCGasCap()) // TODO: add state overrides if err != nil { return err } From 0170977585e7ebadc20acd1bac8d1fa18e514624 Mon Sep 17 00:00:00 2001 From: Amin Talebi Date: Thu, 3 Aug 2023 17:03:45 +0200 Subject: [PATCH 2/6] ethapi: add unit tests for estimate gas state overrides --- internal/ethapi/api.go | 12 ++++++++++-- internal/ethapi/api_test.go | 12 +++++++++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 9d75d12e56f0f..c16bd07e05902 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1176,6 +1176,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr if err != nil { return 0, err } + err = overrides.Apply(state) + if err != nil { + return 0, err + } balance := state.GetBalance(*args.From) // from can't be nil available := new(big.Int).Set(balance) if args.Value != nil { @@ -1221,6 +1225,10 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr if state == nil || err != nil { return 0, err } + err = overrides.Apply(state) + if err != nil { + return 0, err + } // Execute the binary search and hone in on an executable gas limit for lo+1 < hi { s := state.Copy() @@ -1261,12 +1269,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr // EstimateGas returns an estimate of the amount of gas needed to execute the // given transaction against the current pending block. -func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) { +func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) { bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) if blockNrOrHash != nil { bNrOrHash = *blockNrOrHash } - return DoEstimateGas(ctx, s.b, args, bNrOrHash, nil, s.b.RPCGasCap()) // TODO: add state overrides + return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, 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 4d8c7e07074bf..5d62a813fa251 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -424,6 +424,7 @@ func TestEstimateGas(t *testing.T) { var testSuite = []struct { blockNumber rpc.BlockNumber call TransactionArgs + overrides StateOverride expectErr error want uint64 }{ @@ -456,9 +457,18 @@ func TestEstimateGas(t *testing.T) { expectErr: nil, want: 53000, }, + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{}, + overrides: StateOverride{ + randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))}, + }, + expectErr: nil, + want: 53000, + }, } for i, tc := range testSuite { - result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}) + result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides) if tc.expectErr != nil { if err == nil { t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr) From 4b48694789df19abf2c2632470d70ee3d278220a Mon Sep 17 00:00:00 2001 From: Amin Talebi Date: Thu, 3 Aug 2023 17:05:44 +0200 Subject: [PATCH 3/6] ethapi: remove todo comment --- internal/ethapi/transaction_args.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 3dfbf688c20fa..e4cf81a3f4c83 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()) // TODO: add state overrides + estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, b.RPCGasCap()) if err != nil { return err } From 949ce63a2a898649054b1b7550fe097622576545 Mon Sep 17 00:00:00 2001 From: Amin Talebi Date: Thu, 3 Aug 2023 18:00:28 +0200 Subject: [PATCH 4/6] graphql: add state overrides to estimate gas overrides --- graphql/graphql.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index aa042862bd36f..449b49a427683 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1128,9 +1128,10 @@ func (b *Block) Call(ctx context.Context, args struct { } func (b *Block) EstimateGas(ctx context.Context, args struct { - Data ethapi.TransactionArgs + Data ethapi.TransactionArgs + Overrides ethapi.StateOverride }) (hexutil.Uint64, error) { - return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, &args.Overrides, b.r.backend.RPCGasCap()) } type Pending struct { @@ -1191,10 +1192,11 @@ func (p *Pending) Call(ctx context.Context, args struct { } func (p *Pending) EstimateGas(ctx context.Context, args struct { - Data ethapi.TransactionArgs + Data ethapi.TransactionArgs + Overrides ethapi.StateOverride }) (hexutil.Uint64, error) { latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, p.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, &args.Overrides, p.r.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. From 2517087daef79a7a00e397840a875a440f2a42ec Mon Sep 17 00:00:00 2001 From: Amin Talebi Date: Fri, 4 Aug 2023 18:02:13 +0200 Subject: [PATCH 5/6] graphql: revert changes to estimate gas graphql --- graphql/graphql.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index 449b49a427683..088cd33e8d4b9 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -1128,10 +1128,9 @@ func (b *Block) Call(ctx context.Context, args struct { } func (b *Block) EstimateGas(ctx context.Context, args struct { - Data ethapi.TransactionArgs - Overrides ethapi.StateOverride + Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { - return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, &args.Overrides, b.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCGasCap()) } type Pending struct { @@ -1192,11 +1191,10 @@ func (p *Pending) Call(ctx context.Context, args struct { } func (p *Pending) EstimateGas(ctx context.Context, args struct { - Data ethapi.TransactionArgs - Overrides ethapi.StateOverride + Data ethapi.TransactionArgs }) (hexutil.Uint64, error) { latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) - return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, &args.Overrides, p.r.backend.RPCGasCap()) + return ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, latestBlockNr, nil, p.r.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. From c37df5a7b32017d043bfff9877abd45be659d65b Mon Sep 17 00:00:00 2001 From: Amin Talebi Date: Fri, 4 Aug 2023 18:27:01 +0200 Subject: [PATCH 6/6] ethapi: add more tests --- internal/ethapi/api_test.go | 12 ++++++++++++ internal/web3ext/web3ext.go | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go index 5d62a813fa251..421904146958a 100644 --- a/internal/ethapi/api_test.go +++ b/internal/ethapi/api_test.go @@ -466,6 +466,18 @@ func TestEstimateGas(t *testing.T) { expectErr: nil, want: 53000, }, + { + blockNumber: rpc.LatestBlockNumber, + call: TransactionArgs{ + From: &randomAccounts[0].addr, + To: &randomAccounts[1].addr, + Value: (*hexutil.Big)(big.NewInt(1000)), + }, + overrides: StateOverride{ + randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))}, + }, + expectErr: core.ErrInsufficientFunds, + }, } for i, tc := range testSuite { result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index f47564dc855e5..55f19f3104eeb 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -536,8 +536,8 @@ web3._extend({ new web3._extend.Method({ name: 'estimateGas', call: 'eth_estimateGas', - params: 2, - inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter], + params: 3, + inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null], outputFormatter: web3._extend.utils.toDecimal }), new web3._extend.Method({