Skip to content

Commit e2f3465

Browse files
holimankaralabe
authored andcommitted
eth, les, geth: implement cli-configurable global gas cap for RPC calls (#19401)
* eth, les, geth: implement cli-configurable global gas cap for RPC calls * graphql, ethapi: place gas cap in DoCall * ethapi: reformat log message
1 parent ed97517 commit e2f3465

File tree

9 files changed

+42
-13
lines changed

9 files changed

+42
-13
lines changed

cmd/geth/main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ var (
5757
utils.IdentityFlag,
5858
utils.UnlockedAccountFlag,
5959
utils.PasswordFileFlag,
60-
utils.InsecureUnlockAllowedFlag,
6160
utils.BootnodesFlag,
6261
utils.BootnodesV4Flag,
6362
utils.BootnodesV5Flag,
@@ -136,8 +135,6 @@ var (
136135
utils.VMEnableDebugFlag,
137136
utils.NetworkIdFlag,
138137
utils.ConstantinopleOverrideFlag,
139-
utils.RPCCORSDomainFlag,
140-
utils.RPCVirtualHostsFlag,
141138
utils.EthStatsURLFlag,
142139
utils.FakePoWFlag,
143140
utils.NoCompactionFlag,
@@ -152,6 +149,8 @@ var (
152149
utils.RPCEnabledFlag,
153150
utils.RPCListenAddrFlag,
154151
utils.RPCPortFlag,
152+
utils.RPCCORSDomainFlag,
153+
utils.RPCVirtualHostsFlag,
155154
utils.GraphQLEnabledFlag,
156155
utils.GraphQLListenAddrFlag,
157156
utils.GraphQLPortFlag,
@@ -165,6 +164,8 @@ var (
165164
utils.WSAllowedOriginsFlag,
166165
utils.IPCDisabledFlag,
167166
utils.IPCPathFlag,
167+
utils.InsecureUnlockAllowedFlag,
168+
utils.RPCGlobalGasCap,
168169
}
169170

170171
whisperFlags = []cli.Flag{

cmd/geth/usage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ var AppHelpFlagGroups = []flagGroup{
158158
utils.RPCListenAddrFlag,
159159
utils.RPCPortFlag,
160160
utils.RPCApiFlag,
161+
utils.RPCGlobalGasCap,
161162
utils.WSEnabledFlag,
162163
utils.WSListenAddrFlag,
163164
utils.WSPortFlag,

cmd/utils/flags.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,10 @@ var (
448448
Name: "allow-insecure-unlock",
449449
Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
450450
}
451+
RPCGlobalGasCap = cli.Uint64Flag{
452+
Name: "rpc.gascap",
453+
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
454+
}
451455
// Logging and debug settings
452456
EthStatsURLFlag = cli.StringFlag{
453457
Name: "ethstats",
@@ -1400,6 +1404,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
14001404
if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
14011405
cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
14021406
}
1407+
if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
1408+
cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
1409+
}
14031410

14041411
// Override any default configs for hard coded networks.
14051412
switch {

eth/api_backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,10 @@ func (b *EthAPIBackend) ExtRPCEnabled() bool {
218218
return b.extRPCEnabled
219219
}
220220

221+
func (b *EthAPIBackend) RPCGasCap() *big.Int {
222+
return b.eth.config.RPCGasCap
223+
}
224+
221225
func (b *EthAPIBackend) BloomStatus() (uint64, uint64) {
222226
sections, _, _ := b.eth.bloomIndexer.Sections()
223227
return params.BloomBitsBlocks, sections

eth/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ type Config struct {
151151

152152
// Constantinople block override (TODO: remove after the fork)
153153
ConstantinopleOverride *big.Int
154+
155+
// RPCGasCap is the global gas cap for eth-call variants.
156+
RPCGasCap *big.Int `toml:",omitempty"`
154157
}
155158

156159
type configMarshaling struct {

graphql/graphql.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,7 @@ func (b *Block) Call(ctx context.Context, args struct {
856856
}
857857
}
858858

859-
result, gas, failed, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.num, vm.Config{}, 5*time.Second)
859+
result, gas, failed, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.num, vm.Config{}, 5*time.Second, b.backend.RPCGasCap())
860860
status := hexutil.Uint64(1)
861861
if failed {
862862
status = 0
@@ -883,7 +883,7 @@ func (b *Block) EstimateGas(ctx context.Context, args struct {
883883
}
884884
}
885885

886-
gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.num)
886+
gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.num, b.backend.RPCGasCap())
887887
return gas, err
888888
}
889889

@@ -927,7 +927,7 @@ func (p *Pending) Account(ctx context.Context, args struct {
927927
func (p *Pending) Call(ctx context.Context, args struct {
928928
Data ethapi.CallArgs
929929
}) (*CallResult, error) {
930-
result, gas, failed, err := ethapi.DoCall(ctx, p.backend, args.Data, rpc.PendingBlockNumber, vm.Config{}, 5*time.Second)
930+
result, gas, failed, err := ethapi.DoCall(ctx, p.backend, args.Data, rpc.PendingBlockNumber, vm.Config{}, 5*time.Second, p.backend.RPCGasCap())
931931
status := hexutil.Uint64(1)
932932
if failed {
933933
status = 0
@@ -942,7 +942,7 @@ func (p *Pending) Call(ctx context.Context, args struct {
942942
func (p *Pending) EstimateGas(ctx context.Context, args struct {
943943
Data ethapi.CallArgs
944944
}) (hexutil.Uint64, error) {
945-
return ethapi.DoEstimateGas(ctx, p.backend, args.Data, rpc.PendingBlockNumber)
945+
return ethapi.DoEstimateGas(ctx, p.backend, args.Data, rpc.PendingBlockNumber, p.backend.RPCGasCap())
946946
}
947947

948948
// Resolver is the top-level object in the GraphQL hierarchy.

internal/ethapi/api.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ type CallArgs struct {
674674
Data *hexutil.Bytes `json:"data"`
675675
}
676676

677-
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) {
677+
func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
678678
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
679679

680680
state, header, err := b.StateAndHeaderByNumber(ctx, blockNr)
@@ -697,6 +697,10 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
697697
if args.Gas != nil {
698698
gas = uint64(*args.Gas)
699699
}
700+
if globalGasCap != nil && globalGasCap.Uint64() < gas {
701+
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
702+
gas = globalGasCap.Uint64()
703+
}
700704
gasPrice := new(big.Int).SetUint64(defaultGasPrice)
701705
if args.GasPrice != nil {
702706
gasPrice = args.GasPrice.ToInt()
@@ -752,11 +756,11 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb
752756
// Call executes the given transaction on the state for the given block number.
753757
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
754758
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
755-
result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second)
759+
result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second, s.b.RPCGasCap())
756760
return (hexutil.Bytes)(result), err
757761
}
758762

759-
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) {
763+
func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, gasCap *big.Int) (hexutil.Uint64, error) {
760764
// Binary search the gas requirement, as it may be higher than the amount used
761765
var (
762766
lo uint64 = params.TxGas - 1
@@ -773,13 +777,17 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
773777
}
774778
hi = block.GasLimit()
775779
}
780+
if gasCap != nil && hi > gasCap.Uint64() {
781+
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
782+
hi = gasCap.Uint64()
783+
}
776784
cap = hi
777785

778786
// Create a helper to check if a gas allowance results in an executable transaction
779787
executable := func(gas uint64) bool {
780788
args.Gas = (*hexutil.Uint64)(&gas)
781789

782-
_, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0)
790+
_, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0, gasCap)
783791
if err != nil || failed {
784792
return false
785793
}
@@ -797,7 +805,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
797805
// Reject the transaction as invalid if it still fails at the highest allowance
798806
if hi == cap {
799807
if !executable(hi) {
800-
return 0, fmt.Errorf("gas required exceeds allowance or always failing transaction")
808+
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", cap)
801809
}
802810
}
803811
return hexutil.Uint64(hi), nil
@@ -806,7 +814,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl
806814
// EstimateGas returns an estimate of the amount of gas needed to execute the
807815
// given transaction against the current pending block.
808816
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) {
809-
return DoEstimateGas(ctx, s.b, args, rpc.PendingBlockNumber)
817+
return DoEstimateGas(ctx, s.b, args, rpc.PendingBlockNumber, s.b.RPCGasCap())
810818
}
811819

812820
// ExecutionResult groups all structured logs emitted by the EVM

internal/ethapi/backend.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type Backend interface {
4545
EventMux() *event.TypeMux
4646
AccountManager() *accounts.Manager
4747
ExtRPCEnabled() bool
48+
RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
4849

4950
// BlockChain API
5051
SetHead(number uint64)

les/api_backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ func (b *LesApiBackend) ExtRPCEnabled() bool {
192192
return b.extRPCEnabled
193193
}
194194

195+
func (b *LesApiBackend) RPCGasCap() *big.Int {
196+
return b.eth.config.RPCGasCap
197+
}
198+
195199
func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
196200
if b.eth.bloomIndexer == nil {
197201
return 0, 0

0 commit comments

Comments
 (0)