Skip to content

Commit 27913dd

Browse files
draganmgballet
authored andcommitted
accounts/abi/bind: add optional block number for calls (#17942)
1 parent ddaf48b commit 27913dd

File tree

2 files changed

+70
-6
lines changed

2 files changed

+70
-6
lines changed

accounts/abi/bind/base.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra
3636

3737
// CallOpts is the collection of options to fine tune a contract call request.
3838
type CallOpts struct {
39-
Pending bool // Whether to operate on the pending state or the last known one
40-
From common.Address // Optional the sender address, otherwise the first account is used
41-
42-
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
39+
Pending bool // Whether to operate on the pending state or the last known one
40+
From common.Address // Optional the sender address, otherwise the first account is used
41+
BlockNumber *big.Int // Optional the block number on which the call should be performed
42+
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
4343
}
4444

4545
// TransactOpts is the collection of authorization data required to create a
@@ -148,10 +148,10 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
148148
}
149149
}
150150
} else {
151-
output, err = c.caller.CallContract(ctx, msg, nil)
151+
output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber)
152152
if err == nil && len(output) == 0 {
153153
// Make sure we have a contract to operate on, and bail out otherwise.
154-
if code, err = c.caller.CodeAt(ctx, c.address, nil); err != nil {
154+
if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil {
155155
return err
156156
} else if len(code) == 0 {
157157
return ErrNoCode

accounts/abi/bind/base_test.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package bind_test
2+
3+
import (
4+
"context"
5+
"math/big"
6+
"testing"
7+
8+
ethereum "github.com/ethereum/go-ethereum"
9+
"github.com/ethereum/go-ethereum/accounts/abi"
10+
"github.com/ethereum/go-ethereum/accounts/abi/bind"
11+
"github.com/ethereum/go-ethereum/common"
12+
)
13+
14+
type mockCaller struct {
15+
codeAtBlockNumber *big.Int
16+
callContractBlockNumber *big.Int
17+
}
18+
19+
func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
20+
mc.codeAtBlockNumber = blockNumber
21+
return []byte{1, 2, 3}, nil
22+
}
23+
24+
func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
25+
mc.callContractBlockNumber = blockNumber
26+
return nil, nil
27+
}
28+
29+
func TestPassingBlockNumber(t *testing.T) {
30+
31+
mc := &mockCaller{}
32+
33+
bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{
34+
Methods: map[string]abi.Method{
35+
"something": {
36+
Name: "something",
37+
Outputs: abi.Arguments{},
38+
},
39+
},
40+
}, mc, nil, nil)
41+
var ret string
42+
43+
blockNumber := big.NewInt(42)
44+
45+
bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something")
46+
47+
if mc.callContractBlockNumber != blockNumber {
48+
t.Fatalf("CallContract() was not passed the block number")
49+
}
50+
51+
if mc.codeAtBlockNumber != blockNumber {
52+
t.Fatalf("CodeAt() was not passed the block number")
53+
}
54+
55+
bc.Call(&bind.CallOpts{}, &ret, "something")
56+
57+
if mc.callContractBlockNumber != nil {
58+
t.Fatalf("CallContract() was passed a block number when it should not have been")
59+
}
60+
61+
if mc.codeAtBlockNumber != nil {
62+
t.Fatalf("CodeAt() was passed a block number when it should not have been")
63+
}
64+
}

0 commit comments

Comments
 (0)