diff options
Diffstat (limited to 'internal/ethapi')
| -rw-r--r-- | internal/ethapi/api.go | 21 | ||||
| -rw-r--r-- | internal/ethapi/backend.go | 1 | 
2 files changed, 16 insertions, 6 deletions
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)  | 
