Skip to content

Commit

Permalink
accounts/abi/bind: add optional block number for calls (#17942)
Browse files Browse the repository at this point in the history
  • Loading branch information
draganm authored and gballet committed Jan 3, 2019
1 parent ddaf48b commit 27913dd
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 6 deletions.
12 changes: 6 additions & 6 deletions accounts/abi/bind/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra

// CallOpts is the collection of options to fine tune a contract call request.
type CallOpts struct {
Pending bool // Whether to operate on the pending state or the last known one
From common.Address // Optional the sender address, otherwise the first account is used

Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
Pending bool // Whether to operate on the pending state or the last known one
From common.Address // Optional the sender address, otherwise the first account is used
BlockNumber *big.Int // Optional the block number on which the call should be performed
Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}

// TransactOpts is the collection of authorization data required to create a
Expand Down Expand Up @@ -148,10 +148,10 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
}
}
} else {
output, err = c.caller.CallContract(ctx, msg, nil)
output, err = c.caller.CallContract(ctx, msg, opts.BlockNumber)
if err == nil && len(output) == 0 {
// Make sure we have a contract to operate on, and bail out otherwise.
if code, err = c.caller.CodeAt(ctx, c.address, nil); err != nil {
if code, err = c.caller.CodeAt(ctx, c.address, opts.BlockNumber); err != nil {
return err
} else if len(code) == 0 {
return ErrNoCode
Expand Down
64 changes: 64 additions & 0 deletions accounts/abi/bind/base_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package bind_test

import (
"context"
"math/big"
"testing"

ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
)

type mockCaller struct {
codeAtBlockNumber *big.Int
callContractBlockNumber *big.Int
}

func (mc *mockCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
mc.codeAtBlockNumber = blockNumber
return []byte{1, 2, 3}, nil
}

func (mc *mockCaller) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) {
mc.callContractBlockNumber = blockNumber
return nil, nil
}

func TestPassingBlockNumber(t *testing.T) {

mc := &mockCaller{}

bc := bind.NewBoundContract(common.HexToAddress("0x0"), abi.ABI{
Methods: map[string]abi.Method{
"something": {
Name: "something",
Outputs: abi.Arguments{},
},
},
}, mc, nil, nil)
var ret string

blockNumber := big.NewInt(42)

bc.Call(&bind.CallOpts{BlockNumber: blockNumber}, &ret, "something")

if mc.callContractBlockNumber != blockNumber {
t.Fatalf("CallContract() was not passed the block number")
}

if mc.codeAtBlockNumber != blockNumber {
t.Fatalf("CodeAt() was not passed the block number")
}

bc.Call(&bind.CallOpts{}, &ret, "something")

if mc.callContractBlockNumber != nil {
t.Fatalf("CallContract() was passed a block number when it should not have been")
}

if mc.codeAtBlockNumber != nil {
t.Fatalf("CodeAt() was passed a block number when it should not have been")
}
}

0 comments on commit 27913dd

Please sign in to comment.