|
|
|
@ -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 |
|
|
|
|