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 b58ecc133f
commit 36068aae71
3 changed files with 26 additions and 13 deletions

View File

@ -579,6 +579,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
@ -590,14 +592,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()
}
}
cap = hi
@ -653,6 +658,14 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
return 0, fmt.Errorf("gas required exceeds allowance (%d)", cap)
}
}
// 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

@ -453,7 +453,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,
@ -507,7 +507,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)
@ -553,7 +553,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,
@ -562,7 +562,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
e consensus.EpochReader, 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