mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
eth/gasestimator: early exit for plain transfer and error allowance
This commit is contained in:
parent
63979bc9cc
commit
bfcb350f36
2 changed files with 33 additions and 9 deletions
|
|
@ -42,6 +42,8 @@ type Options struct {
|
||||||
Chain core.ChainContext // Chain context to access past block hashes
|
Chain core.ChainContext // Chain context to access past block hashes
|
||||||
Header *types.Header // Header defining the block context to execute in
|
Header *types.Header // Header defining the block context to execute in
|
||||||
State *state.StateDB // Pre-state on top of which to estimate the gas
|
State *state.StateDB // Pre-state on top of which to estimate the gas
|
||||||
|
|
||||||
|
ErrorRatio float64 // Allowed overestimation ratio for faster estimation termination
|
||||||
}
|
}
|
||||||
|
|
||||||
// Estimate returns the lowest possible gas limit that allows the transaction to
|
// Estimate returns the lowest possible gas limit that allows the transaction to
|
||||||
|
|
@ -50,8 +52,8 @@ type Options struct {
|
||||||
func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uint64) (uint64, []byte, error) {
|
func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uint64) (uint64, []byte, error) {
|
||||||
// Binary search the gas limit, as it may need to be higher than the amount used
|
// Binary search the gas limit, as it may need to be higher than the amount used
|
||||||
var (
|
var (
|
||||||
lo uint64 // lowest-known gas limit where tx execution fails
|
lo = params.TxGas - 1 // lowest-known gas limit where tx execution fails
|
||||||
hi uint64 // lowest-known gas limit where tx execution succeeds
|
hi uint64 // lowest-known gas limit where tx execution succeeds
|
||||||
)
|
)
|
||||||
// Determine the highest gas limit can be used during the estimation.
|
// Determine the highest gas limit can be used during the estimation.
|
||||||
hi = opts.Header.GasLimit
|
hi = opts.Header.GasLimit
|
||||||
|
|
@ -86,16 +88,28 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
||||||
if transfer == nil {
|
if transfer == nil {
|
||||||
transfer = new(big.Int)
|
transfer = new(big.Int)
|
||||||
}
|
}
|
||||||
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
|
log.Debug("Gas estimation capped by limited funds", "original", hi, "balance", balance,
|
||||||
"sent", transfer, "maxFeePerGas", feeCap, "fundable", allowance)
|
"sent", transfer, "maxFeePerGas", feeCap, "fundable", allowance)
|
||||||
hi = allowance.Uint64()
|
hi = 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 && hi > gasCap {
|
||||||
log.Warn("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
log.Debug("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
||||||
hi = gasCap
|
hi = gasCap
|
||||||
}
|
}
|
||||||
|
// If the transaction is a plain value transfer, short circuit estimation and
|
||||||
|
// directly try 21000. Returning 21000 without any execution is dangerous as
|
||||||
|
// some tx field combos might bump the price up even for plain transfers (e.g.
|
||||||
|
// unused access list items). Ever so slightly wasteful, but safer overall.
|
||||||
|
if len(call.Data) == 0 {
|
||||||
|
if call.To != nil && opts.State.GetCodeSize(*call.To) == 0 {
|
||||||
|
failed, _, err := execute(ctx, call, opts, params.TxGas)
|
||||||
|
if !failed && err == nil {
|
||||||
|
return params.TxGas, nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// We first execute the transaction at the highest allowable gas limit, since if this fails we
|
// We first execute the transaction at the highest allowable gas limit, since if this fails we
|
||||||
// can return error immediately.
|
// can return error immediately.
|
||||||
failed, result, err := execute(ctx, call, opts, hi)
|
failed, result, err := execute(ctx, call, opts, hi)
|
||||||
|
|
@ -114,9 +128,18 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
||||||
// given limit, but we probably don't want to return the lowest possible gas
|
// given limit, but we probably don't want to return the lowest possible gas
|
||||||
// limit for these cases anyway.
|
// limit for these cases anyway.
|
||||||
lo = result.UsedGas - 1
|
lo = result.UsedGas - 1
|
||||||
|
|
||||||
// Binary search for the smallest gas limit that allows the tx to execute successfully.
|
// Binary search for the smallest gas limit that allows the tx to execute successfully.
|
||||||
for lo+1 < hi {
|
for lo+1 < hi {
|
||||||
|
if opts.ErrorRatio > 0 {
|
||||||
|
// It is a bit pointless to return a perfect estimation, as changing
|
||||||
|
// network conditions require the caller to bump it up anyway. Since
|
||||||
|
// wallets tend to use 20-25% bump, allowing a small approximation
|
||||||
|
// error is fine (as long as it's upwards).
|
||||||
|
if float64(hi-lo)/float64(hi) < opts.ErrorRatio {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
mid := (hi + lo) / 2
|
mid := (hi + lo) / 2
|
||||||
if mid > lo*2 {
|
if mid > lo*2 {
|
||||||
// Most txs don't need much higher gas limit than their gas used, and most txs don't
|
// Most txs don't need much higher gas limit than their gas used, and most txs don't
|
||||||
|
|
|
||||||
|
|
@ -1189,10 +1189,11 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
|
||||||
}
|
}
|
||||||
// Construct the gas estimator option from the user input
|
// Construct the gas estimator option from the user input
|
||||||
opts := &gasestimator.Options{
|
opts := &gasestimator.Options{
|
||||||
Config: b.ChainConfig(),
|
Config: b.ChainConfig(),
|
||||||
Chain: NewChainContext(ctx, b),
|
Chain: NewChainContext(ctx, b),
|
||||||
Header: header,
|
Header: header,
|
||||||
State: state,
|
State: state,
|
||||||
|
ErrorRatio: 0.015,
|
||||||
}
|
}
|
||||||
// Run the gas estimation andwrap any revertals into a custom return
|
// Run the gas estimation andwrap any revertals into a custom return
|
||||||
call, err := args.ToMessage(gasCap, header.BaseFee)
|
call, err := args.ToMessage(gasCap, header.BaseFee)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue