aboutsummaryrefslogtreecommitdiffstats
path: root/internal/ethapi/api.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/ethapi/api.go')
-rw-r--r--internal/ethapi/api.go30
1 files changed, 28 insertions, 2 deletions
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 4359181c8..925f547b6 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -559,8 +559,34 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr r
// EstimateGas returns an estimate of the amount of gas needed to execute the given transaction.
func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) {
- _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber)
- return (*hexutil.Big)(gas), err
+ // Binary search the gas requirement, as it may be higher than the amount used
+ var lo, hi uint64
+ if (*big.Int)(&args.Gas).BitLen() > 0 {
+ hi = (*big.Int)(&args.Gas).Uint64()
+ } else {
+ // Retrieve the current pending block to act as the gas ceiling
+ block, err := s.b.BlockByNumber(ctx, rpc.PendingBlockNumber)
+ if err != nil {
+ return nil, err
+ }
+ hi = block.GasLimit().Uint64()
+ }
+ for lo+1 < hi {
+ // Take a guess at the gas, and check transaction validity
+ mid := (hi + lo) / 2
+ (*big.Int)(&args.Gas).SetUint64(mid)
+
+ _, gas, err := s.doCall(ctx, args, rpc.PendingBlockNumber)
+
+ // If the transaction became invalid or used all the gas (failed), raise the gas limit
+ if err != nil || gas.Cmp((*big.Int)(&args.Gas)) == 0 {
+ lo = mid
+ continue
+ }
+ // Otherwise assume the transaction succeeded, lower the gas limit
+ hi = mid
+ }
+ return (*hexutil.Big)(new(big.Int).SetUint64(hi)), nil
}
// ExecutionResult groups all structured logs emitted by the EVM