From 0c3563eb360f4f61d10e46d4ac9e586587ac47a7 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 8 Apr 2019 13:06:47 +0200 Subject: [PATCH] graphql, ethapi: place gas cap in DoCall --- graphql/graphql.go | 8 ++++---- internal/ethapi/api.go | 41 ++++++++++++++--------------------------- 2 files changed, 18 insertions(+), 31 deletions(-) diff --git a/graphql/graphql.go b/graphql/graphql.go index b3bcbd8a43..d22a3afb6f 100644 --- a/graphql/graphql.go +++ b/graphql/graphql.go @@ -856,7 +856,7 @@ func (b *Block) Call(ctx context.Context, args struct { } } - result, gas, failed, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.num, vm.Config{}, 5*time.Second) + result, gas, failed, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.num, vm.Config{}, 5*time.Second, b.backend.RPCGasCap()) status := hexutil.Uint64(1) if failed { status = 0 @@ -883,7 +883,7 @@ func (b *Block) EstimateGas(ctx context.Context, args struct { } } - gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.num) + gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.num, b.backend.RPCGasCap()) return gas, err } @@ -927,7 +927,7 @@ func (p *Pending) Account(ctx context.Context, args struct { func (p *Pending) Call(ctx context.Context, args struct { Data ethapi.CallArgs }) (*CallResult, error) { - result, gas, failed, err := ethapi.DoCall(ctx, p.backend, args.Data, rpc.PendingBlockNumber, vm.Config{}, 5*time.Second) + result, gas, failed, err := ethapi.DoCall(ctx, p.backend, args.Data, rpc.PendingBlockNumber, vm.Config{}, 5*time.Second, p.backend.RPCGasCap()) status := hexutil.Uint64(1) if failed { status = 0 @@ -942,7 +942,7 @@ func (p *Pending) Call(ctx context.Context, args struct { func (p *Pending) EstimateGas(ctx context.Context, args struct { Data ethapi.CallArgs }) (hexutil.Uint64, error) { - return ethapi.DoEstimateGas(ctx, p.backend, args.Data, rpc.PendingBlockNumber) + return ethapi.DoEstimateGas(ctx, p.backend, args.Data, rpc.PendingBlockNumber, p.backend.RPCGasCap()) } // Resolver is the top-level object in the GraphQL hierarchy. diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 1031ef78a5..8a9788b8cc 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -674,7 +674,7 @@ type CallArgs struct { Data *hexutil.Bytes `json:"data"` } -func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config, timeout time.Duration) ([]byte, uint64, bool, error) { +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) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := b.StateAndHeaderByNumber(ctx, blockNr) @@ -697,6 +697,10 @@ func DoCall(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumb if args.Gas != nil { gas = uint64(*args.Gas) } + if globalGasCap != nil && globalGasCap.Uint64() < gas { + log.Warn("Applying cap on gas, caller requested amount above limit", "cap", globalGasCap, "attempted", gas) + gas = globalGasCap.Uint64() + } gasPrice := new(big.Int).SetUint64(defaultGasPrice) if args.GasPrice != nil { gasPrice = args.GasPrice.ToInt() @@ -752,25 +756,11 @@ 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) { - 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 - } - + result, _, _, err := DoCall(ctx, s.b, args, blockNr, vm.Config{}, 5*time.Second, s.b.RPCGasCap()) + return (hexutil.Bytes)(result), err } -func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber) (hexutil.Uint64, error) { +func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.BlockNumber, gasCap *big.Int) (hexutil.Uint64, error) { // Binary search the gas requirement, as it may be higher than the amount used var ( lo uint64 = params.TxGas - 1 @@ -787,13 +777,17 @@ func DoEstimateGas(ctx context.Context, b Backend, args CallArgs, blockNr rpc.Bl } hi = block.GasLimit() } + if gasCap != nil && hi > gasCap.Uint64() { + log.Warn("Applying cap on gas, caller requested amount above limit", "cap", gasCap, "attempted", hi) + 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 := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0) + _, _, failed, err := DoCall(ctx, b, args, rpc.PendingBlockNumber, vm.Config{}, 0, gasCap) if err != nil || failed { return false } @@ -820,14 +814,7 @@ 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) + return DoEstimateGas(ctx, s.b, args, rpc.PendingBlockNumber, s.b.RPCGasCap()) } // ExecutionResult groups all structured logs emitted by the EVM