Skip to content

ethclient: Add EstimateGasAt[Hash] to estimate gas against a specific block #27508

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

Merged
Merged
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
32 changes: 29 additions & 3 deletions ethclient/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,9 +564,13 @@ func (ec *Client) FeeHistory(ctx context.Context, blockCount uint64, lastBlock *
}

// EstimateGas tries to estimate the gas needed to execute a specific transaction based on
// the current pending state of the backend blockchain. There is no guarantee that this is
// the true gas limit requirement as other transactions may be added or removed by miners,
// but it should provide a basis for setting a reasonable default.
// the current state of the backend blockchain. There is no guarantee that this is the
// true gas limit requirement as other transactions may be added or removed by miners, but
// it should provide a basis for setting a reasonable default.
//
// Note that the state used by this method is implementation-defined by the remote RPC
// server, but it's reasonable to assume that it will either be the pending or latest
// state.
func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg))
Expand All @@ -576,6 +580,28 @@ func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64
return uint64(hex), nil
}

// EstimateGasAtBlock is almost the same as EstimateGas except that it selects the block height
// instead of using the remote RPC's default state for gas estimation.
func (ec *Client) EstimateGasAtBlock(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg), toBlockNumArg(blockNumber))
if err != nil {
return 0, err
}
return uint64(hex), nil
}

// EstimateGasAtBlockHash is almost the same as EstimateGas except that it selects the block
// hash instead of using the remote RPC's default state for gas estimation.
func (ec *Client) EstimateGasAtBlockHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg), rpc.BlockNumberOrHashWithHash(blockHash, false))
if err != nil {
return 0, err
}
return uint64(hex), nil
}

// SendTransaction injects a signed transaction into the pending pool for execution.
//
// If the transaction was a contract creation use the TransactionReceipt method to get the
Expand Down
27 changes: 27 additions & 0 deletions ethclient/ethclient_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,33 @@ func testAtFunctions(t *testing.T, client *rpc.Client) {
if !bytes.Equal(code, penCode) {
t.Fatalf("unexpected code: %v %v", code, penCode)
}
// Use HeaderByNumber to get a header for EstimateGasAtBlock and EstimateGasAtBlockHash
latestHeader, err := ec.HeaderByNumber(context.Background(), nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// EstimateGasAtBlock
msg := ethereum.CallMsg{
From: testAddr,
To: &common.Address{},
Gas: 21000,
Value: big.NewInt(1),
}
gas, err := ec.EstimateGasAtBlock(context.Background(), msg, latestHeader.Number)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gas != 21000 {
t.Fatalf("unexpected gas limit: %v", gas)
}
// EstimateGasAtBlockHash
gas, err = ec.EstimateGasAtBlockHash(context.Background(), msg, latestHeader.Hash())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if gas != 21000 {
t.Fatalf("unexpected gas limit: %v", gas)
}
}

func testTransactionSender(t *testing.T, client *rpc.Client) {
Expand Down