aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/abi
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2016-06-30 17:57:50 +0800
committerGitHub <noreply@github.com>2016-06-30 17:57:50 +0800
commit1e50f5dd281d28b8db1c65b9e80e53080b86e369 (patch)
tree30a0832e6f514fe06fe9308043eaa20d2ba44b13 /accounts/abi
parentf127799d795eaf2d6f99780c058361cd561492f1 (diff)
parent3a97280ae889bb6852ba16e70750a37b2ed08473 (diff)
downloadgo-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.tar
go-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.tar.gz
go-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.tar.bz2
go-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.tar.lz
go-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.tar.xz
go-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.tar.zst
go-tangerine-1e50f5dd281d28b8db1c65b9e80e53080b86e369.zip
Merge pull request #2159 from zsfelfoldi/light-backend
eth: separate common and full node-specific API and backend service
Diffstat (limited to 'accounts/abi')
-rw-r--r--accounts/abi/bind/backend.go27
-rw-r--r--accounts/abi/bind/backends/nil.go19
-rw-r--r--accounts/abi/bind/backends/remote.go47
-rw-r--r--accounts/abi/bind/backends/simulated.go13
-rw-r--r--accounts/abi/bind/base.go19
5 files changed, 77 insertions, 48 deletions
diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/backend.go
index 65806aef4..bec742c29 100644
--- a/accounts/abi/bind/backend.go
+++ b/accounts/abi/bind/backend.go
@@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
+ "golang.org/x/net/context"
)
// ErrNoCode is returned by call and transact operations for which the requested
@@ -35,12 +36,12 @@ type ContractCaller interface {
// HasCode checks if the contract at the given address has any code associated
// with it or not. This is needed to differentiate between contract internal
// errors and the local chain being out of sync.
- HasCode(contract common.Address, pending bool) (bool, error)
+ HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error)
// ContractCall executes an Ethereum contract call with the specified data as
// the input. The pending flag requests execution against the pending block, not
// the stable head of the chain.
- ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error)
+ ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error)
}
// ContractTransactor defines the methods needed to allow operating with contract
@@ -50,26 +51,26 @@ type ContractCaller interface {
type ContractTransactor interface {
// PendingAccountNonce retrieves the current pending nonce associated with an
// account.
- PendingAccountNonce(account common.Address) (uint64, error)
+ PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error)
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
- SuggestGasPrice() (*big.Int, error)
+ SuggestGasPrice(ctx context.Context) (*big.Int, error)
// HasCode checks if the contract at the given address has any code associated
// with it or not. This is needed to differentiate between contract internal
// errors and the local chain being out of sync.
- HasCode(contract common.Address, pending bool) (bool, error)
+ HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error)
// EstimateGasLimit tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain.
// There is no guarantee that this is the true gas limit requirement as other
// transactions may be added or removed by miners, but it should provide a basis
// for setting a reasonable default.
- EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
+ EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
// SendTransaction injects the transaction into the pending pool for execution.
- SendTransaction(tx *types.Transaction) error
+ SendTransaction(ctx context.Context, tx *types.Transaction) error
}
// ContractBackend defines the methods needed to allow operating with contract
@@ -84,28 +85,28 @@ type ContractBackend interface {
// HasCode checks if the contract at the given address has any code associated
// with it or not. This is needed to differentiate between contract internal
// errors and the local chain being out of sync.
- HasCode(contract common.Address, pending bool) (bool, error)
+ HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error)
// ContractCall executes an Ethereum contract call with the specified data as
// the input. The pending flag requests execution against the pending block, not
// the stable head of the chain.
- ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error)
+ ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error)
// PendingAccountNonce retrieves the current pending nonce associated with an
// account.
- PendingAccountNonce(account common.Address) (uint64, error)
+ PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error)
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
- SuggestGasPrice() (*big.Int, error)
+ SuggestGasPrice(ctx context.Context) (*big.Int, error)
// EstimateGasLimit tries to estimate the gas needed to execute a specific
// transaction based on the current pending state of the backend blockchain.
// There is no guarantee that this is the true gas limit requirement as other
// transactions may be added or removed by miners, but it should provide a basis
// for setting a reasonable default.
- EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
+ EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error)
// SendTransaction injects the transaction into the pending pool for execution.
- SendTransaction(tx *types.Transaction) error
+ SendTransaction(ctx context.Context, tx *types.Transaction) error
}
diff --git a/accounts/abi/bind/backends/nil.go b/accounts/abi/bind/backends/nil.go
index f10bb61ac..54b222f1f 100644
--- a/accounts/abi/bind/backends/nil.go
+++ b/accounts/abi/bind/backends/nil.go
@@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
+ "golang.org/x/net/context"
)
// This nil assignment ensures compile time that nilBackend implements bind.ContractBackend.
@@ -32,16 +33,22 @@ var _ bind.ContractBackend = (*nilBackend)(nil)
// wrappers without calling any methods on them.
type nilBackend struct{}
-func (*nilBackend) ContractCall(common.Address, []byte, bool) ([]byte, error) {
+func (*nilBackend) ContractCall(context.Context, common.Address, []byte, bool) ([]byte, error) {
panic("not implemented")
}
-func (*nilBackend) EstimateGasLimit(common.Address, *common.Address, *big.Int, []byte) (*big.Int, error) {
+func (*nilBackend) EstimateGasLimit(context.Context, common.Address, *common.Address, *big.Int, []byte) (*big.Int, error) {
+ panic("not implemented")
+}
+func (*nilBackend) HasCode(context.Context, common.Address, bool) (bool, error) {
+ panic("not implemented")
+}
+func (*nilBackend) SuggestGasPrice(context.Context) (*big.Int, error) { panic("not implemented") }
+func (*nilBackend) PendingAccountNonce(context.Context, common.Address) (uint64, error) {
+ panic("not implemented")
+}
+func (*nilBackend) SendTransaction(context.Context, *types.Transaction) error {
panic("not implemented")
}
-func (*nilBackend) HasCode(common.Address, bool) (bool, error) { panic("not implemented") }
-func (*nilBackend) SuggestGasPrice() (*big.Int, error) { panic("not implemented") }
-func (*nilBackend) PendingAccountNonce(common.Address) (uint64, error) { panic("not implemented") }
-func (*nilBackend) SendTransaction(*types.Transaction) error { panic("not implemented") }
// NewNilBackend creates a new binding backend that can be used for instantiation
// but will panic on any invocation. Its sole purpose is to help testing.
diff --git a/accounts/abi/bind/backends/remote.go b/accounts/abi/bind/backends/remote.go
index d903cbc8f..4793143e4 100644
--- a/accounts/abi/bind/backends/remote.go
+++ b/accounts/abi/bind/backends/remote.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
+ "golang.org/x/net/context"
)
// This nil assignment ensures compile time that rpcBackend implements bind.ContractBackend.
@@ -80,18 +81,23 @@ type failure struct {
//
// This is currently painfully non-concurrent, but it will have to do until we
// find the time for niceties like this :P
-func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessage, error) {
+func (b *rpcBackend) request(ctx context.Context, method string, params []interface{}) (json.RawMessage, error) {
b.lock.Lock()
defer b.lock.Unlock()
+ if ctx == nil {
+ ctx = context.Background()
+ }
+
// Ugly hack to serialize an empty list properly
if params == nil {
params = []interface{}{}
}
// Assemble the request object
+ reqID := int(atomic.AddUint32(&b.autoid, 1))
req := &request{
JSONRPC: "2.0",
- ID: int(atomic.AddUint32(&b.autoid, 1)),
+ ID: reqID,
Method: method,
Params: params,
}
@@ -99,8 +105,17 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
return nil, err
}
res := new(response)
- if err := b.client.Recv(res); err != nil {
- return nil, err
+ errc := make(chan error, 1)
+ go func() {
+ errc <- b.client.Recv(res)
+ }()
+ select {
+ case err := <-errc:
+ if err != nil {
+ return nil, err
+ }
+ case <-ctx.Done():
+ return nil, ctx.Err()
}
if res.Error != nil {
if res.Error.Message == bind.ErrNoCode.Error() {
@@ -113,13 +128,13 @@ func (b *rpcBackend) request(method string, params []interface{}) (json.RawMessa
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
// with the contract from the remote node, and checking its size.
-func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error) {
+func (b *rpcBackend) HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error) {
// Execute the RPC code retrieval
block := "latest"
if pending {
block = "pending"
}
- res, err := b.request("eth_getCode", []interface{}{contract.Hex(), block})
+ res, err := b.request(ctx, "eth_getCode", []interface{}{contract.Hex(), block})
if err != nil {
return false, err
}
@@ -133,7 +148,7 @@ func (b *rpcBackend) HasCode(contract common.Address, pending bool) (bool, error
// ContractCall implements ContractCaller.ContractCall, delegating the execution of
// a contract call to the remote node, returning the reply to for local processing.
-func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {
+func (b *rpcBackend) ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error) {
// Pack up the request into an RPC argument
args := struct {
To common.Address `json:"to"`
@@ -147,7 +162,7 @@ func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending
if pending {
block = "pending"
}
- res, err := b.request("eth_call", []interface{}{args, block})
+ res, err := b.request(ctx, "eth_call", []interface{}{args, block})
if err != nil {
return nil, err
}
@@ -161,8 +176,8 @@ func (b *rpcBackend) ContractCall(contract common.Address, data []byte, pending
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
// the current account nonce retrieval to the remote node.
-func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error) {
- res, err := b.request("eth_getTransactionCount", []interface{}{account.Hex(), "pending"})
+func (b *rpcBackend) PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error) {
+ res, err := b.request(ctx, "eth_getTransactionCount", []interface{}{account.Hex(), "pending"})
if err != nil {
return 0, err
}
@@ -179,8 +194,8 @@ func (b *rpcBackend) PendingAccountNonce(account common.Address) (uint64, error)
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
// gas price oracle request to the remote node.
-func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
- res, err := b.request("eth_gasPrice", nil)
+func (b *rpcBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
+ res, err := b.request(ctx, "eth_gasPrice", nil)
if err != nil {
return nil, err
}
@@ -197,7 +212,7 @@ func (b *rpcBackend) SuggestGasPrice() (*big.Int, error) {
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, delegating
// the gas estimation to the remote node.
-func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
+func (b *rpcBackend) EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
// Pack up the request into an RPC argument
args := struct {
From common.Address `json:"from"`
@@ -211,7 +226,7 @@ func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Ad
Value: rpc.NewHexNumber(value),
}
// Execute the RPC call and retrieve the response
- res, err := b.request("eth_estimateGas", []interface{}{args})
+ res, err := b.request(ctx, "eth_estimateGas", []interface{}{args})
if err != nil {
return nil, err
}
@@ -228,12 +243,12 @@ func (b *rpcBackend) EstimateGasLimit(sender common.Address, contract *common.Ad
// SendTransaction implements ContractTransactor.SendTransaction, delegating the
// raw transaction injection to the remote node.
-func (b *rpcBackend) SendTransaction(tx *types.Transaction) error {
+func (b *rpcBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
data, err := rlp.EncodeToBytes(tx)
if err != nil {
return err
}
- res, err := b.request("eth_sendRawTransaction", []interface{}{common.ToHex(data)})
+ res, err := b.request(ctx, "eth_sendRawTransaction", []interface{}{common.ToHex(data)})
if err != nil {
return err
}
diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 54b1ce603..490da82a6 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
+ "golang.org/x/net/context"
)
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
@@ -80,7 +81,7 @@ func (b *SimulatedBackend) Rollback() {
// HasCode implements ContractVerifier.HasCode, checking whether there is any
// code associated with a certain account in the blockchain.
-func (b *SimulatedBackend) HasCode(contract common.Address, pending bool) (bool, error) {
+func (b *SimulatedBackend) HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error) {
if pending {
return len(b.pendingState.GetCode(contract)) > 0, nil
}
@@ -90,7 +91,7 @@ func (b *SimulatedBackend) HasCode(contract common.Address, pending bool) (bool,
// ContractCall implements ContractCaller.ContractCall, executing the specified
// contract with the given input data.
-func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) {
+func (b *SimulatedBackend) ContractCall(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error) {
// Create a copy of the current state db to screw around with
var (
block *types.Block
@@ -129,20 +130,20 @@ func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pe
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, retrieving
// the nonce currently pending for the account.
-func (b *SimulatedBackend) PendingAccountNonce(account common.Address) (uint64, error) {
+func (b *SimulatedBackend) PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error) {
return b.pendingState.GetOrNewStateObject(account).Nonce(), nil
}
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated
// chain doens't have miners, we just return a gas price of 1 for any call.
-func (b *SimulatedBackend) SuggestGasPrice() (*big.Int, error) {
+func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
return big.NewInt(1), nil
}
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, executing the
// requested code against the currently pending block/state and returning the used
// gas.
-func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
+func (b *SimulatedBackend) EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) {
// Create a copy of the currently pending state db to screw around with
var (
block = b.pendingBlock
@@ -177,7 +178,7 @@ func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *com
// SendTransaction implements ContractTransactor.SendTransaction, delegating the raw
// transaction injection to the remote node.
-func (b *SimulatedBackend) SendTransaction(tx *types.Transaction) error {
+func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error {
blocks, _ := core.GenerateChain(b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
for _, tx := range b.pendingBlock.Transactions() {
block.AddTx(tx)
diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go
index 75e8d5bc8..80948d3f1 100644
--- a/accounts/abi/bind/base.go
+++ b/accounts/abi/bind/base.go
@@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
+ "golang.org/x/net/context"
)
// SignerFn is a signer function callback when a contract requires a method to
@@ -35,6 +36,8 @@ type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, erro
// 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
+
+ Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}
// TransactOpts is the collection of authorization data required to create a
@@ -47,6 +50,8 @@ type TransactOpts struct {
Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds)
GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle)
GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%)
+
+ Context context.Context // Network context to support cancellation and timeouts (nil = no timeout)
}
// BoundContract is the base wrapper object that reflects a contract on the
@@ -102,7 +107,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
}
// 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 {
+ if code, err := c.caller.HasCode(opts.Context, c.address, opts.Pending); err != nil {
return err
} else if !code {
return ErrNoCode
@@ -118,7 +123,7 @@ func (c *BoundContract) Call(opts *CallOpts, result interface{}, method string,
if err != nil {
return err
}
- output, err := c.caller.ContractCall(c.address, input, opts.Pending)
+ output, err := c.caller.ContractCall(opts.Context, c.address, input, opts.Pending)
if err != nil {
return err
}
@@ -153,7 +158,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
}
nonce := uint64(0)
if opts.Nonce == nil {
- nonce, err = c.transactor.PendingAccountNonce(opts.From)
+ nonce, err = c.transactor.PendingAccountNonce(opts.Context, opts.From)
if err != nil {
return nil, fmt.Errorf("failed to retrieve account nonce: %v", err)
}
@@ -163,7 +168,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
// Figure out the gas allowance and gas price values
gasPrice := opts.GasPrice
if gasPrice == nil {
- gasPrice, err = c.transactor.SuggestGasPrice()
+ gasPrice, err = c.transactor.SuggestGasPrice(opts.Context)
if err != nil {
return nil, fmt.Errorf("failed to suggest gas price: %v", err)
}
@@ -172,7 +177,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
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 {
+ if code, err := c.transactor.HasCode(opts.Context, c.address, true); err != nil {
return nil, err
} else if !code {
return nil, ErrNoCode
@@ -180,7 +185,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
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)
+ gasLimit, err = c.transactor.EstimateGasLimit(opts.Context, opts.From, contract, value, input)
if err != nil {
return nil, fmt.Errorf("failed to exstimate gas needed: %v", err)
}
@@ -199,7 +204,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
if err != nil {
return nil, err
}
- if err := c.transactor.SendTransaction(signedTx); err != nil {
+ if err := c.transactor.SendTransaction(opts.Context, signedTx); err != nil {
return nil, err
}
return signedTx, nil