accounts/abi/bind: add optional block number for calls (#17942)
This commit is contained in:
		
				
					committed by
					
						
						Guillaume Ballet
					
				
			
			
				
	
			
			
			
						parent
						
							ddaf48bf84
						
					
				
				
					commit
					27913dd226
				
			@@ -38,7 +38,7 @@ type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Tra
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								accounts/abi/bind/base_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								accounts/abi/bind/base_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -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")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user