mirror of
https://gitlab.com/pulsechaincom/go-pulse.git
synced 2024-12-22 03:30:35 +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) {
|
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 maxGas uint64
|
||||||
var (
|
|
||||||
lo uint64 = params.TxGas - 1
|
|
||||||
hi uint64
|
|
||||||
cap uint64
|
|
||||||
)
|
|
||||||
// Use zero address if sender unspecified.
|
// Use zero address if sender unspecified.
|
||||||
if args.From == nil {
|
if args.From == nil {
|
||||||
args.From = new(common.Address)
|
args.From = new(common.Address)
|
||||||
}
|
}
|
||||||
// Determine the highest gas limit can be used during the estimation.
|
// Determine the highest gas limit can be used during the estimation.
|
||||||
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
|
if args.Gas != nil && uint64(*args.Gas) >= params.TxGas {
|
||||||
hi = uint64(*args.Gas)
|
maxGas = uint64(*args.Gas)
|
||||||
} else {
|
} else {
|
||||||
// Retrieve the block to act as the gas ceiling
|
// Retrieve the block to act as the gas ceiling
|
||||||
block, err := b.BlockByNumberOrHash(ctx, blockNrOrHash)
|
block, err := b.BlockByNumberOrHash(ctx, blockNrOrHash)
|
||||||
@ -1017,7 +1012,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||||||
if block == nil {
|
if block == nil {
|
||||||
return 0, errors.New("block not found")
|
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.
|
// Normalize the max fee per gas the call is willing to spend.
|
||||||
var feeCap *big.Int
|
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)
|
allowance := new(big.Int).Div(available, feeCap)
|
||||||
|
|
||||||
// If the allowance is larger than maximum uint64, skip checking
|
// 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
|
transfer := args.Value
|
||||||
if transfer == nil {
|
if transfer == nil {
|
||||||
transfer = new(hexutil.Big)
|
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)
|
"sent", transfer.ToInt(), "maxFeePerGas", feeCap, "fundable", allowance)
|
||||||
hi = allowance.Uint64()
|
maxGas = allowance.Uint64()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recap the highest gas allowance with specified gascap.
|
// Recap the highest gas allowance with specified gascap.
|
||||||
if gasCap != 0 && hi > gasCap {
|
if gasCap != 0 && maxGas > gasCap {
|
||||||
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
log.Warn("Caller gas above allowance, capping", "requested", maxGas, "cap", gasCap)
|
||||||
hi = gasCap
|
maxGas = gasCap
|
||||||
}
|
}
|
||||||
cap = hi
|
|
||||||
|
|
||||||
// Create a helper to check if a gas allowance results in an executable transaction
|
// Create a helper to check if a gas allowance results in an executable transaction
|
||||||
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
executable := func(gas uint64) (bool, *core.ExecutionResult, error) {
|
||||||
args.Gas = (*hexutil.Uint64)(&gas)
|
args.Gas = (*hexutil.Uint64)(&gas)
|
||||||
@ -1077,41 +1070,23 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
|||||||
}
|
}
|
||||||
return result.Failed(), result, nil
|
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
|
// Reject the transaction as invalid if it still fails at the highest allowance
|
||||||
if hi == cap {
|
failed, result, err := executable(maxGas)
|
||||||
failed, result, err := executable(hi)
|
if err != nil {
|
||||||
if err != nil {
|
return 0, err
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
// EstimateGas returns an estimate of the amount of gas needed to execute the
|
||||||
|
Loading…
Reference in New Issue
Block a user