From 1580ec180414bce1e37acc614bc2445f778efb75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 20 May 2016 12:29:28 +0300 Subject: accounts/abi/bind, eth: rely on getCode for sanity checks, not estimate and call --- accounts/abi/bind/base.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'accounts/abi/bind/base.go') diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index 06621c5ad..75e8d5bc8 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -20,6 +20,7 @@ import ( "errors" "fmt" "math/big" + "sync/atomic" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -56,6 +57,9 @@ type BoundContract struct { abi abi.ABI // Reflect based ABI to access the correct Ethereum methods caller ContractCaller // Read interface to interact with the blockchain transactor ContractTransactor // Write interface to interact with the blockchain + + latestHasCode uint32 // Cached verification that the latest state contains code for this contract + pendingHasCode uint32 // Cached verification that the pending state contains code for this contract } // NewBoundContract creates a low level contract interface through which calls @@ -96,6 +100,19 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string, if opts == nil { opts = new(CallOpts) } + // Make sure we have a contract to operate on, and bail out otherwise + if (opts.Pending && atomic.LoadUint32(&c.pendingHasCode) == 0) || (!opts.Pending && atomic.LoadUint32(&c.latestHasCode) == 0) { + if code, err := c.caller.HasCode(c.address, opts.Pending); err != nil { + return err + } else if !code { + return ErrNoCode + } + if opts.Pending { + atomic.StoreUint32(&c.pendingHasCode, 1) + } else { + atomic.StoreUint32(&c.latestHasCode, 1) + } + } // Pack the input, call and unpack the results input, err := c.abi.Pack(method, params...) if err != nil { @@ -153,6 +170,16 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i } gasLimit := opts.GasLimit if gasLimit == nil { + // Gas estimation cannot succeed without code for method invocations + if contract != nil && atomic.LoadUint32(&c.pendingHasCode) == 0 { + if code, err := c.transactor.HasCode(c.address, true); err != nil { + return nil, err + } else if !code { + return nil, ErrNoCode + } + atomic.StoreUint32(&c.pendingHasCode, 1) + } + // If the contract surely has code (or code is not needed), estimate the transaction gasLimit, err = c.transactor.EstimateGasLimit(opts.From, contract, value, input) if err != nil { return nil, fmt.Errorf("failed to exstimate gas needed: %v", err) -- cgit v1.2.3