mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 10:20:44 +00:00
add TraceCall, backend.StateAtBlock(), RPCGasCap
update gen_config.go by tool `gencodec`
This commit is contained in:
parent
9c03d01614
commit
0245344338
9 changed files with 278 additions and 22 deletions
|
|
@ -358,6 +358,11 @@ var (
|
||||||
Name: "vmdebug",
|
Name: "vmdebug",
|
||||||
Usage: "Record information useful for VM and contract debugging",
|
Usage: "Record information useful for VM and contract debugging",
|
||||||
}
|
}
|
||||||
|
RPCGlobalGasCapFlag = cli.Uint64Flag{
|
||||||
|
Name: "rpc.gascap",
|
||||||
|
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)",
|
||||||
|
Value: eth.DefaultConfig.RPCGasCap,
|
||||||
|
}
|
||||||
// Logging and debug settings
|
// Logging and debug settings
|
||||||
EthStatsURLFlag = cli.StringFlag{
|
EthStatsURLFlag = cli.StringFlag{
|
||||||
Name: "ethstats",
|
Name: "ethstats",
|
||||||
|
|
@ -1176,6 +1181,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
|
||||||
// TODO(fjl): force-enable this in --dev mode
|
// TODO(fjl): force-enable this in --dev mode
|
||||||
cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
|
cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
|
||||||
}
|
}
|
||||||
|
if cfg.RPCGasCap != 0 {
|
||||||
|
log.Info("Set global gas cap", "cap", cfg.RPCGasCap)
|
||||||
|
} else {
|
||||||
|
log.Info("Global gas cap disabled")
|
||||||
|
}
|
||||||
if ctx.GlobalIsSet(StoreRewardFlag.Name) {
|
if ctx.GlobalIsSet(StoreRewardFlag.Name) {
|
||||||
common.StoreRewardFolder = filepath.Join(stack.DataDir(), "XDC", "rewards")
|
common.StoreRewardFolder = filepath.Join(stack.DataDir(), "XDC", "rewards")
|
||||||
if _, err := os.Stat(common.StoreRewardFolder); os.IsNotExist(err) {
|
if _, err := os.Stat(common.StoreRewardFolder); os.IsNotExist(err) {
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,10 @@ func (b *EthApiBackend) EventMux() *event.TypeMux {
|
||||||
return b.eth.EventMux()
|
return b.eth.EventMux()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) RPCGasCap() uint64 {
|
||||||
|
return b.eth.config.RPCGasCap
|
||||||
|
}
|
||||||
|
|
||||||
func (b *EthApiBackend) AccountManager() *accounts.Manager {
|
func (b *EthApiBackend) AccountManager() *accounts.Manager {
|
||||||
return b.eth.AccountManager()
|
return b.eth.AccountManager()
|
||||||
}
|
}
|
||||||
|
|
@ -377,6 +381,10 @@ func (b *EthApiBackend) GetEngine() consensus.Engine {
|
||||||
return b.eth.engine
|
return b.eth.engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (*state.StateDB, error) {
|
||||||
|
return b.eth.stateAtBlock(block, reexec, base, checkLive)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *EthApiBackend) GetRewardByHash(hash common.Hash) map[string]map[string]map[string]*big.Int {
|
func (s *EthApiBackend) GetRewardByHash(hash common.Hash) map[string]map[string]map[string]*big.Int {
|
||||||
header := s.eth.blockchain.GetHeaderByHash(hash)
|
header := s.eth.blockchain.GetHeaderByHash(hash)
|
||||||
if header != nil {
|
if header != nil {
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,13 @@ type txTraceContext struct {
|
||||||
block common.Hash // Hash of the block containing the transaction
|
block common.Hash // Hash of the block containing the transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraceCallConfig is the config for traceCall API. It holds one more
|
||||||
|
// field to override the state for tracing.
|
||||||
|
type TraceCallConfig struct {
|
||||||
|
TraceConfig
|
||||||
|
StateOverrides *ethapi.StateOverride
|
||||||
|
}
|
||||||
|
|
||||||
// txTraceResult is the result of a single transaction trace.
|
// txTraceResult is the result of a single transaction trace.
|
||||||
type txTraceResult struct {
|
type txTraceResult struct {
|
||||||
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
|
||||||
|
|
@ -622,6 +629,59 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha
|
||||||
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
|
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
||||||
|
// created during the execution of EVM if the given transaction was added on
|
||||||
|
// top of the provided block and returns them as a JSON object.
|
||||||
|
// You can provide -2 as a block number to trace on top of the pending block.
|
||||||
|
func (api *PrivateDebugAPI) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
|
||||||
|
// Try to retrieve the specified block
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
block *types.Block
|
||||||
|
)
|
||||||
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
|
block, err = api.eth.ApiBackend.BlockByHash(ctx, hash)
|
||||||
|
} else if number, ok := blockNrOrHash.Number(); ok {
|
||||||
|
if number == rpc.PendingBlockNumber {
|
||||||
|
// We don't have access to the miner here. For tracing 'future' transactions,
|
||||||
|
// it can be done with block- and state-overrides instead, which offers
|
||||||
|
// more flexibility and stability than trying to trace on 'pending', since
|
||||||
|
// the contents of 'pending' is unstable and probably not a true representation
|
||||||
|
// of what the next actual block is likely to contain.
|
||||||
|
return nil, errors.New("tracing on top of pending is not supported")
|
||||||
|
}
|
||||||
|
block, err = api.eth.ApiBackend.BlockByNumber(ctx, number)
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("invalid arguments; neither block nor hash specified")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// try to recompute the state
|
||||||
|
reexec := defaultTraceReexec
|
||||||
|
if config != nil && config.Reexec != nil {
|
||||||
|
reexec = *config.Reexec
|
||||||
|
}
|
||||||
|
statedb, err := api.eth.ApiBackend.StateAtBlock(ctx, block, reexec, nil, true)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// Apply the customized state rules if required.
|
||||||
|
if config != nil {
|
||||||
|
if err := config.StateOverrides.Apply(statedb); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Execute the trace
|
||||||
|
msg := args.ToMessage(api.eth.ApiBackend, block.Number(), api.eth.ApiBackend.RPCGasCap())
|
||||||
|
vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil)
|
||||||
|
var traceConfig *TraceConfig
|
||||||
|
if config != nil {
|
||||||
|
traceConfig = &config.TraceConfig
|
||||||
|
}
|
||||||
|
return api.traceTx(ctx, msg, new(txTraceContext), vmctx, statedb, traceConfig)
|
||||||
|
}
|
||||||
|
|
||||||
// traceTx configures a new tracer according to the provided configuration, and
|
// traceTx configures a new tracer according to the provided configuration, and
|
||||||
// executes the given message in the provided environment. The return value will
|
// executes the given message in the provided environment. The return value will
|
||||||
// be tracer dependent.
|
// be tracer dependent.
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,8 @@ var DefaultConfig = Config{
|
||||||
TrieTimeout: 5 * time.Minute,
|
TrieTimeout: 5 * time.Minute,
|
||||||
GasPrice: big.NewInt(0.25 * params.Shannon),
|
GasPrice: big.NewInt(0.25 * params.Shannon),
|
||||||
|
|
||||||
TxPool: core.DefaultTxPoolConfig,
|
TxPool: core.DefaultTxPoolConfig,
|
||||||
|
RPCGasCap: 25000000,
|
||||||
GPO: gasprice.Config{
|
GPO: gasprice.Config{
|
||||||
Blocks: 20,
|
Blocks: 20,
|
||||||
Percentile: 60,
|
Percentile: 60,
|
||||||
|
|
@ -114,6 +115,9 @@ type Config struct {
|
||||||
|
|
||||||
// Miscellaneous options
|
// Miscellaneous options
|
||||||
DocRoot string `toml:"-"`
|
DocRoot string `toml:"-"`
|
||||||
|
|
||||||
|
// RPCGasCap is the global gas cap for eth-call variants.
|
||||||
|
RPCGasCap uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type configMarshaling struct {
|
type configMarshaling struct {
|
||||||
|
|
|
||||||
|
|
@ -4,46 +4,52 @@ package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core"
|
"github.com/XinFinOrg/XDPoSChain/core"
|
||||||
"github.com/XinFinOrg/XDPoSChain/eth/downloader"
|
"github.com/XinFinOrg/XDPoSChain/eth/downloader"
|
||||||
"github.com/XinFinOrg/XDPoSChain/eth/gasprice"
|
"github.com/XinFinOrg/XDPoSChain/eth/gasprice"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = (*configMarshaling)(nil)
|
// MarshalTOML marshals as TOML.
|
||||||
|
|
||||||
func (c Config) MarshalTOML() (interface{}, error) {
|
func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Genesis *core.Genesis `toml:",omitempty"`
|
Genesis *core.Genesis `toml:",omitempty"`
|
||||||
NetworkId uint64
|
NetworkId uint64
|
||||||
SyncMode downloader.SyncMode
|
SyncMode downloader.SyncMode
|
||||||
|
NoPruning bool
|
||||||
LightServ int `toml:",omitempty"`
|
LightServ int `toml:",omitempty"`
|
||||||
LightPeers int `toml:",omitempty"`
|
LightPeers int `toml:",omitempty"`
|
||||||
SkipBcVersionCheck bool `toml:"-"`
|
SkipBcVersionCheck bool `toml:"-"`
|
||||||
DatabaseHandles int `toml:"-"`
|
DatabaseHandles int `toml:"-"`
|
||||||
DatabaseCache int
|
DatabaseCache int
|
||||||
|
TrieCache int
|
||||||
|
TrieTimeout time.Duration
|
||||||
Etherbase common.Address `toml:",omitempty"`
|
Etherbase common.Address `toml:",omitempty"`
|
||||||
MinerThreads int `toml:",omitempty"`
|
MinerThreads int `toml:",omitempty"`
|
||||||
ExtraData hexutil.Bytes `toml:",omitempty"`
|
ExtraData []byte `toml:",omitempty"`
|
||||||
GasPrice *big.Int
|
GasPrice *big.Int
|
||||||
Ethash ethash.Config
|
Ethash ethash.Config
|
||||||
TxPool core.TxPoolConfig
|
TxPool core.TxPoolConfig
|
||||||
GPO gasprice.Config
|
GPO gasprice.Config
|
||||||
EnablePreimageRecording bool
|
EnablePreimageRecording bool
|
||||||
DocRoot string `toml:"-"`
|
DocRoot string `toml:"-"`
|
||||||
|
RPCGasCap uint64
|
||||||
}
|
}
|
||||||
var enc Config
|
var enc Config
|
||||||
enc.Genesis = c.Genesis
|
enc.Genesis = c.Genesis
|
||||||
enc.NetworkId = c.NetworkId
|
enc.NetworkId = c.NetworkId
|
||||||
enc.SyncMode = c.SyncMode
|
enc.SyncMode = c.SyncMode
|
||||||
|
enc.NoPruning = c.NoPruning
|
||||||
enc.LightServ = c.LightServ
|
enc.LightServ = c.LightServ
|
||||||
enc.LightPeers = c.LightPeers
|
enc.LightPeers = c.LightPeers
|
||||||
enc.SkipBcVersionCheck = c.SkipBcVersionCheck
|
enc.SkipBcVersionCheck = c.SkipBcVersionCheck
|
||||||
enc.DatabaseHandles = c.DatabaseHandles
|
enc.DatabaseHandles = c.DatabaseHandles
|
||||||
enc.DatabaseCache = c.DatabaseCache
|
enc.DatabaseCache = c.DatabaseCache
|
||||||
|
enc.TrieCache = c.TrieCache
|
||||||
|
enc.TrieTimeout = c.TrieTimeout
|
||||||
enc.Etherbase = c.Etherbase
|
enc.Etherbase = c.Etherbase
|
||||||
enc.MinerThreads = c.MinerThreads
|
enc.MinerThreads = c.MinerThreads
|
||||||
enc.ExtraData = c.ExtraData
|
enc.ExtraData = c.ExtraData
|
||||||
|
|
@ -53,28 +59,34 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
enc.GPO = c.GPO
|
enc.GPO = c.GPO
|
||||||
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
||||||
enc.DocRoot = c.DocRoot
|
enc.DocRoot = c.DocRoot
|
||||||
|
enc.RPCGasCap = c.RPCGasCap
|
||||||
return &enc, nil
|
return &enc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalTOML unmarshals from TOML.
|
||||||
func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Genesis *core.Genesis `toml:",omitempty"`
|
Genesis *core.Genesis `toml:",omitempty"`
|
||||||
NetworkId *uint64
|
NetworkId *uint64
|
||||||
SyncMode *downloader.SyncMode
|
SyncMode *downloader.SyncMode
|
||||||
|
NoPruning *bool
|
||||||
LightServ *int `toml:",omitempty"`
|
LightServ *int `toml:",omitempty"`
|
||||||
LightPeers *int `toml:",omitempty"`
|
LightPeers *int `toml:",omitempty"`
|
||||||
SkipBcVersionCheck *bool `toml:"-"`
|
SkipBcVersionCheck *bool `toml:"-"`
|
||||||
DatabaseHandles *int `toml:"-"`
|
DatabaseHandles *int `toml:"-"`
|
||||||
DatabaseCache *int
|
DatabaseCache *int
|
||||||
|
TrieCache *int
|
||||||
|
TrieTimeout *time.Duration
|
||||||
Etherbase *common.Address `toml:",omitempty"`
|
Etherbase *common.Address `toml:",omitempty"`
|
||||||
MinerThreads *int `toml:",omitempty"`
|
MinerThreads *int `toml:",omitempty"`
|
||||||
ExtraData *hexutil.Bytes `toml:",omitempty"`
|
ExtraData []byte `toml:",omitempty"`
|
||||||
GasPrice *big.Int
|
GasPrice *big.Int
|
||||||
Ethash *ethash.Config
|
Ethash *ethash.Config
|
||||||
TxPool *core.TxPoolConfig
|
TxPool *core.TxPoolConfig
|
||||||
GPO *gasprice.Config
|
GPO *gasprice.Config
|
||||||
EnablePreimageRecording *bool
|
EnablePreimageRecording *bool
|
||||||
DocRoot *string `toml:"-"`
|
DocRoot *string `toml:"-"`
|
||||||
|
RPCGasCap *uint64
|
||||||
}
|
}
|
||||||
var dec Config
|
var dec Config
|
||||||
if err := unmarshal(&dec); err != nil {
|
if err := unmarshal(&dec); err != nil {
|
||||||
|
|
@ -89,6 +101,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
if dec.SyncMode != nil {
|
if dec.SyncMode != nil {
|
||||||
c.SyncMode = *dec.SyncMode
|
c.SyncMode = *dec.SyncMode
|
||||||
}
|
}
|
||||||
|
if dec.NoPruning != nil {
|
||||||
|
c.NoPruning = *dec.NoPruning
|
||||||
|
}
|
||||||
if dec.LightServ != nil {
|
if dec.LightServ != nil {
|
||||||
c.LightServ = *dec.LightServ
|
c.LightServ = *dec.LightServ
|
||||||
}
|
}
|
||||||
|
|
@ -104,6 +119,12 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
if dec.DatabaseCache != nil {
|
if dec.DatabaseCache != nil {
|
||||||
c.DatabaseCache = *dec.DatabaseCache
|
c.DatabaseCache = *dec.DatabaseCache
|
||||||
}
|
}
|
||||||
|
if dec.TrieCache != nil {
|
||||||
|
c.TrieCache = *dec.TrieCache
|
||||||
|
}
|
||||||
|
if dec.TrieTimeout != nil {
|
||||||
|
c.TrieTimeout = *dec.TrieTimeout
|
||||||
|
}
|
||||||
if dec.Etherbase != nil {
|
if dec.Etherbase != nil {
|
||||||
c.Etherbase = *dec.Etherbase
|
c.Etherbase = *dec.Etherbase
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +132,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
c.MinerThreads = *dec.MinerThreads
|
c.MinerThreads = *dec.MinerThreads
|
||||||
}
|
}
|
||||||
if dec.ExtraData != nil {
|
if dec.ExtraData != nil {
|
||||||
c.ExtraData = *dec.ExtraData
|
c.ExtraData = dec.ExtraData
|
||||||
}
|
}
|
||||||
if dec.GasPrice != nil {
|
if dec.GasPrice != nil {
|
||||||
c.GasPrice = dec.GasPrice
|
c.GasPrice = dec.GasPrice
|
||||||
|
|
@ -131,5 +152,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
if dec.DocRoot != nil {
|
if dec.DocRoot != nil {
|
||||||
c.DocRoot = *dec.DocRoot
|
c.DocRoot = *dec.DocRoot
|
||||||
}
|
}
|
||||||
|
if dec.RPCGasCap != nil {
|
||||||
|
c.RPCGasCap = *dec.RPCGasCap
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
137
eth/state_accessor.go
Normal file
137
eth/state_accessor.go
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright 2021 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 eth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/trie"
|
||||||
|
)
|
||||||
|
|
||||||
|
// stateAtBlock retrieves the state database associated with a certain block.
|
||||||
|
// If no state is locally available for the given block, a number of blocks
|
||||||
|
// are attempted to be reexecuted to generate the desired state. The optional
|
||||||
|
// base layer statedb can be passed then it's regarded as the statedb of the
|
||||||
|
// parent block.
|
||||||
|
func (eth *Ethereum) stateAtBlock(block *types.Block, reexec uint64, base *state.StateDB, checkLive bool) (statedb *state.StateDB, err error) {
|
||||||
|
var (
|
||||||
|
current *types.Block
|
||||||
|
database state.Database
|
||||||
|
report = true
|
||||||
|
origin = block.NumberU64()
|
||||||
|
)
|
||||||
|
// Check the live database first if we have the state fully available, use that.
|
||||||
|
if checkLive {
|
||||||
|
statedb, err = eth.blockchain.StateAt(block.Root())
|
||||||
|
if err == nil {
|
||||||
|
return statedb, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if base != nil {
|
||||||
|
// The optional base statedb is given, mark the start point as parent block
|
||||||
|
statedb, database, report = base, base.Database(), false
|
||||||
|
current = eth.blockchain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
|
} else {
|
||||||
|
// Otherwise try to reexec blocks until we find a state or reach our limit
|
||||||
|
current = block
|
||||||
|
|
||||||
|
// Create an ephemeral trie.Database for isolating the live one. Otherwise
|
||||||
|
// the internal junks created by tracing will be persisted into the disk.
|
||||||
|
database = state.NewDatabaseWithCache(eth.chainDb, 16)
|
||||||
|
// If we didn't check the dirty database, do check the clean one, otherwise
|
||||||
|
// we would rewind past a persisted block (specific corner case is chain
|
||||||
|
// tracing from the genesis).
|
||||||
|
if !checkLive {
|
||||||
|
statedb, err = state.New(current.Root(), database)
|
||||||
|
if err == nil {
|
||||||
|
return statedb, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Database does not have the state for the given block, try to regenerate
|
||||||
|
for i := uint64(0); i < reexec; i++ {
|
||||||
|
if current.NumberU64() == 0 {
|
||||||
|
return nil, errors.New("genesis state is missing")
|
||||||
|
}
|
||||||
|
parent := eth.blockchain.GetBlock(current.ParentHash(), current.NumberU64()-1)
|
||||||
|
if parent == nil {
|
||||||
|
return nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1)
|
||||||
|
}
|
||||||
|
current = parent
|
||||||
|
|
||||||
|
statedb, err = state.New(current.Root(), database)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
switch err.(type) {
|
||||||
|
case *trie.MissingNodeError:
|
||||||
|
return nil, fmt.Errorf("required historical state unavailable (reexec=%d)", reexec)
|
||||||
|
default:
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// State was available at historical point, regenerate
|
||||||
|
var (
|
||||||
|
start = time.Now()
|
||||||
|
logged time.Time
|
||||||
|
parent common.Hash
|
||||||
|
)
|
||||||
|
for current.NumberU64() < origin {
|
||||||
|
// Print progress logs if long enough time elapsed
|
||||||
|
if time.Since(logged) > 8*time.Second && report {
|
||||||
|
log.Info("Regenerating historical state", "block", current.NumberU64()+1, "target", origin, "remaining", origin-current.NumberU64()-1, "elapsed", time.Since(start))
|
||||||
|
logged = time.Now()
|
||||||
|
}
|
||||||
|
// Retrieve the next block to regenerate and process it
|
||||||
|
next := current.NumberU64() + 1
|
||||||
|
if current = eth.blockchain.GetBlockByNumber(next); current == nil {
|
||||||
|
return nil, fmt.Errorf("block #%d not found", next)
|
||||||
|
}
|
||||||
|
_, _, _, err := eth.blockchain.Processor().Process(current, statedb, nil, vm.Config{}, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err)
|
||||||
|
}
|
||||||
|
// Finalize the state so any modifications are written to the trie
|
||||||
|
root, err := statedb.Commit(eth.blockchain.Config().IsEIP158(current.Number()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
statedb, err = state.New(root, database)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err)
|
||||||
|
}
|
||||||
|
database.TrieDB().Reference(root, common.Hash{})
|
||||||
|
if parent != (common.Hash{}) {
|
||||||
|
database.TrieDB().Dereference(parent)
|
||||||
|
}
|
||||||
|
parent = root
|
||||||
|
}
|
||||||
|
if report {
|
||||||
|
nodes, imgs := database.TrieDB().Size()
|
||||||
|
log.Info("Historical state regenerated", "block", current.NumberU64(), "elapsed", time.Since(start), "nodes", nodes, "preimages", imgs)
|
||||||
|
}
|
||||||
|
return statedb, nil
|
||||||
|
}
|
||||||
|
|
@ -1167,7 +1167,7 @@ type CallArgs struct {
|
||||||
|
|
||||||
// ToMessage converts CallArgs to the Message type used by the core evm
|
// ToMessage converts CallArgs to the Message type used by the core evm
|
||||||
// TODO: set balanceTokenFee
|
// TODO: set balanceTokenFee
|
||||||
func (args *CallArgs) ToMessage(b Backend, number *big.Int) types.Message {
|
func (args *CallArgs) ToMessage(b Backend, number *big.Int, globalGasCap uint64) types.Message {
|
||||||
// Set sender address or use a default if none specified
|
// Set sender address or use a default if none specified
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
if args.From == nil || *args.From == (common.Address{}) {
|
if args.From == nil || *args.From == (common.Address{}) {
|
||||||
|
|
@ -1181,14 +1181,17 @@ func (args *CallArgs) ToMessage(b Backend, number *big.Int) types.Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set default gas & gas price if none were set
|
// Set default gas & gas price if none were set
|
||||||
var gas uint64
|
gas := globalGasCap
|
||||||
if args.Gas != nil {
|
|
||||||
gas = *(*uint64)(args.Gas)
|
|
||||||
}
|
|
||||||
if gas == 0 {
|
if gas == 0 {
|
||||||
gas = math.MaxUint64 / 2
|
gas = uint64(math.MaxUint64 / 2)
|
||||||
|
}
|
||||||
|
if args.Gas != nil {
|
||||||
|
gas = uint64(*args.Gas)
|
||||||
|
}
|
||||||
|
if globalGasCap != 0 && globalGasCap < gas {
|
||||||
|
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
|
||||||
|
gas = globalGasCap
|
||||||
}
|
}
|
||||||
|
|
||||||
gasPrice := new(big.Int)
|
gasPrice := new(big.Int)
|
||||||
if args.GasPrice != nil {
|
if args.GasPrice != nil {
|
||||||
gasPrice = args.GasPrice.ToInt()
|
gasPrice = args.GasPrice.ToInt()
|
||||||
|
|
@ -1220,7 +1223,7 @@ func (args *CallArgs) ToMessage(b Backend, number *big.Int) types.Message {
|
||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error, error) {
|
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, vmCfg vm.Config, timeout time.Duration, globalGasCap uint64) ([]byte, uint64, bool, error, error) {
|
||||||
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
|
||||||
|
|
||||||
statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
statedb, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
|
|
@ -1231,7 +1234,7 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
|
||||||
return nil, 0, false, err, nil
|
return nil, 0, false, err, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := args.ToMessage(b, header.Number)
|
msg := args.ToMessage(b, header.Number, globalGasCap)
|
||||||
|
|
||||||
// Setup context so it may be cancelled the call has completed
|
// Setup context so it may be cancelled the call has completed
|
||||||
// or, in case of unmetered gas, setup a context with a timeout.
|
// or, in case of unmetered gas, setup a context with a timeout.
|
||||||
|
|
@ -1325,7 +1328,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOr
|
||||||
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
latest := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
|
||||||
blockNrOrHash = &latest
|
blockNrOrHash = &latest
|
||||||
}
|
}
|
||||||
result, _, failed, err, vmErr := DoCall(ctx, s.b, args, *blockNrOrHash, overrides, vm.Config{}, 5*time.Second)
|
result, _, failed, err, vmErr := DoCall(ctx, s.b, args, *blockNrOrHash, overrides, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1337,7 +1340,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOr
|
||||||
return (hexutil.Bytes)(result), vmErr
|
return (hexutil.Bytes)(result), vmErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Uint64, error) {
|
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, gasCap uint64) (hexutil.Uint64, error) {
|
||||||
// Retrieve the base state and mutate it with any overrides
|
// Retrieve the base state and mutate it with any overrides
|
||||||
state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
|
|
@ -1370,13 +1373,18 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
|
||||||
}
|
}
|
||||||
hi = block.GasLimit()
|
hi = block.GasLimit()
|
||||||
}
|
}
|
||||||
|
// 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
|
cap = hi
|
||||||
|
|
||||||
// Create a helper to check if a gas allowance results in an executable transaction
|
// Create a helper to check if a gas allowance results in an executable transaction
|
||||||
executable := func(gas uint64) (bool, []byte, error, error) {
|
executable := func(gas uint64) (bool, []byte, error, error) {
|
||||||
args.Gas = (*hexutil.Uint64)(&gas)
|
args.Gas = (*hexutil.Uint64)(&gas)
|
||||||
|
|
||||||
res, _, failed, err, vmErr := DoCall(ctx, b, args, blockNrOrHash, nil, vm.Config{}, 0)
|
res, _, failed, err, vmErr := DoCall(ctx, b, args, blockNrOrHash, nil, vm.Config{}, 0, gasCap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, vm.ErrOutOfGas) || errors.Is(err, core.ErrIntrinsicGas) {
|
if errors.Is(err, vm.ErrOutOfGas) || errors.Is(err, core.ErrIntrinsicGas) {
|
||||||
return false, nil, nil, nil // Special case, raise gas limit
|
return false, nil, nil, nil // Special case, raise gas limit
|
||||||
|
|
@ -1451,7 +1459,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs, bl
|
||||||
if blockNrOrHash != nil {
|
if blockNrOrHash != nil {
|
||||||
bNrOrHash = *blockNrOrHash
|
bNrOrHash = *blockNrOrHash
|
||||||
}
|
}
|
||||||
return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides)
|
return DoEstimateGas(ctx, s.b, args, bNrOrHash, overrides, s.b.RPCGasCap())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionResult groups all structured logs emitted by the EVM
|
// ExecutionResult groups all structured logs emitted by the EVM
|
||||||
|
|
@ -2201,7 +2209,7 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
|
||||||
AccessList: args.AccessList,
|
AccessList: args.AccessList,
|
||||||
}
|
}
|
||||||
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
|
||||||
estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil)
|
estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, nil, b.RPCGasCap())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ type Backend interface {
|
||||||
ChainDb() ethdb.Database
|
ChainDb() ethdb.Database
|
||||||
EventMux() *event.TypeMux
|
EventMux() *event.TypeMux
|
||||||
AccountManager() *accounts.Manager
|
AccountManager() *accounts.Manager
|
||||||
|
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
|
||||||
XDCxService() *XDCx.XDCX
|
XDCxService() *XDCx.XDCX
|
||||||
LendingService() *XDCxlending.Lending
|
LendingService() *XDCxlending.Lending
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -269,6 +269,10 @@ func (b *LesApiBackend) AccountManager() *accounts.Manager {
|
||||||
return b.eth.accountManager
|
return b.eth.accountManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) RPCGasCap() uint64 {
|
||||||
|
return b.eth.config.RPCGasCap
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
|
func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
|
||||||
if b.eth.bloomIndexer == nil {
|
if b.eth.bloomIndexer == nil {
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue