Add padding to gas estimations

Adds a 20% buffer to gas estimations to reduce out-of-gas errors.
This commit is contained in:
Shane Bammel 2023-04-05 22:41:32 -05:00
parent cab77c932e
commit 6c54e8f59e
3 changed files with 26 additions and 13 deletions

View File

@ -612,6 +612,8 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
} else {
hi = b.pendingBlock.GasLimit()
}
// Track the maximum gas based on the account's available funds and the txn feeCap.
var accountGasLimit uint64
// Recap the highest gas allowance with account's balance.
if call.GasPrice != nil && !call.GasPrice.IsZero() {
balance := b.pendingState.GetBalance(call.From) // from can't be nil
@ -623,14 +625,17 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
available.Sub(available, call.Value.ToBig())
}
allowance := new(big.Int).Div(available, call.GasPrice.ToBig())
if allowance.IsUint64() && hi > allowance.Uint64() {
transfer := call.Value
if transfer == nil {
transfer = new(uint256.Int)
if allowance.IsUint64() {
accountGasLimit = allowance.Uint64()
if hi > allowance.Uint64() {
transfer := call.Value
if transfer == nil {
transfer = new(uint256.Int)
}
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
"sent", transfer, "gasprice", call.GasPrice, "fundable", allowance)
hi = allowance.Uint64()
}
log.Warn("Gas estimation capped by limited funds", "original", hi, "balance", balance,
"sent", transfer, "gasprice", call.GasPrice, "fundable", allowance)
hi = allowance.Uint64()
}
}
gasCap = hi
@ -686,6 +691,14 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
return 0, fmt.Errorf("gas required exceeds allowance (%d)", gasCap)
}
}
// Adds a 20% pad to the estimated gas usage, not exceeding account gas limit
// to help mitigate gas underestimations
hi = hi + hi/5
if accountGasLimit != 0 && hi > accountGasLimit {
hi = accountGasLimit
}
return hi, nil
}

View File

@ -450,7 +450,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
GasPrice: u256.Num0,
Value: u256.Num1,
Data: nil,
}, params.TxGas, nil, nil},
}, 25200, nil, nil},
{"plain transfer(invalid)", ethereum.CallMsg{
From: addr,
@ -504,7 +504,7 @@ func TestSimulatedBackend_EstimateGas(t *testing.T) {
GasPrice: u256.Num0,
Value: nil,
Data: common.Hex2Bytes("e09fface"),
}, 21275, nil, nil},
}, 25530, nil, nil},
}
for _, c := range cases {
got, err := sim.EstimateGas(context.Background(), c.message)
@ -550,7 +550,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
GasPrice: uint256.NewInt(0),
Value: uint256.NewInt(1000),
Data: nil,
}, 21000, nil},
}, 25200, nil},
{"EstimateWithPrice", ethereum.CallMsg{
From: addr,
@ -559,7 +559,7 @@ func TestSimulatedBackend_EstimateGasWithPrice(t *testing.T) {
GasPrice: uint256.NewInt(1000),
Value: uint256.NewInt(1000),
Data: nil,
}, 21000, nil},
}, 25200, nil},
{"EstimateWithVeryHighPrice", ethereum.CallMsg{
From: addr,

View File

@ -565,8 +565,8 @@ func (ethash *Ethash) Finalize(config *chain.Config, header *types.Header, state
chain consensus.ChainHeaderReader, syscall consensus.SystemCall,
) (types.Transactions, types.Receipts, error) {
// Apply fork changes on PrimordialPulse block
if cfg := chain.Config(); cfg.IsPrimordialPulseBlock(header.Number.Uint64()) {
pulse.PrimordialPulseFork(state, cfg.PulseChain)
if config.IsPrimordialPulseBlock(header.Number.Uint64()) {
pulse.PrimordialPulseFork(state, config.PulseChain)
}
// Accumulate any block and uncle rewards and commit the final state root