2016-11-09 04:01:56 +03:00
|
|
|
|
// Copyright 2015 The go-ethereum Authors
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// 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 ethapi
|
|
|
|
|
|
|
|
|
|
import (
|
2017-12-18 14:50:21 +03:00
|
|
|
|
"bytes"
|
2017-03-22 20:20:33 +03:00
|
|
|
|
"context"
|
2017-01-11 15:20:24 +03:00
|
|
|
|
"errors"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"fmt"
|
|
|
|
|
"math/big"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
2018-04-05 15:13:02 +03:00
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"github.com/ethereum/go-ethereum/accounts"
|
2020-04-22 11:25:36 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
2017-01-24 12:49:20 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
2018-01-07 21:38:11 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2016-12-16 13:19:03 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
common: move big integer math to common/math (#3699)
* common: remove CurrencyToString
Move denomination values to params instead.
* common: delete dead code
* common: move big integer operations to common/math
This commit consolidates all big integer operations into common/math and
adds tests and documentation.
There should be no change in semantics for BigPow, BigMin, BigMax, S256,
U256, Exp and their behaviour is now locked in by tests.
The BigD, BytesToBig and Bytes2Big functions don't provide additional
value, all uses are replaced by new(big.Int).SetBytes().
BigToBytes is now called PaddedBigBytes, its minimum output size
parameter is now specified as the number of bytes instead of bits. The
single use of this function is in the EVM's MSTORE instruction.
Big and String2Big are replaced by ParseBig, which is slightly stricter.
It previously accepted leading zeros for hexadecimal inputs but treated
decimal inputs as octal if a leading zero digit was present.
ParseUint64 is used in places where String2Big was used to decode a
uint64.
The new functions MustParseBig and MustParseUint64 are now used in many
places where parsing errors were previously ignored.
* common: delete unused big integer variables
* accounts/abi: replace uses of BytesToBig with use of encoding/binary
* common: remove BytesToBig
* common: remove Bytes2Big
* common: remove BigTrue
* cmd/utils: add BigFlag and use it for error-checked integer flags
While here, remove environment variable processing for DirectoryFlag
because we don't use it.
* core: add missing error checks in genesis block parser
* common: remove String2Big
* cmd/evm: use utils.BigFlag
* common/math: check for 256 bit overflow in ParseBig
This is supposed to prevent silent overflow/truncation of values in the
genesis block JSON. Without this check, a genesis block that set a
balance larger than 256 bits would lead to weird behaviour in the VM.
* cmd/utils: fixup import
2017-02-27 00:21:51 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/common/math"
|
2019-02-12 16:00:02 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
2017-04-05 01:16:29 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"github.com/ethereum/go-ethereum/core"
|
2018-05-07 14:35:06 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
|
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
2017-02-22 15:10:07 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"github.com/ethereum/go-ethereum/p2p"
|
common: move big integer math to common/math (#3699)
* common: remove CurrencyToString
Move denomination values to params instead.
* common: delete dead code
* common: move big integer operations to common/math
This commit consolidates all big integer operations into common/math and
adds tests and documentation.
There should be no change in semantics for BigPow, BigMin, BigMax, S256,
U256, Exp and their behaviour is now locked in by tests.
The BigD, BytesToBig and Bytes2Big functions don't provide additional
value, all uses are replaced by new(big.Int).SetBytes().
BigToBytes is now called PaddedBigBytes, its minimum output size
parameter is now specified as the number of bytes instead of bits. The
single use of this function is in the EVM's MSTORE instruction.
Big and String2Big are replaced by ParseBig, which is slightly stricter.
It previously accepted leading zeros for hexadecimal inputs but treated
decimal inputs as octal if a leading zero digit was present.
ParseUint64 is used in places where String2Big was used to decode a
uint64.
The new functions MustParseBig and MustParseUint64 are now used in many
places where parsing errors were previously ignored.
* common: delete unused big integer variables
* accounts/abi: replace uses of BytesToBig with use of encoding/binary
* common: remove BytesToBig
* common: remove Bytes2Big
* common: remove BigTrue
* cmd/utils: add BigFlag and use it for error-checked integer flags
While here, remove environment variable processing for DirectoryFlag
because we don't use it.
* core: add missing error checks in genesis block parser
* common: remove String2Big
* cmd/evm: use utils.BigFlag
* common/math: check for 256 bit overflow in ParseBig
This is supposed to prevent silent overflow/truncation of values in the
genesis block JSON. Without this check, a genesis block that set a
balance larger than 256 bits would lead to weird behaviour in the VM.
* cmd/utils: fixup import
2017-02-27 00:21:51 +03:00
|
|
|
|
"github.com/ethereum/go-ethereum/params"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"github.com/ethereum/go-ethereum/rlp"
|
|
|
|
|
"github.com/ethereum/go-ethereum/rpc"
|
2018-01-07 21:38:11 +03:00
|
|
|
|
"github.com/tyler-smith/go-bip39"
|
2015-12-16 05:26:23 +02:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// PublicEthereumAPI provides an API to access Ethereum related information.
|
|
|
|
|
// It offers only methods that operate on public data that is freely available to anyone.
|
|
|
|
|
type PublicEthereumAPI struct {
|
2016-06-15 01:36:31 +03:00
|
|
|
|
b Backend
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-20 12:31:31 +03:00
|
|
|
|
// NewPublicEthereumAPI creates a new Ethereum protocol API.
|
2016-06-15 01:36:31 +03:00
|
|
|
|
func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
|
|
|
|
|
return &PublicEthereumAPI{b}
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GasPrice returns a suggestion for a gas price.
|
2018-06-11 13:15:59 +03:00
|
|
|
|
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
|
|
|
|
|
price, err := s.b.SuggestPrice(ctx)
|
|
|
|
|
return (*hexutil.Big)(price), err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ProtocolVersion returns the current Ethereum protocol version this node supports
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicEthereumAPI) ProtocolVersion() hexutil.Uint {
|
|
|
|
|
return hexutil.Uint(s.b.ProtocolVersion())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
|
|
|
|
|
// yet received the latest block headers from its pears. In case it is synchronizing:
|
|
|
|
|
// - startingBlock: block number this node started to synchronise from
|
|
|
|
|
// - currentBlock: block number this node is currently importing
|
|
|
|
|
// - highestBlock: block number of the highest block header this node has received from peers
|
|
|
|
|
// - pulledStates: number of state entries processed until now
|
|
|
|
|
// - knownStates: number of known state entries that still need to be pulled
|
|
|
|
|
func (s *PublicEthereumAPI) Syncing() (interface{}, error) {
|
2016-09-06 12:39:14 +03:00
|
|
|
|
progress := s.b.Downloader().Progress()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
|
|
|
|
|
// Return not syncing if the synchronisation already completed
|
2016-09-06 12:39:14 +03:00
|
|
|
|
if progress.CurrentBlock >= progress.HighestBlock {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
// Otherwise gather the block sync stats
|
|
|
|
|
return map[string]interface{}{
|
2016-12-17 17:39:55 +03:00
|
|
|
|
"startingBlock": hexutil.Uint64(progress.StartingBlock),
|
|
|
|
|
"currentBlock": hexutil.Uint64(progress.CurrentBlock),
|
|
|
|
|
"highestBlock": hexutil.Uint64(progress.HighestBlock),
|
|
|
|
|
"pulledStates": hexutil.Uint64(progress.PulledStates),
|
|
|
|
|
"knownStates": hexutil.Uint64(progress.KnownStates),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PublicTxPoolAPI offers and API for the transaction pool. It only operates on data that is non confidential.
|
|
|
|
|
type PublicTxPoolAPI struct {
|
|
|
|
|
b Backend
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPublicTxPoolAPI creates a new tx pool service that gives information about the transaction pool.
|
|
|
|
|
func NewPublicTxPoolAPI(b Backend) *PublicTxPoolAPI {
|
|
|
|
|
return &PublicTxPoolAPI{b}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Content returns the transactions contained within the transaction pool.
|
2016-06-27 18:28:34 +03:00
|
|
|
|
func (s *PublicTxPoolAPI) Content() map[string]map[string]map[string]*RPCTransaction {
|
|
|
|
|
content := map[string]map[string]map[string]*RPCTransaction{
|
|
|
|
|
"pending": make(map[string]map[string]*RPCTransaction),
|
|
|
|
|
"queued": make(map[string]map[string]*RPCTransaction),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
pending, queue := s.b.TxPoolContent()
|
|
|
|
|
|
|
|
|
|
// Flatten the pending transactions
|
2016-06-27 18:28:34 +03:00
|
|
|
|
for account, txs := range pending {
|
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
2017-05-29 11:14:56 +03:00
|
|
|
|
for _, tx := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
content["pending"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
// Flatten the queued transactions
|
2016-06-27 18:28:34 +03:00
|
|
|
|
for account, txs := range queue {
|
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
2017-05-29 11:14:56 +03:00
|
|
|
|
for _, tx := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
content["queued"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
return content
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Status returns the number of pending and queued transaction in the pool.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
pending, queue := s.b.Stats()
|
2016-12-17 17:39:55 +03:00
|
|
|
|
return map[string]hexutil.Uint{
|
|
|
|
|
"pending": hexutil.Uint(pending),
|
|
|
|
|
"queued": hexutil.Uint(queue),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inspect retrieves the content of the transaction pool and flattens it into an
|
|
|
|
|
// easily inspectable list.
|
2016-06-27 18:28:34 +03:00
|
|
|
|
func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string {
|
|
|
|
|
content := map[string]map[string]map[string]string{
|
|
|
|
|
"pending": make(map[string]map[string]string),
|
|
|
|
|
"queued": make(map[string]map[string]string),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
pending, queue := s.b.TxPoolContent()
|
|
|
|
|
|
|
|
|
|
// Define a formatter to flatten a transaction into a string
|
|
|
|
|
var format = func(tx *types.Transaction) string {
|
|
|
|
|
if to := tx.To(); to != nil {
|
2017-11-17 16:07:57 +03:00
|
|
|
|
return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-11-17 16:07:57 +03:00
|
|
|
|
return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value(), tx.Gas(), tx.GasPrice())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
// Flatten the pending transactions
|
2016-06-27 18:28:34 +03:00
|
|
|
|
for account, txs := range pending {
|
|
|
|
|
dump := make(map[string]string)
|
2017-05-29 11:14:56 +03:00
|
|
|
|
for _, tx := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = format(tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
content["pending"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
// Flatten the queued transactions
|
2016-06-27 18:28:34 +03:00
|
|
|
|
for account, txs := range queue {
|
|
|
|
|
dump := make(map[string]string)
|
2017-05-29 11:14:56 +03:00
|
|
|
|
for _, tx := range txs {
|
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = format(tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
content["queued"][account.Hex()] = dump
|
|
|
|
|
}
|
|
|
|
|
return content
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PublicAccountAPI provides an API to access accounts managed by this node.
|
|
|
|
|
// It offers only methods that can retrieve accounts.
|
|
|
|
|
type PublicAccountAPI struct {
|
|
|
|
|
am *accounts.Manager
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPublicAccountAPI creates a new PublicAccountAPI.
|
|
|
|
|
func NewPublicAccountAPI(am *accounts.Manager) *PublicAccountAPI {
|
|
|
|
|
return &PublicAccountAPI{am: am}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Accounts returns the collection of accounts this node manages
|
2017-02-07 13:47:34 +03:00
|
|
|
|
func (s *PublicAccountAPI) Accounts() []common.Address {
|
2019-08-08 12:23:40 +03:00
|
|
|
|
return s.am.Accounts()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PrivateAccountAPI provides an API to access accounts managed by this node.
|
|
|
|
|
// It offers methods to create, (un)lock en list accounts. Some methods accept
|
|
|
|
|
// passwords and are therefore considered private by default.
|
|
|
|
|
type PrivateAccountAPI struct {
|
2017-05-25 18:08:13 +03:00
|
|
|
|
am *accounts.Manager
|
|
|
|
|
nonceLock *AddrLocker
|
|
|
|
|
b Backend
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPrivateAccountAPI create a new PrivateAccountAPI.
|
2017-05-25 18:08:13 +03:00
|
|
|
|
func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return &PrivateAccountAPI{
|
2017-06-01 17:16:12 +03:00
|
|
|
|
am: b.AccountManager(),
|
|
|
|
|
nonceLock: nonceLock,
|
|
|
|
|
b: b,
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
accounts, eth, clique, signer: support for external signer API (#18079)
* accounts, eth, clique: implement external backend + move sighash calc to backend
* signer: implement account_Version on external API
* accounts/external: enable ipc, add copyright
* accounts, internal, signer: formatting
* node: go fmt
* flags: disallow --dev in combo with --externalsigner
* accounts: remove clique-specific signing method, replace with more generic
* accounts, consensus: formatting + fix error in tests
* signer/core: remove (test-) import cycle
* clique: remove unused import
* accounts: remove CliqueHash and avoid dependency on package crypto
* consensus/clique: unduplicate header encoding
2019-02-05 13:23:57 +03:00
|
|
|
|
// listAccounts will return a list of addresses for accounts this node manages.
|
2015-12-16 05:26:23 +02:00
|
|
|
|
func (s *PrivateAccountAPI) ListAccounts() []common.Address {
|
2019-08-08 12:23:40 +03:00
|
|
|
|
return s.am.Accounts()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// rawWallet is a JSON representation of an accounts.Wallet interface, with its
|
|
|
|
|
// data contents extracted into plain fields.
|
|
|
|
|
type rawWallet struct {
|
|
|
|
|
URL string `json:"url"`
|
|
|
|
|
Status string `json:"status"`
|
2017-08-09 12:51:16 +03:00
|
|
|
|
Failure string `json:"failure,omitempty"`
|
|
|
|
|
Accounts []accounts.Account `json:"accounts,omitempty"`
|
2017-02-07 13:47:34 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ListWallets will return a list of wallets this node manages.
|
|
|
|
|
func (s *PrivateAccountAPI) ListWallets() []rawWallet {
|
2017-04-24 15:00:30 +03:00
|
|
|
|
wallets := make([]rawWallet, 0) // return [] instead of nil if empty
|
2017-02-07 13:47:34 +03:00
|
|
|
|
for _, wallet := range s.am.Wallets() {
|
2017-08-09 12:51:16 +03:00
|
|
|
|
status, failure := wallet.Status()
|
|
|
|
|
|
|
|
|
|
raw := rawWallet{
|
2017-02-08 16:53:02 +03:00
|
|
|
|
URL: wallet.URL().String(),
|
2017-08-09 12:51:16 +03:00
|
|
|
|
Status: status,
|
2017-02-07 13:47:34 +03:00
|
|
|
|
Accounts: wallet.Accounts(),
|
2017-08-09 12:51:16 +03:00
|
|
|
|
}
|
|
|
|
|
if failure != nil {
|
|
|
|
|
raw.Failure = failure.Error()
|
|
|
|
|
}
|
|
|
|
|
wallets = append(wallets, raw)
|
2017-02-07 13:47:34 +03:00
|
|
|
|
}
|
|
|
|
|
return wallets
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-01 18:45:17 +03:00
|
|
|
|
// OpenWallet initiates a hardware wallet opening procedure, establishing a USB
|
|
|
|
|
// connection and attempting to authenticate via the provided passphrase. Note,
|
|
|
|
|
// the method may return an extra challenge requiring a second open (e.g. the
|
|
|
|
|
// Trezor PIN matrix challenge).
|
|
|
|
|
func (s *PrivateAccountAPI) OpenWallet(url string, passphrase *string) error {
|
|
|
|
|
wallet, err := s.am.Wallet(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
pass := ""
|
|
|
|
|
if passphrase != nil {
|
|
|
|
|
pass = *passphrase
|
|
|
|
|
}
|
|
|
|
|
return wallet.Open(pass)
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// DeriveAccount requests a HD wallet to derive a new account, optionally pinning
|
|
|
|
|
// it for later reuse.
|
|
|
|
|
func (s *PrivateAccountAPI) DeriveAccount(url string, path string, pin *bool) (accounts.Account, error) {
|
|
|
|
|
wallet, err := s.am.Wallet(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return accounts.Account{}, err
|
|
|
|
|
}
|
2017-02-08 21:25:52 +03:00
|
|
|
|
derivPath, err := accounts.ParseDerivationPath(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return accounts.Account{}, err
|
|
|
|
|
}
|
2017-02-07 13:47:34 +03:00
|
|
|
|
if pin == nil {
|
|
|
|
|
pin = new(bool)
|
|
|
|
|
}
|
2017-02-08 21:25:52 +03:00
|
|
|
|
return wallet.Derive(derivPath, *pin)
|
2017-02-07 13:47:34 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// NewAccount will create a new account and returns the address for the new account.
|
|
|
|
|
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
|
2017-01-24 12:49:20 +03:00
|
|
|
|
acc, err := fetchKeystore(s.am).NewAccount(password)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err == nil {
|
2019-05-07 15:49:51 +03:00
|
|
|
|
log.Info("Your new key was generated", "address", acc.Address)
|
|
|
|
|
log.Warn("Please backup your key file!", "path", acc.URL.Path)
|
|
|
|
|
log.Warn("Please remember your password!")
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return acc.Address, nil
|
|
|
|
|
}
|
|
|
|
|
return common.Address{}, err
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-25 11:21:28 +03:00
|
|
|
|
// fetchKeystore retrieves the encrypted keystore from the account manager.
|
2017-01-24 12:49:20 +03:00
|
|
|
|
func fetchKeystore(am *accounts.Manager) *keystore.KeyStore {
|
2017-02-07 13:47:34 +03:00
|
|
|
|
return am.Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
|
2017-01-24 12:49:20 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// ImportRawKey stores the given hex encoded ECDSA key into the key directory,
|
|
|
|
|
// encrypting it with the passphrase.
|
|
|
|
|
func (s *PrivateAccountAPI) ImportRawKey(privkey string, password string) (common.Address, error) {
|
2017-05-23 14:58:03 +03:00
|
|
|
|
key, err := crypto.HexToECDSA(privkey)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Address{}, err
|
|
|
|
|
}
|
2017-05-23 14:58:03 +03:00
|
|
|
|
acc, err := fetchKeystore(s.am).ImportECDSA(key, password)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return acc.Address, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnlockAccount will unlock the account associated with the given address with
|
|
|
|
|
// the given password for duration seconds. If duration is nil it will use a
|
|
|
|
|
// default of 300 seconds. It returns an indication if the account was unlocked.
|
2019-04-04 14:03:10 +03:00
|
|
|
|
func (s *PrivateAccountAPI) UnlockAccount(ctx context.Context, addr common.Address, password string, duration *uint64) (bool, error) {
|
|
|
|
|
// When the API is exposed by external RPC(http, ws etc), unless the user
|
|
|
|
|
// explicitly specifies to allow the insecure account unlocking, otherwise
|
|
|
|
|
// it is disabled.
|
|
|
|
|
if s.b.ExtRPCEnabled() && !s.b.AccountManager().Config().InsecureUnlockAllowed {
|
|
|
|
|
return false, errors.New("account unlock with HTTP access is forbidden")
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-11 15:20:24 +03:00
|
|
|
|
const max = uint64(time.Duration(math.MaxInt64) / time.Second)
|
2016-12-17 17:39:55 +03:00
|
|
|
|
var d time.Duration
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if duration == nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
d = 300 * time.Second
|
2017-01-11 15:20:24 +03:00
|
|
|
|
} else if *duration > max {
|
|
|
|
|
return false, errors.New("unlock duration too large")
|
2016-12-17 17:39:55 +03:00
|
|
|
|
} else {
|
|
|
|
|
d = time.Duration(*duration) * time.Second
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-01-24 12:49:20 +03:00
|
|
|
|
err := fetchKeystore(s.am).TimedUnlock(accounts.Account{Address: addr}, password, d)
|
2018-10-10 12:29:05 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
log.Warn("Failed account unlock attempt", "address", addr, "err", err)
|
|
|
|
|
}
|
2017-01-11 15:20:24 +03:00
|
|
|
|
return err == nil, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LockAccount will lock the account associated with the given address when it's unlocked.
|
|
|
|
|
func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool {
|
2017-01-24 12:49:20 +03:00
|
|
|
|
return fetchKeystore(s.am).Lock(addr) == nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-15 12:11:14 +03:00
|
|
|
|
// signTransaction sets defaults and signs the given transaction
|
2018-01-26 20:32:43 +03:00
|
|
|
|
// NOTE: the caller needs to ensure that the nonceLock is held, if applicable,
|
|
|
|
|
// and release it after the transaction has been submitted to the tx pool
|
2018-10-10 12:29:05 +03:00
|
|
|
|
func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *SendTxArgs, passwd string) (*types.Transaction, error) {
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
|
account := accounts.Account{Address: args.From}
|
|
|
|
|
wallet, err := s.am.Find(account)
|
|
|
|
|
if err != nil {
|
2018-01-26 20:32:43 +03:00
|
|
|
|
return nil, err
|
2017-05-25 18:08:13 +03:00
|
|
|
|
}
|
|
|
|
|
// Set some sanity defaults and terminate on failure
|
|
|
|
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
2018-01-26 20:32:43 +03:00
|
|
|
|
return nil, err
|
2017-05-25 18:08:13 +03:00
|
|
|
|
}
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Assemble the transaction and sign with the wallet
|
2016-12-17 17:39:55 +03:00
|
|
|
|
tx := args.toTransaction()
|
2017-01-24 12:49:20 +03:00
|
|
|
|
|
2019-02-07 13:59:17 +03:00
|
|
|
|
return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID)
|
2018-01-26 20:32:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SendTransaction will create a transaction from the given arguments and
|
|
|
|
|
// tries to sign it with the key associated with args.To. If the given passwd isn't
|
|
|
|
|
// able to decrypt the key it fails.
|
|
|
|
|
func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) {
|
|
|
|
|
if args.Nonce == nil {
|
|
|
|
|
// Hold the addresse's mutex around signing to prevent concurrent assignment of
|
|
|
|
|
// the same nonce to multiple accounts.
|
|
|
|
|
s.nonceLock.LockAddr(args.From)
|
|
|
|
|
defer s.nonceLock.UnlockAddr(args.From)
|
|
|
|
|
}
|
2018-10-10 12:29:05 +03:00
|
|
|
|
signed, err := s.signTransaction(ctx, &args, passwd)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err != nil {
|
2018-10-10 12:29:05 +03:00
|
|
|
|
log.Warn("Failed transaction send attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
2019-01-21 17:38:13 +03:00
|
|
|
|
return SubmitTransaction(ctx, s.b, signed)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-01-26 20:32:43 +03:00
|
|
|
|
// SignTransaction will create a transaction from the given arguments and
|
|
|
|
|
// tries to sign it with the key associated with args.To. If the given passwd isn't
|
|
|
|
|
// able to decrypt the key it fails. The transaction is returned in RLP-form, not broadcast
|
|
|
|
|
// to other nodes
|
|
|
|
|
func (s *PrivateAccountAPI) SignTransaction(ctx context.Context, args SendTxArgs, passwd string) (*SignTransactionResult, error) {
|
|
|
|
|
// No need to obtain the noncelock mutex, since we won't be sending this
|
|
|
|
|
// tx into the transaction pool, but right back to the user
|
|
|
|
|
if args.Gas == nil {
|
|
|
|
|
return nil, fmt.Errorf("gas not specified")
|
|
|
|
|
}
|
|
|
|
|
if args.GasPrice == nil {
|
|
|
|
|
return nil, fmt.Errorf("gasPrice not specified")
|
|
|
|
|
}
|
|
|
|
|
if args.Nonce == nil {
|
|
|
|
|
return nil, fmt.Errorf("nonce not specified")
|
|
|
|
|
}
|
2018-10-10 12:29:05 +03:00
|
|
|
|
signed, err := s.signTransaction(ctx, &args, passwd)
|
2018-01-26 20:32:43 +03:00
|
|
|
|
if err != nil {
|
2018-10-10 12:29:05 +03:00
|
|
|
|
log.Warn("Failed transaction sign attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err)
|
2018-01-26 20:32:43 +03:00
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
data, err := rlp.EncodeToBytes(signed)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return &SignTransactionResult{data, signed}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 22:25:49 +03:00
|
|
|
|
// Sign calculates an Ethereum ECDSA signature for:
|
|
|
|
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
|
|
|
|
|
//
|
2017-01-05 13:35:23 +03:00
|
|
|
|
// Note, the produced signature conforms to the secp256k1 curve R, S and V values,
|
|
|
|
|
// where the V value will be 27 or 28 for legacy reasons.
|
|
|
|
|
//
|
2016-10-28 22:25:49 +03:00
|
|
|
|
// The key used to calculate the signature is decrypted with the given password.
|
|
|
|
|
//
|
|
|
|
|
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
|
2016-12-16 13:19:03 +03:00
|
|
|
|
func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) {
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
|
account := accounts.Account{Address: addr}
|
|
|
|
|
|
|
|
|
|
wallet, err := s.b.AccountManager().Find(account)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// Assemble sign the data with the wallet
|
accounts, eth, clique, signer: support for external signer API (#18079)
* accounts, eth, clique: implement external backend + move sighash calc to backend
* signer: implement account_Version on external API
* accounts/external: enable ipc, add copyright
* accounts, internal, signer: formatting
* node: go fmt
* flags: disallow --dev in combo with --externalsigner
* accounts: remove clique-specific signing method, replace with more generic
* accounts, consensus: formatting + fix error in tests
* signer/core: remove (test-) import cycle
* clique: remove unused import
* accounts: remove CliqueHash and avoid dependency on package crypto
* consensus/clique: unduplicate header encoding
2019-02-05 13:23:57 +03:00
|
|
|
|
signature, err := wallet.SignTextWithPassphrase(account, passwd, data)
|
2017-01-05 13:35:23 +03:00
|
|
|
|
if err != nil {
|
2018-10-10 12:29:05 +03:00
|
|
|
|
log.Warn("Failed data sign attempt", "address", addr, "err", err)
|
2017-01-05 13:35:23 +03:00
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2019-08-22 16:14:06 +03:00
|
|
|
|
signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
2017-01-05 13:35:23 +03:00
|
|
|
|
return signature, nil
|
2016-10-28 22:25:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EcRecover returns the address for the account that was used to create the signature.
|
|
|
|
|
// Note, this function is compatible with eth_sign and personal_sign. As such it recovers
|
|
|
|
|
// the address of:
|
|
|
|
|
// hash = keccak256("\x19Ethereum Signed Message:\n"${message length}${message})
|
|
|
|
|
// addr = ecrecover(hash, signature)
|
|
|
|
|
//
|
2017-01-05 13:35:23 +03:00
|
|
|
|
// Note, the signature must conform to the secp256k1 curve R, S and V values, where
|
2018-09-25 13:26:35 +03:00
|
|
|
|
// the V value must be 27 or 28 for legacy reasons.
|
2017-01-05 13:35:23 +03:00
|
|
|
|
//
|
2016-10-28 22:25:49 +03:00
|
|
|
|
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
2016-12-16 13:19:03 +03:00
|
|
|
|
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
|
2019-08-22 16:14:06 +03:00
|
|
|
|
if len(sig) != crypto.SignatureLength {
|
|
|
|
|
return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength)
|
2016-10-28 22:25:49 +03:00
|
|
|
|
}
|
2019-08-22 16:14:06 +03:00
|
|
|
|
if sig[crypto.RecoveryIDOffset] != 27 && sig[crypto.RecoveryIDOffset] != 28 {
|
2017-01-05 13:35:23 +03:00
|
|
|
|
return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
2016-10-28 22:25:49 +03:00
|
|
|
|
}
|
2019-08-22 16:14:06 +03:00
|
|
|
|
sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
2017-01-05 13:35:23 +03:00
|
|
|
|
|
accounts, eth, clique, signer: support for external signer API (#18079)
* accounts, eth, clique: implement external backend + move sighash calc to backend
* signer: implement account_Version on external API
* accounts/external: enable ipc, add copyright
* accounts, internal, signer: formatting
* node: go fmt
* flags: disallow --dev in combo with --externalsigner
* accounts: remove clique-specific signing method, replace with more generic
* accounts, consensus: formatting + fix error in tests
* signer/core: remove (test-) import cycle
* clique: remove unused import
* accounts: remove CliqueHash and avoid dependency on package crypto
* consensus/clique: unduplicate header encoding
2019-02-05 13:23:57 +03:00
|
|
|
|
rpk, err := crypto.SigToPub(accounts.TextHash(data), sig)
|
2016-10-28 22:25:49 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Address{}, err
|
|
|
|
|
}
|
2018-06-12 16:26:08 +03:00
|
|
|
|
return crypto.PubkeyToAddress(*rpk), nil
|
2016-10-28 22:25:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-15 11:43:32 +03:00
|
|
|
|
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
|
|
|
|
|
// and will be removed in the future. It primary goal is to give clients time to update.
|
|
|
|
|
func (s *PrivateAccountAPI) SignAndSendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) {
|
|
|
|
|
return s.SendTransaction(ctx, args, passwd)
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 16:27:41 +03:00
|
|
|
|
// InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key.
|
2018-01-07 21:38:11 +03:00
|
|
|
|
func (s *PrivateAccountAPI) InitializeWallet(ctx context.Context, url string) (string, error) {
|
|
|
|
|
wallet, err := s.am.Wallet(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entropy, err := bip39.NewEntropy(256)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mnemonic, err := bip39.NewMnemonic(entropy)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
seed := bip39.NewSeed(mnemonic, "")
|
|
|
|
|
|
|
|
|
|
switch wallet := wallet.(type) {
|
|
|
|
|
case *scwallet.Wallet:
|
|
|
|
|
return mnemonic, wallet.Initialize(seed)
|
|
|
|
|
default:
|
2019-11-29 13:40:02 +03:00
|
|
|
|
return "", fmt.Errorf("specified wallet does not support initialization")
|
2018-01-07 21:38:11 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-22 16:27:41 +03:00
|
|
|
|
// Unpair deletes a pairing between wallet and geth.
|
2018-01-07 21:38:11 +03:00
|
|
|
|
func (s *PrivateAccountAPI) Unpair(ctx context.Context, url string, pin string) error {
|
|
|
|
|
wallet, err := s.am.Wallet(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch wallet := wallet.(type) {
|
|
|
|
|
case *scwallet.Wallet:
|
|
|
|
|
return wallet.Unpair([]byte(pin))
|
|
|
|
|
default:
|
2019-11-29 13:40:02 +03:00
|
|
|
|
return fmt.Errorf("specified wallet does not support pairing")
|
2018-01-07 21:38:11 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// PublicBlockChainAPI provides an API to access the Ethereum blockchain.
|
|
|
|
|
// It offers only methods that operate on public data that is freely available to anyone.
|
|
|
|
|
type PublicBlockChainAPI struct {
|
2016-07-27 18:47:46 +03:00
|
|
|
|
b Backend
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-20 12:31:31 +03:00
|
|
|
|
// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
|
2015-12-16 05:26:23 +02:00
|
|
|
|
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
|
2016-07-27 18:47:46 +03:00
|
|
|
|
return &PublicBlockChainAPI{b}
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-11 14:12:33 +03:00
|
|
|
|
// ChainId returns the chainID value for transaction replay protection.
|
|
|
|
|
func (s *PublicBlockChainAPI) ChainId() *hexutil.Big {
|
|
|
|
|
return (*hexutil.Big)(s.b.ChainConfig().ChainID)
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// BlockNumber returns the block number of the chain head.
|
2018-06-11 13:15:59 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
|
2016-10-14 06:51:29 +03:00
|
|
|
|
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
|
2018-06-11 13:15:59 +03:00
|
|
|
|
return hexutil.Uint64(header.Number.Uint64())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBalance returns the amount of wei for the given address in the state of the
|
|
|
|
|
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
|
|
|
|
// block numbers are also allowed.
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
|
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if state == nil || err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-06-11 13:15:59 +03:00
|
|
|
|
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 22:41:22 +03:00
|
|
|
|
// Result structs for GetProof
|
|
|
|
|
type AccountResult struct {
|
|
|
|
|
Address common.Address `json:"address"`
|
|
|
|
|
AccountProof []string `json:"accountProof"`
|
|
|
|
|
Balance *hexutil.Big `json:"balance"`
|
|
|
|
|
CodeHash common.Hash `json:"codeHash"`
|
|
|
|
|
Nonce hexutil.Uint64 `json:"nonce"`
|
|
|
|
|
StorageHash common.Hash `json:"storageHash"`
|
|
|
|
|
StorageProof []StorageResult `json:"storageProof"`
|
|
|
|
|
}
|
|
|
|
|
type StorageResult struct {
|
|
|
|
|
Key string `json:"key"`
|
|
|
|
|
Value *hexutil.Big `json:"value"`
|
|
|
|
|
Proof []string `json:"proof"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetProof returns the Merkle-proof for a given account and optionally some storage keys.
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
|
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
2018-10-18 22:41:22 +03:00
|
|
|
|
if state == nil || err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
storageTrie := state.StorageTrie(address)
|
|
|
|
|
storageHash := types.EmptyRootHash
|
|
|
|
|
codeHash := state.GetCodeHash(address)
|
|
|
|
|
storageProof := make([]StorageResult, len(storageKeys))
|
|
|
|
|
|
|
|
|
|
// if we have a storageTrie, (which means the account exists), we can update the storagehash
|
|
|
|
|
if storageTrie != nil {
|
|
|
|
|
storageHash = storageTrie.Hash()
|
|
|
|
|
} else {
|
|
|
|
|
// no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray.
|
|
|
|
|
codeHash = crypto.Keccak256Hash(nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the proof for the storageKeys
|
|
|
|
|
for i, key := range storageKeys {
|
|
|
|
|
if storageTrie != nil {
|
|
|
|
|
proof, storageError := state.GetStorageProof(address, common.HexToHash(key))
|
|
|
|
|
if storageError != nil {
|
|
|
|
|
return nil, storageError
|
|
|
|
|
}
|
|
|
|
|
storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), common.ToHexArray(proof)}
|
|
|
|
|
} else {
|
|
|
|
|
storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// create the accountProof
|
|
|
|
|
accountProof, proofErr := state.GetProof(address)
|
|
|
|
|
if proofErr != nil {
|
|
|
|
|
return nil, proofErr
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &AccountResult{
|
|
|
|
|
Address: address,
|
|
|
|
|
AccountProof: common.ToHexArray(accountProof),
|
|
|
|
|
Balance: (*hexutil.Big)(state.GetBalance(address)),
|
|
|
|
|
CodeHash: codeHash,
|
|
|
|
|
Nonce: hexutil.Uint64(state.GetNonce(address)),
|
|
|
|
|
StorageHash: storageHash,
|
|
|
|
|
StorageProof: storageProof,
|
|
|
|
|
}, state.Error()
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:52:24 +03:00
|
|
|
|
// GetHeaderByNumber returns the requested canonical block header.
|
|
|
|
|
// * When blockNr is -1 the chain head is returned.
|
|
|
|
|
// * When blockNr is -2 the pending chain head is returned.
|
|
|
|
|
func (s *PublicBlockChainAPI) GetHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) {
|
|
|
|
|
header, err := s.b.HeaderByNumber(ctx, number)
|
|
|
|
|
if header != nil && err == nil {
|
|
|
|
|
response := s.rpcMarshalHeader(header)
|
|
|
|
|
if number == rpc.PendingBlockNumber {
|
|
|
|
|
// Pending header need to nil out a few fields
|
|
|
|
|
for _, field := range []string{"hash", "nonce", "miner"} {
|
|
|
|
|
response[field] = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return response, err
|
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetHeaderByHash returns the requested header by hash.
|
|
|
|
|
func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) map[string]interface{} {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
header, _ := s.b.HeaderByHash(ctx, hash)
|
2019-07-23 16:52:24 +03:00
|
|
|
|
if header != nil {
|
|
|
|
|
return s.rpcMarshalHeader(header)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBlockByNumber returns the requested canonical block.
|
|
|
|
|
// * When blockNr is -1 the chain head is returned.
|
|
|
|
|
// * When blockNr is -2 the pending chain head is returned.
|
|
|
|
|
// * When fullTx is true all transactions in the block are returned, otherwise
|
|
|
|
|
// only the transaction hash is returned.
|
|
|
|
|
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
|
|
|
|
block, err := s.b.BlockByNumber(ctx, number)
|
|
|
|
|
if block != nil && err == nil {
|
|
|
|
|
response, err := s.rpcMarshalBlock(block, true, fullTx)
|
|
|
|
|
if err == nil && number == rpc.PendingBlockNumber {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// Pending blocks need to nil out a few fields
|
2020-02-07 12:44:32 +03:00
|
|
|
|
for _, field := range []string{"hash", "nonce", "miner"} {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
response[field] = nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return response, err
|
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
|
|
|
|
// detail, otherwise only the transaction hash is returned.
|
2019-07-23 16:52:24 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
block, err := s.b.BlockByHash(ctx, hash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if block != nil {
|
2019-07-23 16:52:24 +03:00
|
|
|
|
return s.rpcMarshalBlock(block, true, fullTx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
|
|
|
|
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
block, err := s.b.BlockByNumber(ctx, blockNr)
|
|
|
|
|
if block != nil {
|
|
|
|
|
uncles := block.Uncles()
|
2016-12-17 17:39:55 +03:00
|
|
|
|
if index >= hexutil.Uint(len(uncles)) {
|
2017-03-03 12:41:52 +03:00
|
|
|
|
log.Debug("Requested uncle not found", "number", blockNr, "hash", block.Hash(), "index", index)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
block = types.NewBlockWithHeader(uncles[index])
|
2019-07-23 16:52:24 +03:00
|
|
|
|
return s.rpcMarshalBlock(block, false, false)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. When fullTx is true
|
|
|
|
|
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
block, err := s.b.BlockByHash(ctx, blockHash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if block != nil {
|
|
|
|
|
uncles := block.Uncles()
|
2016-12-17 17:39:55 +03:00
|
|
|
|
if index >= hexutil.Uint(len(uncles)) {
|
2017-03-03 12:41:52 +03:00
|
|
|
|
log.Debug("Requested uncle not found", "number", block.Number(), "hash", blockHash, "index", index)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
block = types.NewBlockWithHeader(uncles[index])
|
2019-07-23 16:52:24 +03:00
|
|
|
|
return s.rpcMarshalBlock(block, false, false)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
n := hexutil.Uint(len(block.Uncles()))
|
|
|
|
|
return &n
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
n := hexutil.Uint(len(block.Uncles()))
|
|
|
|
|
return &n
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetCode returns the code stored at the given address in the state for the given block number.
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if state == nil || err != nil {
|
2017-06-27 16:57:06 +03:00
|
|
|
|
return nil, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-06-27 16:57:06 +03:00
|
|
|
|
code := state.GetCode(address)
|
|
|
|
|
return code, state.Error()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetStorageAt returns the storage from the state at the given address, key and
|
|
|
|
|
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
|
|
|
|
// numbers are also allowed.
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if state == nil || err != nil {
|
2017-06-27 16:57:06 +03:00
|
|
|
|
return nil, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-06-27 16:57:06 +03:00
|
|
|
|
res := state.GetState(address, common.HexToHash(key))
|
|
|
|
|
return res[:], state.Error()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CallArgs represents the arguments for a call.
|
|
|
|
|
type CallArgs struct {
|
2019-01-21 17:38:13 +03:00
|
|
|
|
From *common.Address `json:"from"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
To *common.Address `json:"to"`
|
2019-01-21 17:38:13 +03:00
|
|
|
|
Gas *hexutil.Uint64 `json:"gas"`
|
|
|
|
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
|
|
|
|
Value *hexutil.Big `json:"value"`
|
|
|
|
|
Data *hexutil.Bytes `json:"data"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-03 21:10:53 +03:00
|
|
|
|
// ToMessage converts CallArgs to the Message type used by the core evm
|
|
|
|
|
func (args *CallArgs) ToMessage(globalGasCap *big.Int) types.Message {
|
|
|
|
|
// Set sender address or use zero address if none specified.
|
|
|
|
|
var addr common.Address
|
|
|
|
|
if args.From != nil {
|
|
|
|
|
addr = *args.From
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set default gas & gas price if none were set
|
|
|
|
|
gas := uint64(math.MaxUint64 / 2)
|
|
|
|
|
if args.Gas != nil {
|
|
|
|
|
gas = uint64(*args.Gas)
|
|
|
|
|
}
|
|
|
|
|
if globalGasCap != nil && globalGasCap.Uint64() < gas {
|
|
|
|
|
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
|
|
|
|
|
gas = globalGasCap.Uint64()
|
|
|
|
|
}
|
|
|
|
|
gasPrice := new(big.Int)
|
|
|
|
|
if args.GasPrice != nil {
|
|
|
|
|
gasPrice = args.GasPrice.ToInt()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value := new(big.Int)
|
|
|
|
|
if args.Value != nil {
|
|
|
|
|
value = args.Value.ToInt()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var data []byte
|
|
|
|
|
if args.Data != nil {
|
|
|
|
|
data = []byte(*args.Data)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false)
|
|
|
|
|
return msg
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 16:44:11 +03:00
|
|
|
|
// account indicates the overriding fields of account during the execution of
|
|
|
|
|
// a message call.
|
|
|
|
|
// Note, state and stateDiff can't be specified at the same time. If state is
|
|
|
|
|
// set, message execution will only use the data in the given state. Otherwise
|
|
|
|
|
// if statDiff is set, all diff will be applied first and then execute the call
|
|
|
|
|
// message.
|
|
|
|
|
type account struct {
|
|
|
|
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
|
|
|
|
Code *hexutil.Bytes `json:"code"`
|
|
|
|
|
Balance **hexutil.Big `json:"balance"`
|
|
|
|
|
State *map[common.Hash]common.Hash `json:"state"`
|
|
|
|
|
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-22 11:25:36 +03:00
|
|
|
|
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides map[common.Address]account, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) (*core.ExecutionResult, error) {
|
2017-03-03 12:41:52 +03:00
|
|
|
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
2016-09-27 13:13:13 +03:00
|
|
|
|
|
2019-09-26 11:47:31 +03:00
|
|
|
|
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if state == nil || err != nil {
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return nil, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2019-08-08 16:44:11 +03:00
|
|
|
|
// Override the fields of specified contracts before execution.
|
|
|
|
|
for addr, account := range overrides {
|
|
|
|
|
// Override account nonce.
|
|
|
|
|
if account.Nonce != nil {
|
|
|
|
|
state.SetNonce(addr, uint64(*account.Nonce))
|
|
|
|
|
}
|
|
|
|
|
// Override account(contract) code.
|
|
|
|
|
if account.Code != nil {
|
|
|
|
|
state.SetCode(addr, *account.Code)
|
|
|
|
|
}
|
|
|
|
|
// Override account balance.
|
|
|
|
|
if account.Balance != nil {
|
|
|
|
|
state.SetBalance(addr, (*big.Int)(*account.Balance))
|
|
|
|
|
}
|
|
|
|
|
if account.State != nil && account.StateDiff != nil {
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return nil, fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
2019-08-08 16:44:11 +03:00
|
|
|
|
}
|
|
|
|
|
// Replace entire state if caller requires.
|
|
|
|
|
if account.State != nil {
|
|
|
|
|
state.SetStorage(addr, *account.State)
|
|
|
|
|
}
|
|
|
|
|
// Apply state diff into specified accounts.
|
|
|
|
|
if account.StateDiff != nil {
|
|
|
|
|
for key, value := range *account.StateDiff {
|
|
|
|
|
state.SetState(addr, key, value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-04 22:17:24 +03:00
|
|
|
|
// Setup context so it may be cancelled the call has completed
|
|
|
|
|
// or, in case of unmetered gas, setup a context with a timeout.
|
|
|
|
|
var cancel context.CancelFunc
|
2018-03-02 15:35:02 +03:00
|
|
|
|
if timeout > 0 {
|
|
|
|
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
2017-01-04 22:17:24 +03:00
|
|
|
|
} else {
|
|
|
|
|
ctx, cancel = context.WithCancel(ctx)
|
2017-02-08 15:39:26 +03:00
|
|
|
|
}
|
2017-01-04 22:17:24 +03:00
|
|
|
|
// Make sure the context is cancelled when the call has completed
|
|
|
|
|
// this makes sure resources are cleaned up.
|
2018-03-02 15:35:02 +03:00
|
|
|
|
defer cancel()
|
2017-01-04 22:17:24 +03:00
|
|
|
|
|
|
|
|
|
// Get a new instance of the EVM.
|
2020-04-03 21:10:53 +03:00
|
|
|
|
msg := args.ToMessage(globalGasCap)
|
2019-01-21 17:38:13 +03:00
|
|
|
|
evm, vmError, err := b.GetEVM(ctx, msg, state, header)
|
2017-01-04 22:17:24 +03:00
|
|
|
|
if err != nil {
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return nil, err
|
2017-01-04 22:17:24 +03:00
|
|
|
|
}
|
|
|
|
|
// Wait for the context to be done and cancel the evm. Even if the
|
|
|
|
|
// EVM has finished, cancelling may be done (repeatedly)
|
|
|
|
|
go func() {
|
2017-08-07 18:14:40 +03:00
|
|
|
|
<-ctx.Done()
|
|
|
|
|
evm.Cancel()
|
2017-01-04 22:17:24 +03:00
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
// Setup the gas pool (also for unmetered requests)
|
|
|
|
|
// and apply the message.
|
2017-11-13 14:47:27 +03:00
|
|
|
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
2020-04-22 11:25:36 +03:00
|
|
|
|
result, err := core.ApplyMessage(evm, msg, gp)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err := vmError(); err != nil {
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return nil, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2019-06-24 11:54:06 +03:00
|
|
|
|
// If the timer caused an abort, return an appropriate error message
|
|
|
|
|
if evm.Cancelled() {
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
2019-06-24 11:54:06 +03:00
|
|
|
|
}
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return result, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-08 11:09:49 +03:00
|
|
|
|
func newRevertError(result *core.ExecutionResult) *revertError {
|
|
|
|
|
reason, errUnpack := abi.UnpackRevert(result.Revert())
|
|
|
|
|
err := errors.New("execution reverted")
|
|
|
|
|
if errUnpack == nil {
|
|
|
|
|
err = fmt.Errorf("execution reverted: %v", reason)
|
|
|
|
|
}
|
|
|
|
|
return &revertError{
|
|
|
|
|
error: err,
|
|
|
|
|
reason: hexutil.Encode(result.Revert()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// revertError is an API error that encompassas an EVM revertal with JSON error
|
|
|
|
|
// code and a binary data blob.
|
|
|
|
|
type revertError struct {
|
|
|
|
|
error
|
|
|
|
|
reason string // revert reason hex encoded
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ErrorCode returns the JSON error code for a revertal.
|
|
|
|
|
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
|
|
|
|
func (e *revertError) ErrorCode() int {
|
|
|
|
|
return 3
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ErrorData returns the hex encoded revert reason.
|
|
|
|
|
func (e *revertError) ErrorData() interface{} {
|
|
|
|
|
return e.reason
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// Call executes the given transaction on the state for the given block number.
|
2019-08-08 16:44:11 +03:00
|
|
|
|
//
|
|
|
|
|
// Additionally, the caller can specify a batch of contract for fields overriding.
|
|
|
|
|
//
|
|
|
|
|
// Note, this function doesn't make and changes in the state/blockchain and is
|
|
|
|
|
// useful to execute and retrieve values.
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]account) (hexutil.Bytes, error) {
|
2019-08-08 16:44:11 +03:00
|
|
|
|
var accounts map[common.Address]account
|
|
|
|
|
if overrides != nil {
|
|
|
|
|
accounts = *overrides
|
|
|
|
|
}
|
2020-04-22 11:25:36 +03:00
|
|
|
|
result, err := DoCall(ctx, s.b, args, blockNrOrHash, accounts, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-06-08 11:09:49 +03:00
|
|
|
|
// If the result contains a revert reason, try to unpack and return it.
|
|
|
|
|
if len(result.Revert()) > 0 {
|
|
|
|
|
return nil, newRevertError(result)
|
2020-04-22 11:25:36 +03:00
|
|
|
|
}
|
2020-06-08 11:09:49 +03:00
|
|
|
|
return result.Return(), result.Err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap *big.Int) (hexutil.Uint64, error) {
|
2017-11-13 14:47:27 +03:00
|
|
|
|
// Binary search the gas requirement, as it may be higher than the amount used
|
2017-08-24 06:18:21 +03:00
|
|
|
|
var (
|
2017-11-14 19:26:31 +03:00
|
|
|
|
lo uint64 = params.TxGas - 1
|
|
|
|
|
hi uint64
|
|
|
|
|
cap uint64
|
2017-08-24 06:18:21 +03:00
|
|
|
|
)
|
2020-05-11 11:08:20 +03:00
|
|
|
|
// Use zero address if sender unspecified.
|
|
|
|
|
if args.From == nil {
|
|
|
|
|
args.From = new(common.Address)
|
|
|
|
|
}
|
|
|
|
|
// Determine the highest gas limit can be used during the estimation.
|
2019-01-21 17:38:13 +03:00
|
|
|
|
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
|
|
|
|
|
hi = uint64(*args.Gas)
|
2017-01-21 01:39:16 +03:00
|
|
|
|
} else {
|
2019-01-21 17:38:13 +03:00
|
|
|
|
// Retrieve the block to act as the gas ceiling
|
2019-09-26 11:47:31 +03:00
|
|
|
|
block, err := b.BlockByNumberOrHash(ctx, blockNrOrHash)
|
2017-01-21 01:39:16 +03:00
|
|
|
|
if err != nil {
|
2017-11-13 14:47:27 +03:00
|
|
|
|
return 0, err
|
2017-01-21 01:39:16 +03:00
|
|
|
|
}
|
2017-11-13 14:47:27 +03:00
|
|
|
|
hi = block.GasLimit()
|
2017-01-21 01:39:16 +03:00
|
|
|
|
}
|
2020-05-11 11:08:20 +03:00
|
|
|
|
// Recap the highest gas limit with account's available balance.
|
|
|
|
|
if args.GasPrice != nil && args.GasPrice.ToInt().Uint64() != 0 {
|
|
|
|
|
state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
balance := state.GetBalance(*args.From) // from can't be nil
|
|
|
|
|
available := new(big.Int).Set(balance)
|
|
|
|
|
if args.Value != nil {
|
|
|
|
|
if args.Value.ToInt().Cmp(available) >= 0 {
|
|
|
|
|
return 0, errors.New("insufficient funds for transfer")
|
|
|
|
|
}
|
|
|
|
|
available.Sub(available, args.Value.ToInt())
|
|
|
|
|
}
|
|
|
|
|
allowance := new(big.Int).Div(available, args.GasPrice.ToInt())
|
|
|
|
|
if hi > allowance.Uint64() {
|
|
|
|
|
transfer := args.Value
|
|
|
|
|
if transfer == nil {
|
|
|
|
|
transfer = new(hexutil.Big)
|
|
|
|
|
}
|
|
|
|
|
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
|
|
|
|
|
"sent", transfer.ToInt(), "gasprice", args.GasPrice.ToInt(), "fundable", allowance)
|
|
|
|
|
hi = allowance.Uint64()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Recap the highest gas allowance with specified gascap.
|
2019-04-08 14:49:52 +03:00
|
|
|
|
if gasCap != nil && hi > gasCap.Uint64() {
|
|
|
|
|
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
|
|
|
|
hi = gasCap.Uint64()
|
|
|
|
|
}
|
2017-11-14 19:26:31 +03:00
|
|
|
|
cap = hi
|
2017-01-21 01:39:16 +03:00
|
|
|
|
|
2017-11-14 19:26:31 +03:00
|
|
|
|
// Create a helper to check if a gas allowance results in an executable transaction
|
2020-04-22 11:25:36 +03:00
|
|
|
|
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
2019-01-21 17:38:13 +03:00
|
|
|
|
args.Gas = (*hexutil.Uint64)(&gas)
|
2017-11-13 14:47:27 +03:00
|
|
|
|
|
2020-04-22 11:25:36 +03:00
|
|
|
|
result, err := DoCall(ctx, b, args, blockNrOrHash, nil, vm.Config{}, 0, gasCap)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if err == core.ErrIntrinsicGas {
|
|
|
|
|
return true, nil, nil // Special case, raise gas limit
|
|
|
|
|
}
|
|
|
|
|
return true, nil, err // Bail out
|
2017-11-14 19:26:31 +03:00
|
|
|
|
}
|
2020-04-22 11:25:36 +03:00
|
|
|
|
return result.Failed(), result, nil
|
2017-11-14 19:26:31 +03:00
|
|
|
|
}
|
|
|
|
|
// Execute the binary search and hone in on an executable gas limit
|
|
|
|
|
for lo+1 < hi {
|
|
|
|
|
mid := (hi + lo) / 2
|
2020-04-22 11:25:36 +03:00
|
|
|
|
failed, _, err := executable(mid)
|
|
|
|
|
|
|
|
|
|
// If the error is not nil(consensus error), it means the provided message
|
|
|
|
|
// call or transaction will never be accepted no matter how much gas it is
|
2020-06-10 23:25:32 +03:00
|
|
|
|
// assigned. Return the error directly, don't struggle any more.
|
2020-04-22 11:25:36 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
if failed {
|
2017-01-21 01:39:16 +03:00
|
|
|
|
lo = mid
|
2017-11-14 19:26:31 +03:00
|
|
|
|
} else {
|
|
|
|
|
hi = mid
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Reject the transaction as invalid if it still fails at the highest allowance
|
|
|
|
|
if hi == cap {
|
2020-04-22 11:25:36 +03:00
|
|
|
|
failed, result, err := executable(hi)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return 0, err
|
|
|
|
|
}
|
|
|
|
|
if failed {
|
|
|
|
|
if result != nil && result.Err != vm.ErrOutOfGas {
|
|
|
|
|
if len(result.Revert()) > 0 {
|
2020-06-08 11:09:49 +03:00
|
|
|
|
return 0, newRevertError(result)
|
2020-04-22 11:25:36 +03:00
|
|
|
|
}
|
2020-06-08 11:09:49 +03:00
|
|
|
|
return 0, result.Err
|
2020-04-22 11:25:36 +03:00
|
|
|
|
}
|
|
|
|
|
// Otherwise, the specified gas cap is too low
|
2020-06-08 11:09:49 +03:00
|
|
|
|
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
|
2017-01-21 01:39:16 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-13 14:47:27 +03:00
|
|
|
|
return hexutil.Uint64(hi), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 17:38:13 +03:00
|
|
|
|
// EstimateGas returns an estimate of the amount of gas needed to execute the
|
|
|
|
|
// given transaction against the current pending block.
|
|
|
|
|
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) {
|
2019-09-26 11:47:31 +03:00
|
|
|
|
blockNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
|
|
|
|
return DoEstimateGas(ctx, s.b, args, blockNrOrHash, s.b.RPCGasCap())
|
2019-01-21 17:38:13 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// ExecutionResult groups all structured logs emitted by the EVM
|
2017-08-24 06:18:21 +03:00
|
|
|
|
// while replaying a transaction in debug mode as well as transaction
|
|
|
|
|
// execution status, the amount of gas used and the return value
|
2015-12-16 05:26:23 +02:00
|
|
|
|
type ExecutionResult struct {
|
2017-11-13 14:47:27 +03:00
|
|
|
|
Gas uint64 `json:"gas"`
|
2017-08-24 06:18:21 +03:00
|
|
|
|
Failed bool `json:"failed"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
ReturnValue string `json:"returnValue"`
|
|
|
|
|
StructLogs []StructLogRes `json:"structLogs"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
|
|
|
|
// transaction in debug mode
|
|
|
|
|
type StructLogRes struct {
|
2017-11-16 19:53:18 +03:00
|
|
|
|
Pc uint64 `json:"pc"`
|
|
|
|
|
Op string `json:"op"`
|
|
|
|
|
Gas uint64 `json:"gas"`
|
|
|
|
|
GasCost uint64 `json:"gasCost"`
|
|
|
|
|
Depth int `json:"depth"`
|
|
|
|
|
Error error `json:"error,omitempty"`
|
|
|
|
|
Stack *[]string `json:"stack,omitempty"`
|
|
|
|
|
Memory *[]string `json:"memory,omitempty"`
|
|
|
|
|
Storage *map[string]string `json:"storage,omitempty"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 17:38:13 +03:00
|
|
|
|
// FormatLogs formats EVM returned structured logs for json output
|
2017-11-16 19:53:18 +03:00
|
|
|
|
func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
|
|
|
|
formatted := make([]StructLogRes, len(logs))
|
|
|
|
|
for index, trace := range logs {
|
|
|
|
|
formatted[index] = StructLogRes{
|
2015-12-16 05:26:23 +02:00
|
|
|
|
Pc: trace.Pc,
|
|
|
|
|
Op: trace.Op.String(),
|
|
|
|
|
Gas: trace.Gas,
|
|
|
|
|
GasCost: trace.GasCost,
|
|
|
|
|
Depth: trace.Depth,
|
|
|
|
|
Error: trace.Err,
|
|
|
|
|
}
|
2017-11-16 19:53:18 +03:00
|
|
|
|
if trace.Stack != nil {
|
|
|
|
|
stack := make([]string, len(trace.Stack))
|
|
|
|
|
for i, stackValue := range trace.Stack {
|
|
|
|
|
stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32))
|
|
|
|
|
}
|
|
|
|
|
formatted[index].Stack = &stack
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-11-16 19:53:18 +03:00
|
|
|
|
if trace.Memory != nil {
|
|
|
|
|
memory := make([]string, 0, (len(trace.Memory)+31)/32)
|
|
|
|
|
for i := 0; i+32 <= len(trace.Memory); i += 32 {
|
|
|
|
|
memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32]))
|
|
|
|
|
}
|
|
|
|
|
formatted[index].Memory = &memory
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-11-16 19:53:18 +03:00
|
|
|
|
if trace.Storage != nil {
|
|
|
|
|
storage := make(map[string]string)
|
|
|
|
|
for i, storageValue := range trace.Storage {
|
|
|
|
|
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
|
|
|
|
|
}
|
|
|
|
|
formatted[index].Storage = &storage
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-16 19:53:18 +03:00
|
|
|
|
return formatted
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:52:24 +03:00
|
|
|
|
// RPCMarshalHeader converts the given header to the RPC output .
|
|
|
|
|
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
|
|
|
|
return map[string]interface{}{
|
2016-12-17 17:39:55 +03:00
|
|
|
|
"number": (*hexutil.Big)(head.Number),
|
2019-07-23 16:52:24 +03:00
|
|
|
|
"hash": head.Hash(),
|
2016-08-04 02:40:50 +03:00
|
|
|
|
"parentHash": head.ParentHash,
|
|
|
|
|
"nonce": head.Nonce,
|
|
|
|
|
"mixHash": head.MixDigest,
|
|
|
|
|
"sha3Uncles": head.UncleHash,
|
|
|
|
|
"logsBloom": head.Bloom,
|
|
|
|
|
"stateRoot": head.Root,
|
|
|
|
|
"miner": head.Coinbase,
|
2016-12-17 17:39:55 +03:00
|
|
|
|
"difficulty": (*hexutil.Big)(head.Difficulty),
|
2016-12-12 14:25:59 +03:00
|
|
|
|
"extraData": hexutil.Bytes(head.Extra),
|
2019-07-23 16:52:24 +03:00
|
|
|
|
"size": hexutil.Uint64(head.Size()),
|
2017-11-13 14:47:27 +03:00
|
|
|
|
"gasLimit": hexutil.Uint64(head.GasLimit),
|
|
|
|
|
"gasUsed": hexutil.Uint64(head.GasUsed),
|
2019-04-02 23:28:48 +03:00
|
|
|
|
"timestamp": hexutil.Uint64(head.Time),
|
2016-08-04 02:40:50 +03:00
|
|
|
|
"transactionsRoot": head.TxHash,
|
2016-10-07 01:38:00 +03:00
|
|
|
|
"receiptsRoot": head.ReceiptHash,
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2019-07-23 16:52:24 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
|
|
|
|
|
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
|
|
|
|
|
// transaction hashes.
|
|
|
|
|
func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
|
|
|
|
fields := RPCMarshalHeader(block.Header())
|
2019-07-25 09:25:16 +03:00
|
|
|
|
fields["size"] = hexutil.Uint64(block.Size())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
|
|
|
|
|
if inclTx {
|
|
|
|
|
formatTx := func(tx *types.Transaction) (interface{}, error) {
|
|
|
|
|
return tx.Hash(), nil
|
|
|
|
|
}
|
|
|
|
|
if fullTx {
|
|
|
|
|
formatTx = func(tx *types.Transaction) (interface{}, error) {
|
2019-07-23 16:52:24 +03:00
|
|
|
|
return newRPCTransactionFromBlockHash(block, tx.Hash()), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-07-23 16:52:24 +03:00
|
|
|
|
txs := block.Transactions()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
transactions := make([]interface{}, len(txs))
|
|
|
|
|
var err error
|
2018-06-11 11:03:40 +03:00
|
|
|
|
for i, tx := range txs {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if transactions[i], err = formatTx(tx); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fields["transactions"] = transactions
|
|
|
|
|
}
|
2019-07-23 16:52:24 +03:00
|
|
|
|
uncles := block.Uncles()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
uncleHashes := make([]common.Hash, len(uncles))
|
|
|
|
|
for i, uncle := range uncles {
|
|
|
|
|
uncleHashes[i] = uncle.Hash()
|
|
|
|
|
}
|
|
|
|
|
fields["uncles"] = uncleHashes
|
|
|
|
|
|
|
|
|
|
return fields, nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-23 16:52:24 +03:00
|
|
|
|
// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires
|
|
|
|
|
// a `PublicBlockchainAPI`.
|
|
|
|
|
func (s *PublicBlockChainAPI) rpcMarshalHeader(header *types.Header) map[string]interface{} {
|
|
|
|
|
fields := RPCMarshalHeader(header)
|
|
|
|
|
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(header.Hash()))
|
|
|
|
|
return fields
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires
|
2018-06-11 11:03:40 +03:00
|
|
|
|
// a `PublicBlockchainAPI`.
|
2019-07-23 16:52:24 +03:00
|
|
|
|
func (s *PublicBlockChainAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
2018-06-11 11:03:40 +03:00
|
|
|
|
fields, err := RPCMarshalBlock(b, inclTx, fullTx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2020-01-06 14:25:38 +03:00
|
|
|
|
if inclTx {
|
|
|
|
|
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash()))
|
|
|
|
|
}
|
2018-06-11 11:03:40 +03:00
|
|
|
|
return fields, err
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
|
|
|
|
type RPCTransaction struct {
|
2019-07-30 16:39:48 +03:00
|
|
|
|
BlockHash *common.Hash `json:"blockHash"`
|
2016-12-17 17:39:55 +03:00
|
|
|
|
BlockNumber *hexutil.Big `json:"blockNumber"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
From common.Address `json:"from"`
|
2017-11-13 14:47:27 +03:00
|
|
|
|
Gas hexutil.Uint64 `json:"gas"`
|
2016-12-17 17:39:55 +03:00
|
|
|
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
Hash common.Hash `json:"hash"`
|
2016-12-12 14:25:59 +03:00
|
|
|
|
Input hexutil.Bytes `json:"input"`
|
2016-12-17 17:39:55 +03:00
|
|
|
|
Nonce hexutil.Uint64 `json:"nonce"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
To *common.Address `json:"to"`
|
2019-07-30 16:39:48 +03:00
|
|
|
|
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
2016-12-17 17:39:55 +03:00
|
|
|
|
Value *hexutil.Big `json:"value"`
|
|
|
|
|
V *hexutil.Big `json:"v"`
|
|
|
|
|
R *hexutil.Big `json:"r"`
|
|
|
|
|
S *hexutil.Big `json:"s"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// newRPCTransaction returns a transaction that will serialize to the RPC
|
|
|
|
|
// representation, with the given location metadata set (if available).
|
|
|
|
|
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
|
2016-11-02 15:44:13 +03:00
|
|
|
|
var signer types.Signer = types.FrontierSigner{}
|
|
|
|
|
if tx.Protected() {
|
|
|
|
|
signer = types.NewEIP155Signer(tx.ChainId())
|
|
|
|
|
}
|
|
|
|
|
from, _ := types.Sender(signer, tx)
|
2016-12-17 17:39:55 +03:00
|
|
|
|
v, r, s := tx.RawSignatureValues()
|
2017-07-14 19:39:53 +03:00
|
|
|
|
|
|
|
|
|
result := &RPCTransaction{
|
2015-12-16 05:26:23 +02:00
|
|
|
|
From: from,
|
2017-11-13 14:47:27 +03:00
|
|
|
|
Gas: hexutil.Uint64(tx.Gas()),
|
2016-12-17 17:39:55 +03:00
|
|
|
|
GasPrice: (*hexutil.Big)(tx.GasPrice()),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
Hash: tx.Hash(),
|
2016-12-12 14:25:59 +03:00
|
|
|
|
Input: hexutil.Bytes(tx.Data()),
|
2016-12-17 17:39:55 +03:00
|
|
|
|
Nonce: hexutil.Uint64(tx.Nonce()),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
To: tx.To(),
|
2016-12-17 17:39:55 +03:00
|
|
|
|
Value: (*hexutil.Big)(tx.Value()),
|
|
|
|
|
V: (*hexutil.Big)(v),
|
|
|
|
|
R: (*hexutil.Big)(r),
|
|
|
|
|
S: (*hexutil.Big)(s),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
if blockHash != (common.Hash{}) {
|
2019-07-30 16:39:48 +03:00
|
|
|
|
result.BlockHash = &blockHash
|
2017-07-14 19:39:53 +03:00
|
|
|
|
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
2019-07-30 16:39:48 +03:00
|
|
|
|
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
2017-07-14 19:39:53 +03:00
|
|
|
|
}
|
|
|
|
|
return result
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
|
|
|
|
|
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
|
|
|
|
return newRPCTransaction(tx, common.Hash{}, 0, 0)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
|
|
|
|
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction {
|
|
|
|
|
txs := b.Transactions()
|
|
|
|
|
if index >= uint64(len(txs)) {
|
|
|
|
|
return nil
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index)
|
|
|
|
|
}
|
2016-10-07 01:38:00 +03:00
|
|
|
|
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
|
|
|
|
|
func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes {
|
|
|
|
|
txs := b.Transactions()
|
|
|
|
|
if index >= uint64(len(txs)) {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
blob, _ := rlp.EncodeToBytes(txs[index])
|
|
|
|
|
return blob
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
|
|
|
|
|
func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
for idx, tx := range b.Transactions() {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
if tx.Hash() == hash {
|
|
|
|
|
return newRPCTransactionFromBlockIndex(b, uint64(idx))
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PublicTransactionPoolAPI exposes methods for the RPC interface
|
|
|
|
|
type PublicTransactionPoolAPI struct {
|
2017-05-25 18:08:13 +03:00
|
|
|
|
b Backend
|
|
|
|
|
nonceLock *AddrLocker
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
2017-05-25 18:08:13 +03:00
|
|
|
|
func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
|
|
|
|
|
return &PublicTransactionPoolAPI{b, nonceLock}
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
n := hexutil.Uint(len(block.Transactions()))
|
|
|
|
|
return &n
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
n := hexutil.Uint(len(block.Transactions()))
|
|
|
|
|
return &n
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
2017-07-14 19:39:53 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
|
2017-07-14 19:39:53 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-07 01:38:00 +03:00
|
|
|
|
// GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
|
2017-07-14 19:39:53 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes {
|
2016-10-07 01:38:00 +03:00
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return nil
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index.
|
2017-07-14 19:39:53 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes {
|
2019-07-25 09:29:53 +03:00
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
return nil
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
2019-09-26 11:47:31 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
|
2019-01-07 11:47:11 +03:00
|
|
|
|
// Ask transaction pool for the nonce which includes pending transactions
|
2019-09-26 11:47:31 +03:00
|
|
|
|
if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber {
|
2019-01-07 11:47:11 +03:00
|
|
|
|
nonce, err := s.b.GetPoolNonce(ctx, address)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return (*hexutil.Uint64)(&nonce), nil
|
|
|
|
|
}
|
|
|
|
|
// Resolve block number and use its state to ask for the nonce
|
2019-09-26 11:47:31 +03:00
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if state == nil || err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2017-06-27 16:57:06 +03:00
|
|
|
|
nonce := state.GetNonce(address)
|
|
|
|
|
return (*hexutil.Uint64)(&nonce), state.Error()
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetTransactionByHash returns the transaction for the given hash
|
2019-05-13 14:41:10 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// Try to return an already finalized transaction
|
2019-05-13 14:41:10 +03:00
|
|
|
|
tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if tx != nil {
|
|
|
|
|
return newRPCTransaction(tx, blockHash, blockNumber, index), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// No finalized transaction, try to retrieve it from the pool
|
|
|
|
|
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
2019-05-13 14:41:10 +03:00
|
|
|
|
return newRPCPendingTransaction(tx), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2019-05-13 14:41:10 +03:00
|
|
|
|
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// Transaction unknown, return as such
|
2019-05-13 14:41:10 +03:00
|
|
|
|
return nil, nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-07 01:38:00 +03:00
|
|
|
|
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
|
2017-03-03 12:41:52 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// Retrieve a finalized transaction, or a pooled otherwise
|
2019-05-13 14:41:10 +03:00
|
|
|
|
tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if tx == nil {
|
2017-07-14 19:39:53 +03:00
|
|
|
|
if tx = s.b.GetPoolTransaction(hash); tx == nil {
|
|
|
|
|
// Transaction not found anywhere, abort
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
2016-10-07 01:38:00 +03:00
|
|
|
|
}
|
2017-07-14 19:39:53 +03:00
|
|
|
|
// Serialize to RLP and return
|
2016-10-07 01:38:00 +03:00
|
|
|
|
return rlp.EncodeToBytes(tx)
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
2018-02-22 13:48:14 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
2018-05-07 14:35:06 +03:00
|
|
|
|
tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
|
2017-07-14 19:39:53 +03:00
|
|
|
|
if tx == nil {
|
2018-02-28 13:40:15 +03:00
|
|
|
|
return nil, nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2018-02-22 13:48:14 +03:00
|
|
|
|
receipts, err := s.b.GetReceipts(ctx, blockHash)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if len(receipts) <= int(index) {
|
2018-02-28 13:40:15 +03:00
|
|
|
|
return nil, nil
|
2017-12-14 15:24:34 +03:00
|
|
|
|
}
|
2018-02-22 13:48:14 +03:00
|
|
|
|
receipt := receipts[index]
|
2015-12-16 05:26:23 +02:00
|
|
|
|
|
2016-11-02 15:44:13 +03:00
|
|
|
|
var signer types.Signer = types.FrontierSigner{}
|
|
|
|
|
if tx.Protected() {
|
|
|
|
|
signer = types.NewEIP155Signer(tx.ChainId())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2016-11-02 15:44:13 +03:00
|
|
|
|
from, _ := types.Sender(signer, tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
2017-07-14 19:39:53 +03:00
|
|
|
|
"blockHash": blockHash,
|
|
|
|
|
"blockNumber": hexutil.Uint64(blockNumber),
|
2017-03-03 12:41:52 +03:00
|
|
|
|
"transactionHash": hash,
|
2016-12-17 17:39:55 +03:00
|
|
|
|
"transactionIndex": hexutil.Uint64(index),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"from": from,
|
|
|
|
|
"to": tx.To(),
|
2017-11-13 14:47:27 +03:00
|
|
|
|
"gasUsed": hexutil.Uint64(receipt.GasUsed),
|
|
|
|
|
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
|
2015-12-16 05:26:23 +02:00
|
|
|
|
"contractAddress": nil,
|
|
|
|
|
"logs": receipt.Logs,
|
2016-08-04 02:40:50 +03:00
|
|
|
|
"logsBloom": receipt.Bloom,
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-08-26 10:30:56 +03:00
|
|
|
|
|
|
|
|
|
// Assign receipt status or post state.
|
|
|
|
|
if len(receipt.PostState) > 0 {
|
|
|
|
|
fields["root"] = hexutil.Bytes(receipt.PostState)
|
|
|
|
|
} else {
|
2017-10-02 11:42:08 +03:00
|
|
|
|
fields["status"] = hexutil.Uint(receipt.Status)
|
2017-08-26 10:30:56 +03:00
|
|
|
|
}
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if receipt.Logs == nil {
|
2017-01-05 16:03:50 +03:00
|
|
|
|
fields["logs"] = [][]*types.Log{}
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
|
2016-08-04 02:40:50 +03:00
|
|
|
|
if receipt.ContractAddress != (common.Address{}) {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
fields["contractAddress"] = receipt.ContractAddress
|
|
|
|
|
}
|
|
|
|
|
return fields, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sign is a helper function that signs a transaction with the private key of the given address.
|
|
|
|
|
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
|
account := accounts.Account{Address: addr}
|
|
|
|
|
|
|
|
|
|
wallet, err := s.b.AccountManager().Find(account)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// Request the wallet to sign the transaction
|
2019-02-07 13:59:17 +03:00
|
|
|
|
return wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
|
|
|
|
|
type SendTxArgs struct {
|
|
|
|
|
From common.Address `json:"from"`
|
|
|
|
|
To *common.Address `json:"to"`
|
2017-11-13 14:47:27 +03:00
|
|
|
|
Gas *hexutil.Uint64 `json:"gas"`
|
2016-12-17 17:39:55 +03:00
|
|
|
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
|
|
|
|
Value *hexutil.Big `json:"value"`
|
|
|
|
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
2017-12-18 14:50:21 +03:00
|
|
|
|
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
|
|
|
|
|
// newer name and should be preferred by clients.
|
|
|
|
|
Data *hexutil.Bytes `json:"data"`
|
|
|
|
|
Input *hexutil.Bytes `json:"input"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-12 20:55:39 +03:00
|
|
|
|
// setDefaults is a helper function that fills in default values for unspecified tx fields.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if args.GasPrice == nil {
|
|
|
|
|
price, err := b.SuggestPrice(ctx)
|
|
|
|
|
if err != nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
return err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
args.GasPrice = (*hexutil.Big)(price)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
if args.Value == nil {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
args.Value = new(hexutil.Big)
|
|
|
|
|
}
|
|
|
|
|
if args.Nonce == nil {
|
|
|
|
|
nonce, err := b.GetPoolNonce(ctx, args.From)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
args.Nonce = (*hexutil.Uint64)(&nonce)
|
|
|
|
|
}
|
2017-12-18 14:50:21 +03:00
|
|
|
|
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
|
2019-11-29 13:40:02 +03:00
|
|
|
|
return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`)
|
2017-12-18 14:50:21 +03:00
|
|
|
|
}
|
2018-02-21 17:10:18 +03:00
|
|
|
|
if args.To == nil {
|
|
|
|
|
// Contract creation
|
|
|
|
|
var input []byte
|
|
|
|
|
if args.Data != nil {
|
|
|
|
|
input = *args.Data
|
|
|
|
|
} else if args.Input != nil {
|
|
|
|
|
input = *args.Input
|
|
|
|
|
}
|
|
|
|
|
if len(input) == 0 {
|
|
|
|
|
return errors.New(`contract creation without any data provided`)
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-30 11:02:34 +03:00
|
|
|
|
// Estimate the gas usage if necessary.
|
|
|
|
|
if args.Gas == nil {
|
|
|
|
|
// For backwards-compatibility reason, we try both input and data
|
|
|
|
|
// but input is preferred.
|
|
|
|
|
input := args.Input
|
|
|
|
|
if input == nil {
|
|
|
|
|
input = args.Data
|
|
|
|
|
}
|
|
|
|
|
callArgs := CallArgs{
|
|
|
|
|
From: &args.From, // From shouldn't be nil
|
|
|
|
|
To: args.To,
|
|
|
|
|
GasPrice: args.GasPrice,
|
|
|
|
|
Value: args.Value,
|
|
|
|
|
Data: input,
|
|
|
|
|
}
|
2019-09-26 11:47:31 +03:00
|
|
|
|
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
|
|
|
|
estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap())
|
2019-04-30 11:02:34 +03:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
args.Gas = &estimated
|
|
|
|
|
log.Trace("Estimate gas usage automatically", "gas", args.Gas)
|
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (args *SendTxArgs) toTransaction() *types.Transaction {
|
2017-12-18 14:50:21 +03:00
|
|
|
|
var input []byte
|
2019-04-30 11:02:34 +03:00
|
|
|
|
if args.Input != nil {
|
2017-12-18 14:50:21 +03:00
|
|
|
|
input = *args.Input
|
2019-04-30 11:02:34 +03:00
|
|
|
|
} else if args.Data != nil {
|
|
|
|
|
input = *args.Data
|
2017-12-18 14:50:21 +03:00
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
if args.To == nil {
|
2017-11-13 14:47:27 +03:00
|
|
|
|
return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-11-13 14:47:27 +03:00
|
|
|
|
return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 17:38:13 +03:00
|
|
|
|
// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
|
|
|
|
|
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
|
2017-01-24 12:49:20 +03:00
|
|
|
|
if err := b.SendTx(ctx, tx); err != nil {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
2017-01-24 12:49:20 +03:00
|
|
|
|
if tx.To() == nil {
|
|
|
|
|
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
|
2017-09-25 11:38:42 +03:00
|
|
|
|
from, err := types.Sender(signer, tx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
2017-01-24 12:49:20 +03:00
|
|
|
|
addr := crypto.CreateAddress(from, tx.Nonce())
|
2017-03-03 12:41:52 +03:00
|
|
|
|
log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
} else {
|
2017-03-03 12:41:52 +03:00
|
|
|
|
log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2017-01-24 12:49:20 +03:00
|
|
|
|
return tx.Hash(), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SendTransaction creates a transaction for the given argument, sign it and submit it to the
|
|
|
|
|
// transaction pool.
|
|
|
|
|
func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) {
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
|
account := accounts.Account{Address: args.From}
|
|
|
|
|
|
|
|
|
|
wallet, err := s.b.AccountManager().Find(account)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
2017-05-25 18:08:13 +03:00
|
|
|
|
|
|
|
|
|
if args.Nonce == nil {
|
|
|
|
|
// Hold the addresse's mutex around signing to prevent concurrent assignment of
|
|
|
|
|
// the same nonce to multiple accounts.
|
|
|
|
|
s.nonceLock.LockAddr(args.From)
|
|
|
|
|
defer s.nonceLock.UnlockAddr(args.From)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set some sanity defaults and terminate on failure
|
|
|
|
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Assemble the transaction and sign with the wallet
|
2016-12-17 17:39:55 +03:00
|
|
|
|
tx := args.toTransaction()
|
2017-01-24 12:49:20 +03:00
|
|
|
|
|
2019-02-07 13:59:17 +03:00
|
|
|
|
signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
2019-01-21 17:38:13 +03:00
|
|
|
|
return SubmitTransaction(ctx, s.b, signed)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-08-08 11:22:10 +03:00
|
|
|
|
// FillTransaction fills the defaults (nonce, gas, gasPrice) on a given unsigned transaction,
|
|
|
|
|
// and returns it to the caller for further processing (signing + broadcast)
|
|
|
|
|
func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) {
|
|
|
|
|
// Set some sanity defaults and terminate on failure
|
|
|
|
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// Assemble the transaction and obtain rlp
|
|
|
|
|
tx := args.toTransaction()
|
|
|
|
|
data, err := rlp.EncodeToBytes(tx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return &SignTransactionResult{data, tx}, nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// SendRawTransaction will add the signed transaction to the transaction pool.
|
|
|
|
|
// The sender is responsible for signing the transaction and using the correct nonce.
|
2017-09-25 11:38:42 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
tx := new(types.Transaction)
|
2016-12-20 16:31:10 +03:00
|
|
|
|
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
|
2017-09-25 11:38:42 +03:00
|
|
|
|
return common.Hash{}, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2019-01-21 17:38:13 +03:00
|
|
|
|
return SubmitTransaction(ctx, s.b, tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-28 22:25:49 +03:00
|
|
|
|
// Sign calculates an ECDSA signature for:
|
|
|
|
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
|
|
|
|
|
//
|
2017-01-05 13:35:23 +03:00
|
|
|
|
// Note, the produced signature conforms to the secp256k1 curve R, S and V values,
|
|
|
|
|
// where the V value will be 27 or 28 for legacy reasons.
|
|
|
|
|
//
|
2016-10-28 22:25:49 +03:00
|
|
|
|
// The account associated with addr must be unlocked.
|
|
|
|
|
//
|
|
|
|
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
|
2016-12-16 13:19:03 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
|
2017-02-07 13:47:34 +03:00
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
|
account := accounts.Account{Address: addr}
|
|
|
|
|
|
|
|
|
|
wallet, err := s.b.AccountManager().Find(account)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
// Sign the requested hash with the wallet
|
accounts, eth, clique, signer: support for external signer API (#18079)
* accounts, eth, clique: implement external backend + move sighash calc to backend
* signer: implement account_Version on external API
* accounts/external: enable ipc, add copyright
* accounts, internal, signer: formatting
* node: go fmt
* flags: disallow --dev in combo with --externalsigner
* accounts: remove clique-specific signing method, replace with more generic
* accounts, consensus: formatting + fix error in tests
* signer/core: remove (test-) import cycle
* clique: remove unused import
* accounts: remove CliqueHash and avoid dependency on package crypto
* consensus/clique: unduplicate header encoding
2019-02-05 13:23:57 +03:00
|
|
|
|
signature, err := wallet.SignText(account, data)
|
2017-01-05 13:35:23 +03:00
|
|
|
|
if err == nil {
|
2016-12-08 15:42:31 +03:00
|
|
|
|
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
2017-01-05 13:35:23 +03:00
|
|
|
|
}
|
|
|
|
|
return signature, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SignTransactionResult represents a RLP encoded signed transaction.
|
|
|
|
|
type SignTransactionResult struct {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
Raw hexutil.Bytes `json:"raw"`
|
|
|
|
|
Tx *types.Transaction `json:"tx"`
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SignTransaction will sign the given transaction with the from account.
|
|
|
|
|
// The node needs to have the private key of the account corresponding with
|
|
|
|
|
// the given from address and it needs to be unlocked.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) {
|
2018-01-26 20:32:43 +03:00
|
|
|
|
if args.Gas == nil {
|
|
|
|
|
return nil, fmt.Errorf("gas not specified")
|
|
|
|
|
}
|
|
|
|
|
if args.GasPrice == nil {
|
|
|
|
|
return nil, fmt.Errorf("gasPrice not specified")
|
|
|
|
|
}
|
2017-05-19 16:03:56 +03:00
|
|
|
|
if args.Nonce == nil {
|
2018-01-26 20:32:43 +03:00
|
|
|
|
return nil, fmt.Errorf("nonce not specified")
|
2017-05-19 16:03:56 +03:00
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
|
|
|
|
return nil, err
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
tx, err := s.sign(args.From, args.toTransaction())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
data, err := rlp.EncodeToBytes(tx)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
return &SignTransactionResult{data, tx}, nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-12 13:40:16 +03:00
|
|
|
|
// PendingTransactions returns the transactions that are in the transaction pool
|
|
|
|
|
// and have a from address that is one of the accounts this node manages.
|
2016-12-11 01:54:58 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
|
|
|
|
|
pending, err := s.b.GetPoolTransactions()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-06-12 13:40:16 +03:00
|
|
|
|
accounts := make(map[common.Address]struct{})
|
|
|
|
|
for _, wallet := range s.b.AccountManager().Wallets() {
|
|
|
|
|
for _, account := range wallet.Accounts() {
|
|
|
|
|
accounts[account.Address] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-12-16 05:26:23 +02:00
|
|
|
|
transactions := make([]*RPCTransaction, 0, len(pending))
|
|
|
|
|
for _, tx := range pending {
|
2016-11-02 15:44:13 +03:00
|
|
|
|
var signer types.Signer = types.HomesteadSigner{}
|
|
|
|
|
if tx.Protected() {
|
|
|
|
|
signer = types.NewEIP155Signer(tx.ChainId())
|
|
|
|
|
}
|
|
|
|
|
from, _ := types.Sender(signer, tx)
|
2018-06-12 13:40:16 +03:00
|
|
|
|
if _, exists := accounts[from]; exists {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
transactions = append(transactions, newRPCPendingTransaction(tx))
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-11 01:54:58 +03:00
|
|
|
|
return transactions, nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-17 17:39:55 +03:00
|
|
|
|
// Resend accepts an existing transaction and a new gas price and limit. It will remove
|
|
|
|
|
// the given transaction from the pool and reinsert it with the new gas price and limit.
|
2017-11-13 14:47:27 +03:00
|
|
|
|
func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
if sendArgs.Nonce == nil {
|
|
|
|
|
return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec")
|
|
|
|
|
}
|
|
|
|
|
if err := sendArgs.setDefaults(ctx, s.b); err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
|
|
|
|
matchTx := sendArgs.toTransaction()
|
2016-12-11 01:54:58 +03:00
|
|
|
|
pending, err := s.b.GetPoolTransactions()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
for _, p := range pending {
|
2016-11-02 15:44:13 +03:00
|
|
|
|
var signer types.Signer = types.HomesteadSigner{}
|
|
|
|
|
if p.Protected() {
|
|
|
|
|
signer = types.NewEIP155Signer(p.ChainId())
|
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
wantSigHash := signer.Hash(matchTx)
|
2016-11-02 15:44:13 +03:00
|
|
|
|
|
2016-12-17 17:39:55 +03:00
|
|
|
|
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.From && signer.Hash(p) == wantSigHash {
|
|
|
|
|
// Match. Re-sign and send the transaction.
|
2018-03-08 13:29:42 +03:00
|
|
|
|
if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
sendArgs.GasPrice = gasPrice
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2018-03-08 13:29:42 +03:00
|
|
|
|
if gasLimit != nil && *gasLimit != 0 {
|
2016-12-17 17:39:55 +03:00
|
|
|
|
sendArgs.Gas = gasLimit
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
2016-12-17 17:39:55 +03:00
|
|
|
|
signedTx, err := s.sign(sendArgs.From, sendArgs.toTransaction())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
|
|
|
|
if err = s.b.SendTx(ctx, signedTx); err != nil {
|
|
|
|
|
return common.Hash{}, err
|
|
|
|
|
}
|
|
|
|
|
return signedTx.Hash(), nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-29 13:40:02 +03:00
|
|
|
|
return common.Hash{}, fmt.Errorf("transaction %#x not found", matchTx.Hash())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-20 12:31:31 +03:00
|
|
|
|
// PublicDebugAPI is the collection of Ethereum APIs exposed over the public
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// debugging endpoint.
|
|
|
|
|
type PublicDebugAPI struct {
|
|
|
|
|
b Backend
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPublicDebugAPI creates a new API definition for the public debug methods
|
|
|
|
|
// of the Ethereum service.
|
|
|
|
|
func NewPublicDebugAPI(b Backend) *PublicDebugAPI {
|
|
|
|
|
return &PublicDebugAPI{b: b}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetBlockRlp retrieves the RLP encoded for of a single block.
|
|
|
|
|
func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (string, error) {
|
|
|
|
|
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
|
|
|
|
if block == nil {
|
|
|
|
|
return "", fmt.Errorf("block #%d not found", number)
|
|
|
|
|
}
|
|
|
|
|
encoded, err := rlp.EncodeToBytes(block)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return fmt.Sprintf("%x", encoded), nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-12 16:00:02 +03:00
|
|
|
|
// TestSignCliqueBlock fetches the given block number, and attempts to sign it as a clique header with the
|
|
|
|
|
// given address, returning the address of the recovered signature
|
|
|
|
|
//
|
|
|
|
|
// This is a temporary method to debug the externalsigner integration,
|
|
|
|
|
// TODO: Remove this method when the integration is mature
|
|
|
|
|
func (api *PublicDebugAPI) TestSignCliqueBlock(ctx context.Context, address common.Address, number uint64) (common.Address, error) {
|
|
|
|
|
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
|
|
|
|
if block == nil {
|
|
|
|
|
return common.Address{}, fmt.Errorf("block #%d not found", number)
|
|
|
|
|
}
|
|
|
|
|
header := block.Header()
|
|
|
|
|
header.Extra = make([]byte, 32+65)
|
|
|
|
|
encoded := clique.CliqueRLP(header)
|
|
|
|
|
|
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
|
account := accounts.Account{Address: address}
|
|
|
|
|
wallet, err := api.b.AccountManager().Find(account)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Address{}, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signature, err := wallet.SignData(account, accounts.MimetypeClique, encoded)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Address{}, err
|
|
|
|
|
}
|
|
|
|
|
sealHash := clique.SealHash(header).Bytes()
|
|
|
|
|
log.Info("test signing of clique block",
|
|
|
|
|
"Sealhash", fmt.Sprintf("%x", sealHash),
|
|
|
|
|
"signature", fmt.Sprintf("%x", signature))
|
|
|
|
|
pubkey, err := crypto.Ecrecover(sealHash, signature)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return common.Address{}, err
|
|
|
|
|
}
|
|
|
|
|
var signer common.Address
|
|
|
|
|
copy(signer[:], crypto.Keccak256(pubkey[1:])[12:])
|
|
|
|
|
|
|
|
|
|
return signer, nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// PrintBlock retrieves a block and returns its pretty printed form.
|
|
|
|
|
func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) {
|
|
|
|
|
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
|
|
|
|
if block == nil {
|
|
|
|
|
return "", fmt.Errorf("block #%d not found", number)
|
|
|
|
|
}
|
2018-04-05 15:13:02 +03:00
|
|
|
|
return spew.Sdump(block), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SeedHash retrieves the seed hash of a block.
|
|
|
|
|
func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string, error) {
|
|
|
|
|
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
|
|
|
|
if block == nil {
|
|
|
|
|
return "", fmt.Errorf("block #%d not found", number)
|
|
|
|
|
}
|
2017-04-05 01:16:29 +03:00
|
|
|
|
return fmt.Sprintf("0x%x", ethash.SeedHash(number)), nil
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-20 12:31:31 +03:00
|
|
|
|
// PrivateDebugAPI is the collection of Ethereum APIs exposed over the private
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// debugging endpoint.
|
|
|
|
|
type PrivateDebugAPI struct {
|
|
|
|
|
b Backend
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPrivateDebugAPI creates a new API definition for the private debug methods
|
|
|
|
|
// of the Ethereum service.
|
|
|
|
|
func NewPrivateDebugAPI(b Backend) *PrivateDebugAPI {
|
|
|
|
|
return &PrivateDebugAPI{b: b}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-18 16:15:09 +03:00
|
|
|
|
// ChaindbProperty returns leveldb properties of the key-value database.
|
2015-12-16 05:26:23 +02:00
|
|
|
|
func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) {
|
|
|
|
|
if property == "" {
|
|
|
|
|
property = "leveldb.stats"
|
|
|
|
|
} else if !strings.HasPrefix(property, "leveldb.") {
|
|
|
|
|
property = "leveldb." + property
|
|
|
|
|
}
|
2019-07-18 16:15:09 +03:00
|
|
|
|
return api.b.ChainDb().Stat(property)
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-18 16:15:09 +03:00
|
|
|
|
// ChaindbCompact flattens the entire key-value database into a single level,
|
|
|
|
|
// removing all unused slots and merging all keys.
|
2016-10-20 15:36:48 +03:00
|
|
|
|
func (api *PrivateDebugAPI) ChaindbCompact() error {
|
|
|
|
|
for b := byte(0); b < 255; b++ {
|
2017-03-03 12:41:52 +03:00
|
|
|
|
log.Info("Compacting chain database", "range", fmt.Sprintf("0x%0.2X-0x%0.2X", b, b+1))
|
2018-09-24 15:57:49 +03:00
|
|
|
|
if err := api.b.ChainDb().Compact([]byte{b}, []byte{b + 1}); err != nil {
|
2017-03-03 12:41:52 +03:00
|
|
|
|
log.Error("Database compaction failed", "err", err)
|
2016-10-20 15:36:48 +03:00
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-16 05:26:23 +02:00
|
|
|
|
// SetHead rewinds the head of the blockchain to a previous block.
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) {
|
|
|
|
|
api.b.SetHead(uint64(number))
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PublicNetAPI offers network related RPC methods
|
|
|
|
|
type PublicNetAPI struct {
|
|
|
|
|
net *p2p.Server
|
2017-04-25 14:31:15 +03:00
|
|
|
|
networkVersion uint64
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewPublicNetAPI creates a new net API instance.
|
2017-04-25 14:31:15 +03:00
|
|
|
|
func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI {
|
2015-12-16 05:26:23 +02:00
|
|
|
|
return &PublicNetAPI{net, networkVersion}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Listening returns an indication if the node is listening for network connections.
|
|
|
|
|
func (s *PublicNetAPI) Listening() bool {
|
|
|
|
|
return true // always listening
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PeerCount returns the number of connected peers
|
2016-12-17 17:39:55 +03:00
|
|
|
|
func (s *PublicNetAPI) PeerCount() hexutil.Uint {
|
|
|
|
|
return hexutil.Uint(s.net.PeerCount())
|
2015-12-16 05:26:23 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Version returns the current ethereum protocol version.
|
|
|
|
|
func (s *PublicNetAPI) Version() string {
|
|
|
|
|
return fmt.Sprintf("%d", s.networkVersion)
|
|
|
|
|
}
|