mirror of
https://gitlab.com/pulsechaincom/go-pulse.git
synced 2024-12-22 03:30:35 +00:00
Add padding to gas estimations
Adds a 20% buffer to gas estimations to reduce out-of-gas errors.
This commit is contained in:
parent
680085c60b
commit
6e382ac942
@ -69,6 +69,8 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
|||||||
} else {
|
} else {
|
||||||
feeCap = common.Big0
|
feeCap = common.Big0
|
||||||
}
|
}
|
||||||
|
// Track the maximum gas based on the account's available funds and the txn feeCap.
|
||||||
|
var accountGasLimit uint64
|
||||||
// Recap the highest gas limit with account's available balance.
|
// Recap the highest gas limit with account's available balance.
|
||||||
if feeCap.BitLen() != 0 {
|
if feeCap.BitLen() != 0 {
|
||||||
balance := opts.State.GetBalance(call.From).ToBig()
|
balance := opts.State.GetBalance(call.From).ToBig()
|
||||||
@ -83,7 +85,9 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
|||||||
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() {
|
||||||
|
accountGasLimit = allowance.Uint64()
|
||||||
|
if hi > allowance.Uint64() {
|
||||||
transfer := call.Value
|
transfer := call.Value
|
||||||
if transfer == nil {
|
if transfer == nil {
|
||||||
transfer = new(big.Int)
|
transfer = new(big.Int)
|
||||||
@ -93,11 +97,23 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
|||||||
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.Debug("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
log.Debug("Caller gas above allowance, capping", "requested", hi, "cap", gasCap)
|
||||||
hi = gasCap
|
hi = gasCap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds a 20% pad to the estimated gas usage, not exceeding account gas limit
|
||||||
|
// to help mitigate gas underestimations
|
||||||
|
padResult := func(gas uint64) uint64 {
|
||||||
|
gas = gas + gas/5
|
||||||
|
if accountGasLimit != 0 && gas > accountGasLimit {
|
||||||
|
gas = accountGasLimit
|
||||||
|
}
|
||||||
|
return gas
|
||||||
|
}
|
||||||
|
|
||||||
// If the transaction is a plain value transfer, short circuit estimation and
|
// If the transaction is a plain value transfer, short circuit estimation and
|
||||||
// directly try 21000. Returning 21000 without any execution is dangerous as
|
// 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.
|
// some tx field combos might bump the price up even for plain transfers (e.g.
|
||||||
@ -106,7 +122,7 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
|||||||
if call.To != nil && opts.State.GetCodeSize(*call.To) == 0 {
|
if call.To != nil && opts.State.GetCodeSize(*call.To) == 0 {
|
||||||
failed, _, err := execute(ctx, call, opts, params.TxGas)
|
failed, _, err := execute(ctx, call, opts, params.TxGas)
|
||||||
if !failed && err == nil {
|
if !failed && err == nil {
|
||||||
return params.TxGas, nil, nil
|
return padResult(params.TxGas), nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,7 +194,7 @@ func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uin
|
|||||||
hi = mid
|
hi = mid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hi, nil, nil
|
return padResult(hi), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// execute is a helper that executes the transaction under a given gas limit and
|
// execute is a helper that executes the transaction under a given gas limit and
|
||||||
|
@ -553,7 +553,7 @@ func testCallContractAtHash(t *testing.T, client *rpc.Client) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if gas != 21000 {
|
if gas != 25200 {
|
||||||
t.Fatalf("unexpected gas price: %v", gas)
|
t.Fatalf("unexpected gas price: %v", gas)
|
||||||
}
|
}
|
||||||
block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1))
|
block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1))
|
||||||
@ -580,7 +580,7 @@ func testCallContract(t *testing.T, client *rpc.Client) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if gas != 21000 {
|
if gas != 25200 {
|
||||||
t.Fatalf("unexpected gas price: %v", gas)
|
t.Fatalf("unexpected gas price: %v", gas)
|
||||||
}
|
}
|
||||||
// CallContract
|
// CallContract
|
||||||
|
@ -139,7 +139,7 @@ func TestGraphQLBlockSerialization(t *testing.T) {
|
|||||||
// should return `estimateGas` as decimal
|
// should return `estimateGas` as decimal
|
||||||
{
|
{
|
||||||
body: `{"query": "{block{ estimateGas(data:{}) }}"}`,
|
body: `{"query": "{block{ estimateGas(data:{}) }}"}`,
|
||||||
want: `{"data":{"block":{"estimateGas":"0xd221"}}}`,
|
want: `{"data":{"block":{"estimateGas":"0xfc27"}}}`,
|
||||||
code: 200,
|
code: 200,
|
||||||
},
|
},
|
||||||
// should return `status` as decimal
|
// should return `status` as decimal
|
||||||
|
@ -663,7 +663,7 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
},
|
},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 21000,
|
want: 25200,
|
||||||
},
|
},
|
||||||
// simple transfer with insufficient funds on latest block
|
// simple transfer with insufficient funds on latest block
|
||||||
{
|
{
|
||||||
@ -674,14 +674,14 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
Value: (*hexutil.Big)(big.NewInt(1000)),
|
Value: (*hexutil.Big)(big.NewInt(1000)),
|
||||||
},
|
},
|
||||||
expectErr: core.ErrInsufficientFunds,
|
expectErr: core.ErrInsufficientFunds,
|
||||||
want: 21000,
|
want: 25200,
|
||||||
},
|
},
|
||||||
// empty create
|
// empty create
|
||||||
{
|
{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
call: TransactionArgs{},
|
call: TransactionArgs{},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 53000,
|
want: 64551,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
@ -690,7 +690,7 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
|
||||||
},
|
},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 53000,
|
want: 64551,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
@ -722,7 +722,7 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
GasPrice: (*hexutil.Big)(big.NewInt(1_000_000_000)), // Legacy as pricing
|
GasPrice: (*hexutil.Big)(big.NewInt(1_000_000_000)), // Legacy as pricing
|
||||||
},
|
},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 67617,
|
want: 82171,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
@ -732,7 +732,7 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
MaxFeePerGas: (*hexutil.Big)(big.NewInt(1_000_000_000)), // 1559 gas pricing
|
MaxFeePerGas: (*hexutil.Big)(big.NewInt(1_000_000_000)), // 1559 gas pricing
|
||||||
},
|
},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 67617,
|
want: 82171,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
blockNumber: rpc.LatestBlockNumber,
|
blockNumber: rpc.LatestBlockNumber,
|
||||||
@ -743,7 +743,7 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
MaxFeePerGas: nil, // No 1559 gas pricing
|
MaxFeePerGas: nil, // No 1559 gas pricing
|
||||||
},
|
},
|
||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
want: 67595,
|
want: 82144,
|
||||||
},
|
},
|
||||||
// Blobs should have no effect on gas estimate
|
// Blobs should have no effect on gas estimate
|
||||||
{
|
{
|
||||||
@ -755,7 +755,7 @@ func TestEstimateGas(t *testing.T) {
|
|||||||
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
|
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
|
||||||
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
||||||
},
|
},
|
||||||
want: 21000,
|
want: 25200,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for i, tc := range testSuite {
|
for i, tc := range testSuite {
|
||||||
@ -1008,7 +1008,7 @@ func TestSignTransaction(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
expect := `{"type":"0x2","chainId":"0x1","nonce":"0x0","to":"0x703c4b2bd70c169f5717101caee543299fc946c7","gas":"0x5208","gasPrice":null,"maxPriorityFeePerGas":"0x0","maxFeePerGas":"0x684ee180","value":"0x1","input":"0x","accessList":[],"v":"0x0","r":"0x8fabeb142d585dd9247f459f7e6fe77e2520c88d50ba5d220da1533cea8b34e1","s":"0x582dd68b21aef36ba23f34e49607329c20d981d30404daf749077f5606785ce7","yParity":"0x0","hash":"0x93927839207cfbec395da84b8a2bc38b7b65d2cb2819e9fef1f091f5b1d4cc8f"}`
|
expect := `{"type":"0x2","chainId":"0x1","nonce":"0x0","to":"0x703c4b2bd70c169f5717101caee543299fc946c7","gas":"0x6270","gasPrice":null,"maxPriorityFeePerGas":"0x0","maxFeePerGas":"0x684ee180","value":"0x1","input":"0x","accessList":[],"v":"0x0","r":"0xecde8d8a090f99fa06adcb5dacd9ca415cd31b002355b8285639e78f227fe56e","s":"0x91b92ca049b354ab795430e0d465d9901ef34fdb12a28a598be126441761dc6","yParity":"0x0","hash":"0x79368920659e6e4a5b1fca57cbe28657b4263fa447a8412bdb474347447d2ceb"}`
|
||||||
if !bytes.Equal(tx, []byte(expect)) {
|
if !bytes.Equal(tx, []byte(expect)) {
|
||||||
t.Errorf("result mismatch. Have:\n%s\nWant:\n%s\n", tx, expect)
|
t.Errorf("result mismatch. Have:\n%s\nWant:\n%s\n", tx, expect)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user