aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraaronbuchwald <[email protected]>2020-11-20 10:06:46 -0500
committerGitHub <[email protected]>2020-11-20 10:06:46 -0500
commitef19d4da57f99c0c4d93b1ad7dbcbd0b3892bff7 (patch)
tree2dccd3942cdea2f00ae67c95ba2d26d0479f12d3
parent59453f4676ae1d778a32fd9a4edcc94d74747e14 (diff)
parent9feab9d470278e4eecffa059b476dbf3c9417d8d (diff)
Merge pull request #58 from ava-labs/ethclient
Ethclient
-rw-r--r--coreth.go1
-rw-r--r--ethclient/ethclient.go576
-rw-r--r--ethclient/signer.go59
-rw-r--r--examples/client/main.go220
-rw-r--r--go.mod2
-rw-r--r--go.sum36
-rw-r--r--interfaces.go211
-rw-r--r--node/node.go37
-rw-r--r--notes/hacked-list.txt4
9 files changed, 1125 insertions, 21 deletions
diff --git a/coreth.go b/coreth.go
index d1fd29f..01bc9af 100644
--- a/coreth.go
+++ b/coreth.go
@@ -19,6 +19,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/trie"
+
//"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/mattn/go-isatty"
diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go
new file mode 100644
index 0000000..ed02182
--- /dev/null
+++ b/ethclient/ethclient.go
@@ -0,0 +1,576 @@
+// 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 (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/ava-labs/avalanchego/ids"
+ "github.com/ava-labs/coreth"
+ "github.com/ava-labs/coreth/core/types"
+ "github.com/ava-labs/coreth/rpc"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+// 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) {
+ return DialContext(context.Background(), rawurl)
+}
+
+func DialContext(ctx context.Context, rawurl string) (*Client, error) {
+ c, err := rpc.DialContext(ctx, 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}
+}
+
+func (ec *Client) Close() {
+ ec.c.Close()
+}
+
+// Blockchain Access
+
+// ChainId retrieves the current chain ID for transaction replay protection.
+func (ec *Client) ChainID(ctx context.Context) (*big.Int, error) {
+ var result hexutil.Big
+ err := ec.c.CallContext(ctx, &result, "eth_chainId")
+ if err != nil {
+ return nil, err
+ }
+ return (*big.Int)(&result), err
+}
+
+// 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)
+}
+
+// BlockNumber returns the most recent block number
+func (ec *Client) BlockNumber(ctx context.Context) (uint64, error) {
+ var result hexutil.Uint64
+ err := ec.c.CallContext(ctx, &result, "eth_blockNumber")
+ return uint64(result), err
+}
+
+type rpcBlock struct {
+ Hash common.Hash `json:"hash"`
+ Transactions []rpcTransaction `json:"transactions"`
+ UncleHashes []common.Hash `json:"uncles"`
+ Version uint32 `json:"version"`
+ ExtraData *[]byte `json:"blockExtraData"`
+}
+
+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
+ } else if len(raw) == 0 {
+ return nil, coreth.NotFound
+ }
+ // 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, hexutil.EncodeUint64(uint64(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
+ }
+ if uncles[i] == nil {
+ return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:])
+ }
+ }
+ }
+ // Fill the sender cache of transactions in the block.
+ txs := make([]*types.Transaction, len(body.Transactions))
+ for i, tx := range body.Transactions {
+ if tx.From != nil {
+ setSenderFromServer(tx.tx, *tx.From, body.Hash)
+ }
+ txs[i] = tx.tx
+ }
+ return types.NewBlockWithHeader(head).WithBody(txs, uncles, body.Version, body.ExtraData), 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)
+ if err == nil && head == nil {
+ err = coreth.NotFound
+ }
+ 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)
+ if err == nil && head == nil {
+ err = coreth.NotFound
+ }
+ return head, err
+}
+
+type rpcTransaction struct {
+ tx *types.Transaction
+ txExtraInfo
+}
+
+type txExtraInfo struct {
+ BlockNumber *string `json:"blockNumber,omitempty"`
+ BlockHash *common.Hash `json:"blockHash,omitempty"`
+ From *common.Address `json:"from,omitempty"`
+}
+
+func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
+ if err := json.Unmarshal(msg, &tx.tx); err != nil {
+ return err
+ }
+ return json.Unmarshal(msg, &tx.txExtraInfo)
+}
+
+// TransactionByHash returns the transaction with the given hash.
+func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) {
+ var json *rpcTransaction
+ err = ec.c.CallContext(ctx, &json, "eth_getTransactionByHash", hash)
+ if err != nil {
+ return nil, false, err
+ } else if json == nil {
+ return nil, false, coreth.NotFound
+ } else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
+ return nil, false, fmt.Errorf("server returned transaction without signature")
+ }
+ if json.From != nil && json.BlockHash != nil {
+ setSenderFromServer(json.tx, *json.From, *json.BlockHash)
+ }
+ return json.tx, json.BlockNumber == nil, nil
+}
+
+// TransactionSender returns the sender address of the given transaction. The transaction
+// must be known to the remote node and included in the blockchain at the given block and
+// index. The sender is the one derived by the protocol at the time of inclusion.
+//
+// There is a fast-path for transactions retrieved by TransactionByHash and
+// TransactionInBlock. Getting their sender address can be done without an RPC interaction.
+func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) {
+ // Try to load the address from the cache.
+ sender, err := types.Sender(&senderFromServer{blockhash: block}, tx)
+ if err == nil {
+ return sender, nil
+ }
+ var meta struct {
+ Hash common.Hash
+ From common.Address
+ }
+ if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil {
+ return common.Address{}, err
+ }
+ if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() {
+ return common.Address{}, errors.New("wrong inclusion block/index")
+ }
+ return meta.From, nil
+}
+
+// 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 hexutil.Uint
+ err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash)
+ return uint(num), 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 json *rpcTransaction
+ err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index))
+ if err != nil {
+ return nil, err
+ }
+ if json == nil {
+ return nil, coreth.NotFound
+ } else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
+ return nil, fmt.Errorf("server returned transaction without signature")
+ }
+ if json.From != nil && json.BlockHash != nil {
+ setSenderFromServer(json.tx, *json.From, *json.BlockHash)
+ }
+ return json.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 {
+ if r == nil {
+ return nil, coreth.NotFound
+ }
+ }
+ return r, err
+}
+
+func toBlockNumArg(number *big.Int) string {
+ // The Ethereum implementation uses a different mapping from
+ // negative numbers to special strings (latest, pending) then is
+ // used on its server side. See rpc/types.go for the comparison.
+ // if number == nil {
+ // return "latest"
+ // }
+ // pending := big.NewInt(-1)
+ // if number.Cmp(pending) == 0 {
+ // return "pending"
+ // }
+
+ // In Coreth, latest, pending, and accepted are all treated the same
+ // therefore, if [number] is nil or a negative number in [-3, -1]
+ // we want the latest accepted block
+ if number == nil {
+ return "latest"
+ }
+ low := big.NewInt(-3)
+ high := big.NewInt(-1)
+ if number.Cmp(low) >= 0 && number.Cmp(high) <= 0 {
+ return "latest"
+ }
+ return hexutil.EncodeBig(number)
+}
+
+type rpcProgress struct {
+ StartingBlock hexutil.Uint64
+ CurrentBlock hexutil.Uint64
+ HighestBlock hexutil.Uint64
+ PulledStates hexutil.Uint64
+ KnownStates hexutil.Uint64
+}
+
+// SyncProgress retrieves the current progress of the sync algorithm. If there's
+// no sync currently running, it returns nil.
+// eth_syncing is not implemented in Coreth
+// func (ec *Client) SyncProgress(ctx context.Context) (*coreth.SyncProgress, error) {
+// var raw json.RawMessage
+// if err := ec.c.CallContext(ctx, &raw, "eth_syncing"); err != nil {
+// return nil, err
+// }
+// // Handle the possible response types
+// var syncing bool
+// if err := json.Unmarshal(raw, &syncing); err == nil {
+// return nil, nil // Not syncing (always false)
+// }
+// var progress *rpcProgress
+// if err := json.Unmarshal(raw, &progress); err != nil {
+// return nil, err
+// }
+// return &coreth.SyncProgress{
+// StartingBlock: uint64(progress.StartingBlock),
+// CurrentBlock: uint64(progress.CurrentBlock),
+// HighestBlock: uint64(progress.HighestBlock),
+// PulledStates: uint64(progress.PulledStates),
+// KnownStates: uint64(progress.KnownStates),
+// }, nil
+// }
+
+// SubscribeNewHead subscribes to notifications about the current blockchain head
+// on the given channel.
+func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (coreth.Subscription, error) {
+ return ec.c.EthSubscribe(ctx, ch, "newHeads")
+}
+
+// State Access
+
+// NetworkID returns the network ID (also known as the chain ID) for this chain.
+func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) {
+ version := new(big.Int)
+ var ver string
+ if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil {
+ return nil, err
+ }
+ if _, ok := version.SetString(ver, 10); !ok {
+ return nil, fmt.Errorf("invalid net_version result %q", ver)
+ }
+ return version, nil
+}
+
+// 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 hexutil.Big
+ err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber))
+ return (*big.Int)(&result), err
+}
+
+// AssetBalanceAt returns the [assetID] 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) AssetBalanceAt(ctx context.Context, account common.Address, assetID ids.ID, blockNumber *big.Int) (*big.Int, error) {
+ var result hexutil.Big
+ err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber), assetID)
+ 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 hexutil.Bytes
+ 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 hexutil.Bytes
+ 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 hexutil.Uint64
+ err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, toBlockNumArg(blockNumber))
+ return uint64(result), err
+}
+
+// Filters
+
+// FilterLogs executes a filter query.
+func (ec *Client) FilterLogs(ctx context.Context, q coreth.FilterQuery) ([]types.Log, error) {
+ var result []types.Log
+ arg, err := toFilterArg(q)
+ if err != nil {
+ return nil, err
+ }
+ err = ec.c.CallContext(ctx, &result, "eth_getLogs", arg)
+ return result, err
+}
+
+// SubscribeFilterLogs subscribes to the results of a streaming filter query.
+func (ec *Client) SubscribeFilterLogs(ctx context.Context, q coreth.FilterQuery, ch chan<- types.Log) (coreth.Subscription, error) {
+ arg, err := toFilterArg(q)
+ if err != nil {
+ return nil, err
+ }
+ return ec.c.EthSubscribe(ctx, ch, "logs", arg)
+}
+
+func toFilterArg(q coreth.FilterQuery) (interface{}, error) {
+ arg := map[string]interface{}{
+ "address": q.Addresses,
+ "topics": q.Topics,
+ }
+ if q.BlockHash != nil {
+ arg["blockHash"] = *q.BlockHash
+ if q.FromBlock != nil || q.ToBlock != nil {
+ return nil, fmt.Errorf("cannot specify both BlockHash and FromBlock/ToBlock")
+ }
+ } else {
+ if q.FromBlock == nil {
+ arg["fromBlock"] = "0x0"
+ } else {
+ arg["fromBlock"] = toBlockNumArg(q.FromBlock)
+ }
+ arg["toBlock"] = toBlockNumArg(q.ToBlock)
+ }
+ return arg, nil
+}
+
+// Pending State is irrelevant in Coreth
+
+// // 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 hexutil.Big
+// 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 hexutil.Bytes
+// 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 hexutil.Bytes
+// 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 hexutil.Uint64
+// err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending")
+// return uint64(result), err
+// }
+
+// // PendingTransactionCount returns the total number of transactions in the pending state.
+// func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) {
+// var num hexutil.Uint
+// err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", "pending")
+// return uint(num), 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 coreth.CallMsg, blockNumber *big.Int) ([]byte, error) {
+ var hex hexutil.Bytes
+ err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber))
+ if err != nil {
+ return nil, err
+ }
+ return 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 coreth.CallMsg) ([]byte, error) {
+// var hex hexutil.Bytes
+// err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "pending")
+// if err != nil {
+// return nil, err
+// }
+// return 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 hexutil.Big
+ 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 coreth.CallMsg) (uint64, error) {
+ var hex hexutil.Uint64
+ err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg))
+ if err != nil {
+ return 0, err
+ }
+ return uint64(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", hexutil.Encode(data))
+}
+
+func toCallArg(msg coreth.CallMsg) interface{} {
+ arg := map[string]interface{}{
+ "from": msg.From,
+ "to": msg.To,
+ }
+ if len(msg.Data) > 0 {
+ arg["data"] = hexutil.Bytes(msg.Data)
+ }
+ if msg.Value != nil {
+ arg["value"] = (*hexutil.Big)(msg.Value)
+ }
+ if msg.Gas != 0 {
+ arg["gas"] = hexutil.Uint64(msg.Gas)
+ }
+ if msg.GasPrice != nil {
+ arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice)
+ }
+ return arg
+}
diff --git a/ethclient/signer.go b/ethclient/signer.go
new file mode 100644
index 0000000..4a9f645
--- /dev/null
+++ b/ethclient/signer.go
@@ -0,0 +1,59 @@
+// Copyright 2017 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
+
+import (
+ "errors"
+ "math/big"
+
+ "github.com/ava-labs/coreth/core/types"
+ "github.com/ethereum/go-ethereum/common"
+)
+
+// senderFromServer is a types.Signer that remembers the sender address returned by the RPC
+// server. It is stored in the transaction's sender address cache to avoid an additional
+// request in TransactionSender.
+type senderFromServer struct {
+ addr common.Address
+ blockhash common.Hash
+}
+
+var errNotCached = errors.New("sender not cached")
+
+func setSenderFromServer(tx *types.Transaction, addr common.Address, block common.Hash) {
+ // Use types.Sender for side-effect to store our signer into the cache.
+ types.Sender(&senderFromServer{addr, block}, tx)
+}
+
+func (s *senderFromServer) Equal(other types.Signer) bool {
+ os, ok := other.(*senderFromServer)
+ return ok && os.blockhash == s.blockhash
+}
+
+func (s *senderFromServer) Sender(tx *types.Transaction) (common.Address, error) {
+ if s.blockhash == (common.Hash{}) {
+ return common.Address{}, errNotCached
+ }
+ return s.addr, nil
+}
+
+func (s *senderFromServer) Hash(tx *types.Transaction) common.Hash {
+ panic("can't sign with senderFromServer")
+}
+func (s *senderFromServer) SignatureValues(tx *types.Transaction, sig []byte) (R, S, V *big.Int, err error) {
+ panic("can't sign with senderFromServer")
+}
diff --git a/examples/client/main.go b/examples/client/main.go
new file mode 100644
index 0000000..5f61e6a
--- /dev/null
+++ b/examples/client/main.go
@@ -0,0 +1,220 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "time"
+
+ "math/big"
+
+ "github.com/ava-labs/avalanchego/utils/crypto"
+ "github.com/ava-labs/avalanchego/utils/formatting"
+ "github.com/ava-labs/coreth/ethclient"
+ "github.com/ava-labs/coreth/plugin/evm"
+
+ "github.com/ava-labs/coreth"
+ "github.com/ava-labs/coreth/core/types"
+ "github.com/ethereum/go-ethereum/common"
+)
+
+var (
+ key = "ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN"
+ prefixedPrivateKey = fmt.Sprintf("PrivateKey-%s", key)
+ ipAddr = "127.0.0.1"
+ port = 9650
+)
+
+type ethWSAPITestExecutor struct {
+ uri string
+ requestTimeout time.Duration
+}
+
+// ExecuteTest ...
+func (e *ethWSAPITestExecutor) ExecuteTest() error {
+ client, err := ethclient.Dial(e.uri)
+ if err != nil {
+ return fmt.Errorf("Failed to create ethclient: %w", err)
+ }
+ fmt.Printf("Created ethclient\n")
+
+ ctx := context.Background()
+
+ cb58 := formatting.CB58{}
+ factory := crypto.FactorySECP256K1R{}
+ _ = cb58.FromString(key)
+ pk, _ := factory.ToPrivateKey(cb58.Bytes)
+ secpKey := pk.(*crypto.PrivateKeySECP256K1R)
+ ethAddr := evm.GetEthAddress(secpKey)
+
+ if err := testSubscription(ctx, client); err != nil {
+ return fmt.Errorf("Subscription Test failed: %w", err)
+ }
+
+ if err := testHeaderAndBlockCalls(ctx, client, ethAddr); err != nil {
+ return fmt.Errorf("HeaderAndBlockCalls Test failed: %w", err)
+ }
+
+ return nil
+}
+
+type ethRPCAPITestExecutor struct {
+ uri string
+ requestTimeout time.Duration
+}
+
+// ExecuteTest ...
+func (e *ethRPCAPITestExecutor) ExecuteTest() error {
+ client, err := ethclient.Dial(e.uri)
+ if err != nil {
+ return fmt.Errorf("Failed to create ethclient: %w", err)
+ }
+ fmt.Printf("Created ethclient\n")
+
+ ctx := context.Background()
+
+ cb58 := formatting.CB58{}
+ factory := crypto.FactorySECP256K1R{}
+ _ = cb58.FromString(key)
+ pk, _ := factory.ToPrivateKey(cb58.Bytes)
+ secpKey := pk.(*crypto.PrivateKeySECP256K1R)
+ ethAddr := evm.GetEthAddress(secpKey)
+
+ if err := testHeaderAndBlockCalls(ctx, client, ethAddr); err != nil {
+ return fmt.Errorf("HeaderAndBlockCalls Test failed: %w", err)
+ }
+
+ return nil
+}
+
+func testSubscription(ctx context.Context, client *ethclient.Client) error {
+ headerChan := make(chan *types.Header)
+ subscription, err := client.SubscribeNewHead(ctx, headerChan)
+ if err != nil {
+ return fmt.Errorf("Failed to create subscription: %s", err)
+ }
+ fmt.Printf("Created subscription: %s\n", subscription)
+
+ suggestedGasPrice, err := client.SuggestGasPrice(ctx)
+ if err != nil {
+ return fmt.Errorf("Failed to get suggested gas price: %s", err)
+ }
+ fmt.Printf("Suggested gas price: %d\n", suggestedGasPrice.Uint64())
+
+ logChan := make(chan types.Log)
+ query := coreth.FilterQuery{
+ BlockHash: nil,
+ FromBlock: nil,
+ ToBlock: nil,
+ Addresses: []common.Address{},
+ Topics: [][]common.Hash{},
+ }
+ subscription, err = client.SubscribeFilterLogs(ctx, query, logChan)
+ if err != nil {
+ return fmt.Errorf("Failed to create subscription: %s", err)
+ }
+ fmt.Printf("Created subscription: %s\n", subscription)
+
+ return nil
+}
+
+func testHeaderAndBlockCalls(ctx context.Context, client *ethclient.Client, ethAddr common.Address) error {
+ // Test Header and Block ByNumber work for special cases
+ for i := 0; i > -3; i-- {
+ if err := checkHeaderAndBlocks(ctx, client, i, ethAddr); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func checkHeaderAndBlocks(ctx context.Context, client *ethclient.Client, i int, ethAddr common.Address) error {
+ fmt.Printf("Checking HeaderAndBlocks for i = %d\n", i)
+
+ header1, err := client.HeaderByNumber(ctx, big.NewInt(int64(i)))
+ if err != nil {
+ return fmt.Errorf("Failed to retrieve HeaderByNumber: %w", err)
+ }
+ fmt.Printf("HeaderByNumber (Block Number: %d, Block Hash: %s)\n", header1.Number, header1.Hash().Hex())
+
+ originalHash := header1.Hash()
+ originalBlockNumber := header1.Number
+ if i >= 0 && int(originalBlockNumber.Int64()) != i {
+ return fmt.Errorf("Requested block number %d, but found block number %d", i, originalBlockNumber)
+ }
+
+ header2, err := client.HeaderByHash(ctx, header1.Hash())
+ if err != nil {
+ return fmt.Errorf("Failed to retrieve HeaderByHash: %w", err)
+ }
+ fmt.Printf("HeaderByNumber (Block Number: %d, Block Hash: %s)\n", header2.Number, header2.Hash().Hex())
+
+ if originalHash.Hex() != header2.Hash().Hex() {
+ return fmt.Errorf("Expected HeaderByHash with Hash: %s, but found: %s", originalHash.Hex(), header2.Hash().Hex())
+ }
+
+ if originalBlockNumber.Cmp(header2.Number) != 0 {
+ return fmt.Errorf("Expected HeaderByHash with Number: %d, but found %d", originalBlockNumber, header2.Number)
+ }
+
+ block1, err := client.BlockByNumber(ctx, big.NewInt(int64(i)))
+ if err != nil {
+ return fmt.Errorf("Failed to retrieve BlockByNumber: %w", err)
+ }
+ header3 := block1.Header()
+ fmt.Printf("BlockByNumber (Block Number: %d, Block Hash: %s)\n", header3.Number, header3.Hash().Hex())
+
+ if originalHash.Hex() != header3.Hash().Hex() {
+ return fmt.Errorf("Expected HeaderByHash with Hash: %s, but found: %s", originalHash.Hex(), header3.Hash().Hex())
+ }
+
+ if originalBlockNumber.Cmp(header3.Number) != 0 {
+ return fmt.Errorf("Expected HeaderByHash with Number: %d, but found %d", originalBlockNumber, header3.Number)
+ }
+
+ block2, err := client.BlockByHash(ctx, header1.Hash())
+ if err != nil {
+ return fmt.Errorf("Failed to retrieve BlockByHash: %w", err)
+ }
+ header4 := block2.Header()
+ fmt.Printf("BlockByHash (Block Number: %d, Block Hash: %s)\n", header4.Number, header4.Hash().Hex())
+ if originalHash.Hex() != header4.Hash().Hex() {
+ return fmt.Errorf("Expected HeaderByHash with Hash: %s, but found: %s", originalHash.Hex(), header4.Hash().Hex())
+ }
+
+ if originalBlockNumber.Cmp(header4.Number) != 0 {
+ return fmt.Errorf("Expected HeaderByHash with Number: %d, but found %d", originalBlockNumber, header4.Number)
+ }
+
+ balance, err := client.BalanceAt(ctx, ethAddr, big.NewInt(int64(i)))
+ if err != nil {
+ return fmt.Errorf("Failed to get balance: %s", err)
+ }
+ fmt.Printf("Balance: %d for address: %s\n", balance, ethAddr.Hex())
+
+ return nil
+}
+
+func main() {
+ wsURI := fmt.Sprintf("ws://%s:%d/ext/bc/C/ws", ipAddr, port)
+ wsTest := &ethWSAPITestExecutor{
+ uri: wsURI,
+ requestTimeout: 3 * time.Second,
+ }
+ if err := wsTest.ExecuteTest(); err != nil {
+ fmt.Printf("WebSocket Test failed due to %s\n", err)
+ } else {
+ fmt.Printf("WebSocket Test succeeded!\n")
+ }
+
+ rpcURI := fmt.Sprintf("http://%s:%d/ext/bc/C/rpc", ipAddr, port)
+ rpcTest := &ethRPCAPITestExecutor{
+ uri: rpcURI,
+ requestTimeout: 3 * time.Second,
+ }
+ if err := rpcTest.ExecuteTest(); err != nil {
+ fmt.Printf("RPC Test failed due to %s\n", err)
+ } else {
+ fmt.Printf("RPC Test succeeded!\n")
+ }
+}
diff --git a/go.mod b/go.mod
index e9e7a78..7431960 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,7 @@ go 1.14
require (
github.com/VictoriaMetrics/fastcache v1.5.7
- github.com/ava-labs/avalanchego v1.0.4-update-id-2
+ github.com/ava-labs/avalanchego v1.0.5
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.7.1
github.com/edsrzf/mmap-go v1.0.0
diff --git a/go.sum b/go.sum
index 428792c..e8af04f 100644
--- a/go.sum
+++ b/go.sum
@@ -30,6 +30,7 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw=
github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8=
@@ -38,14 +39,15 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
-github.com/ava-labs/avalanchego v1.0.4-update-id-2 h1:C4Ss43XgWw1NdCm74mHiQbgsP02+I6QvTCfvIEgmkM0=
-github.com/ava-labs/avalanchego v1.0.4-update-id-2/go.mod h1:4GfedhY9S6k/SOUeMzDh6cuLoPAtnkFsL4R89xg5wf0=
+github.com/ava-labs/avalanchego v1.0.5 h1:zjBaM/9l2VjnL7j6SEwmqKjPie1W9NSEDLrd2ZotMCA=
+github.com/ava-labs/avalanchego v1.0.5/go.mod h1:4GfedhY9S6k/SOUeMzDh6cuLoPAtnkFsL4R89xg5wf0=
github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -54,6 +56,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ=
+github.com/btcsuite/btcd v0.20.1-beta h1:Ik4hyJqN8Jfyv3S4AGBOmyouMsYE3EdYODkMbQjwPGw=
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
@@ -65,6 +68,7 @@ github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
@@ -86,7 +90,9 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
+github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU=
github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60=
+github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0-20200627015759-01fd2de07837 h1:g2cyFTu5FKWhCo7L4hVJ797Q506B4EywA7L9I6OebgA=
github.com/decred/dcrd/dcrec/secp256k1/v3 v3.0.0-20200627015759-01fd2de07837/go.mod h1:J70FGZSbzsjecRTiTzER+3f1KZLNaXkuv+yeFTKoxM8=
@@ -94,6 +100,7 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M=
github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
@@ -111,8 +118,10 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv
github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 h1:FtmdgXiUlNeRsoNMFlKLDt+S+6hbjVMEW6RGQ7aUf7c=
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0=
+github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays=
@@ -120,9 +129,12 @@ github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
@@ -131,6 +143,7 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
@@ -155,6 +168,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -220,6 +234,7 @@ github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH
github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -229,6 +244,7 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/julienschmidt/httprouter v1.2.0 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356 h1:I/yrLt2WilKxlQKCM52clh5rGzTKpVctGT1lH4Dc8Jw=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
@@ -236,10 +252,13 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -285,6 +304,7 @@ github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1ORQBMvzfzBgpsctsbQikCVpvC+tX285E=
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
+github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
@@ -296,9 +316,11 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
@@ -312,6 +334,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -355,6 +378,7 @@ github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -375,9 +399,11 @@ github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca h1:Ld/zXl5t4+D69SiV4JoN7kkfvJdOWlPpfxrzxpLMoUk=
@@ -514,6 +540,7 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@@ -556,14 +583,17 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
@@ -572,7 +602,9 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
diff --git a/interfaces.go b/interfaces.go
new file mode 100644
index 0000000..4772dac
--- /dev/null
+++ b/interfaces.go
@@ -0,0 +1,211 @@
+// 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 coreth
+
+import (
+ "context"
+ "errors"
+ "math/big"
+
+ "github.com/ava-labs/coreth/core/types"
+ "github.com/ethereum/go-ethereum/common"
+)
+
+// NotFound is returned by API methods if the requested item does not exist.
+var NotFound = errors.New("not found")
+
+// 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.
+//
+// The returned error is NotFound if the requested item does not exist.
+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)
+
+ // This method subscribes to notifications about changes of the head block of
+ // the canonical chain.
+ SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (Subscription, error)
+}
+
+// TransactionReader provides access to past transactions and their receipts.
+// Implementations may impose arbitrary restrictions on the transactions and receipts that
+// can be retrieved. Historic transactions may not be available.
+//
+// Avoid relying on this interface if possible. Contract logs (through the LogFilterer
+// interface) are more reliable and usually safer in the presence of chain
+// reorganisations.
+//
+// The returned error is NotFound if the requested item does not exist.
+type TransactionReader interface {
+ // TransactionByHash checks the pool of pending transactions in addition to the
+ // blockchain. The isPending return value indicates whether the transaction has been
+ // mined yet. Note that the transaction may not be part of the canonical chain even if
+ // it's not pending.
+ TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error)
+ // TransactionReceipt returns the receipt of a mined transaction. Note that the
+ // transaction may not be included in the current canonical chain even if a receipt
+ // exists.
+ 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)
+}
+
+// SyncProgress gives progress indications when the node is synchronising with
+// the Ethereum network.
+type SyncProgress struct {
+ StartingBlock uint64 // Block number where sync began
+ CurrentBlock uint64 // Current block number where sync is at
+ HighestBlock uint64 // Highest alleged block number in the chain
+ PulledStates uint64 // Number of state trie entries already downloaded
+ KnownStates uint64 // Total number of state trie entries known about
+}
+
+// ChainSyncReader wraps access to the node's current sync status. If there's no
+// sync currently running, it returns nil.
+type ChainSyncReader interface {
+ SyncProgress(ctx context.Context) (*SyncProgress, 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 uint64 // if 0, 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 contract log filtering.
+type FilterQuery struct {
+ BlockHash *common.Hash // used by eth_getLogs, return logs only from block with this hash
+ 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 AND B in second position
+ // {{A}, {B}} matches topic A in first position AND B in second position
+ // {{A, B}, {C, D}} matches topic (A OR B) in first position AND (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.
+//
+// Logs received through a streaming query subscription may have Removed set to true,
+// indicating that the log was reverted due to a chain reorganisation.
+type LogFilterer interface {
+ FilterLogs(ctx context.Context, q FilterQuery) ([]types.Log, error)
+ SubscribeFilterLogs(ctx context.Context, q FilterQuery, ch chan<- types.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) (uint64, 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)
+}
diff --git a/node/node.go b/node/node.go
index 3ed89ed..e0a6424 100644
--- a/node/node.go
+++ b/node/node.go
@@ -113,8 +113,8 @@ func New(conf *Config) (*Node, error) {
eventmux: new(event.TypeMux),
log: conf.Logger,
stop: make(chan struct{}),
- server: &p2p.Server{Config: conf.P2P},
- databases: make(map[*closeTrackingDB]struct{}),
+ // server: &p2p.Server{Config: conf.P2P},
+ databases: make(map[*closeTrackingDB]struct{}),
}
// Register built-in APIs.
@@ -133,19 +133,19 @@ func New(conf *Config) (*Node, error) {
node.accman = am
node.ephemKeystore = ephemeralKeystore
- // Initialize the p2p server. This creates the node key and discovery databases.
- node.server.Config.PrivateKey = node.config.NodeKey()
- node.server.Config.Name = node.config.NodeName()
- node.server.Config.Logger = node.log
- if node.server.Config.StaticNodes == nil {
- node.server.Config.StaticNodes = node.config.StaticNodes()
- }
- if node.server.Config.TrustedNodes == nil {
- node.server.Config.TrustedNodes = node.config.TrustedNodes()
- }
- if node.server.Config.NodeDatabase == "" {
- node.server.Config.NodeDatabase = node.config.NodeDB()
- }
+ // // Initialize the p2p server. This creates the node key and discovery databases.
+ // node.server.Config.PrivateKey = node.config.NodeKey()
+ // node.server.Config.Name = node.config.NodeName()
+ // node.server.Config.Logger = node.log
+ // if node.server.Config.StaticNodes == nil {
+ // node.server.Config.StaticNodes = node.config.StaticNodes()
+ // }
+ // if node.server.Config.TrustedNodes == nil {
+ // node.server.Config.TrustedNodes = node.config.TrustedNodes()
+ // }
+ // if node.server.Config.NodeDatabase == "" {
+ // node.server.Config.NodeDatabase = node.config.NodeDB()
+ // }
// Configure RPC servers.
@@ -161,10 +161,11 @@ func (n *Node) Config() *Config {
// only to inspect fields of the currently running server. Callers should not
// start or stop the returned server.
func (n *Node) Server() *p2p.Server {
- n.lock.Lock()
- defer n.lock.Unlock()
+ // n.lock.Lock()
+ // defer n.lock.Unlock()
- return n.server
+ // return n.server
+ return nil
}
// DataDir retrieves the current datadir used by the protocol stack.
diff --git a/notes/hacked-list.txt b/notes/hacked-list.txt
index 3182b56..0ae1db0 100644
--- a/notes/hacked-list.txt
+++ b/notes/hacked-list.txt
@@ -30,6 +30,9 @@
./eth/config.go
./eth/gen_config.go
./eth/tracers/internal/tracers/assets.go
+./ethclient/ethclient.go
+./ethclient/ethclient_test.go
+./ethclient/signer.go
./internal/ethapi/api.go
./internal/ethapi/backend.go
./miner/miner.go
@@ -41,3 +44,4 @@
./params/protocol_params.go
./rpc/client.go
./rpc/types.go
+./interfaces.go