@@ -14,6 +14,8 @@ import (
14
14
15
15
var (
16
16
fallBackBinarySearchCutoff = int64 (30000 )
17
+ maxRetries = int64 (7 )
18
+ baseVGLBuffer = int64 (25 )
17
19
)
18
20
19
21
func isPrefundNotPaid (err error ) bool {
@@ -41,13 +43,34 @@ func isExecutionReverted(err error) bool {
41
43
}
42
44
43
45
type EstimateInput struct {
44
- Rpc * rpc.Client
45
- EntryPoint common.Address
46
- Op * userop.UserOperation
47
- Ov * Overhead
48
- ChainID * big.Int
49
- MaxGasLimit * big.Int
50
- PaymasterBuffer int64
46
+ Rpc * rpc.Client
47
+ EntryPoint common.Address
48
+ Op * userop.UserOperation
49
+ Ov * Overhead
50
+ ChainID * big.Int
51
+ MaxGasLimit * big.Int
52
+
53
+ attempts int64
54
+ lastVGL int64
55
+ }
56
+
57
+ // retryEstimateGas will recursively call estimateGas if execution has caused VGL to be under estimated. This
58
+ // can occur for edge cases where a paymaster's postOp > gas required during verification or if verification
59
+ // has a dependency on CGL. Reset the estimate with a higher buffer on VGL.
60
+ func retryEstimateGas (err error , vgl int64 , in * EstimateInput ) (uint64 , uint64 , error ) {
61
+ if isValidationOOG (err ) && in .attempts < maxRetries {
62
+ return EstimateGas (& EstimateInput {
63
+ Rpc : in .Rpc ,
64
+ EntryPoint : in .EntryPoint ,
65
+ Op : in .Op ,
66
+ Ov : in .Ov ,
67
+ ChainID : in .ChainID ,
68
+ MaxGasLimit : in .MaxGasLimit ,
69
+ attempts : in .attempts + 1 ,
70
+ lastVGL : vgl ,
71
+ })
72
+ }
73
+ return 0 , 0 , err
51
74
}
52
75
53
76
// EstimateGas uses the simulateHandleOp method on the EntryPoint to derive an estimate for
@@ -76,9 +99,9 @@ func EstimateGas(in *EstimateInput) (verificationGas uint64, callGas uint64, err
76
99
// estimate.
77
100
l := int64 (0 )
78
101
r := in .MaxGasLimit .Int64 ()
79
- f := int64 ( 0 )
102
+ f := in . lastVGL
80
103
var simErr error
81
- for r - l >= fallBackBinarySearchCutoff {
104
+ for in . lastVGL == 0 && r - l >= fallBackBinarySearchCutoff {
82
105
m := (l + r ) / 2
83
106
84
107
data ["verificationGasLimit" ] = hexutil .EncodeBig (big .NewInt (int64 (m )))
@@ -113,12 +136,7 @@ func EstimateGas(in *EstimateInput) (verificationGas uint64, callGas uint64, err
113
136
if f == 0 {
114
137
return 0 , 0 , simErr
115
138
}
116
- // TODO: Find a more reliable approach for the edge case where the gas required during a paymaster's
117
- // postOp > gas required during verification. As a workaround we add a configurable percentage buffer if a
118
- // paymaster is included.
119
- if in .Op .GetPaymaster () != common .HexToAddress ("0x" ) {
120
- f = (f * (100 + in .PaymasterBuffer )) / 100
121
- }
139
+ f = (f * (100 + baseVGLBuffer )) / 100
122
140
data ["verificationGasLimit" ] = hexutil .EncodeBig (big .NewInt (int64 (f )))
123
141
124
142
// Find the optimal callGasLimit by setting the gas price to 0 and maxing out the gas limit. We don't run
@@ -138,7 +156,7 @@ func EstimateGas(in *EstimateInput) (verificationGas uint64, callGas uint64, err
138
156
TraceFeeCap : in .Op .MaxFeePerGas ,
139
157
})
140
158
if err != nil {
141
- return 0 , 0 , err
159
+ return retryEstimateGas ( err , f , in )
142
160
}
143
161
144
162
// Calculate final values for verificationGasLimit and callGasLimit.
@@ -211,7 +229,7 @@ func EstimateGas(in *EstimateInput) (verificationGas uint64, callGas uint64, err
211
229
}
212
230
return simOp .VerificationGasLimit .Uint64 (), big .NewInt (f ).Uint64 (), nil
213
231
}
214
- return 0 , 0 , err
232
+ return retryEstimateGas ( err , simOp . VerificationGasLimit . Int64 (), in )
215
233
}
216
234
return simOp .VerificationGasLimit .Uint64 (), simOp .CallGasLimit .Uint64 (), nil
217
235
}
0 commit comments