aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/geth/main.go3
-rw-r--r--cmd/geth/usage.go1
-rw-r--r--cmd/utils/flags.go7
-rw-r--r--eth/api_backend.go4
-rw-r--r--eth/config.go3
-rw-r--r--internal/ethapi/api.go21
-rw-r--r--internal/ethapi/backend.go1
-rw-r--r--les/api_backend.go4
8 files changed, 36 insertions, 8 deletions
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index e60a27e43..458608112 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -125,8 +125,6 @@ var (
utils.VMEnableDebugFlag,
utils.NetworkIdFlag,
utils.ConstantinopleOverrideFlag,
- utils.RPCCORSDomainFlag,
- utils.RPCVirtualHostsFlag,
utils.EthStatsURLFlag,
utils.MetricsEnabledFlag,
utils.FakePoWFlag,
@@ -150,6 +148,7 @@ var (
utils.WSAllowedOriginsFlag,
utils.IPCDisabledFlag,
utils.IPCPathFlag,
+ utils.RPCGlobalGasCap,
}
whisperFlags = []cli.Flag{
diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go
index 6823aa36c..259e6d30a 100644
--- a/cmd/geth/usage.go
+++ b/cmd/geth/usage.go
@@ -153,6 +153,7 @@ var AppHelpFlagGroups = []flagGroup{
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.RPCApiFlag,
+ utils.RPCGlobalGasCap,
utils.WSEnabledFlag,
utils.WSListenAddrFlag,
utils.WSPortFlag,
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 55e84b876..052660ba1 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -411,6 +411,10 @@ var (
Name: "vmdebug",
Usage: "Record information useful for VM and contract debugging",
}
+ 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",
@@ -1256,6 +1260,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 {
diff --git a/eth/api_backend.go b/eth/api_backend.go
index a48815e0d..3efc09cc1 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -213,6 +213,10 @@ func (b *EthAPIBackend) AccountManager() *accounts.Manager {
return b.eth.AccountManager()
}
+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
diff --git a/eth/config.go b/eth/config.go
index 7c041d1af..5b9db2502 100644
--- a/eth/config.go
+++ b/eth/config.go
@@ -135,6 +135,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 {
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index b732adff6..e1ca71104 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -683,7 +683,7 @@ type CallArgs struct {
Data hexutil.Bytes `json:"data"`
}
-func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, timeout time.Duration) ([]byte, uint64, bool, error) {
+func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now())
state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
@@ -700,14 +700,18 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
}
}
// Set default gas & gas price if none were set
- gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt()
+ gas := uint64(args.Gas)
if gas == 0 {
gas = math.MaxUint64 / 2
}
+ if globalGasCap != nil && globalGasCap.Uint64() < gas {
+ log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
+ gas = globalGasCap.Uint64()
+ }
+ gasPrice := args.GasPrice.ToInt()
if gasPrice.Sign() == 0 {
gasPrice = new(big.Int).SetUint64(defaultGasPrice)
}
-
// Create new call message
msg := types.NewMessage(addr, args.To, 0, args.Value.ToInt(), gas, gasPrice, args.Data, false)
@@ -748,7 +752,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
// 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 := s.doCall(ctx, args, blockNr, 5*time.Second)
+ result, _, _, err := s.doCall(ctx, args, blockNr, 5*time.Second, s.b.RPCGasCap())
return (hexutil.Bytes)(result), err
}
@@ -771,13 +775,18 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
}
hi = block.GasLimit()
}
+ gasCap := s.b.RPCGasCap()
+ if gasCap != nil && hi > gasCap.Uint64() {
+ log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
+ hi = gasCap.Uint64()
+ }
cap = hi
// Create a helper to check if a gas allowance results in an executable transaction
executable := func(gas uint64) bool {
args.Gas = hexutil.Uint64(gas)
- _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, 0)
+ _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, 0, gasCap)
if err != nil || failed {
return false
}
@@ -795,7 +804,7 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
// 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
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index e23ee03b1..56a3daffa 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -44,6 +44,7 @@ type Backend interface {
ChainDb() ethdb.Database
EventMux() *event.TypeMux
AccountManager() *accounts.Manager
+ RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
// BlockChain API
SetHead(number uint64)
diff --git a/les/api_backend.go b/les/api_backend.go
index 753139623..f03d32fed 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -187,6 +187,10 @@ func (b *LesApiBackend) AccountManager() *accounts.Manager {
return b.eth.accountManager
}
+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