Skip to content

Commit b135064

Browse files
committed
ethapi: add block override to estimateGas
1 parent 84a8021 commit b135064

File tree

6 files changed

+128
-23
lines changed

6 files changed

+128
-23
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ profile.cov
4242

4343
# IdeaIDE
4444
.idea
45+
*.iml
4546

4647
# VS Code
4748
.vscode

accounts/abi/abi.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,3 +309,13 @@ func UnpackRevert(data []byte) (string, error) {
309309
return "", errors.New("invalid data for unpacking")
310310
}
311311
}
312+
313+
func PackRevert(revertMessage string) []byte {
314+
stringType, _ := NewType("string", "", nil)
315+
args := Arguments{
316+
{Type: stringType},
317+
}
318+
encodedMessage, _ := args.Pack(revertMessage)
319+
320+
return append(revertSelector, encodedMessage...)
321+
}

internal/ethapi/api.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,20 +1311,28 @@ func (api *BlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrO
13111311
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
13121312
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
13131313
// non-zero) and `gasCap` (if non-zero).
1314-
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) {
1314+
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides, gasCap uint64) (hexutil.Uint64, error) {
13151315
// Retrieve the base state and mutate it with any overrides
13161316
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
13171317
if state == nil || err != nil {
13181318
return 0, err
13191319
}
1320-
if err := overrides.Apply(state, nil); err != nil {
1320+
chainContext := NewChainContext(ctx, b)
1321+
blockCtx := core.NewEVMBlockContext(header, chainContext, nil)
1322+
if blockOverrides != nil {
1323+
blockOverrides.Apply(&blockCtx)
1324+
}
1325+
1326+
rules := b.ChainConfig().Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time)
1327+
precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules))
1328+
if err := overrides.Apply(state, precompiles); err != nil {
13211329
return 0, err
13221330
}
13231331
// Construct the gas estimator option from the user input
13241332
opts := &gasestimator.Options{
13251333
Config: b.ChainConfig(),
1326-
Chain: NewChainContext(ctx, b),
1327-
Header: header,
1334+
Chain: chainContext,
1335+
Header: blockOverrides.MakeHeader(header),
13281336
State: state,
13291337
ErrorRatio: estimateGasErrorRatio,
13301338
}
@@ -1355,12 +1363,12 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
13551363
// value is capped by both `args.Gas` (if non-nil & non-zero) and the backend's RPCGasCap
13561364
// configuration (if non-zero).
13571365
// Note: Required blob gas is not computed in this method.
1358-
func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) {
1366+
func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash, overrides *StateOverride, blockOverrides *BlockOverrides) (hexutil.Uint64, error) {
13591367
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
13601368
if blockNrOrHash != nil {
13611369
bNrOrHash = *blockNrOrHash
13621370
}
1363-
return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.b.RPCGasCap())
1371+
return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, blockOverrides, api.b.RPCGasCap())
13641372
}
13651373

13661374
// RPCMarshalHeader converts the given header to the RPC output .

internal/ethapi/api_test.go

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"encoding/json"
2525
"errors"
2626
"fmt"
27+
"github.com/ethereum/go-ethereum/accounts/abi"
2728
"maps"
2829
"math/big"
2930
"os"
@@ -644,6 +645,7 @@ func TestEstimateGas(t *testing.T) {
644645
signer = types.HomesteadSigner{}
645646
randomAccounts = newAccounts(2)
646647
)
648+
647649
api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
648650
// Transfer from account[0] to account[1]
649651
// value: 1000 wei
@@ -652,14 +654,16 @@ func TestEstimateGas(t *testing.T) {
652654
b.AddTx(tx)
653655
b.SetPoS()
654656
}))
657+
655658
var testSuite = []struct {
656-
blockNumber rpc.BlockNumber
657-
call TransactionArgs
658-
overrides StateOverride
659-
expectErr error
660-
want uint64
659+
blockNumber rpc.BlockNumber
660+
call TransactionArgs
661+
overrides StateOverride
662+
blockOverrides BlockOverrides
663+
expectErr error
664+
want uint64
661665
}{
662-
// simple transfer on latest block
666+
//simple transfer on latest block
663667
{
664668
blockNumber: rpc.LatestBlockNumber,
665669
call: TransactionArgs{
@@ -762,16 +766,65 @@ func TestEstimateGas(t *testing.T) {
762766
},
763767
want: 21000,
764768
},
769+
// // SPDX-License-Identifier: GPL-3.0
770+
//pragma solidity >=0.8.2 <0.9.0;
771+
//
772+
//contract BlockOverridesTest {
773+
// function call() public view returns (uint256) {
774+
// return block.number;
775+
// }
776+
//
777+
// function estimate() public view {
778+
// revert(string.concat("block ", uint2str(block.number)));
779+
// }
780+
//
781+
// function uint2str(uint256 _i) internal pure returns (string memory str) {
782+
// if (_i == 0) {
783+
// return "0";
784+
// }
785+
// uint256 j = _i;
786+
// uint256 length;
787+
// while (j != 0) {
788+
// length++;
789+
// j /= 10;
790+
// }
791+
// bytes memory bstr = new bytes(length);
792+
// uint256 k = length;
793+
// j = _i;
794+
// while (j != 0) {
795+
// bstr[--k] = bytes1(uint8(48 + (j % 10)));
796+
// j /= 10;
797+
// }
798+
// str = string(bstr);
799+
// }
800+
//}
801+
{
802+
blockNumber: rpc.LatestBlockNumber,
803+
call: TransactionArgs{
804+
From: &accounts[0].addr,
805+
To: &accounts[1].addr,
806+
Data: hex2Bytes("0x3592d016"), //estimate
807+
},
808+
overrides: StateOverride{
809+
accounts[1].addr: OverrideAccount{
810+
Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"),
811+
},
812+
},
813+
blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
814+
expectErr: newRevertError(abi.PackRevert("block 11")),
815+
},
765816
}
766817
for i, tc := range testSuite {
767-
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
818+
result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
768819
if tc.expectErr != nil {
769820
if err == nil {
770821
t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
771822
continue
772823
}
773824
if !errors.Is(err, tc.expectErr) {
774-
t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
825+
if !reflect.DeepEqual(err, tc.expectErr) {
826+
t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
827+
}
775828
}
776829
continue
777830
}
@@ -932,16 +985,49 @@ func TestCall(t *testing.T) {
932985
},
933986
want: "0x000000000000000000000000000000000000000000000000000000000000007b",
934987
},
935-
// Block overrides should work
988+
// // SPDX-License-Identifier: GPL-3.0
989+
//pragma solidity >=0.8.2 <0.9.0;
990+
//
991+
//contract BlockOverridesTest {
992+
// function call() public view returns (uint256) {
993+
// return block.number;
994+
// }
995+
//
996+
// function estimate() public view {
997+
// revert(string.concat("block ", uint2str(block.number)));
998+
// }
999+
//
1000+
// function uint2str(uint256 _i) internal pure returns (string memory str) {
1001+
// if (_i == 0) {
1002+
// return "0";
1003+
// }
1004+
// uint256 j = _i;
1005+
// uint256 length;
1006+
// while (j != 0) {
1007+
// length++;
1008+
// j /= 10;
1009+
// }
1010+
// bytes memory bstr = new bytes(length);
1011+
// uint256 k = length;
1012+
// j = _i;
1013+
// while (j != 0) {
1014+
// bstr[--k] = bytes1(uint8(48 + (j % 10)));
1015+
// j /= 10;
1016+
// }
1017+
// str = string(bstr);
1018+
// }
1019+
//}
9361020
{
937-
name: "block-override",
1021+
name: "block-override-with-state-override",
9381022
blockNumber: rpc.LatestBlockNumber,
9391023
call: TransactionArgs{
9401024
From: &accounts[1].addr,
941-
Input: &hexutil.Bytes{
942-
0x43, // NUMBER
943-
0x60, 0x00, 0x52, // MSTORE offset 0
944-
0x60, 0x20, 0x60, 0x00, 0xf3,
1025+
To: &accounts[2].addr,
1026+
Data: hex2Bytes("0x28b5e32b"), //call
1027+
},
1028+
overrides: StateOverride{
1029+
accounts[2].addr: OverrideAccount{
1030+
Code: hex2Bytes("608060405234801561000f575f5ffd5b5060043610610034575f3560e01c806328b5e32b146100385780633592d0161461004b575b5f5ffd5b4360405190815260200160405180910390f35b610053610055565b005b61005e4361009d565b60405160200161006e91906101a5565b60408051601f198184030181529082905262461bcd60e51b8252610094916004016101cd565b60405180910390fd5b6060815f036100c35750506040805180820190915260018152600360fc1b602082015290565b815f5b81156100ec57806100d681610216565b91506100e59050600a83610242565b91506100c6565b5f8167ffffffffffffffff81111561010657610106610255565b6040519080825280601f01601f191660200182016040528015610130576020820181803683370190505b508593509050815b831561019c57610149600a85610269565b61015490603061027c565b60f81b8261016183610295565b92508281518110610174576101746102aa565b60200101906001600160f81b03191690815f1a905350610195600a85610242565b9350610138565b50949350505050565b650313637b1b5960d51b81525f82518060208501600685015e5f920160060191825250919050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b5f6001820161022757610227610202565b5060010190565b634e487b7160e01b5f52601260045260245ffd5b5f826102505761025061022e565b500490565b634e487b7160e01b5f52604160045260245ffd5b5f826102775761027761022e565b500690565b8082018082111561028f5761028f610202565b92915050565b5f816102a3576102a3610202565b505f190190565b634e487b7160e01b5f52603260045260245ffdfea2646970667358221220a253cad1e2e3523b8c053c1d0cd1e39d7f3bafcedd73440a244872701f05dab264736f6c634300081c0033"),
9451031
},
9461032
},
9471033
blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},

internal/ethapi/transaction_args.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGas
160160
BlobHashes: args.BlobHashes,
161161
}
162162
latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
163-
estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, b.RPCGasCap())
163+
estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, nil, b.RPCGasCap())
164164
if err != nil {
165165
return err
166166
}

internal/web3ext/web3ext.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,8 @@ web3._extend({
504504
new web3._extend.Method({
505505
name: 'estimateGas',
506506
call: 'eth_estimateGas',
507-
params: 3,
508-
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null],
507+
params: 4,
508+
inputFormatter: [web3._extend.formatters.inputCallFormatter, web3._extend.formatters.inputBlockNumberFormatter, null, null],
509509
outputFormatter: web3._extend.utils.toDecimal
510510
}),
511511
new web3._extend.Method({

0 commit comments

Comments
 (0)