Skip to content

Commit e872ba7

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 9d9c6b5 commit e872ba7

File tree

8 files changed

+36
-8
lines changed

8 files changed

+36
-8
lines changed

cmd/geth/main.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ var (
125125
utils.VMEnableDebugFlag,
126126
utils.NetworkIdFlag,
127127
utils.ConstantinopleOverrideFlag,
128-
utils.RPCCORSDomainFlag,
129-
utils.RPCVirtualHostsFlag,
130128
utils.EthStatsURLFlag,
131129
utils.MetricsEnabledFlag,
132130
utils.FakePoWFlag,
@@ -150,6 +148,7 @@ var (
150148
utils.WSAllowedOriginsFlag,
151149
utils.IPCDisabledFlag,
152150
utils.IPCPathFlag,
151+
utils.RPCGlobalGasCap,
153152
}
154153

155154
whisperFlags = []cli.Flag{

cmd/geth/usage.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ var AppHelpFlagGroups = []flagGroup{
153153
utils.RPCListenAddrFlag,
154154
utils.RPCPortFlag,
155155
utils.RPCApiFlag,
156+
utils.RPCGlobalGasCap,
156157
utils.WSEnabledFlag,
157158
utils.WSListenAddrFlag,
158159
utils.WSPortFlag,

cmd/utils/flags.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,10 @@ var (
411411
Name: "vmdebug",
412412
Usage: "Record information useful for VM and contract debugging",
413413
}
414+
RPCGlobalGasCap = cli.Uint64Flag{
415+
Name: "rpc.gascap",
416+
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
417+
}
414418
// Logging and debug settings
415419
EthStatsURLFlag = cli.StringFlag{
416420
Name: "ethstats",
@@ -1256,6 +1260,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
12561260
if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
12571261
cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
12581262
}
1263+
if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
1264+
cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
1265+
}
12591266

12601267
// Override any default configs for hard coded networks.
12611268
switch {

eth/api_backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,10 @@ func (b *EthAPIBackend) AccountManager() *accounts.Manager {
213213
return b.eth.AccountManager()
214214
}
215215

216+
func (b *EthAPIBackend) RPCGasCap() *big.Int {
217+
return b.eth.config.RPCGasCap
218+
}
219+
216220
func (b *EthAPIBackend) BloomStatus() (uint64, uint64) {
217221
sections, _, _ := b.eth.bloomIndexer.Sections()
218222
return params.BloomBitsBlocks, sections

eth/config.go

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

136136
// Constantinople block override (TODO: remove after the fork)
137137
ConstantinopleOverride *big.Int
138+
139+
// RPCGasCap is the global gas cap for eth-call variants.
140+
RPCGasCap *big.Int `toml:",omitempty"`
138141
}
139142

140143
type configMarshaling struct {

internal/ethapi/api.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ type CallArgs struct {
683683
Data hexutil.Bytes `json:"data"`
684684
}
685685

686-
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, timeout time.Duration) ([]byte, uint64, bool, error) {
686+
func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
687687
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
688688

689689
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
@@ -700,14 +700,18 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
700700
}
701701
}
702702
// Set default gas & gas price if none were set
703-
gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt()
703+
gas := uint64(args.Gas)
704704
if gas == 0 {
705705
gas = math.MaxUint64 / 2
706706
}
707+
if globalGasCap != nil && globalGasCap.Uint64() < gas {
708+
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
709+
gas = globalGasCap.Uint64()
710+
}
711+
gasPrice := args.GasPrice.ToInt()
707712
if gasPrice.Sign() == 0 {
708713
gasPrice = new(big.Int).SetUint64(defaultGasPrice)
709714
}
710-
711715
// Create new call message
712716
msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false)
713717

@@ -748,7 +752,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
748752
// Call executes the given transaction on the state for the given block number.
749753
// It doesn't make and changes in the state/blockchain and is useful to execute and retrieve values.
750754
func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Bytes, error) {
751-
result, _, _, err := s.doCall(ctx, args, blockNr, 5*time.Second)
755+
result, _, _, err := s.doCall(ctx, args, blockNr, 5*time.Second, s.b.RPCGasCap())
752756
return (hexutil.Bytes)(result), err
753757
}
754758

@@ -771,13 +775,18 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
771775
}
772776
hi = block.GasLimit()
773777
}
778+
gasCap := s.b.RPCGasCap()
779+
if gasCap != nil && hi > gasCap.Uint64() {
780+
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
781+
hi = gasCap.Uint64()
782+
}
774783
cap = hi
775784

776785
// Create a helper to check if a gas allowance results in an executable transaction
777786
executable := func(gas uint64) bool {
778787
args.Gas = hexutil.Uint64(gas)
779788

780-
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, 0)
789+
_, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, 0, gasCap)
781790
if err != nil || failed {
782791
return false
783792
}
@@ -795,7 +804,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
795804
// Reject the transaction as invalid if it still fails at the highest allowance
796805
if hi == cap {
797806
if !executable(hi) {
798-
return 0, fmt.Errorf("gas required exceeds allowance or always failing transaction")
807+
return 0, fmt.Errorf("gas required exceeds allowance (%d) or always failing transaction", cap)
799808
}
800809
}
801810
return hexutil.Uint64(hi), nil

internal/ethapi/backend.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Backend interface {
4444
ChainDb() ethdb.Database
4545
EventMux() *event.TypeMux
4646
AccountManager() *accounts.Manager
47+
RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
4748

4849
// BlockChain API
4950
SetHead(number uint64)

les/api_backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ func (b *LesApiBackend) AccountManager() *accounts.Manager {
187187
return b.eth.accountManager
188188
}
189189

190+
func (b *LesApiBackend) RPCGasCap() *big.Int {
191+
return b.eth.config.RPCGasCap
192+
}
193+
190194
func (b *LesApiBackend) BloomStatus() (uint64, uint64) {
191195
if b.eth.bloomIndexer == nil {
192196
return 0, 0

0 commit comments

Comments
 (0)