|
|
|
// Copyright 2015 The go-ethereum Authors
|
|
|
|
// This file is part of the go-ethereum library.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package ethapi
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/davecgh/go-spew/spew"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
|
|
|
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"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
8 years ago
|
|
|
"github.com/ethereum/go-ethereum/common/math"
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
|
|
|
"github.com/ethereum/go-ethereum/core"
|
|
|
|
"github.com/ethereum/go-ethereum/core/state"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
|
|
|
"github.com/ethereum/go-ethereum/log"
|
|
|
|
"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
8 years ago
|
|
|
"github.com/ethereum/go-ethereum/params"
|
|
|
|
"github.com/ethereum/go-ethereum/rlp"
|
|
|
|
"github.com/ethereum/go-ethereum/rpc"
|
|
|
|
"github.com/tyler-smith/go-bip39"
|
|
|
|
)
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
b Backend
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPublicEthereumAPI creates a new Ethereum protocol API.
|
|
|
|
func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
|
|
|
|
return &PublicEthereumAPI{b}
|
|
|
|
}
|
|
|
|
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
// GasPrice returns a suggestion for a gas price for legacy transactions.
|
|
|
|
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
tipcap, err := s.b.SuggestGasTipCap(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if head := s.b.CurrentHeader(); head.BaseFee != nil {
|
|
|
|
tipcap.Add(tipcap, head.BaseFee)
|
|
|
|
}
|
|
|
|
return (*hexutil.Big)(tipcap), err
|
|
|
|
}
|
|
|
|
|
|
|
|
// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions.
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
func (s *PublicEthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) {
|
|
|
|
tipcap, err := s.b.SuggestGasTipCap(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return (*hexutil.Big)(tipcap), err
|
|
|
|
}
|
|
|
|
|
|
|
|
type feeHistoryResult struct {
|
|
|
|
OldestBlock *hexutil.Big `json:"oldestBlock"`
|
|
|
|
Reward [][]*hexutil.Big `json:"reward,omitempty"`
|
|
|
|
BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"`
|
|
|
|
GasUsedRatio []float64 `json:"gasUsedRatio"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *PublicEthereumAPI) FeeHistory(ctx context.Context, blockCount rpc.DecimalOrHex, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) {
|
|
|
|
oldest, reward, baseFee, gasUsed, err := s.b.FeeHistory(ctx, int(blockCount), lastBlock, rewardPercentiles)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
results := &feeHistoryResult{
|
|
|
|
OldestBlock: (*hexutil.Big)(oldest),
|
|
|
|
GasUsedRatio: gasUsed,
|
|
|
|
}
|
|
|
|
if reward != nil {
|
|
|
|
results.Reward = make([][]*hexutil.Big, len(reward))
|
|
|
|
for i, w := range reward {
|
|
|
|
results.Reward[i] = make([]*hexutil.Big, len(w))
|
|
|
|
for j, v := range w {
|
|
|
|
results.Reward[i][j] = (*hexutil.Big)(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if baseFee != nil {
|
|
|
|
results.BaseFee = make([]*hexutil.Big, len(baseFee))
|
|
|
|
for i, v := range baseFee {
|
|
|
|
results.BaseFee[i] = (*hexutil.Big)(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
progress := s.b.SyncProgress()
|
|
|
|
|
|
|
|
// Return not syncing if the synchronisation already completed
|
|
|
|
if progress.CurrentBlock >= progress.HighestBlock {
|
|
|
|
return false, nil
|
|
|
|
}
|
|
|
|
// Otherwise gather the block sync stats
|
|
|
|
return map[string]interface{}{
|
|
|
|
"startingBlock": hexutil.Uint64(progress.StartingBlock),
|
|
|
|
"currentBlock": hexutil.Uint64(progress.CurrentBlock),
|
|
|
|
"highestBlock": hexutil.Uint64(progress.HighestBlock),
|
|
|
|
"syncedAccounts": hexutil.Uint64(progress.SyncedAccounts),
|
|
|
|
"syncedAccountBytes": hexutil.Uint64(progress.SyncedAccountBytes),
|
|
|
|
"syncedBytecodes": hexutil.Uint64(progress.SyncedBytecodes),
|
|
|
|
"syncedBytecodeBytes": hexutil.Uint64(progress.SyncedBytecodeBytes),
|
|
|
|
"syncedStorage": hexutil.Uint64(progress.SyncedStorage),
|
|
|
|
"syncedStorageBytes": hexutil.Uint64(progress.SyncedStorageBytes),
|
|
|
|
"healedTrienodes": hexutil.Uint64(progress.HealedTrienodes),
|
|
|
|
"healedTrienodeBytes": hexutil.Uint64(progress.HealedTrienodeBytes),
|
|
|
|
"healedBytecodes": hexutil.Uint64(progress.HealedBytecodes),
|
|
|
|
"healedBytecodeBytes": hexutil.Uint64(progress.HealedBytecodeBytes),
|
|
|
|
"healingTrienodes": hexutil.Uint64(progress.HealingTrienodes),
|
|
|
|
"healingBytecode": hexutil.Uint64(progress.HealingBytecode),
|
|
|
|
}, 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.
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
pending, queue := s.b.TxPoolContent()
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
curHeader := s.b.CurrentHeader()
|
|
|
|
// Flatten the pending transactions
|
|
|
|
for account, txs := range pending {
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
|
|
|
for _, tx := range txs {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())
|
|
|
|
}
|
|
|
|
content["pending"][account.Hex()] = dump
|
|
|
|
}
|
|
|
|
// Flatten the queued transactions
|
|
|
|
for account, txs := range queue {
|
|
|
|
dump := make(map[string]*RPCTransaction)
|
|
|
|
for _, tx := range txs {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())
|
|
|
|
}
|
|
|
|
content["queued"][account.Hex()] = dump
|
|
|
|
}
|
|
|
|
return content
|
|
|
|
}
|
|
|
|
|
|
|
|
// ContentFrom returns the transactions contained within the transaction pool.
|
|
|
|
func (s *PublicTxPoolAPI) ContentFrom(addr common.Address) map[string]map[string]*RPCTransaction {
|
|
|
|
content := make(map[string]map[string]*RPCTransaction, 2)
|
|
|
|
pending, queue := s.b.TxPoolContentFrom(addr)
|
|
|
|
curHeader := s.b.CurrentHeader()
|
|
|
|
|
|
|
|
// Build the pending transactions
|
|
|
|
dump := make(map[string]*RPCTransaction, len(pending))
|
|
|
|
for _, tx := range pending {
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())
|
|
|
|
}
|
|
|
|
content["pending"] = dump
|
|
|
|
|
|
|
|
// Build the queued transactions
|
|
|
|
dump = make(map[string]*RPCTransaction, len(queue))
|
|
|
|
for _, tx := range queue {
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig())
|
|
|
|
}
|
|
|
|
content["queued"] = dump
|
|
|
|
|
|
|
|
return content
|
|
|
|
}
|
|
|
|
|
|
|
|
// Status returns the number of pending and queued transaction in the pool.
|
|
|
|
func (s *PublicTxPoolAPI) Status() map[string]hexutil.Uint {
|
|
|
|
pending, queue := s.b.Stats()
|
|
|
|
return map[string]hexutil.Uint{
|
|
|
|
"pending": hexutil.Uint(pending),
|
|
|
|
"queued": hexutil.Uint(queue),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inspect retrieves the content of the transaction pool and flattens it into an
|
|
|
|
// easily inspectable list.
|
|
|
|
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),
|
|
|
|
}
|
|
|
|
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 {
|
|
|
|
return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("contract creation: %v wei + %v gas × %v wei", tx.Value(), tx.Gas(), tx.GasPrice())
|
|
|
|
}
|
|
|
|
// Flatten the pending transactions
|
|
|
|
for account, txs := range pending {
|
|
|
|
dump := make(map[string]string)
|
|
|
|
for _, tx := range txs {
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = format(tx)
|
|
|
|
}
|
|
|
|
content["pending"][account.Hex()] = dump
|
|
|
|
}
|
|
|
|
// Flatten the queued transactions
|
|
|
|
for account, txs := range queue {
|
|
|
|
dump := make(map[string]string)
|
|
|
|
for _, tx := range txs {
|
|
|
|
dump[fmt.Sprintf("%d", tx.Nonce())] = format(tx)
|
|
|
|
}
|
|
|
|
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
|
|
|
|
func (s *PublicAccountAPI) Accounts() []common.Address {
|
|
|
|
return s.am.Accounts()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
am *accounts.Manager
|
|
|
|
nonceLock *AddrLocker
|
|
|
|
b Backend
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPrivateAccountAPI create a new PrivateAccountAPI.
|
|
|
|
func NewPrivateAccountAPI(b Backend, nonceLock *AddrLocker) *PrivateAccountAPI {
|
|
|
|
return &PrivateAccountAPI{
|
|
|
|
am: b.AccountManager(),
|
|
|
|
nonceLock: nonceLock,
|
|
|
|
b: b,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListAccounts will return a list of addresses for accounts this node manages.
|
|
|
|
func (s *PrivateAccountAPI) ListAccounts() []common.Address {
|
|
|
|
return s.am.Accounts()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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"`
|
|
|
|
Failure string `json:"failure,omitempty"`
|
|
|
|
Accounts []accounts.Account `json:"accounts,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListWallets will return a list of wallets this node manages.
|
|
|
|
func (s *PrivateAccountAPI) ListWallets() []rawWallet {
|
|
|
|
wallets := make([]rawWallet, 0) // return [] instead of nil if empty
|
|
|
|
for _, wallet := range s.am.Wallets() {
|
|
|
|
status, failure := wallet.Status()
|
|
|
|
|
|
|
|
raw := rawWallet{
|
|
|
|
URL: wallet.URL().String(),
|
|
|
|
Status: status,
|
|
|
|
Accounts: wallet.Accounts(),
|
|
|
|
}
|
|
|
|
if failure != nil {
|
|
|
|
raw.Failure = failure.Error()
|
|
|
|
}
|
|
|
|
wallets = append(wallets, raw)
|
|
|
|
}
|
|
|
|
return wallets
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
derivPath, err := accounts.ParseDerivationPath(path)
|
|
|
|
if err != nil {
|
|
|
|
return accounts.Account{}, err
|
|
|
|
}
|
|
|
|
if pin == nil {
|
|
|
|
pin = new(bool)
|
|
|
|
}
|
|
|
|
return wallet.Derive(derivPath, *pin)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewAccount will create a new account and returns the address for the new account.
|
|
|
|
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) {
|
|
|
|
ks, err := fetchKeystore(s.am)
|
|
|
|
if err != nil {
|
|
|
|
return common.Address{}, err
|
|
|
|
}
|
|
|
|
acc, err := ks.NewAccount(password)
|
|
|
|
if err == nil {
|
|
|
|
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!")
|
|
|
|
return acc.Address, nil
|
|
|
|
}
|
|
|
|
return common.Address{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetchKeystore retrieves the encrypted keystore from the account manager.
|
|
|
|
func fetchKeystore(am *accounts.Manager) (*keystore.KeyStore, error) {
|
|
|
|
if ks := am.Backends(keystore.KeyStoreType); len(ks) > 0 {
|
|
|
|
return ks[0].(*keystore.KeyStore), nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("local keystore not used")
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
key, err := crypto.HexToECDSA(privkey)
|
|
|
|
if err != nil {
|
|
|
|
return common.Address{}, err
|
|
|
|
}
|
|
|
|
ks, err := fetchKeystore(s.am)
|
|
|
|
if err != nil {
|
|
|
|
return common.Address{}, err
|
|
|
|
}
|
|
|
|
acc, err := ks.ImportECDSA(key, password)
|
|
|
|
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.
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
|
|
|
const max = uint64(time.Duration(math.MaxInt64) / time.Second)
|
|
|
|
var d time.Duration
|
|
|
|
if duration == nil {
|
|
|
|
d = 300 * time.Second
|
|
|
|
} else if *duration > max {
|
|
|
|
return false, errors.New("unlock duration too large")
|
|
|
|
} else {
|
|
|
|
d = time.Duration(*duration) * time.Second
|
|
|
|
}
|
|
|
|
ks, err := fetchKeystore(s.am)
|
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
err = ks.TimedUnlock(accounts.Account{Address: addr}, password, d)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("Failed account unlock attempt", "address", addr, "err", err)
|
|
|
|
}
|
|
|
|
return err == nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// LockAccount will lock the account associated with the given address when it's unlocked.
|
|
|
|
func (s *PrivateAccountAPI) LockAccount(addr common.Address) bool {
|
|
|
|
if ks, err := fetchKeystore(s.am); err == nil {
|
|
|
|
return ks.Lock(addr) == nil
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// signTransaction sets defaults and signs the given transaction
|
|
|
|
// 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
|
|
|
|
func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *TransactionArgs, passwd string) (*types.Transaction, error) {
|
|
|
|
// Look up the wallet containing the requested signer
|
|
|
|
account := accounts.Account{Address: args.from()}
|
|
|
|
wallet, err := s.am.Find(account)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Set some sanity defaults and terminate on failure
|
|
|
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Assemble the transaction and sign with the wallet
|
|
|
|
tx := args.toTransaction()
|
|
|
|
|
|
|
|
return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendTransaction will create a transaction from the given arguments and
|
|
|
|
// tries to sign it with the key associated with args.From. If the given
|
|
|
|
// passwd isn't able to decrypt the key it fails.
|
|
|
|
func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args TransactionArgs, 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())
|
|
|
|
}
|
|
|
|
signed, err := s.signTransaction(ctx, &args, passwd)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("Failed transaction send attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err)
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
return SubmitTransaction(ctx, s.b, signed)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignTransaction will create a transaction from the given arguments and
|
|
|
|
// tries to sign it with the key associated with args.From. 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 TransactionArgs, 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.From == nil {
|
|
|
|
return nil, fmt.Errorf("sender not specified")
|
|
|
|
}
|
|
|
|
if args.Gas == nil {
|
|
|
|
return nil, fmt.Errorf("gas not specified")
|
|
|
|
}
|
|
|
|
if args.GasPrice == nil && (args.MaxFeePerGas == nil || args.MaxPriorityFeePerGas == nil) {
|
|
|
|
return nil, fmt.Errorf("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
|
|
|
|
}
|
|
|
|
if args.Nonce == nil {
|
|
|
|
return nil, fmt.Errorf("nonce not specified")
|
|
|
|
}
|
|
|
|
// Before actually signing the transaction, ensure the transaction fee is reasonable.
|
|
|
|
tx := args.toTransaction()
|
|
|
|
if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
signed, err := s.signTransaction(ctx, &args, passwd)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("Failed transaction sign attempt", "from", args.from(), "to", args.To, "value", args.Value.ToInt(), "err", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
data, err := signed.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &SignTransactionResult{data, signed}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sign calculates an Ethereum ECDSA signature for:
|
|
|
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message))
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// The key used to calculate the signature is decrypted with the given password.
|
|
|
|
//
|
|
|
|
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_sign
|
|
|
|
func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr common.Address, passwd string) (hexutil.Bytes, error) {
|
|
|
|
// 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
6 years ago
|
|
|
signature, err := wallet.SignTextWithPassphrase(account, passwd, data)
|
|
|
|
if err != nil {
|
|
|
|
log.Warn("Failed data sign attempt", "address", addr, "err", err)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
|
|
|
return signature, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
//
|
|
|
|
// Note, the signature must conform to the secp256k1 curve R, S and V values, where
|
|
|
|
// the V value must be 27 or 28 for legacy reasons.
|
|
|
|
//
|
|
|
|
// https://github.com/ethereum/go-ethereum/wiki/Management-APIs#personal_ecRecover
|
|
|
|
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
|
|
|
|
if len(sig) != crypto.SignatureLength {
|
|
|
|
return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength)
|
|
|
|
}
|
|
|
|
if sig[crypto.RecoveryIDOffset] != 27 && sig[crypto.RecoveryIDOffset] != 28 {
|
|
|
|
return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
|
|
|
}
|
|
|
|
sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
|
|
|
|
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
6 years ago
|
|
|
rpk, err := crypto.SigToPub(accounts.TextHash(data), sig)
|
|
|
|
if err != nil {
|
|
|
|
return common.Address{}, err
|
|
|
|
}
|
|
|
|
return crypto.PubkeyToAddress(*rpk), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 TransactionArgs, passwd string) (common.Hash, error) {
|
|
|
|
return s.SendTransaction(ctx, args, passwd)
|
|
|
|
}
|
|
|
|
|
|
|
|
// InitializeWallet initializes a new wallet at the provided URL, by generating and returning a new private key.
|
|
|
|
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:
|
|
|
|
return "", fmt.Errorf("specified wallet does not support initialization")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unpair deletes a pairing between wallet and geth.
|
|
|
|
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:
|
|
|
|
return fmt.Errorf("specified wallet does not support pairing")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
b Backend
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
|
|
|
|
func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
|
|
|
|
return &PublicBlockChainAPI{b}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
|
|
|
|
func (api *PublicBlockChainAPI) ChainId() (*hexutil.Big, error) {
|
|
|
|
// if current block is at or past the EIP-155 replay-protection fork block, return chainID from config
|
|
|
|
if config := api.b.ChainConfig(); config.IsEIP155(api.b.CurrentBlock().Number()) {
|
|
|
|
return (*hexutil.Big)(config.ChainID), nil
|
|
|
|
}
|
|
|
|
return nil, fmt.Errorf("chain not synced beyond EIP-155 replay-protection fork block")
|
|
|
|
}
|
|
|
|
|
|
|
|
// BlockNumber returns the block number of the chain head.
|
|
|
|
func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
|
|
|
|
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
|
|
|
|
return hexutil.Uint64(header.Number.Uint64())
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if state == nil || err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
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()), toHexSlice(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: toHexSlice(accountProof),
|
|
|
|
Balance: (*hexutil.Big)(state.GetBalance(address)),
|
|
|
|
CodeHash: codeHash,
|
|
|
|
Nonce: hexutil.Uint64(state.GetNonce(address)),
|
|
|
|
StorageHash: storageHash,
|
|
|
|
StorageProof: storageProof,
|
|
|
|
}, state.Error()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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(ctx, 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{} {
|
|
|
|
header, _ := s.b.HeaderByHash(ctx, hash)
|
|
|
|
if header != nil {
|
|
|
|
return s.rpcMarshalHeader(ctx, 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(ctx, block, true, fullTx)
|
|
|
|
if err == nil && number == rpc.PendingBlockNumber {
|
|
|
|
// Pending blocks need to nil out a few fields
|
|
|
|
for _, field := range []string{"hash", "nonce", "miner"} {
|
|
|
|
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.
|
|
|
|
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
|
|
|
block, err := s.b.BlockByHash(ctx, hash)
|
|
|
|
if block != nil {
|
|
|
|
return s.rpcMarshalBlock(ctx, block, true, fullTx)
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index.
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) {
|
|
|
|
block, err := s.b.BlockByNumber(ctx, blockNr)
|
|
|
|
if block != nil {
|
|
|
|
uncles := block.Uncles()
|
|
|
|
if index >= hexutil.Uint(len(uncles)) {
|
|
|
|
log.Debug("Requested uncle not found", "number", blockNr, "hash", block.Hash(), "index", index)
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
block = types.NewBlockWithHeader(uncles[index])
|
|
|
|
return s.rpcMarshalBlock(ctx, block, false, false)
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index.
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) {
|
|
|
|
block, err := s.b.BlockByHash(ctx, blockHash)
|
|
|
|
if block != nil {
|
|
|
|
uncles := block.Uncles()
|
|
|
|
if index >= hexutil.Uint(len(uncles)) {
|
|
|
|
log.Debug("Requested uncle not found", "number", block.Number(), "hash", blockHash, "index", index)
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
block = types.NewBlockWithHeader(uncles[index])
|
|
|
|
return s.rpcMarshalBlock(ctx, block, false, false)
|
|
|
|
}
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
|
|
|
n := hexutil.Uint(len(block.Uncles()))
|
|
|
|
return &n
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
|
|
|
|
func (s *PublicBlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
|
|
|
n := hexutil.Uint(len(block.Uncles()))
|
|
|
|
return &n
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetCode returns the code stored at the given address in the state for the given block number.
|
|
|
|
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if state == nil || err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
code := state.GetCode(address)
|
|
|
|
return code, state.Error()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
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)
|
|
|
|
if state == nil || err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := state.GetState(address, common.HexToHash(key))
|
|
|
|
return res[:], state.Error()
|
|
|
|
}
|
|
|
|
|
|
|
|
// OverrideAccount 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 OverrideAccount 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"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// StateOverride is the collection of overridden accounts.
|
|
|
|
type StateOverride map[common.Address]OverrideAccount
|
|
|
|
|
|
|
|
// Apply overrides the fields of specified accounts into the given state.
|
|
|
|
func (diff *StateOverride) Apply(state *state.StateDB) error {
|
|
|
|
if diff == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
for addr, account := range *diff {
|
|
|
|
// 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 {
|
|
|
|
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
|
|
|
}
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// BlockOverrides is a set of header fields to override.
|
|
|
|
type BlockOverrides struct {
|
|
|
|
Number *hexutil.Big
|
|
|
|
Difficulty *hexutil.Big
|
|
|
|
Time *hexutil.Big
|
|
|
|
GasLimit *hexutil.Uint64
|
|
|
|
Coinbase *common.Address
|
|
|
|
Random *common.Hash
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply overrides the given header fields into the given block context.
|
|
|
|
func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
|
|
|
|
if diff == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if diff.Number != nil {
|
|
|
|
blockCtx.BlockNumber = diff.Number.ToInt()
|
|
|
|
}
|
|
|
|
if diff.Difficulty != nil {
|
|
|
|
blockCtx.Difficulty = diff.Difficulty.ToInt()
|
|
|
|
}
|
|
|
|
if diff.Time != nil {
|
|
|
|
blockCtx.Time = diff.Time.ToInt()
|
|
|
|
}
|
|
|
|
if diff.GasLimit != nil {
|
|
|
|
blockCtx.GasLimit = uint64(*diff.GasLimit)
|
|
|
|
}
|
|
|
|
if diff.Coinbase != nil {
|
|
|
|
blockCtx.Coinbase = *diff.Coinbase
|
|
|
|
}
|
|
|
|
if diff.Random != nil {
|
|
|
|
blockCtx.Random = diff.Random
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
|
|
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
|
|
|
|
|
|
|
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if state == nil || err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if err := overrides.Apply(state); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// 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
|
|
|
|
if timeout > 0 {
|
|
|
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
|
|
|
} else {
|
|
|
|
ctx, cancel = context.WithCancel(ctx)
|
|
|
|
}
|
|
|
|
// Make sure the context is cancelled when the call has completed
|
|
|
|
// this makes sure resources are cleaned up.
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
// Get a new instance of the EVM.
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
msg, err := args.ToMessage(globalGasCap, header.BaseFee)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Wait for the context to be done and cancel the evm. Even if the
|
|
|
|
// EVM has finished, cancelling may be done (repeatedly)
|
|
|
|
go func() {
|
|
|
|
<-ctx.Done()
|
|
|
|
evm.Cancel()
|
|
|
|
}()
|
|
|
|
|
|
|
|
// Execute the message.
|
|
|
|
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
|
|
|
result, err := core.ApplyMessage(evm, msg, gp)
|
|
|
|
if err := vmError(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the timer caused an abort, return an appropriate error message
|
|
|
|
if evm.Cancelled() {
|
|
|
|
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
// Call executes the given transaction on the state for the given block number.
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
|
|
|
|
result, err := DoCall(ctx, s.b, args, blockNrOrHash, overrides, s.b.RPCEVMTimeout(), s.b.RPCGasCap())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// If the result contains a revert reason, try to unpack and return it.
|
|
|
|
if len(result.Revert()) > 0 {
|
|
|
|
return nil, newRevertError(result)
|
|
|
|
}
|
|
|
|
return result.Return(), result.Err
|
|
|
|
}
|
|
|
|
|
|
|
|
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap uint64) (hexutil.Uint64, error) {
|
|
|
|
// Binary search the gas requirement, as it may be higher than the amount used
|
|
|
|
var (
|
|
|
|
lo uint64 = params.TxGas - 1
|
|
|
|
hi uint64
|
|
|
|
cap uint64
|
|
|
|
)
|
|
|
|
// 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.
|
|
|
|
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
|
|
|
|
hi = uint64(*args.Gas)
|
|
|
|
} else {
|
|
|
|
// Retrieve the block to act as the gas ceiling
|
|
|
|
block, err := b.BlockByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
if block == nil {
|
|
|
|
return 0, errors.New("block not found")
|
|
|
|
}
|
|
|
|
hi = block.GasLimit()
|
|
|
|
}
|
|
|
|
// Normalize the max fee per gas the call is willing to spend.
|
|
|
|
var feeCap *big.Int
|
|
|
|
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
|
|
|
|
return 0, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
|
|
|
} else if args.GasPrice != nil {
|
|
|
|
feeCap = args.GasPrice.ToInt()
|
|
|
|
} else if args.MaxFeePerGas != nil {
|
|
|
|
feeCap = args.MaxFeePerGas.ToInt()
|
|
|
|
} else {
|
|
|
|
feeCap = common.Big0
|
|
|
|
}
|
|
|
|
// Recap the highest gas limit with account's available balance.
|
|
|
|
if feeCap.BitLen() != 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, feeCap)
|
|
|
|
|
|
|
|
// If the allowance is larger than maximum uint64, skip checking
|
|
|
|
if allowance.IsUint64() && 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(), "maxFeePerGas", feeCap, "fundable", allowance)
|
|
|
|
hi = allowance.Uint64()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Recap the highest gas allowance with specified gascap.
|
|
|
|
if gasCap != 0 && hi > gasCap {
|
|
|
|
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
|
|
|
hi = gasCap
|
|
|
|
}
|
|
|
|
cap = hi
|
|
|
|
|
|
|
|
// Create a helper to check if a gas allowance results in an executable transaction
|
|
|
|
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
|
|
|
args.Gas = (*hexutil.Uint64)(&gas)
|
|
|
|
|
|
|
|
result, err := DoCall(ctx, b, args, blockNrOrHash, nil, 0, gasCap)
|
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, core.ErrIntrinsicGas) {
|
|
|
|
return true, nil, nil // Special case, raise gas limit
|
|
|
|
}
|
|
|
|
return true, nil, err // Bail out
|
|
|
|
}
|
|
|
|
return result.Failed(), result, nil
|
|
|
|
}
|
|
|
|
// Execute the binary search and hone in on an executable gas limit
|
|
|
|
for lo+1 < hi {
|
|
|
|
mid := (hi + lo) / 2
|
|
|
|
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
|
|
|
|
// assigned. Return the error directly, don't struggle any more.
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
if failed {
|
|
|
|
lo = mid
|
|
|
|
} else {
|
|
|
|
hi = mid
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Reject the transaction as invalid if it still fails at the highest allowance
|
|
|
|
if hi == cap {
|
|
|
|
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 {
|
|
|
|
return 0, newRevertError(result)
|
|
|
|
}
|
|
|
|
return 0, result.Err
|
|
|
|
}
|
|
|
|
// Otherwise, the specified gas cap is too low
|
|
|
|
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hexutil.Uint64(hi), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) {
|
|
|
|
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
|
|
|
if blockNrOrHash != nil {
|
|
|
|
bNrOrHash = *blockNrOrHash
|
|
|
|
}
|
|
|
|
return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap())
|
|
|
|
}
|
|
|
|
|
|
|
|
// RPCMarshalHeader converts the given header to the RPC output .
|
|
|
|
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
result := map[string]interface{}{
|
|
|
|
"number": (*hexutil.Big)(head.Number),
|
|
|
|
"hash": head.Hash(),
|
|
|
|
"parentHash": head.ParentHash,
|
|
|
|
"nonce": head.Nonce,
|
|
|
|
"mixHash": head.MixDigest,
|
|
|
|
"sha3Uncles": head.UncleHash,
|
|
|
|
"logsBloom": head.Bloom,
|
|
|
|
"stateRoot": head.Root,
|
|
|
|
"miner": head.Coinbase,
|
|
|
|
"difficulty": (*hexutil.Big)(head.Difficulty),
|
|
|
|
"extraData": hexutil.Bytes(head.Extra),
|
|
|
|
"size": hexutil.Uint64(head.Size()),
|
|
|
|
"gasLimit": hexutil.Uint64(head.GasLimit),
|
|
|
|
"gasUsed": hexutil.Uint64(head.GasUsed),
|
|
|
|
"timestamp": hexutil.Uint64(head.Time),
|
|
|
|
"transactionsRoot": head.TxHash,
|
|
|
|
"receiptsRoot": head.ReceiptHash,
|
|
|
|
}
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
|
|
|
|
if head.BaseFee != nil {
|
|
|
|
result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, config *params.ChainConfig) (map[string]interface{}, error) {
|
|
|
|
fields := RPCMarshalHeader(block.Header())
|
|
|
|
fields["size"] = hexutil.Uint64(block.Size())
|
|
|
|
|
|
|
|
if inclTx {
|
|
|
|
formatTx := func(tx *types.Transaction) (interface{}, error) {
|
|
|
|
return tx.Hash(), nil
|
|
|
|
}
|
|
|
|
if fullTx {
|
|
|
|
formatTx = func(tx *types.Transaction) (interface{}, error) {
|
|
|
|
return newRPCTransactionFromBlockHash(block, tx.Hash(), config), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
txs := block.Transactions()
|
|
|
|
transactions := make([]interface{}, len(txs))
|
|
|
|
var err error
|
|
|
|
for i, tx := range txs {
|
|
|
|
if transactions[i], err = formatTx(tx); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fields["transactions"] = transactions
|
|
|
|
}
|
|
|
|
uncles := block.Uncles()
|
|
|
|
uncleHashes := make([]common.Hash, len(uncles))
|
|
|
|
for i, uncle := range uncles {
|
|
|
|
uncleHashes[i] = uncle.Hash()
|
|
|
|
}
|
|
|
|
fields["uncles"] = uncleHashes
|
|
|
|
|
|
|
|
return fields, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires
|
|
|
|
// a `PublicBlockchainAPI`.
|
|
|
|
func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} {
|
|
|
|
fields := RPCMarshalHeader(header)
|
|
|
|
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash()))
|
|
|
|
return fields
|
|
|
|
}
|
|
|
|
|
|
|
|
// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires
|
|
|
|
// a `PublicBlockchainAPI`.
|
|
|
|
func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
|
|
|
fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if inclTx {
|
|
|
|
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, b.Hash()))
|
|
|
|
}
|
|
|
|
return fields, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
|
|
|
type RPCTransaction struct {
|
|
|
|
BlockHash *common.Hash `json:"blockHash"`
|
|
|
|
BlockNumber *hexutil.Big `json:"blockNumber"`
|
|
|
|
From common.Address `json:"from"`
|
|
|
|
Gas hexutil.Uint64 `json:"gas"`
|
|
|
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
|
|
|
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
|
|
|
|
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
|
|
|
|
Hash common.Hash `json:"hash"`
|
|
|
|
Input hexutil.Bytes `json:"input"`
|
|
|
|
Nonce hexutil.Uint64 `json:"nonce"`
|
|
|
|
To *common.Address `json:"to"`
|
|
|
|
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
|
|
|
Value *hexutil.Big `json:"value"`
|
|
|
|
Type hexutil.Uint64 `json:"type"`
|
|
|
|
Accesses *types.AccessList `json:"accessList,omitempty"`
|
|
|
|
ChainID *hexutil.Big `json:"chainId,omitempty"`
|
|
|
|
V *hexutil.Big `json:"v"`
|
|
|
|
R *hexutil.Big `json:"r"`
|
|
|
|
S *hexutil.Big `json:"s"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction {
|
|
|
|
signer := types.MakeSigner(config, big.NewInt(0).SetUint64(blockNumber))
|
|
|
|
from, _ := types.Sender(signer, tx)
|
|
|
|
v, r, s := tx.RawSignatureValues()
|
|
|
|
result := &RPCTransaction{
|
|
|
|
Type: hexutil.Uint64(tx.Type()),
|
|
|
|
From: from,
|
|
|
|
Gas: hexutil.Uint64(tx.Gas()),
|
|
|
|
GasPrice: (*hexutil.Big)(tx.GasPrice()),
|
|
|
|
Hash: tx.Hash(),
|
|
|
|
Input: hexutil.Bytes(tx.Data()),
|
|
|
|
Nonce: hexutil.Uint64(tx.Nonce()),
|
|
|
|
To: tx.To(),
|
|
|
|
Value: (*hexutil.Big)(tx.Value()),
|
|
|
|
V: (*hexutil.Big)(v),
|
|
|
|
R: (*hexutil.Big)(r),
|
|
|
|
S: (*hexutil.Big)(s),
|
|
|
|
}
|
|
|
|
if blockHash != (common.Hash{}) {
|
|
|
|
result.BlockHash = &blockHash
|
|
|
|
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
|
|
|
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
|
|
|
}
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
switch tx.Type() {
|
|
|
|
case types.AccessListTxType:
|
|
|
|
al := tx.AccessList()
|
|
|
|
result.Accesses = &al
|
|
|
|
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
|
|
|
case types.DynamicFeeTxType:
|
|
|
|
al := tx.AccessList()
|
|
|
|
result.Accesses = &al
|
|
|
|
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
|
|
|
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
|
|
|
|
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
// if the transaction has been mined, compute the effective gas price
|
|
|
|
if baseFee != nil && blockHash != (common.Hash{}) {
|
|
|
|
// price = min(tip, gasFeeCap - baseFee) + baseFee
|
|
|
|
price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
result.GasPrice = (*hexutil.Big)(price)
|
|
|
|
} else {
|
|
|
|
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
}
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
func newRPCPendingTransaction(tx *types.Transaction, current *types.Header, config *params.ChainConfig) *RPCTransaction {
|
|
|
|
var baseFee *big.Int
|
|
|
|
blockNumber := uint64(0)
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
if current != nil {
|
|
|
|
baseFee = misc.CalcBaseFee(config, current)
|
|
|
|
blockNumber = current.Number.Uint64()
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
}
|
|
|
|
return newRPCTransaction(tx, common.Hash{}, blockNumber, 0, baseFee, config)
|
|
|
|
}
|
|
|
|
|
|
|
|
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
|
|
|
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig) *RPCTransaction {
|
|
|
|
txs := b.Transactions()
|
|
|
|
if index >= uint64(len(txs)) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee(), config)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, _ := txs[index].MarshalBinary()
|
|
|
|
return blob
|
|
|
|
}
|
|
|
|
|
|
|
|
// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
|
|
|
|
func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig) *RPCTransaction {
|
|
|
|
for idx, tx := range b.Transactions() {
|
|
|
|
if tx.Hash() == hash {
|
|
|
|
return newRPCTransactionFromBlockIndex(b, uint64(idx), config)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// accessListResult returns an optional accesslist
|
|
|
|
// Its the result of the `debug_createAccessList` RPC call.
|
|
|
|
// It contains an error if the transaction itself failed.
|
|
|
|
type accessListResult struct {
|
|
|
|
Accesslist *types.AccessList `json:"accessList"`
|
|
|
|
Error string `json:"error,omitempty"`
|
|
|
|
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateAccessList creates a EIP-2930 type AccessList for the given transaction.
|
|
|
|
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
|
|
|
|
func (s *PublicBlockChainAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
|
|
|
|
bNrOrHash := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
|
|
|
if blockNrOrHash != nil {
|
|
|
|
bNrOrHash = *blockNrOrHash
|
|
|
|
}
|
|
|
|
acl, gasUsed, vmerr, err := AccessList(ctx, s.b, bNrOrHash, args)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result := &accessListResult{Accesslist: &acl, GasUsed: hexutil.Uint64(gasUsed)}
|
|
|
|
if vmerr != nil {
|
|
|
|
result.Error = vmerr.Error()
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AccessList creates an access list for the given transaction.
|
|
|
|
// If the accesslist creation fails an error is returned.
|
|
|
|
// If the transaction itself fails, an vmErr is returned.
|
|
|
|
func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrHash, args TransactionArgs) (acl types.AccessList, gasUsed uint64, vmErr error, err error) {
|
|
|
|
// Retrieve the execution context
|
|
|
|
db, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if db == nil || err != nil {
|
|
|
|
return nil, 0, nil, err
|
|
|
|
}
|
|
|
|
// If the gas amount is not set, extract this as it will depend on access
|
|
|
|
// lists and we'll need to reestimate every time
|
|
|
|
nogas := args.Gas == nil
|
|
|
|
|
|
|
|
// Ensure any missing fields are filled, extract the recipient and input data
|
|
|
|
if err := args.setDefaults(ctx, b); err != nil {
|
|
|
|
return nil, 0, nil, err
|
|
|
|
}
|
|
|
|
var to common.Address
|
|
|
|
if args.To != nil {
|
|
|
|
to = *args.To
|
|
|
|
} else {
|
|
|
|
to = crypto.CreateAddress(args.from(), uint64(*args.Nonce))
|
|
|
|
}
|
|
|
|
isPostMerge := header.Difficulty.Cmp(common.Big0) == 0
|
|
|
|
// Retrieve the precompiles since they don't need to be added to the access list
|
|
|
|
precompiles := vm.ActivePrecompiles(b.ChainConfig().Rules(header.Number, isPostMerge))
|
|
|
|
|
|
|
|
// Create an initial tracer
|
|
|
|
prevTracer := logger.NewAccessListTracer(nil, args.from(), to, precompiles)
|
|
|
|
if args.AccessList != nil {
|
|
|
|
prevTracer = logger.NewAccessListTracer(*args.AccessList, args.from(), to, precompiles)
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
// Retrieve the current access list to expand
|
|
|
|
accessList := prevTracer.AccessList()
|
|
|
|
log.Trace("Creating access list", "input", accessList)
|
|
|
|
|
|
|
|
// If no gas amount was specified, each unique access list needs it's own
|
|
|
|
// gas calculation. This is quite expensive, but we need to be accurate
|
|
|
|
// and it's convered by the sender only anyway.
|
|
|
|
if nogas {
|
|
|
|
args.Gas = nil
|
|
|
|
if err := args.setDefaults(ctx, b); err != nil {
|
|
|
|
return nil, 0, nil, err // shouldn't happen, just in case
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Copy the original db so we don't modify it
|
|
|
|
statedb := db.Copy()
|
|
|
|
// Set the accesslist to the last al
|
|
|
|
args.AccessList = &accessList
|
|
|
|
msg, err := args.ToMessage(b.RPCGasCap(), header.BaseFee)
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply the transaction with the access list tracer
|
|
|
|
tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles)
|
|
|
|
config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true}
|
|
|
|
vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config)
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, nil, err
|
|
|
|
}
|
|
|
|
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
|
|
|
|
if err != nil {
|
|
|
|
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
|
|
|
|
}
|
|
|
|
if tracer.Equal(prevTracer) {
|
|
|
|
return accessList, res.UsedGas, res.Err, nil
|
|
|
|
}
|
|
|
|
prevTracer = tracer
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicTransactionPoolAPI exposes methods for the RPC interface
|
|
|
|
type PublicTransactionPoolAPI struct {
|
|
|
|
b Backend
|
|
|
|
nonceLock *AddrLocker
|
|
|
|
signer types.Signer
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
|
|
|
func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
|
|
|
|
// The signer used by the API should always be the 'latest' known one because we expect
|
|
|
|
// signers to be backwards-compatible with old transactions.
|
|
|
|
signer := types.LatestSigner(b.ChainConfig())
|
|
|
|
return &PublicTransactionPoolAPI{b, nonceLock, signer}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
|
|
|
n := hexutil.Uint(len(block.Transactions()))
|
|
|
|
return &n
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
|
|
|
n := hexutil.Uint(len(block.Transactions()))
|
|
|
|
return &n
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
|
|
|
return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
|
|
|
return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes {
|
|
|
|
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil {
|
|
|
|
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes {
|
|
|
|
if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil {
|
|
|
|
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) {
|
|
|
|
// Ask transaction pool for the nonce which includes pending transactions
|
|
|
|
if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber {
|
|
|
|
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
|
|
|
|
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if state == nil || err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
nonce := state.GetNonce(address)
|
|
|
|
return (*hexutil.Uint64)(&nonce), state.Error()
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransactionByHash returns the transaction for the given hash
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
|
|
|
// Try to return an already finalized transaction
|
|
|
|
tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if tx != nil {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
header, err := s.b.HeaderByHash(ctx, blockHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return newRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee, s.b.ChainConfig()), nil
|
|
|
|
}
|
|
|
|
// No finalized transaction, try to retrieve it from the pool
|
|
|
|
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
return newRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transaction unknown, return as such
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
|
|
|
|
// Retrieve a finalized transaction, or a pooled otherwise
|
|
|
|
tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if tx == nil {
|
|
|
|
if tx = s.b.GetPoolTransaction(hash); tx == nil {
|
|
|
|
// Transaction not found anywhere, abort
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Serialize to RLP and return
|
|
|
|
return tx.MarshalBinary()
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
|
|
|
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
|
|
|
tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
receipts, err := s.b.GetReceipts(ctx, blockHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(receipts) <= int(index) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
receipt := receipts[index]
|
|
|
|
|
|
|
|
// Derive the sender.
|
|
|
|
bigblock := new(big.Int).SetUint64(blockNumber)
|
|
|
|
signer := types.MakeSigner(s.b.ChainConfig(), bigblock)
|
|
|
|
from, _ := types.Sender(signer, tx)
|
|
|
|
|
|
|
|
fields := map[string]interface{}{
|
|
|
|
"blockHash": blockHash,
|
|
|
|
"blockNumber": hexutil.Uint64(blockNumber),
|
|
|
|
"transactionHash": hash,
|
|
|
|
"transactionIndex": hexutil.Uint64(index),
|
|
|
|
"from": from,
|
|
|
|
"to": tx.To(),
|
|
|
|
"gasUsed": hexutil.Uint64(receipt.GasUsed),
|
|
|
|
"cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed),
|
|
|
|
"contractAddress": nil,
|
|
|
|
"logs": receipt.Logs,
|
|
|
|
"logsBloom": receipt.Bloom,
|
|
|
|
"type": hexutil.Uint(tx.Type()),
|
|
|
|
}
|
|
|
|
// Assign the effective gas price paid
|
|
|
|
if !s.b.ChainConfig().IsLondon(bigblock) {
|
|
|
|
fields["effectiveGasPrice"] = hexutil.Uint64(tx.GasPrice().Uint64())
|
|
|
|
} else {
|
|
|
|
header, err := s.b.HeaderByHash(ctx, blockHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
gasPrice := new(big.Int).Add(header.BaseFee, tx.EffectiveGasTipValue(header.BaseFee))
|
|
|
|
fields["effectiveGasPrice"] = hexutil.Uint64(gasPrice.Uint64())
|
|
|
|
}
|
|
|
|
// Assign receipt status or post state.
|
|
|
|
if len(receipt.PostState) > 0 {
|
|
|
|
fields["root"] = hexutil.Bytes(receipt.PostState)
|
|
|
|
} else {
|
|
|
|
fields["status"] = hexutil.Uint(receipt.Status)
|
|
|
|
}
|
|
|
|
if receipt.Logs == nil {
|
|
|
|
fields["logs"] = []*types.Log{}
|
|
|
|
}
|
|
|
|
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
|
|
|
|
if receipt.ContractAddress != (common.Address{}) {
|
|
|
|
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) {
|
|
|
|
// 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
|
|
|
|
return wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
|
|
|
// If the transaction fee cap is already specified, ensure the
|
|
|
|
// fee of the given transaction is _reasonable_.
|
|
|
|
if err := checkTxFee(tx.GasPrice(), tx.Gas(), b.RPCTxFeeCap()); err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
if !b.UnprotectedAllowed() && !tx.Protected() {
|
|
|
|
// Ensure only eip155 signed transactions are submitted if EIP155Required is set.
|
|
|
|
return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC")
|
|
|
|
}
|
|
|
|
if err := b.SendTx(ctx, tx); err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
// Print a log with full tx details for manual investigations and interventions
|
|
|
|
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
|
|
|
|
from, err := types.Sender(signer, tx)
|
|
|
|
if err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if tx.To() == nil {
|
|
|
|
addr := crypto.CreateAddress(from, tx.Nonce())
|
|
|
|
log.Info("Submitted contract creation", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.Nonce(), "contract", addr.Hex(), "value", tx.Value())
|
|
|
|
} else {
|
|
|
|
log.Info("Submitted transaction", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.Nonce(), "recipient", tx.To(), "value", tx.Value())
|
|
|
|
}
|
|
|
|
return tx.Hash(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 TransactionArgs) (common.Hash, error) {
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
// Assemble the transaction and sign with the wallet
|
|
|
|
tx := args.toTransaction()
|
|
|
|
|
|
|
|
signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
|
|
|
|
if err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
return SubmitTransaction(ctx, s.b, signed)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FillTransaction fills the defaults (nonce, gas, gasPrice or 1559 fields)
|
|
|
|
// on a given unsigned transaction, and returns it to the caller for further
|
|
|
|
// processing (signing + broadcast).
|
|
|
|
func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args TransactionArgs) (*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 := tx.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &SignTransactionResult{data, tx}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendRawTransaction will add the signed transaction to the transaction pool.
|
|
|
|
// The sender is responsible for signing the transaction and using the correct nonce.
|
|
|
|
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) {
|
|
|
|
tx := new(types.Transaction)
|
|
|
|
if err := tx.UnmarshalBinary(input); err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
return SubmitTransaction(ctx, s.b, tx)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sign calculates an ECDSA signature for:
|
|
|
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// The account associated with addr must be unlocked.
|
|
|
|
//
|
|
|
|
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign
|
|
|
|
func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) {
|
|
|
|
// 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
6 years ago
|
|
|
signature, err := wallet.SignText(account, data)
|
|
|
|
if err == nil {
|
|
|
|
signature[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
|
|
|
|
}
|
|
|
|
return signature, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// SignTransactionResult represents a RLP encoded signed transaction.
|
|
|
|
type SignTransactionResult struct {
|
|
|
|
Raw hexutil.Bytes `json:"raw"`
|
|
|
|
Tx *types.Transaction `json:"tx"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args TransactionArgs) (*SignTransactionResult, error) {
|
|
|
|
if args.Gas == nil {
|
|
|
|
return nil, fmt.Errorf("gas not specified")
|
|
|
|
}
|
|
|
|
if args.GasPrice == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) {
|
|
|
|
return nil, fmt.Errorf("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas")
|
|
|
|
}
|
|
|
|
if args.Nonce == nil {
|
|
|
|
return nil, fmt.Errorf("nonce not specified")
|
|
|
|
}
|
|
|
|
if err := args.setDefaults(ctx, s.b); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Before actually sign the transaction, ensure the transaction fee is reasonable.
|
|
|
|
tx := args.toTransaction()
|
|
|
|
if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
signed, err := s.sign(args.from(), tx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
data, err := signed.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &SignTransactionResult{data, signed}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PendingTransactions returns the transactions that are in the transaction pool
|
|
|
|
// and have a from address that is one of the accounts this node manages.
|
|
|
|
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
|
|
|
|
pending, err := s.b.GetPoolTransactions()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
accounts := make(map[common.Address]struct{})
|
|
|
|
for _, wallet := range s.b.AccountManager().Wallets() {
|
|
|
|
for _, account := range wallet.Accounts() {
|
|
|
|
accounts[account.Address] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
curHeader := s.b.CurrentHeader()
|
|
|
|
transactions := make([]*RPCTransaction, 0, len(pending))
|
|
|
|
for _, tx := range pending {
|
|
|
|
from, _ := types.Sender(s.signer, tx)
|
|
|
|
if _, exists := accounts[from]; exists {
|
core, eth, internal, les: RPC methods and fields for EIP 1559 (#22964)
* internal/ethapi: add baseFee to RPCMarshalHeader
* internal/ethapi: add FeeCap, Tip and correct GasPrice to EIP-1559 RPCTransaction results
* core,eth,les,internal: add support for tip estimation in gas price oracle
* internal/ethapi,eth/gasprice: don't suggest tip larger than fee cap
* core/types,internal: use correct eip1559 terminology for json marshalling
* eth, internal/ethapi: fix rebase problems
* internal/ethapi: fix rpc name of basefee
* internal/ethapi: address review concerns
* core, eth, internal, les: simplify gasprice oracle (#25)
* core, eth, internal, les: simplify gasprice oracle
* eth/gasprice: fix typo
* internal/ethapi: minor tweak in tx args
* internal/ethapi: calculate basefee for pending block
* internal/ethapi: fix panic
* internal/ethapi, eth/tracers: simplify txargs ToMessage
* internal/ethapi: remove unused param
* core, eth, internal: fix regressions wrt effective gas price in the evm
* eth/gasprice: drop weird debug println
* internal/jsre/deps: hack in 1559 gas conversions into embedded web3
* internal/jsre/deps: hack basFee to decimal conversion
* internal/ethapi: init feecap and tipcap for legacy txs too
* eth, graphql, internal, les: fix gas price suggestion on all combos
* internal/jsre/deps: handle decimal tipcap and feecap
* eth, internal: minor review fixes
* graphql, internal: export max fee cap RPC endpoint
* internal/ethapi: fix crash in transaction_args
* internal/ethapi: minor refactor to make the code safer
Co-authored-by: Ryan Schneider <ryanleeschneider@gmail.com>
Co-authored-by: lightclient@protonmail.com <lightclient@protonmail.com>
Co-authored-by: gary rong <garyrong0905@gmail.com>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
4 years ago
|
|
|
transactions = append(transactions, newRPCPendingTransaction(tx, curHeader, s.b.ChainConfig()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return transactions, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs TransactionArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) {
|
|
|
|
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()
|
|
|
|
|
|
|
|
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
|
|
|
|
var price = matchTx.GasPrice()
|
|
|
|
if gasPrice != nil {
|
|
|
|
price = gasPrice.ToInt()
|
|
|
|
}
|
|
|
|
var gas = matchTx.Gas()
|
|
|
|
if gasLimit != nil {
|
|
|
|
gas = uint64(*gasLimit)
|
|
|
|
}
|
|
|
|
if err := checkTxFee(price, gas, s.b.RPCTxFeeCap()); err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
// Iterate the pending list for replacement
|
|
|
|
pending, err := s.b.GetPoolTransactions()
|
|
|
|
if err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
for _, p := range pending {
|
|
|
|
wantSigHash := s.signer.Hash(matchTx)
|
|
|
|
pFrom, err := types.Sender(s.signer, p)
|
|
|
|
if err == nil && pFrom == sendArgs.from() && s.signer.Hash(p) == wantSigHash {
|
|
|
|
// Match. Re-sign and send the transaction.
|
|
|
|
if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 {
|
|
|
|
sendArgs.GasPrice = gasPrice
|
|
|
|
}
|
|
|
|
if gasLimit != nil && *gasLimit != 0 {
|
|
|
|
sendArgs.Gas = gasLimit
|
|
|
|
}
|
|
|
|
signedTx, err := s.sign(sendArgs.from(), sendArgs.toTransaction())
|
|
|
|
if err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
if err = s.b.SendTx(ctx, signedTx); err != nil {
|
|
|
|
return common.Hash{}, err
|
|
|
|
}
|
|
|
|
return signedTx.Hash(), nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return common.Hash{}, fmt.Errorf("transaction %#x not found", matchTx.Hash())
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicDebugAPI is the collection of Ethereum APIs exposed over the public
|
|
|
|
// 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}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetHeaderRlp retrieves the RLP encoded for of a single header.
|
|
|
|
func (api *PublicDebugAPI) GetHeaderRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) {
|
|
|
|
header, _ := api.b.HeaderByNumber(ctx, rpc.BlockNumber(number))
|
|
|
|
if header == nil {
|
|
|
|
return nil, fmt.Errorf("header #%d not found", number)
|
|
|
|
}
|
|
|
|
return rlp.EncodeToBytes(header)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetBlockRlp retrieves the RLP encoded for of a single block.
|
|
|
|
func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (hexutil.Bytes, error) {
|
|
|
|
block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number))
|
|
|
|
if block == nil {
|
|
|
|
return nil, fmt.Errorf("block #%d not found", number)
|
|
|
|
}
|
|
|
|
return rlp.EncodeToBytes(block)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetRawReceipts retrieves the binary-encoded raw receipts of a single block.
|
|
|
|
func (api *PublicDebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]hexutil.Bytes, error) {
|
|
|
|
var hash common.Hash
|
|
|
|
if h, ok := blockNrOrHash.Hash(); ok {
|
|
|
|
hash = h
|
|
|
|
} else {
|
|
|
|
block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
hash = block.Hash()
|
|
|
|
}
|
|
|
|
receipts, err := api.b.GetReceipts(ctx, hash)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result := make([]hexutil.Bytes, len(receipts))
|
|
|
|
for i, receipt := range receipts {
|
|
|
|
b, err := receipt.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
result[i] = b
|
|
|
|
}
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
return spew.Sdump(block), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("0x%x", ethash.SeedHash(number)), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrivateDebugAPI is the collection of Ethereum APIs exposed over the private
|
|
|
|
// 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}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChaindbProperty returns leveldb properties of the key-value database.
|
|
|
|
func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) {
|
|
|
|
if property == "" {
|
|
|
|
property = "leveldb.stats"
|
|
|
|
} else if !strings.HasPrefix(property, "leveldb.") {
|
|
|
|
property = "leveldb." + property
|
|
|
|
}
|
|
|
|
return api.b.ChainDb().Stat(property)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ChaindbCompact flattens the entire key-value database into a single level,
|
|
|
|
// removing all unused slots and merging all keys.
|
|
|
|
func (api *PrivateDebugAPI) ChaindbCompact() error {
|
|
|
|
for b := byte(0); b < 255; b++ {
|
|
|
|
log.Info("Compacting chain database", "range", fmt.Sprintf("0x%0.2X-0x%0.2X", b, b+1))
|
|
|
|
if err := api.b.ChainDb().Compact([]byte{b}, []byte{b + 1}); err != nil {
|
|
|
|
log.Error("Database compaction failed", "err", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetHead rewinds the head of the blockchain to a previous block.
|
|
|
|
func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) {
|
|
|
|
api.b.SetHead(uint64(number))
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicNetAPI offers network related RPC methods
|
|
|
|
type PublicNetAPI struct {
|
|
|
|
net *p2p.Server
|
|
|
|
networkVersion uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPublicNetAPI creates a new net API instance.
|
|
|
|
func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI {
|
|
|
|
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
|
|
|
|
func (s *PublicNetAPI) PeerCount() hexutil.Uint {
|
|
|
|
return hexutil.Uint(s.net.PeerCount())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Version returns the current ethereum protocol version.
|
|
|
|
func (s *PublicNetAPI) Version() string {
|
|
|
|
return fmt.Sprintf("%d", s.networkVersion)
|
|
|
|
}
|
|
|
|
|
|
|
|
// checkTxFee is an internal function used to check whether the fee of
|
|
|
|
// the given transaction is _reasonable_(under the cap).
|
|
|
|
func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error {
|
|
|
|
// Short circuit if there is no cap for transaction fee at all.
|
|
|
|
if cap == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
feeEth := new(big.Float).Quo(new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas))), new(big.Float).SetInt(big.NewInt(params.Ether)))
|
|
|
|
feeFloat, _ := feeEth.Float64()
|
|
|
|
if feeFloat > cap {
|
|
|
|
return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// toHexSlice creates a slice of hex-strings based on []byte.
|
|
|
|
func toHexSlice(b [][]byte) []string {
|
|
|
|
r := make([]string, len(b))
|
|
|
|
for i := range b {
|
|
|
|
r[i] = hexutil.Encode(b[i])
|
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|