mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core, eth/gasestimator: hard guess at a possible required gas
This commit is contained in:
parent
bfcb350f36
commit
a0b41b670f
2 changed files with 33 additions and 10 deletions
|
|
@ -32,7 +32,8 @@ import (
|
||||||
// ExecutionResult includes all output after executing given evm
|
// ExecutionResult includes all output after executing given evm
|
||||||
// message no matter the execution itself is successful or not.
|
// message no matter the execution itself is successful or not.
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
UsedGas uint64 // Total used gas but include the refunded gas
|
UsedGas uint64 // Total used gas, not including the refunded gas
|
||||||
|
RefundedGas uint64 // Total gas refunded after execution
|
||||||
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
Err error // Any error encountered during the execution(listed in core/vm/errors.go)
|
||||||
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
ReturnData []byte // Returned data from evm(function result or data supplied with revert opcode)
|
||||||
}
|
}
|
||||||
|
|
@ -419,12 +420,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, msg.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gasRefund uint64
|
||||||
if !rules.IsLondon {
|
if !rules.IsLondon {
|
||||||
// Before EIP-3529: refunds were capped to gasUsed / 2
|
// Before EIP-3529: refunds were capped to gasUsed / 2
|
||||||
st.refundGas(params.RefundQuotient)
|
gasRefund = st.refundGas(params.RefundQuotient)
|
||||||
} else {
|
} else {
|
||||||
// After EIP-3529: refunds are capped to gasUsed / 5
|
// After EIP-3529: refunds are capped to gasUsed / 5
|
||||||
st.refundGas(params.RefundQuotientEIP3529)
|
gasRefund = st.refundGas(params.RefundQuotientEIP3529)
|
||||||
}
|
}
|
||||||
effectiveTip := msg.GasPrice
|
effectiveTip := msg.GasPrice
|
||||||
if rules.IsLondon {
|
if rules.IsLondon {
|
||||||
|
|
@ -443,12 +445,13 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
|
|
||||||
return &ExecutionResult{
|
return &ExecutionResult{
|
||||||
UsedGas: st.gasUsed(),
|
UsedGas: st.gasUsed(),
|
||||||
|
RefundedGas: gasRefund,
|
||||||
Err: vmerr,
|
Err: vmerr,
|
||||||
ReturnData: ret,
|
ReturnData: ret,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) refundGas(refundQuotient uint64) {
|
func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
|
||||||
// Apply refund counter, capped to a refund quotient
|
// Apply refund counter, capped to a refund quotient
|
||||||
refund := st.gasUsed() / refundQuotient
|
refund := st.gasUsed() / refundQuotient
|
||||||
if refund > st.state.GetRefund() {
|
if refund > st.state.GetRefund() {
|
||||||
|
|
@ -463,6 +466,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
|
||||||
// Also return remaining gas to the block gas counter so it is
|
// Also return remaining gas to the block gas counter so it is
|
||||||
// available for the next transaction.
|
// available for the next transaction.
|
||||||
st.gp.AddGas(st.gasRemaining)
|
st.gp.AddGas(st.gasRemaining)
|
||||||
|
|
||||||
|
return refund
|
||||||
}
|
}
|
||||||
|
|
||||||
// gasUsed returns the amount of gas used up by the state transition.
|
// gasUsed returns the amount of gas used up by the state transition.
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,24 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
||||||
// limit for these cases anyway.
|
// limit for these cases anyway.
|
||||||
lo = result.UsedGas - 1
|
lo = result.UsedGas - 1
|
||||||
|
|
||||||
|
// There's a fairly high chance for the transaction to execute successfully
|
||||||
|
// with gasLimit set to the first execution's usedGas + gasRefund. Explicitly
|
||||||
|
// check that gas amount and use as a limit for the binary search.
|
||||||
|
optimisticGasLimit := (result.UsedGas + result.RefundedGas + params.CallStipend) * 64 / 63
|
||||||
|
if optimisticGasLimit < hi {
|
||||||
|
failed, _, err = execute(ctx, call, opts, optimisticGasLimit)
|
||||||
|
if err != nil {
|
||||||
|
// This should not happen under normal conditions since if we make it this far the
|
||||||
|
// transaction had run without error at least once before.
|
||||||
|
log.Error("Execution error in estimate gas", "err", err)
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
if failed {
|
||||||
|
lo = optimisticGasLimit
|
||||||
|
} else {
|
||||||
|
hi = optimisticGasLimit
|
||||||
|
}
|
||||||
|
}
|
||||||
// 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 {
|
if opts.ErrorRatio > 0 {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue