mirror of https://github.com/ethereum/go-ethereum
commit
5fc032a9d1
@ -1,57 +0,0 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package backends |
||||
|
||||
import ( |
||||
"math/big" |
||||
|
||||
"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.
|
||||
var _ bind.ContractBackend = (*nilBackend)(nil) |
||||
|
||||
// nilBackend implements bind.ContractBackend, but panics on any method call.
|
||||
// Its sole purpose is to support the binding tests to construct the generated
|
||||
// wrappers without calling any methods on them.
|
||||
type nilBackend struct{} |
||||
|
||||
func (*nilBackend) ContractCall(context.Context, common.Address, []byte, bool) ([]byte, error) { |
||||
panic("not implemented") |
||||
} |
||||
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") |
||||
} |
||||
|
||||
// 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.
|
||||
func NewNilBackend() bind.ContractBackend { |
||||
return new(nilBackend) |
||||
} |
@ -1,136 +0,0 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package backends |
||||
|
||||
import ( |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind" |
||||
"github.com/ethereum/go-ethereum/common" |
||||
"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.
|
||||
var _ bind.ContractBackend = (*rpcBackend)(nil) |
||||
|
||||
// rpcBackend implements bind.ContractBackend, and acts as the data provider to
|
||||
// Ethereum contracts bound to Go structs. It uses an RPC connection to delegate
|
||||
// all its functionality.
|
||||
type rpcBackend struct { |
||||
client *rpc.Client // RPC client connection to interact with an API server
|
||||
} |
||||
|
||||
// NewRPCBackend creates a new binding backend to an RPC provider that can be
|
||||
// used to interact with remote contracts.
|
||||
func NewRPCBackend(client *rpc.Client) bind.ContractBackend { |
||||
return &rpcBackend{client: client} |
||||
} |
||||
|
||||
// HasCode implements ContractVerifier.HasCode by retrieving any code associated
|
||||
// with the contract from the remote node, and checking its size.
|
||||
func (b *rpcBackend) HasCode(ctx context.Context, contract common.Address, pending bool) (bool, error) { |
||||
block := "latest" |
||||
if pending { |
||||
block = "pending" |
||||
} |
||||
var hex string |
||||
err := b.client.CallContext(ctx, &hex, "eth_getCode", contract, block) |
||||
if err != nil { |
||||
return false, err |
||||
} |
||||
return len(common.FromHex(hex)) > 0, nil |
||||
} |
||||
|
||||
// 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(ctx context.Context, contract common.Address, data []byte, pending bool) ([]byte, error) { |
||||
args := struct { |
||||
To common.Address `json:"to"` |
||||
Data string `json:"data"` |
||||
}{ |
||||
To: contract, |
||||
Data: common.ToHex(data), |
||||
} |
||||
block := "latest" |
||||
if pending { |
||||
block = "pending" |
||||
} |
||||
var hex string |
||||
err := b.client.CallContext(ctx, &hex, "eth_call", args, block) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return common.FromHex(hex), nil |
||||
|
||||
} |
||||
|
||||
// PendingAccountNonce implements ContractTransactor.PendingAccountNonce, delegating
|
||||
// the current account nonce retrieval to the remote node.
|
||||
func (b *rpcBackend) PendingAccountNonce(ctx context.Context, account common.Address) (uint64, error) { |
||||
var hex rpc.HexNumber |
||||
err := b.client.CallContext(ctx, &hex, "eth_getTransactionCount", account.Hex(), "pending") |
||||
if err != nil { |
||||
return 0, err |
||||
} |
||||
return hex.Uint64(), nil |
||||
} |
||||
|
||||
// SuggestGasPrice implements ContractTransactor.SuggestGasPrice, delegating the
|
||||
// gas price oracle request to the remote node.
|
||||
func (b *rpcBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { |
||||
var hex rpc.HexNumber |
||||
if err := b.client.CallContext(ctx, &hex, "eth_gasPrice"); err != nil { |
||||
return nil, err |
||||
} |
||||
return (*big.Int)(&hex), nil |
||||
} |
||||
|
||||
// EstimateGasLimit implements ContractTransactor.EstimateGasLimit, delegating
|
||||
// the gas estimation to the remote node.
|
||||
func (b *rpcBackend) EstimateGasLimit(ctx context.Context, sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) { |
||||
args := struct { |
||||
From common.Address `json:"from"` |
||||
To *common.Address `json:"to"` |
||||
Value *rpc.HexNumber `json:"value"` |
||||
Data string `json:"data"` |
||||
}{ |
||||
From: sender, |
||||
To: contract, |
||||
Data: common.ToHex(data), |
||||
Value: rpc.NewHexNumber(value), |
||||
} |
||||
// Execute the RPC call and retrieve the response
|
||||
var hex rpc.HexNumber |
||||
err := b.client.CallContext(ctx, &hex, "eth_estimateGas", args) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return (*big.Int)(&hex), nil |
||||
} |
||||
|
||||
// SendTransaction implements ContractTransactor.SendTransaction, delegating the
|
||||
// raw transaction injection to the remote node.
|
||||
func (b *rpcBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { |
||||
data, err := rlp.EncodeToBytes(tx) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return b.client.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data)) |
||||
} |
File diff suppressed because one or more lines are too long
@ -0,0 +1,76 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package bind |
||||
|
||||
import ( |
||||
"fmt" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/logger" |
||||
"github.com/ethereum/go-ethereum/logger/glog" |
||||
"golang.org/x/net/context" |
||||
) |
||||
|
||||
// WaitMined waits for tx to be mined on the blockchain.
|
||||
// It stops waiting when the context is canceled.
|
||||
func WaitMined(ctx context.Context, b DeployBackend, tx *types.Transaction) (*types.Receipt, error) { |
||||
queryTicker := time.NewTicker(1 * time.Second) |
||||
defer queryTicker.Stop() |
||||
loghash := tx.Hash().Hex()[:8] |
||||
for { |
||||
receipt, err := b.TransactionReceipt(ctx, tx.Hash()) |
||||
if receipt != nil { |
||||
return receipt, nil |
||||
} |
||||
if err != nil { |
||||
glog.V(logger.Detail).Infof("tx %x error: %v", loghash, err) |
||||
} else { |
||||
glog.V(logger.Detail).Infof("tx %x not yet mined...", loghash) |
||||
} |
||||
// Wait for the next round.
|
||||
select { |
||||
case <-ctx.Done(): |
||||
return nil, ctx.Err() |
||||
case <-queryTicker.C: |
||||
} |
||||
} |
||||
} |
||||
|
||||
// WaitDeployed waits for a contract deployment transaction and returns the on-chain
|
||||
// contract address when it is mined. It stops waiting when ctx is canceled.
|
||||
func WaitDeployed(ctx context.Context, b DeployBackend, tx *types.Transaction) (common.Address, error) { |
||||
if tx.To() != nil { |
||||
return common.Address{}, fmt.Errorf("tx is not contract creation") |
||||
} |
||||
receipt, err := WaitMined(ctx, b, tx) |
||||
if err != nil { |
||||
return common.Address{}, err |
||||
} |
||||
if receipt.ContractAddress == (common.Address{}) { |
||||
return common.Address{}, fmt.Errorf("zero address") |
||||
} |
||||
// Check that code has indeed been deployed at the address.
|
||||
// This matters on pre-Homestead chains: OOG in the constructor
|
||||
// could leave an empty account behind.
|
||||
code, err := b.CodeAt(ctx, receipt.ContractAddress, nil) |
||||
if err == nil && len(code) == 0 { |
||||
err = ErrNoCodeAfterDeploy |
||||
} |
||||
return receipt.ContractAddress, err |
||||
} |
@ -0,0 +1,93 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package bind_test |
||||
|
||||
import ( |
||||
"math/big" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind" |
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind/backends" |
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"golang.org/x/net/context" |
||||
) |
||||
|
||||
var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") |
||||
|
||||
var waitDeployedTests = map[string]struct { |
||||
code string |
||||
gas *big.Int |
||||
wantAddress common.Address |
||||
wantErr error |
||||
}{ |
||||
"successful deploy": { |
||||
code: `6060604052600a8060106000396000f360606040526008565b00`, |
||||
gas: big.NewInt(3000000), |
||||
wantAddress: common.HexToAddress("0x3a220f351252089d385b29beca14e27f204c296a"), |
||||
}, |
||||
"empty code": { |
||||
code: ``, |
||||
gas: big.NewInt(300000), |
||||
wantErr: bind.ErrNoCodeAfterDeploy, |
||||
wantAddress: common.HexToAddress("0x3a220f351252089d385b29beca14e27f204c296a"), |
||||
}, |
||||
} |
||||
|
||||
func TestWaitDeployed(t *testing.T) { |
||||
for name, test := range waitDeployedTests { |
||||
backend := backends.NewSimulatedBackend(core.GenesisAccount{ |
||||
Address: crypto.PubkeyToAddress(testKey.PublicKey), |
||||
Balance: big.NewInt(10000000000), |
||||
}) |
||||
|
||||
// Create the transaction.
|
||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code)) |
||||
tx, _ = tx.SignECDSA(testKey) |
||||
|
||||
// Wait for it to get mined in the background.
|
||||
var ( |
||||
err error |
||||
address common.Address |
||||
mined = make(chan struct{}) |
||||
ctx = context.Background() |
||||
) |
||||
go func() { |
||||
address, err = bind.WaitDeployed(ctx, backend, tx) |
||||
close(mined) |
||||
}() |
||||
|
||||
// Send and mine the transaction.
|
||||
backend.SendTransaction(ctx, tx) |
||||
backend.Commit() |
||||
|
||||
select { |
||||
case <-mined: |
||||
if err != test.wantErr { |
||||
t.Errorf("test %q: error mismatch: got %q, want %q", name, err, test.wantErr) |
||||
} |
||||
if address != test.wantAddress { |
||||
t.Errorf("test %q: unexpected contract address %s", name, address.Hex()) |
||||
} |
||||
case <-time.After(2 * time.Second): |
||||
t.Errorf("test %q: timeout", name) |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,87 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"fmt" |
||||
"math/big" |
||||
) |
||||
|
||||
// JSON unmarshaling utilities.
|
||||
|
||||
type hexBytes []byte |
||||
|
||||
func (b *hexBytes) UnmarshalJSON(input []byte) error { |
||||
if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' { |
||||
return fmt.Errorf("cannot unmarshal non-string into hexBytes") |
||||
} |
||||
input = input[1 : len(input)-1] |
||||
if len(input) < 2 || input[0] != '0' || input[1] != 'x' { |
||||
return fmt.Errorf("missing 0x prefix in hexBytes input %q", input) |
||||
} |
||||
dec := make(hexBytes, (len(input)-2)/2) |
||||
if _, err := hex.Decode(dec, input[2:]); err != nil { |
||||
return err |
||||
} |
||||
*b = dec |
||||
return nil |
||||
} |
||||
|
||||
type hexBig big.Int |
||||
|
||||
func (b *hexBig) UnmarshalJSON(input []byte) error { |
||||
raw, err := checkHexNumber(input) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
dec, ok := new(big.Int).SetString(string(raw), 16) |
||||
if !ok { |
||||
return fmt.Errorf("invalid hex number") |
||||
} |
||||
*b = (hexBig)(*dec) |
||||
return nil |
||||
} |
||||
|
||||
type hexUint64 uint64 |
||||
|
||||
func (b *hexUint64) UnmarshalJSON(input []byte) error { |
||||
raw, err := checkHexNumber(input) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = fmt.Sscanf(string(raw), "%x", b) |
||||
return err |
||||
} |
||||
|
||||
func checkHexNumber(input []byte) (raw []byte, err error) { |
||||
if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' { |
||||
return nil, fmt.Errorf("cannot unmarshal non-string into hex number") |
||||
} |
||||
input = input[1 : len(input)-1] |
||||
if len(input) < 2 || input[0] != '0' || input[1] != 'x' { |
||||
return nil, fmt.Errorf("missing 0x prefix in hex number input %q", input) |
||||
} |
||||
if len(input) == 2 { |
||||
return nil, fmt.Errorf("empty hex number") |
||||
} |
||||
raw = input[2:] |
||||
if len(raw)%2 != 0 { |
||||
raw = append([]byte{'0'}, raw...) |
||||
} |
||||
return raw, nil |
||||
} |
@ -0,0 +1,136 @@ |
||||
package types |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"testing" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
) |
||||
|
||||
var unmarshalHeaderTests = map[string]struct { |
||||
input string |
||||
wantHash common.Hash |
||||
wantError error |
||||
}{ |
||||
"block 0x1e2200": { |
||||
input: `{"difficulty":"0x311ca98cebfe","extraData":"0x7777772e62772e636f6d","gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","mixHash":"0x1ccfddb506dac5afc09b6f92eb09a043ffc8e08f7592250af57b9c64c20f9b25","nonce":"0x670bd98c79585197","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`, |
||||
wantHash: common.HexToHash("0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48"), |
||||
}, |
||||
"bad nonce": { |
||||
input: `{"difficulty":"0x311ca98cebfe","extraData":"0x7777772e62772e636f6d","gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","mixHash":"0x1ccfddb506dac5afc09b6f92eb09a043ffc8e08f7592250af57b9c64c20f9b25","nonce":"0x670bd98c7958","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`, |
||||
wantError: errBadNonceSize, |
||||
}, |
||||
"missing mixHash": { |
||||
input: `{"difficulty":"0x311ca98cebfe","extraData":"0x7777772e62772e636f6d","gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","nonce":"0x670bd98c79585197","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`, |
||||
wantError: errMissingHeaderMixDigest, |
||||
}, |
||||
"missing fields": { |
||||
input: `{"gasLimit":"0x47db3d","gasUsed":"0x43760c","hash":"0x3724bc6b9dcd4a2b3a26e0ed9b821e7380b5b3d7dec7166c7983cead62a37e48","logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","miner":"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1","mixHash":"0x1ccfddb506dac5afc09b6f92eb09a043ffc8e08f7592250af57b9c64c20f9b25","nonce":"0x670bd98c79585197","number":"0x1e2200","parentHash":"0xd3e13296d064e7344f20c57c57b67a022f6bf7741fa42428c2db77e91abdf1f8","receiptRoot":"0xeeab1776c1fafbe853a8ee0c1bafe2e775a1b6fdb6ff3e9f9410ddd4514889ff","sha3Uncles":"0x5fbfa4ec8b089678c53b6798cc0d9260ea40a529e06d5300aae35596262e0eb3","size":"0x57f","stateRoot":"0x62ad2007e4a3f31ea98e5d2fd150d894887bafde36eeac7331a60ae12053ec76","timestamp":"0x579b82f2","totalDifficulty":"0x24fe813c101d00f97","transactions":["0xb293408e85735bfc78b35aa89de8b48e49641e3d82e3d52ea2d44ec42a4e88cf","0x124acc383ff2da6faa0357829084dae64945221af6f6f09da1d11688b779f939","0xee090208b6051c442ccdf9ec19f66389e604d342a6d71144c7227ce995bef46f"],"transactionsRoot":"0xce0042dd9af0c1923dd7f58ca6faa156d39d4ef39fdb65c5bcd1d4b4720096db","uncles":["0x6818a31d1f204cf640c952082940b68b8db6d1b39ee71f7efe0e3629ed5d7eb3"]}`, |
||||
wantError: errMissingHeaderFields, |
||||
}, |
||||
} |
||||
|
||||
func TestUnmarshalHeader(t *testing.T) { |
||||
for name, test := range unmarshalHeaderTests { |
||||
var head *Header |
||||
err := json.Unmarshal([]byte(test.input), &head) |
||||
if !checkError(t, name, err, test.wantError) { |
||||
continue |
||||
} |
||||
if head.Hash() != test.wantHash { |
||||
t.Errorf("test %q: got hash %x, want %x", name, head.Hash(), test.wantHash) |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
|
||||
var unmarshalTransactionTests = map[string]struct { |
||||
input string |
||||
wantHash common.Hash |
||||
wantFrom common.Address |
||||
wantError error |
||||
}{ |
||||
"value transfer": { |
||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x1c","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, |
||||
wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"), |
||||
wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"), |
||||
}, |
||||
"bad signature fields": { |
||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, |
||||
wantError: ErrInvalidSig, |
||||
}, |
||||
"missing signature v": { |
||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, |
||||
wantError: errMissingTxSignatureFields, |
||||
}, |
||||
"missing signature fields": { |
||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00"}`, |
||||
wantError: errMissingTxSignatureFields, |
||||
}, |
||||
"missing fields": { |
||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x1c","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`, |
||||
wantError: errMissingTxFields, |
||||
}, |
||||
} |
||||
|
||||
func TestUnmarshalTransaction(t *testing.T) { |
||||
for name, test := range unmarshalTransactionTests { |
||||
var tx *Transaction |
||||
err := json.Unmarshal([]byte(test.input), &tx) |
||||
if !checkError(t, name, err, test.wantError) { |
||||
continue |
||||
} |
||||
if tx.Hash() != test.wantHash { |
||||
t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash) |
||||
continue |
||||
} |
||||
from, err := tx.From() |
||||
if err != nil { |
||||
t.Errorf("test %q: From error %v", name, err) |
||||
} |
||||
if from != test.wantFrom { |
||||
t.Errorf("test %q: sender mismatch: got %x, want %x", name, from, test.wantFrom) |
||||
} |
||||
} |
||||
} |
||||
|
||||
var unmarshalReceiptTests = map[string]struct { |
||||
input string |
||||
wantError error |
||||
}{ |
||||
"ok": { |
||||
input: `{"blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","blockNumber":"0x1e773b","contractAddress":null,"cumulativeGasUsed":"0x10cea","from":"0xdf21fa922215b1a56f5a6d6294e6e36c85a0acfb","gasUsed":"0xbae2","logs":[{"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000df21fa922215b1a56f5a6d6294e6e36c85a0acfb","0x00000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d88"],"data":"0x0000000000000000000000000000000000000000000000027cfefc4f3f392700","blockNumber":"0x1e773b","transactionIndex":"0x1","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","logIndex":"0x0"}],"logsBloom":"0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000040000000000000100000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000010000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000","root":"0x6e8a06b2dac39ac5c9d4db5fb2a2a94ef7a6e5ec1c554079112112caf162998a","to":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","transactionIndex":"0x1"}`, |
||||
}, |
||||
"missing post state": { |
||||
input: `{"blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","blockNumber":"0x1e773b","contractAddress":null,"cumulativeGasUsed":"0x10cea","from":"0xdf21fa922215b1a56f5a6d6294e6e36c85a0acfb","gasUsed":"0xbae2","logs":[{"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000df21fa922215b1a56f5a6d6294e6e36c85a0acfb","0x00000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d88"],"data":"0x0000000000000000000000000000000000000000000000027cfefc4f3f392700","blockNumber":"0x1e773b","transactionIndex":"0x1","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","logIndex":"0x0"}],"logsBloom":"0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000040000000000000100000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000010000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000","to":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","transactionIndex":"0x1"}`, |
||||
wantError: errMissingReceiptPostState, |
||||
}, |
||||
"missing fields": { |
||||
input: `{"blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","blockNumber":"0x1e773b","contractAddress":null,"cumulativeGasUsed":"0x10cea","from":"0xdf21fa922215b1a56f5a6d6294e6e36c85a0acfb","gasUsed":"0xbae2","logs":[{"address":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x000000000000000000000000df21fa922215b1a56f5a6d6294e6e36c85a0acfb","0x00000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d88"],"data":"0x0000000000000000000000000000000000000000000000027cfefc4f3f392700","blockNumber":"0x1e773b","transactionIndex":"0x1","transactionHash":"0x0b4cc7844537023b709953390e3881ec5b233703a8e8824dc03e13729a1bd95a","blockHash":"0xad20a0f78d19d7857067a9c06e6411efeab7673e183e4a545f53b724bb7fabf0","logIndex":"0x0"}],"logsBloom":"0x00000000000000020000000000020000000000000000000000000000000000000000000000000000000000000000000000040000000000000100000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000010000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000002002000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000","root":"0x6e8a06b2dac39ac5c9d4db5fb2a2a94ef7a6e5ec1c554079112112caf162998a","to":"0xbb9bc244d798123fde783fcc1c72d3bb8c189413"}`, |
||||
wantError: errMissingReceiptFields, |
||||
}, |
||||
} |
||||
|
||||
func TestUnmarshalReceipt(t *testing.T) { |
||||
for name, test := range unmarshalReceiptTests { |
||||
var r *Receipt |
||||
err := json.Unmarshal([]byte(test.input), &r) |
||||
checkError(t, name, err, test.wantError) |
||||
} |
||||
} |
||||
|
||||
func checkError(t *testing.T, testname string, got, want error) bool { |
||||
if got == nil { |
||||
if want != nil { |
||||
t.Errorf("test %q: got no error, want %q", testname, want) |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
if want == nil { |
||||
t.Errorf("test %q: unexpected error %q", testname, got) |
||||
} else if got.Error() != want.Error() { |
||||
t.Errorf("test %q: got error %q, want %q", testname, got, want) |
||||
} |
||||
return false |
||||
} |
@ -0,0 +1,59 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package vm |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"testing" |
||||
) |
||||
|
||||
var unmarshalLogTests = map[string]struct { |
||||
input string |
||||
wantError error |
||||
}{ |
||||
"ok": { |
||||
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","data":"0x000000000000000000000000000000000000000000000001a055690d9db80000","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`, |
||||
}, |
||||
"missing data": { |
||||
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`, |
||||
wantError: errMissingLogFields, |
||||
}, |
||||
} |
||||
|
||||
func TestUnmarshalLog(t *testing.T) { |
||||
for name, test := range unmarshalLogTests { |
||||
var log *Log |
||||
err := json.Unmarshal([]byte(test.input), &log) |
||||
checkError(t, name, err, test.wantError) |
||||
} |
||||
} |
||||
|
||||
func checkError(t *testing.T, testname string, got, want error) bool { |
||||
if got == nil { |
||||
if want != nil { |
||||
t.Errorf("test %q: got no error, want %q", testname, want) |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
if want == nil { |
||||
t.Errorf("test %q: unexpected error %q", testname, got) |
||||
} else if got.Error() != want.Error() { |
||||
t.Errorf("test %q: got error %q, want %q", testname, got, want) |
||||
} |
||||
return false |
||||
} |
@ -0,0 +1,382 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package ethclient provides a client for the Ethereum RPC API.
|
||||
package ethclient |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum" |
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
"github.com/ethereum/go-ethereum/rpc" |
||||
"golang.org/x/net/context" |
||||
) |
||||
|
||||
// Client defines typed wrappers for the Ethereum RPC API.
|
||||
type Client struct { |
||||
c *rpc.Client |
||||
} |
||||
|
||||
// Dial connects a client to the given URL.
|
||||
func Dial(rawurl string) (*Client, error) { |
||||
c, err := rpc.Dial(rawurl) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return NewClient(c), nil |
||||
} |
||||
|
||||
// NewClient creates a client that uses the given RPC client.
|
||||
func NewClient(c *rpc.Client) *Client { |
||||
return &Client{c} |
||||
} |
||||
|
||||
// Blockchain Access
|
||||
|
||||
// BlockByHash returns the given full block.
|
||||
//
|
||||
// Note that loading full blocks requires two requests. Use HeaderByHash
|
||||
// if you don't need all transactions or uncle headers.
|
||||
func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { |
||||
return ec.getBlock(ctx, "eth_getBlockByHash", hash, true) |
||||
} |
||||
|
||||
// BlockByNumber returns a block from the current canonical chain. If number is nil, the
|
||||
// latest known block is returned.
|
||||
//
|
||||
// Note that loading full blocks requires two requests. Use HeaderByNumber
|
||||
// if you don't need all transactions or uncle headers.
|
||||
func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { |
||||
return ec.getBlock(ctx, "eth_getBlockByNumber", toBlockNumArg(number), true) |
||||
} |
||||
|
||||
type rpcBlock struct { |
||||
Hash common.Hash `json:"hash"` |
||||
Transactions []*types.Transaction `json:"transactions"` |
||||
UncleHashes []common.Hash `json:"uncles"` |
||||
} |
||||
|
||||
func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { |
||||
var raw json.RawMessage |
||||
err := ec.c.CallContext(ctx, &raw, method, args...) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
// Decode header and transactions.
|
||||
var head *types.Header |
||||
var body rpcBlock |
||||
if err := json.Unmarshal(raw, &head); err != nil { |
||||
return nil, err |
||||
} |
||||
if err := json.Unmarshal(raw, &body); err != nil { |
||||
return nil, err |
||||
} |
||||
// Quick-verify transaction and uncle lists. This mostly helps with debugging the server.
|
||||
if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { |
||||
return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles") |
||||
} |
||||
if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { |
||||
return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles") |
||||
} |
||||
if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 { |
||||
return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") |
||||
} |
||||
if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 { |
||||
return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") |
||||
} |
||||
// Load uncles because they are not included in the block response.
|
||||
var uncles []*types.Header |
||||
if len(body.UncleHashes) > 0 { |
||||
uncles = make([]*types.Header, len(body.UncleHashes)) |
||||
reqs := make([]rpc.BatchElem, len(body.UncleHashes)) |
||||
for i := range reqs { |
||||
reqs[i] = rpc.BatchElem{ |
||||
Method: "eth_getUncleByBlockHashAndIndex", |
||||
Args: []interface{}{body.Hash, fmt.Sprintf("%#x", i)}, |
||||
Result: &uncles[i], |
||||
} |
||||
} |
||||
if err := ec.c.BatchCallContext(ctx, reqs); err != nil { |
||||
return nil, err |
||||
} |
||||
for i := range reqs { |
||||
if reqs[i].Error != nil { |
||||
return nil, reqs[i].Error |
||||
} |
||||
} |
||||
} |
||||
return types.NewBlockWithHeader(head).WithBody(body.Transactions, uncles), nil |
||||
} |
||||
|
||||
// HeaderByHash returns the block header with the given hash.
|
||||
func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { |
||||
var head *types.Header |
||||
err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false) |
||||
return head, err |
||||
} |
||||
|
||||
// HeaderByNumber returns a block header from the current canonical chain. If number is
|
||||
// nil, the latest known header is returned.
|
||||
func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { |
||||
var head *types.Header |
||||
err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) |
||||
return head, err |
||||
} |
||||
|
||||
// TransactionByHash returns the transaction with the given hash.
|
||||
func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*types.Transaction, error) { |
||||
var tx *types.Transaction |
||||
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash, false) |
||||
if err == nil { |
||||
if _, r, _ := tx.SignatureValues(); r == nil { |
||||
return nil, fmt.Errorf("server returned transaction without signature") |
||||
} |
||||
} |
||||
return tx, err |
||||
} |
||||
|
||||
// TransactionCount returns the total number of transactions in the given block.
|
||||
func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) { |
||||
var num rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash) |
||||
return num.Uint(), err |
||||
} |
||||
|
||||
// TransactionInBlock returns a single transaction at index in the given block.
|
||||
func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { |
||||
var tx *types.Transaction |
||||
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index) |
||||
if err == nil { |
||||
if _, r, _ := tx.SignatureValues(); r == nil { |
||||
return nil, fmt.Errorf("server returned transaction without signature") |
||||
} |
||||
} |
||||
return tx, err |
||||
} |
||||
|
||||
// TransactionReceipt returns the receipt of a transaction by transaction hash.
|
||||
// Note that the receipt is not available for pending transactions.
|
||||
func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { |
||||
var r *types.Receipt |
||||
err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) |
||||
if err == nil && r != nil && len(r.PostState) == 0 { |
||||
return nil, fmt.Errorf("server returned receipt without post state") |
||||
} |
||||
return r, err |
||||
} |
||||
|
||||
func toBlockNumArg(number *big.Int) string { |
||||
if number == nil { |
||||
return "latest" |
||||
} |
||||
return fmt.Sprintf("%#x", number) |
||||
} |
||||
|
||||
// SubscribeNewHead subscribes to notifications about the current blockchain head
|
||||
// on the given channel.
|
||||
func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { |
||||
return ec.c.EthSubscribe(ctx, ch, "newBlocks", map[string]struct{}{}) |
||||
} |
||||
|
||||
// State Access
|
||||
|
||||
// BalanceAt returns the wei balance of the given account.
|
||||
// The block number can be nil, in which case the balance is taken from the latest known block.
|
||||
func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { |
||||
var result rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber)) |
||||
return (*big.Int)(&result), err |
||||
} |
||||
|
||||
// StorageAt returns the value of key in the contract storage of the given account.
|
||||
// The block number can be nil, in which case the value is taken from the latest known block.
|
||||
func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { |
||||
var result rpc.HexBytes |
||||
err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, toBlockNumArg(blockNumber)) |
||||
return result, err |
||||
} |
||||
|
||||
// CodeAt returns the contract code of the given account.
|
||||
// The block number can be nil, in which case the code is taken from the latest known block.
|
||||
func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { |
||||
var result rpc.HexBytes |
||||
err := ec.c.CallContext(ctx, &result, "eth_getCode", account, toBlockNumArg(blockNumber)) |
||||
return result, err |
||||
} |
||||
|
||||
// NonceAt returns the account nonce of the given account.
|
||||
// The block number can be nil, in which case the nonce is taken from the latest known block.
|
||||
func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { |
||||
var result rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, toBlockNumArg(blockNumber)) |
||||
return result.Uint64(), err |
||||
} |
||||
|
||||
// Filters
|
||||
|
||||
// FilterLogs executes a filter query.
|
||||
func (ec *Client) FilterLogs(ctx context.Context, q ethereum.FilterQuery) ([]vm.Log, error) { |
||||
var result []vm.Log |
||||
err := ec.c.CallContext(ctx, &result, "eth_getFilterLogs", toFilterArg(q)) |
||||
return result, err |
||||
} |
||||
|
||||
// SubscribeFilterLogs subscribes to the results of a streaming filter query.
|
||||
func (ec *Client) SubscribeFilterLogs(ctx context.Context, q ethereum.FilterQuery, ch chan<- vm.Log) (ethereum.Subscription, error) { |
||||
return ec.c.EthSubscribe(ctx, ch, "logs", toFilterArg(q)) |
||||
} |
||||
|
||||
func toFilterArg(q ethereum.FilterQuery) interface{} { |
||||
arg := map[string]interface{}{ |
||||
"fromBlock": toBlockNumArg(q.FromBlock), |
||||
"endBlock": toBlockNumArg(q.ToBlock), |
||||
"addresses": q.Addresses, |
||||
"topics": q.Topics, |
||||
} |
||||
if q.FromBlock == nil { |
||||
arg["fromBlock"] = "0x0" |
||||
} |
||||
return arg |
||||
} |
||||
|
||||
// Pending State
|
||||
|
||||
// PendingBalanceAt returns the wei balance of the given account in the pending state.
|
||||
func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) { |
||||
var result rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, "pending") |
||||
return (*big.Int)(&result), err |
||||
} |
||||
|
||||
// PendingStorageAt returns the value of key in the contract storage of the given account in the pending state.
|
||||
func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) { |
||||
var result rpc.HexBytes |
||||
err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, "pending") |
||||
return result, err |
||||
} |
||||
|
||||
// PendingCodeAt returns the contract code of the given account in the pending state.
|
||||
func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { |
||||
var result rpc.HexBytes |
||||
err := ec.c.CallContext(ctx, &result, "eth_getCode", account, "pending") |
||||
return result, err |
||||
} |
||||
|
||||
// PendingNonceAt returns the account nonce of the given account in the pending state.
|
||||
// This is the nonce that should be used for the next transaction.
|
||||
func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { |
||||
var result rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending") |
||||
return result.Uint64(), err |
||||
} |
||||
|
||||
// PendingTransactionCount returns the total number of transactions in the pending state.
|
||||
func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) { |
||||
var num rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", "pending") |
||||
return num.Uint(), err |
||||
} |
||||
|
||||
// TODO: SubscribePendingTransactions (needs server side)
|
||||
|
||||
// Contract Calling
|
||||
|
||||
// CallContract executes a message call transaction, which is directly executed in the VM
|
||||
// of the node, but never mined into the blockchain.
|
||||
//
|
||||
// blockNumber selects the block height at which the call runs. It can be nil, in which
|
||||
// case the code is taken from the latest known block. Note that state from very old
|
||||
// blocks might not be available.
|
||||
func (ec *Client) CallContract(ctx context.Context, msg ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { |
||||
var hex string |
||||
err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return common.FromHex(hex), nil |
||||
} |
||||
|
||||
// PendingCallContract executes a message call transaction using the EVM.
|
||||
// The state seen by the contract call is the pending state.
|
||||
func (ec *Client) PendingCallContract(ctx context.Context, msg ethereum.CallMsg) ([]byte, error) { |
||||
var hex string |
||||
err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "pending") |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return common.FromHex(hex), nil |
||||
} |
||||
|
||||
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
|
||||
// execution of a transaction.
|
||||
func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { |
||||
var hex rpc.HexNumber |
||||
if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil { |
||||
return nil, err |
||||
} |
||||
return (*big.Int)(&hex), nil |
||||
} |
||||
|
||||
// EstimateGas 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.
|
||||
func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) { |
||||
var hex rpc.HexNumber |
||||
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return (*big.Int)(&hex), nil |
||||
} |
||||
|
||||
// SendTransaction injects a signed transaction into the pending pool for execution.
|
||||
//
|
||||
// If the transaction was a contract creation use the TransactionReceipt method to get the
|
||||
// contract address after the transaction has been mined.
|
||||
func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { |
||||
data, err := rlp.EncodeToBytes(tx) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data)) |
||||
} |
||||
|
||||
func toCallArg(msg ethereum.CallMsg) interface{} { |
||||
arg := map[string]interface{}{ |
||||
"from": msg.From, |
||||
"to": msg.To, |
||||
} |
||||
if len(msg.Data) > 0 { |
||||
arg["data"] = fmt.Sprintf("%#x", msg.Data) |
||||
} |
||||
if msg.Value != nil { |
||||
arg["value"] = fmt.Sprintf("%#x", msg.Value) |
||||
} |
||||
if msg.Gas != nil { |
||||
arg["gas"] = fmt.Sprintf("%#x", msg.Gas) |
||||
} |
||||
if msg.GasPrice != nil { |
||||
arg["gasPrice"] = fmt.Sprintf("%#x", msg.GasPrice) |
||||
} |
||||
return arg |
||||
} |
@ -0,0 +1,17 @@ |
||||
package ethclient |
||||
|
||||
import "github.com/ethereum/go-ethereum" |
||||
|
||||
// Verify that Client implements the ethereum interfaces.
|
||||
var ( |
||||
_ = ethereum.ChainReader(&Client{}) |
||||
_ = ethereum.ChainStateReader(&Client{}) |
||||
_ = ethereum.ChainHeadEventer(&Client{}) |
||||
_ = ethereum.ContractCaller(&Client{}) |
||||
_ = ethereum.GasEstimator(&Client{}) |
||||
_ = ethereum.GasPricer(&Client{}) |
||||
_ = ethereum.LogFilterer(&Client{}) |
||||
_ = ethereum.PendingStateReader(&Client{}) |
||||
// _ = ethereum.PendingStateEventer(&Client{})
|
||||
_ = ethereum.PendingContractCaller(&Client{}) |
||||
) |
@ -0,0 +1,168 @@ |
||||
// Copyright 2016 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package ethereum defines interfaces for interacting with Ethereum.
|
||||
package ethereum |
||||
|
||||
import ( |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/core/types" |
||||
"github.com/ethereum/go-ethereum/core/vm" |
||||
"golang.org/x/net/context" |
||||
) |
||||
|
||||
// TODO: move subscription to package event
|
||||
|
||||
// Subscription represents an event subscription where events are
|
||||
// delivered on a data channel.
|
||||
type Subscription interface { |
||||
// Unsubscribe cancels the sending of events to the data channel
|
||||
// and closes the error channel.
|
||||
Unsubscribe() |
||||
// Err returns the subscription error channel. The error channel receives
|
||||
// a value if there is an issue with the subscription (e.g. the network connection
|
||||
// delivering the events has been closed). Only one value will ever be sent.
|
||||
// The error channel is closed by Unsubscribe.
|
||||
Err() <-chan error |
||||
} |
||||
|
||||
// ChainReader provides access to the blockchain. The methods in this interface access raw
|
||||
// data from either the canonical chain (when requesting by block number) or any
|
||||
// blockchain fork that was previously downloaded and processed by the node. The block
|
||||
// number argument can be nil to select the latest canonical block. Reading block headers
|
||||
// should be preferred over full blocks whenever possible.
|
||||
type ChainReader interface { |
||||
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) |
||||
BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) |
||||
HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) |
||||
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) |
||||
TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) |
||||
TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) |
||||
TransactionByHash(ctx context.Context, txHash common.Hash) (*types.Transaction, error) |
||||
TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) |
||||
} |
||||
|
||||
// ChainStateReader wraps access to the state trie of the canonical blockchain. Note that
|
||||
// implementations of the interface may be unable to return state values for old blocks.
|
||||
// In many cases, using CallContract can be preferable to reading raw contract storage.
|
||||
type ChainStateReader interface { |
||||
BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) |
||||
StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) |
||||
CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) |
||||
NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) |
||||
} |
||||
|
||||
// A ChainHeadEventer returns notifications whenever the canonical head block is updated.
|
||||
type ChainHeadEventer interface { |
||||
SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (Subscription, error) |
||||
} |
||||
|
||||
// CallMsg contains parameters for contract calls.
|
||||
type CallMsg struct { |
||||
From common.Address // the sender of the 'transaction'
|
||||
To *common.Address // the destination contract (nil for contract creation)
|
||||
Gas *big.Int // if nil, the call executes with near-infinite gas
|
||||
GasPrice *big.Int // wei <-> gas exchange ratio
|
||||
Value *big.Int // amount of wei sent along with the call
|
||||
Data []byte // input data, usually an ABI-encoded contract method invocation
|
||||
} |
||||
|
||||
// A ContractCaller provides contract calls, essentially transactions that are executed by
|
||||
// the EVM but not mined into the blockchain. ContractCall is a low-level method to
|
||||
// execute such calls. For applications which are structured around specific contracts,
|
||||
// the abigen tool provides a nicer, properly typed way to perform calls.
|
||||
type ContractCaller interface { |
||||
CallContract(ctx context.Context, call CallMsg, blockNumber *big.Int) ([]byte, error) |
||||
} |
||||
|
||||
// FilterQuery contains options for contact log filtering.
|
||||
type FilterQuery struct { |
||||
FromBlock *big.Int // beginning of the queried range, nil means genesis block
|
||||
ToBlock *big.Int // end of the range, nil means latest block
|
||||
Addresses []common.Address // restricts matches to events created by specific contracts
|
||||
|
||||
// The Topic list restricts matches to particular event topics. Each event has a list
|
||||
// of topics. Topics matches a prefix of that list. An empty element slice matches any
|
||||
// topic. Non-empty elements represent an alternative that matches any of the
|
||||
// contained topics.
|
||||
//
|
||||
// Examples:
|
||||
// {} or nil matches any topic list
|
||||
// {{A}} matches topic A in first position
|
||||
// {{}, {B}} matches any topic in first position, B in second position
|
||||
// {{A}}, {B}} matches topic A in first position, B in second position
|
||||
// {{A, B}}, {C, D}} matches topic (A OR B) in first position, (C OR D) in second position
|
||||
Topics [][]common.Hash |
||||
} |
||||
|
||||
// LogFilterer provides access to contract log events using a one-off query or continuous
|
||||
// event subscription.
|
||||
type LogFilterer interface { |
||||
FilterLogs(ctx context.Context, q FilterQuery) ([]vm.Log, error) |
||||
SubscribeFilterLogs(ctx context.Context, q FilterQuery, ch chan<- vm.Log) (Subscription, error) |
||||
} |
||||
|
||||
// TransactionSender wraps transaction sending. The SendTransaction method injects a
|
||||
// signed transaction into the pending transaction pool for execution. If the transaction
|
||||
// was a contract creation, the TransactionReceipt method can be used to retrieve the
|
||||
// contract address after the transaction has been mined.
|
||||
//
|
||||
// The transaction must be signed and have a valid nonce to be included. Consumers of the
|
||||
// API can use package accounts to maintain local private keys and need can retrieve the
|
||||
// next available nonce using PendingNonceAt.
|
||||
type TransactionSender interface { |
||||
SendTransaction(ctx context.Context, tx *types.Transaction) error |
||||
} |
||||
|
||||
// GasPricer wraps the gas price oracle, which monitors the blockchain to determine the
|
||||
// optimal gas price given current fee market conditions.
|
||||
type GasPricer interface { |
||||
SuggestGasPrice(ctx context.Context) (*big.Int, error) |
||||
} |
||||
|
||||
// A PendingStateReader provides access to the pending state, which is the result of all
|
||||
// known executable transactions which have not yet been included in the blockchain. It is
|
||||
// commonly used to display the result of ’unconfirmed’ actions (e.g. wallet value
|
||||
// transfers) initiated by the user. The PendingNonceAt operation is a good way to
|
||||
// retrieve the next available transaction nonce for a specific account.
|
||||
type PendingStateReader interface { |
||||
PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) |
||||
PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) |
||||
PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) |
||||
PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) |
||||
PendingTransactionCount(ctx context.Context) (uint, error) |
||||
} |
||||
|
||||
// PendingContractCaller can be used to perform calls against the pending state.
|
||||
type PendingContractCaller interface { |
||||
PendingCallContract(ctx context.Context, call CallMsg) ([]byte, error) |
||||
} |
||||
|
||||
// GasEstimator wraps EstimateGas, which tries to estimate the gas needed to execute a
|
||||
// specific transaction based on the pending state. 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.
|
||||
type GasEstimator interface { |
||||
EstimateGas(ctx context.Context, call CallMsg) (usedGas *big.Int, err error) |
||||
} |
||||
|
||||
// A PendingStateEventer provides access to real time notifications about changes to the
|
||||
// pending state.
|
||||
type PendingStateEventer interface { |
||||
SubscribePendingTransactions(ctx context.Context, ch chan<- *types.Transaction) (Subscription, error) |
||||
} |
Loading…
Reference in new issue