From ed6e5175d675bbe5f766a0b28ec85dcbd7778533 Mon Sep 17 00:00:00 2001 From: zhiqiangxu <652732310@qq.com> Date: Tue, 15 Feb 2022 17:55:55 +0800 Subject: [PATCH] ethclient: add CallContractAtHash (#24355) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add CallContractAtHash to ethclient * add docstring and test * optimize test * ethclient: nits Co-authored-by: Péter Szilágyi --- ethclient/ethclient.go | 11 +++++++++++ ethclient/ethclient_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index e6a93c96f6a07..68389efbf4370 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -456,6 +456,17 @@ func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockN return hex, nil } +// CallContractAtHash is almost the same as CallContract except that it selects +// the block by block hash instead of block height. +func (ec *Client) CallContractAtHash(ctx context.Context, msg ethereum.CallMsg, blockHash common.Hash) ([]byte, error) { + var hex hexutil.Bytes + err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), rpc.BlockNumberOrHashWithHash(blockHash, false)) + if err != nil { + return nil, err + } + return hex, nil +} + // PendingCallContract executes a message call transaction using the EVM. // The state seen by the contract call is the pending state. func (ec *Client) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index d56febc91d746..4a8727b37478e 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -285,6 +285,9 @@ func TestEthClient(t *testing.T) { "CallContract": { func(t *testing.T) { testCallContract(t, client) }, }, + "CallContractAtHash": { + func(t *testing.T) { testCallContractAtHash(t, client) }, + }, "AtFunctions": { func(t *testing.T) { testAtFunctions(t, client) }, }, @@ -507,6 +510,33 @@ func testStatusFunctions(t *testing.T, client *rpc.Client) { } } +func testCallContractAtHash(t *testing.T, client *rpc.Client) { + ec := NewClient(client) + + // EstimateGas + msg := ethereum.CallMsg{ + From: testAddr, + To: &common.Address{}, + Gas: 21000, + Value: big.NewInt(1), + } + gas, err := ec.EstimateGas(context.Background(), msg) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if gas != 21000 { + t.Fatalf("unexpected gas price: %v", gas) + } + block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1)) + if err != nil { + t.Fatalf("BlockByNumber error: %v", err) + } + // CallContract + if _, err := ec.CallContractAtHash(context.Background(), msg, block.Hash()); err != nil { + t.Fatalf("unexpected error: %v", err) + } +} + func testCallContract(t *testing.T, client *rpc.Client) { ec := NewClient(client)