mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
commit
d6a5095fa1
10 changed files with 284 additions and 22 deletions
|
|
@ -118,7 +118,7 @@ var (
|
|||
Enable0xPrefixFlag = cli.BoolFlag{
|
||||
Name: "enable-0x-prefix",
|
||||
Usage: "Addres use 0x-prefix (Deprecated: this is on by default, to use xdc prefix use --enable-xdc-prefix)",
|
||||
}
|
||||
}
|
||||
EnableXDCPrefixFlag = cli.BoolFlag{
|
||||
Name: "enable-xdc-prefix",
|
||||
Usage: "Addres use xdc-prefix (default = false)",
|
||||
|
|
@ -358,6 +358,11 @@ var (
|
|||
Name: "vmdebug",
|
||||
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
|
||||
EthStatsURLFlag = cli.StringFlag{
|
||||
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
|
||||
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) {
|
||||
common.StoreRewardFolder = filepath.Join(stack.DataDir(), "XDC", "rewards")
|
||||
if _, err := os.Stat(common.StoreRewardFolder); os.IsNotExist(err) {
|
||||
|
|
|
|||
|
|
@ -348,6 +348,10 @@ func (b *EthApiBackend) EventMux() *event.TypeMux {
|
|||
return b.eth.EventMux()
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) RPCGasCap() uint64 {
|
||||
return b.eth.config.RPCGasCap
|
||||
}
|
||||
|
||||
func (b *EthApiBackend) AccountManager() *accounts.Manager {
|
||||
return b.eth.AccountManager()
|
||||
}
|
||||
|
|
@ -377,6 +381,10 @@ func (b *EthApiBackend) GetEngine() consensus.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 {
|
||||
header := s.eth.blockchain.GetHeaderByHash(hash)
|
||||
if header != nil {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,13 @@ type txTraceContext struct {
|
|||
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.
|
||||
type txTraceResult struct {
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
// executes the given message in the provided environment. The return value will
|
||||
// be tracer dependent.
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ var DefaultConfig = Config{
|
|||
TrieTimeout: 5 * time.Minute,
|
||||
GasPrice: big.NewInt(0.25 * params.Shannon),
|
||||
|
||||
TxPool: core.DefaultTxPoolConfig,
|
||||
TxPool: core.DefaultTxPoolConfig,
|
||||
RPCGasCap: 25000000,
|
||||
GPO: gasprice.Config{
|
||||
Blocks: 20,
|
||||
Percentile: 60,
|
||||
|
|
@ -114,6 +115,9 @@ type Config struct {
|
|||
|
||||
// Miscellaneous options
|
||||
DocRoot string `toml:"-"`
|
||||
|
||||
// RPCGasCap is the global gas cap for eth-call variants.
|
||||
RPCGasCap uint64
|
||||
}
|
||||
|
||||
type configMarshaling struct {
|
||||
|
|
|
|||
|
|
@ -4,46 +4,52 @@ package eth
|
|||
|
||||
import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/XinFinOrg/XDPoSChain/consensus/ethash"
|
||||
"github.com/XinFinOrg/XDPoSChain/core"
|
||||
"github.com/XinFinOrg/XDPoSChain/eth/downloader"
|
||||
"github.com/XinFinOrg/XDPoSChain/eth/gasprice"
|
||||
)
|
||||
|
||||
var _ = (*configMarshaling)(nil)
|
||||
|
||||
// MarshalTOML marshals as TOML.
|
||||
func (c Config) MarshalTOML() (interface{}, error) {
|
||||
type Config struct {
|
||||
Genesis *core.Genesis `toml:",omitempty"`
|
||||
NetworkId uint64
|
||||
SyncMode downloader.SyncMode
|
||||
NoPruning bool
|
||||
LightServ int `toml:",omitempty"`
|
||||
LightPeers int `toml:",omitempty"`
|
||||
SkipBcVersionCheck bool `toml:"-"`
|
||||
DatabaseHandles int `toml:"-"`
|
||||
DatabaseCache int
|
||||
TrieCache int
|
||||
TrieTimeout time.Duration
|
||||
Etherbase common.Address `toml:",omitempty"`
|
||||
MinerThreads int `toml:",omitempty"`
|
||||
ExtraData hexutil.Bytes `toml:",omitempty"`
|
||||
ExtraData []byte `toml:",omitempty"`
|
||||
GasPrice *big.Int
|
||||
Ethash ethash.Config
|
||||
TxPool core.TxPoolConfig
|
||||
GPO gasprice.Config
|
||||
EnablePreimageRecording bool
|
||||
DocRoot string `toml:"-"`
|
||||
RPCGasCap uint64
|
||||
}
|
||||
var enc Config
|
||||
enc.Genesis = c.Genesis
|
||||
enc.NetworkId = c.NetworkId
|
||||
enc.SyncMode = c.SyncMode
|
||||
enc.NoPruning = c.NoPruning
|
||||
enc.LightServ = c.LightServ
|
||||
enc.LightPeers = c.LightPeers
|
||||
enc.SkipBcVersionCheck = c.SkipBcVersionCheck
|
||||
enc.DatabaseHandles = c.DatabaseHandles
|
||||
enc.DatabaseCache = c.DatabaseCache
|
||||
enc.TrieCache = c.TrieCache
|
||||
enc.TrieTimeout = c.TrieTimeout
|
||||
enc.Etherbase = c.Etherbase
|
||||
enc.MinerThreads = c.MinerThreads
|
||||
enc.ExtraData = c.ExtraData
|
||||
|
|
@ -53,28 +59,34 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
enc.GPO = c.GPO
|
||||
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
||||
enc.DocRoot = c.DocRoot
|
||||
enc.RPCGasCap = c.RPCGasCap
|
||||
return &enc, nil
|
||||
}
|
||||
|
||||
// UnmarshalTOML unmarshals from TOML.
|
||||
func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
type Config struct {
|
||||
Genesis *core.Genesis `toml:",omitempty"`
|
||||
NetworkId *uint64
|
||||
SyncMode *downloader.SyncMode
|
||||
NoPruning *bool
|
||||
LightServ *int `toml:",omitempty"`
|
||||
LightPeers *int `toml:",omitempty"`
|
||||
SkipBcVersionCheck *bool `toml:"-"`
|
||||
DatabaseHandles *int `toml:"-"`
|
||||
DatabaseCache *int
|
||||
TrieCache *int
|
||||
TrieTimeout *time.Duration
|
||||
Etherbase *common.Address `toml:",omitempty"`
|
||||
MinerThreads *int `toml:",omitempty"`
|
||||
ExtraData *hexutil.Bytes `toml:",omitempty"`
|
||||
ExtraData []byte `toml:",omitempty"`
|
||||
GasPrice *big.Int
|
||||
Ethash *ethash.Config
|
||||
TxPool *core.TxPoolConfig
|
||||
GPO *gasprice.Config
|
||||
EnablePreimageRecording *bool
|
||||
DocRoot *string `toml:"-"`
|
||||
RPCGasCap *uint64
|
||||
}
|
||||
var dec Config
|
||||
if err := unmarshal(&dec); err != nil {
|
||||
|
|
@ -89,6 +101,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.SyncMode != nil {
|
||||
c.SyncMode = *dec.SyncMode
|
||||
}
|
||||
if dec.NoPruning != nil {
|
||||
c.NoPruning = *dec.NoPruning
|
||||
}
|
||||
if dec.LightServ != nil {
|
||||
c.LightServ = *dec.LightServ
|
||||
}
|
||||
|
|
@ -104,6 +119,12 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.DatabaseCache != nil {
|
||||
c.DatabaseCache = *dec.DatabaseCache
|
||||
}
|
||||
if dec.TrieCache != nil {
|
||||
c.TrieCache = *dec.TrieCache
|
||||
}
|
||||
if dec.TrieTimeout != nil {
|
||||
c.TrieTimeout = *dec.TrieTimeout
|
||||
}
|
||||
if dec.Etherbase != nil {
|
||||
c.Etherbase = *dec.Etherbase
|
||||
}
|
||||
|
|
@ -111,7 +132,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
c.MinerThreads = *dec.MinerThreads
|
||||
}
|
||||
if dec.ExtraData != nil {
|
||||
c.ExtraData = *dec.ExtraData
|
||||
c.ExtraData = dec.ExtraData
|
||||
}
|
||||
if dec.GasPrice != nil {
|
||||
c.GasPrice = dec.GasPrice
|
||||
|
|
@ -131,5 +152,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.DocRoot != nil {
|
||||
c.DocRoot = *dec.DocRoot
|
||||
}
|
||||
if dec.RPCGasCap != nil {
|
||||
c.RPCGasCap = *dec.RPCGasCap
|
||||
}
|
||||
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
|
||||
// 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
|
||||
var addr 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
|
||||
var gas uint64
|
||||
if args.Gas != nil {
|
||||
gas = *(*uint64)(args.Gas)
|
||||
}
|
||||
gas := globalGasCap
|
||||
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)
|
||||
if args.GasPrice != nil {
|
||||
gasPrice = args.GasPrice.ToInt()
|
||||
|
|
@ -1220,7 +1223,7 @@ func (args *CallArgs) ToMessage(b Backend, number *big.Int) types.Message {
|
|||
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())
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
msg := args.ToMessage(b, header.Number)
|
||||
msg := args.ToMessage(b, header.Number, globalGasCap)
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
// 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)
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1337,7 +1340,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOr
|
|||
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
|
||||
state, _, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
if state == nil || err != nil {
|
||||
|
|
@ -1370,13 +1373,18 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
|
|||
}
|
||||
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
|
||||
|
||||
// Create a helper to check if a gas allowance results in an executable transaction
|
||||
executable := func(gas uint64) (bool, []byte, error, error) {
|
||||
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 errors.Is(err, vm.ErrOutOfGas) || errors.Is(err, core.ErrIntrinsicGas) {
|
||||
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 {
|
||||
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
|
||||
|
|
@ -2201,7 +2209,7 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
|
|||
AccessList: args.AccessList,
|
||||
}
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ type Backend interface {
|
|||
ChainDb() ethdb.Database
|
||||
EventMux() *event.TypeMux
|
||||
AccountManager() *accounts.Manager
|
||||
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
|
||||
XDCxService() *XDCx.XDCX
|
||||
LendingService() *XDCxlending.Lending
|
||||
|
||||
|
|
|
|||
|
|
@ -420,6 +420,12 @@ web3._extend({
|
|||
params: 2,
|
||||
inputFormatter: [null, null]
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'traceCall',
|
||||
call: 'debug_traceCall',
|
||||
params: 3,
|
||||
inputFormatter: [null, null, null]
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'preimage',
|
||||
call: 'debug_preimage',
|
||||
|
|
|
|||
|
|
@ -269,6 +269,10 @@ func (b *LesApiBackend) AccountManager() *accounts.Manager {
|
|||
return b.eth.accountManager
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) RPCGasCap() uint64 {
|
||||
return b.eth.config.RPCGasCap
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
|
||||
if b.eth.bloomIndexer == nil {
|
||||
return 0, 0
|
||||
|
|
|
|||
Loading…
Reference in a new issue