mirror of
https://gitlab.com/pulsechaincom/go-pulse.git
synced 2024-12-21 19:20:37 +00:00
Simplify DoEstimateGas with RequiredGas field
By tracking the RequiredGas independently from refunds, DoEstimateGas() can return an accurate gas estimate without the complexity of the binary search.
This commit is contained in:
parent
f6ce963881
commit
f04f51cd0c
@ -995,19 +995,14 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, bl
|
||||
}
|
||||
|
||||
func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, gasCap uint64) (hexutil.Uint64, error) {
|
||||
// Binary search the gas requirement, as it may be higher than the amount used
|
||||
var (
|
||||
lo uint64 = params.TxGas - 1
|
||||
hi uint64
|
||||
cap uint64
|
||||
)
|
||||
var maxGas uint64
|
||||
// Use zero address if sender unspecified.
|
||||
if args.From == nil {
|
||||
args.From = new(common.Address)
|
||||
}
|
||||
// Determine the highest gas limit can be used during the estimation.
|
||||
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
|
||||
hi = uint64(*args.Gas)
|
||||
maxGas = uint64(*args.Gas)
|
||||
} else {
|
||||
// Retrieve the block to act as the gas ceiling
|
||||
block, err := b.BlockByNumberOrHash(ctx, blockNrOrHash)
|
||||
@ -1017,7 +1012,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||
if block == nil {
|
||||
return 0, errors.New("block not found")
|
||||
}
|
||||
hi = block.GasLimit()
|
||||
maxGas = block.GasLimit()
|
||||
}
|
||||
// Normalize the max fee per gas the call is willing to spend.
|
||||
var feeCap *big.Int
|
||||
@ -1047,23 +1042,21 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||
allowance := new(big.Int).Div(available, feeCap)
|
||||
|
||||
// If the allowance is larger than maximum uint64, skip checking
|
||||
if allowance.IsUint64() && hi > allowance.Uint64() {
|
||||
if allowance.IsUint64() && maxGas > allowance.Uint64() {
|
||||
transfer := args.Value
|
||||
if transfer == nil {
|
||||
transfer = new(hexutil.Big)
|
||||
}
|
||||
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
|
||||
log.Warn("Gas estimation capped by limited funds", "original", maxGas, "balance", balance,
|
||||
"sent", transfer.ToInt(), "maxFeePerGas", feeCap, "fundable", allowance)
|
||||
hi = allowance.Uint64()
|
||||
maxGas = allowance.Uint64()
|
||||
}
|
||||
}
|
||||
// Recap the highest gas allowance with specified gascap.
|
||||
if gasCap != 0 && hi > gasCap {
|
||||
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
||||
hi = gasCap
|
||||
if gasCap != 0 && maxGas > gasCap {
|
||||
log.Warn("Caller gas above allowance, capping", "requested", maxGas, "cap", gasCap)
|
||||
maxGas = gasCap
|
||||
}
|
||||
cap = hi
|
||||
|
||||
// Create a helper to check if a gas allowance results in an executable transaction
|
||||
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
||||
args.Gas = (*hexutil.Uint64)(&gas)
|
||||
@ -1077,41 +1070,23 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||
}
|
||||
return result.Failed(), result, nil
|
||||
}
|
||||
// Execute the binary search and hone in on an executable gas limit
|
||||
for lo+1 < hi {
|
||||
mid := (hi + lo) / 2
|
||||
failed, _, err := executable(mid)
|
||||
|
||||
// If the error is not nil(consensus error), it means the provided message
|
||||
// call or transaction will never be accepted no matter how much gas it is
|
||||
// assigned. Return the error directly, don't struggle any more.
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if failed {
|
||||
lo = mid
|
||||
} else {
|
||||
hi = mid
|
||||
}
|
||||
}
|
||||
// Reject the transaction as invalid if it still fails at the highest allowance
|
||||
if hi == cap {
|
||||
failed, result, err := executable(hi)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if failed {
|
||||
if result != nil && result.Err != vm.ErrOutOfGas {
|
||||
if len(result.Revert()) > 0 {
|
||||
return 0, newRevertError(result)
|
||||
}
|
||||
return 0, result.Err
|
||||
}
|
||||
// Otherwise, the specified gas cap is too low
|
||||
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
|
||||
}
|
||||
failed, result, err := executable(maxGas)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return hexutil.Uint64(hi), nil
|
||||
if failed {
|
||||
if result != nil && result.Err != vm.ErrOutOfGas {
|
||||
if len(result.Revert()) > 0 {
|
||||
return 0, newRevertError(result)
|
||||
}
|
||||
return 0, result.Err
|
||||
}
|
||||
// Otherwise, the specified gas cap is too low
|
||||
return 0, fmt.Errorf("gas required exceeds allowance (%d)", maxGas)
|
||||
}
|
||||
return hexutil.Uint64(result.RequiredGas), nil
|
||||
}
|
||||
|
||||
// EstimateGas returns an estimate of the amount of gas needed to execute the
|
||||
|
Loading…
Reference in New Issue
Block a user