eth, les, geth: implement cli-configurable global gas cap for RPC calls

This commit is contained in:
Martin Holst Swende 2019-04-05 11:52:59 +02:00
parent 36f81118f6
commit 9e93063e16
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
8 changed files with 48 additions and 6 deletions

View file

@ -57,7 +57,6 @@ var (
utils.IdentityFlag,
utils.UnlockedAccountFlag,
utils.PasswordFileFlag,
utils.InsecureUnlockAllowedFlag,
utils.BootnodesFlag,
utils.BootnodesV4Flag,
utils.BootnodesV5Flag,
@ -136,8 +135,6 @@ var (
utils.VMEnableDebugFlag,
utils.NetworkIdFlag,
utils.ConstantinopleOverrideFlag,
utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag,
utils.EthStatsURLFlag,
utils.FakePoWFlag,
utils.NoCompactionFlag,
@ -152,6 +149,8 @@ var (
utils.RPCEnabledFlag,
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.RPCCORSDomainFlag,
utils.RPCVirtualHostsFlag,
utils.GraphQLEnabledFlag,
utils.GraphQLListenAddrFlag,
utils.GraphQLPortFlag,
@ -165,6 +164,8 @@ var (
utils.WSAllowedOriginsFlag,
utils.IPCDisabledFlag,
utils.IPCPathFlag,
utils.InsecureUnlockAllowedFlag,
utils.RPCGlobalGasCap,
}
whisperFlags = []cli.Flag{

View file

@ -158,6 +158,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.RPCApiFlag,
utils.RPCGlobalGasCap,
utils.WSEnabledFlag,
utils.WSListenAddrFlag,
utils.WSPortFlag,

View file

@ -448,6 +448,10 @@ var (
Name: "allow-insecure-unlock",
Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
}
RPCGlobalGasCap = cli.Uint64Flag{
Name: "rpc.gascap",
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
}
// Logging and debug settings
EthStatsURLFlag = cli.StringFlag{
Name: "ethstats",
@ -1400,6 +1404,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
}
if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
}
// Override any default configs for hard coded networks.
switch {

View file

@ -218,6 +218,10 @@ func (b *EthAPIBackend) ExtRPCEnabled() bool {
return b.extRPCEnabled
}
func (b *EthAPIBackend) RPCGasCap() *big.Int {
return b.eth.config.RPCGasCap
}
func (b *EthAPIBackend) BloomStatus() (uint64, uint64) {
sections, _, _ := b.eth.bloomIndexer.Sections()
return params.BloomBitsBlocks, sections

View file

@ -151,6 +151,9 @@ type Config struct {
// Constantinople block override (TODO: remove after the fork)
ConstantinopleOverride *big.Int
// RPCGasCap is the global gas cap for eth-call variants.
RPCGasCap *big.Int `toml:",omitempty"`
}
type configMarshaling struct {

View file

@ -752,8 +752,22 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
// Call executes the given transaction on the state for the given block number.
// It 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 CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second)
return (hexutil.Bytes)(result), err
if gasCap := s.b.RPCGasCap(); gasCap != nil {
if new(big.Int).SetUint64(uint64(*args.Gas)).Cmp(gasCap) > 0 {
log.Warn("Applying cap on gas, caller requested amount above limit", "cap", gasCap, "requested", args.Gas)
newGas := hexutil.Uint64(gasCap.Uint64())
*args.Gas = newGas
}
result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second)
if err != nil {
err = fmt.Errorf("%v (gas capped at: %d)", err, *args.Gas)
}
return (hexutil.Bytes)(result), err
} else {
result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second)
return (hexutil.Bytes)(result), err
}
}
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) {
@ -797,7 +811,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
// Reject the transaction as invalid if it still fails at the highest allowance
if hi == cap {
if !executable(hi) {
return 0, fmt.Errorf("gas required exceeds allowance or always failing transaction")
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", cap)
}
}
return hexutil.Uint64(hi), nil
@ -806,6 +820,13 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
// EstimateGas returns an estimate of the amount of gas needed to execute the
// given transaction against the current pending block.
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) {
if gasCap := s.b.RPCGasCap(); gasCap != nil {
if new(big.Int).SetUint64(uint64(*args.Gas)).Cmp(gasCap) > 0 {
log.Warn("Applying cap on gas, caller requested amount above limit", "cap", gasCap, "requested", args.Gas)
newGas := hexutil.Uint64(gasCap.Uint64())
*args.Gas = newGas
}
}
return DoEstimateGas(ctx, s.b, args, rpc.PendingBlockNumber)
}

View file

@ -45,6 +45,7 @@ type Backend interface {
EventMux() *event.TypeMux
AccountManager() *accounts.Manager
ExtRPCEnabled() bool
RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
// BlockChain API
SetHead(number uint64)

View file

@ -192,6 +192,10 @@ func (b *LesApiBackend) ExtRPCEnabled() bool {
return b.extRPCEnabled
}
func (b *LesApiBackend) RPCGasCap() *big.Int {
return b.eth.config.RPCGasCap
}
func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
if b.eth.bloomIndexer == nil {
return 0, 0