rpc, internal/ethapi: default rpc gascap at 25M + better error message (#21229)

* rpc, internal/ethapi: default rpc gascap at 50M + better error message

* eth,internal: make globalgascap uint64

* core/tests: fix compilation failure

* eth/config: gascap at 25M + minor review concerns
This commit is contained in:
Martin Holst Swende 2020-07-01 19:54:21 +02:00 committed by GitHub
parent af5c97aebe
commit 12867d152c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 31 additions and 21 deletions

View File

@ -476,7 +476,8 @@ var (
} }
RPCGlobalGasCap = cli.Uint64Flag{ RPCGlobalGasCap = cli.Uint64Flag{
Name: "rpc.gascap", Name: "rpc.gascap",
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas", Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)",
Value: eth.DefaultConfig.RPCGasCap,
} }
RPCGlobalTxFeeCap = cli.Float64Flag{ RPCGlobalTxFeeCap = cli.Float64Flag{
Name: "rpc.txfeecap", Name: "rpc.txfeecap",
@ -1563,7 +1564,12 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name) cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
} }
if ctx.GlobalIsSet(RPCGlobalGasCap.Name) { if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name)) cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCap.Name)
}
if cfg.RPCGasCap != 0 {
log.Info("Set global gas cap", "cap", cfg.RPCGasCap)
} else {
log.Info("Global gas cap disabled")
} }
if ctx.GlobalIsSet(RPCGlobalTxFeeCap.Name) { if ctx.GlobalIsSet(RPCGlobalTxFeeCap.Name) {
cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCap.Name) cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCap.Name)

View File

@ -18,6 +18,7 @@ package core
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -245,7 +246,7 @@ func TestInvalidTransactions(t *testing.T) {
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice()))
pool.currentState.AddBalance(from, balance) pool.currentState.AddBalance(from, balance)
if err := pool.AddRemote(tx); err != ErrIntrinsicGas { if err := pool.AddRemote(tx); !errors.Is(err, ErrIntrinsicGas) {
t.Error("expected", ErrIntrinsicGas, "got", err) t.Error("expected", ErrIntrinsicGas, "got", err)
} }

View File

@ -289,7 +289,7 @@ func (b *EthAPIBackend) ExtRPCEnabled() bool {
return b.extRPCEnabled return b.extRPCEnabled
} }
func (b *EthAPIBackend) RPCGasCap() *big.Int { func (b *EthAPIBackend) RPCGasCap() uint64 {
return b.eth.config.RPCGasCap return b.eth.config.RPCGasCap
} }

View File

@ -60,6 +60,7 @@ var DefaultConfig = Config{
Recommit: 3 * time.Second, Recommit: 3 * time.Second,
}, },
TxPool: core.DefaultTxPoolConfig, TxPool: core.DefaultTxPoolConfig,
RPCGasCap: 25000000,
GPO: gasprice.Config{ GPO: gasprice.Config{
Blocks: 20, Blocks: 20,
Percentile: 60, Percentile: 60,
@ -158,7 +159,7 @@ type Config struct {
EVMInterpreter string EVMInterpreter string
// RPCGasCap is the global gas cap for eth-call variants. // RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"` RPCGasCap uint64 `toml:",omitempty"`
// RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for // RPCTxFeeCap is the global transaction fee(price * gaslimit) cap for
// send-transction variants. The unit is ether. // send-transction variants. The unit is ether.

View File

@ -3,7 +3,6 @@
package eth package eth
import ( import (
"math/big"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -49,7 +48,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
DocRoot string `toml:"-"` DocRoot string `toml:"-"`
EWASMInterpreter string EWASMInterpreter string
EVMInterpreter string EVMInterpreter string
RPCGasCap *big.Int `toml:",omitempty"` RPCGasCap uint64 `toml:",omitempty"`
RPCTxFeeCap float64 `toml:",omitempty"` RPCTxFeeCap float64 `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
@ -127,7 +126,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
DocRoot *string `toml:"-"` DocRoot *string `toml:"-"`
EWASMInterpreter *string EWASMInterpreter *string
EVMInterpreter *string EVMInterpreter *string
RPCGasCap *big.Int `toml:",omitempty"` RPCGasCap *uint64 `toml:",omitempty"`
RPCTxFeeCap *float64 `toml:",omitempty"` RPCTxFeeCap *float64 `toml:",omitempty"`
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"` Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
@ -230,7 +229,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
c.EVMInterpreter = *dec.EVMInterpreter c.EVMInterpreter = *dec.EVMInterpreter
} }
if dec.RPCGasCap != nil { if dec.RPCGasCap != nil {
c.RPCGasCap = dec.RPCGasCap c.RPCGasCap = *dec.RPCGasCap
} }
if dec.RPCTxFeeCap != nil { if dec.RPCTxFeeCap != nil {
c.RPCTxFeeCap = *dec.RPCTxFeeCap c.RPCTxFeeCap = *dec.RPCTxFeeCap

View File

@ -741,7 +741,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
func (args *CallArgs) ToMessage(globalGasCap *big.Int) types.Message { func (args *CallArgs) ToMessage(globalGasCap uint64) types.Message {
// Set sender address or use zero address if none specified. // Set sender address or use zero address if none specified.
var addr common.Address var addr common.Address
if args.From != nil { if args.From != nil {
@ -753,9 +753,9 @@ func (args *CallArgs) ToMessage(globalGasCap *big.Int) types.Message {
if args.Gas != nil { if args.Gas != nil {
gas = uint64(*args.Gas) gas = uint64(*args.Gas)
} }
if globalGasCap != nil && globalGasCap.Uint64() < gas { if globalGasCap != 0 && globalGasCap < gas {
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
gas = globalGasCap.Uint64() gas = globalGasCap
} }
gasPrice := new(big.Int) gasPrice := new(big.Int)
if args.GasPrice != nil { if args.GasPrice != nil {
@ -790,7 +790,7 @@ type account struct {
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"` StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
} }
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides map[common.Address]account, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) (*core.ExecutionResult, error) { func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides map[common.Address]account, vmCfg vm.Config, 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()) defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
@ -861,7 +861,10 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.Blo
if evm.Cancelled() { if evm.Cancelled() {
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout) return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
} }
return result, err if err != nil {
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
}
return result, nil
} }
func newRevertError(result *core.ExecutionResult) *revertError { func newRevertError(result *core.ExecutionResult) *revertError {
@ -916,7 +919,7 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNrOr
return result.Return(), result.Err return result.Return(), result.Err
} }
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap *big.Int) (hexutil.Uint64, error) { func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap uint64) (hexutil.Uint64, error) {
// Binary search the gas requirement, as it may be higher than the amount used // Binary search the gas requirement, as it may be higher than the amount used
var ( var (
lo uint64 = params.TxGas - 1 lo uint64 = params.TxGas - 1
@ -964,9 +967,9 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
} }
} }
// Recap the highest gas allowance with specified gascap. // Recap the highest gas allowance with specified gascap.
if gasCap != nil && hi > gasCap.Uint64() { if gasCap != 0 && hi > gasCap {
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap) log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
hi = gasCap.Uint64() hi = gasCap
} }
cap = hi cap = hi
@ -976,7 +979,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNrOrHash
result, err := DoCall(ctx, b, args, blockNrOrHash, nil, vm.Config{}, 0, gasCap) result, err := DoCall(ctx, b, args, blockNrOrHash, nil, vm.Config{}, 0, gasCap)
if err != nil { if err != nil {
if err == core.ErrIntrinsicGas { if errors.Is(err, core.ErrIntrinsicGas) {
return true, nil, nil // Special case, raise gas limit return true, nil, nil // Special case, raise gas limit
} }
return true, nil, err // Bail out return true, nil, err // Bail out

View File

@ -45,8 +45,8 @@ type Backend interface {
ChainDb() ethdb.Database ChainDb() ethdb.Database
AccountManager() *accounts.Manager AccountManager() *accounts.Manager
ExtRPCEnabled() bool ExtRPCEnabled() bool
RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
// Blockchain API // Blockchain API
SetHead(number uint64) SetHead(number uint64)

View File

@ -258,7 +258,7 @@ func (b *LesApiBackend) ExtRPCEnabled() bool {
return b.extRPCEnabled return b.extRPCEnabled
} }
func (b *LesApiBackend) RPCGasCap() *big.Int { func (b *LesApiBackend) RPCGasCap() uint64 {
return b.eth.config.RPCGasCap return b.eth.config.RPCGasCap
} }