@@ -27,6 +27,7 @@ async fn revert_protection_monitor_transaction_gc() -> eyre::Result<()> {
27
27
. with_revert ( )
28
28
. with_bundle ( BundleOpts {
29
29
block_number_max : Some ( i) ,
30
+ block_number_min : None ,
30
31
} )
31
32
. send ( )
32
33
. await ?;
@@ -123,42 +124,106 @@ async fn revert_protection_bundle() -> eyre::Result<()> {
123
124
assert ! ( block_generated. includes( * valid_bundle. tx_hash( ) ) ) ;
124
125
125
126
let bundle_opts = BundleOpts {
126
- block_number_max : Some ( 4 ) ,
127
+ block_number_max : Some ( 5 ) ,
128
+ block_number_min : None ,
127
129
} ;
128
130
129
- let reverted_bundle = harness
131
+ let reverted_bundle_0 = harness
130
132
. create_transaction ( )
131
133
. with_revert ( )
134
+ . with_reverted_hash ( )
132
135
. with_bundle ( bundle_opts)
133
136
. send ( )
134
137
. await ?;
135
138
136
- // Test 2: Bundle reverts. It is not included in the block
139
+ // Test 2: Bundle reverts. It is included in the block since the transaction
140
+ // includes the reverted_hashes field
137
141
let block_generated = generator. generate_block ( ) . await ?; // Block 3
138
- assert ! ( block_generated. not_includes( * reverted_bundle. tx_hash( ) ) ) ;
142
+ assert ! ( block_generated. includes( * reverted_bundle_0. tx_hash( ) ) ) ;
143
+
144
+ let reverted_bundle_1 = harness
145
+ . create_transaction ( )
146
+ . with_revert ( )
147
+ . with_bundle ( bundle_opts)
148
+ . send ( )
149
+ . await ?;
150
+
151
+ // Test 3: Bundle reverts. It is not included in the block since it reverts
152
+ // and the hash is not in the reverted_hashes field.
153
+ let block_generated = generator. generate_block ( ) . await ?; // Block 4
154
+ assert ! ( block_generated. not_includes( * reverted_bundle_1. tx_hash( ) ) ) ;
139
155
140
156
// After the block the transaction is still pending in the pool
141
157
assert ! ( harness
142
- . check_tx_in_pool( * reverted_bundle . tx_hash( ) )
158
+ . check_tx_in_pool( * reverted_bundle_1 . tx_hash( ) )
143
159
. await ?
144
160
. is_pending( ) ) ;
145
161
146
162
// Test 3: Chain progresses beyond the bundle range. The transaction is dropped from the pool
147
- generator. generate_block ( ) . await ?; // Block 4
163
+ generator. generate_block ( ) . await ?; // Block 5
148
164
assert ! ( harness
149
- . check_tx_in_pool( * reverted_bundle . tx_hash( ) )
165
+ . check_tx_in_pool( * reverted_bundle_1 . tx_hash( ) )
150
166
. await ?
151
167
. is_pending( ) ) ;
152
168
153
- generator. generate_block ( ) . await ?; // Block 5
169
+ generator. generate_block ( ) . await ?; // Block 6
154
170
assert ! ( harness
155
- . check_tx_in_pool( * reverted_bundle . tx_hash( ) )
171
+ . check_tx_in_pool( * reverted_bundle_1 . tx_hash( ) )
156
172
. await ?
157
173
. is_dropped( ) ) ;
158
174
159
175
Ok ( ( ) )
160
176
}
161
177
178
+ /// Test the behaviour of the revert protection bundle with a min block number.
179
+ #[ tokio:: test]
180
+ async fn revert_protection_bundle_min_block_number ( ) -> eyre:: Result < ( ) > {
181
+ let harness = TestHarnessBuilder :: new ( "revert_protection_bundle_min_block_number" )
182
+ . with_revert_protection ( )
183
+ . build ( )
184
+ . await ?;
185
+
186
+ let mut generator = harness. block_generator ( ) . await ?;
187
+
188
+ // The bundle is valid when the min block number is equal to the current block
189
+ let bundle_with_min_block = harness
190
+ . create_transaction ( )
191
+ . with_revert ( ) // the transaction reverts but it is included in the block
192
+ . with_reverted_hash ( )
193
+ . with_bundle ( BundleOpts {
194
+ block_number_max : None ,
195
+ block_number_min : Some ( 2 ) ,
196
+ } )
197
+ . send ( )
198
+ . await ?;
199
+
200
+ let block = generator. generate_block ( ) . await ?; // Block 1, bundle still not valid
201
+ assert ! ( block. not_includes( * bundle_with_min_block. tx_hash( ) ) ) ;
202
+
203
+ let block = generator. generate_block ( ) . await ?; // Block 2, bundle is valid
204
+ assert ! ( block. includes( * bundle_with_min_block. tx_hash( ) ) ) ;
205
+
206
+ // Send a bundle with a match of min and max block number
207
+ let bundle_with_min_and_max_block = harness
208
+ . create_transaction ( )
209
+ . with_revert ( )
210
+ . with_reverted_hash ( )
211
+ . with_bundle ( BundleOpts {
212
+ block_number_max : Some ( 4 ) ,
213
+ block_number_min : Some ( 4 ) ,
214
+ } )
215
+ . send ( )
216
+ . await ?;
217
+
218
+ let block = generator. generate_block ( ) . await ?; // Block 3, bundle still not valid
219
+ assert ! ( block. not_includes( * bundle_with_min_and_max_block. tx_hash( ) ) ) ;
220
+
221
+ let block = generator. generate_block ( ) . await ?; // Block 4, bundle is valid
222
+ assert ! ( block. includes( * bundle_with_min_and_max_block. tx_hash( ) ) ) ;
223
+
224
+ Ok ( ( ) )
225
+ }
226
+
162
227
/// Test the range limits for the revert protection bundle.
163
228
#[ tokio:: test]
164
229
async fn revert_protection_bundle_range_limits ( ) -> eyre:: Result < ( ) > {
@@ -176,31 +241,54 @@ async fn revert_protection_bundle_range_limits() -> eyre::Result<()> {
176
241
async fn send_bundle (
177
242
harness : & TestHarness ,
178
243
block_number_max : u64 ,
244
+ block_number_min : Option < u64 > ,
179
245
) -> eyre:: Result < PendingTransactionBuilder < Optimism > > {
180
246
harness
181
247
. create_transaction ( )
182
248
. with_bundle ( BundleOpts {
183
249
block_number_max : Some ( block_number_max) ,
250
+ block_number_min : block_number_min,
184
251
} )
185
252
. send ( )
186
253
. await
187
254
}
188
255
189
256
// Max block cannot be a past block
190
- assert ! ( send_bundle( & harness, 1 ) . await . is_err( ) ) ;
257
+ assert ! ( send_bundle( & harness, 1 , None ) . await . is_err( ) ) ;
191
258
192
259
// Bundles are valid if their max block in in between the current block and the max block range
193
- let next_valid_block = 3 ;
260
+ let current_block = 2 ;
261
+ let next_valid_block = current_block + 1 ;
194
262
195
263
for i in next_valid_block..next_valid_block + MAX_BLOCK_RANGE_BLOCKS {
196
- assert ! ( send_bundle( & harness, i) . await . is_ok( ) ) ;
264
+ assert ! ( send_bundle( & harness, i, None ) . await . is_ok( ) ) ;
197
265
}
198
266
199
267
// A bundle with a block out of range is invalid
268
+ assert ! ( send_bundle(
269
+ & harness,
270
+ next_valid_block + MAX_BLOCK_RANGE_BLOCKS + 1 ,
271
+ None
272
+ )
273
+ . await
274
+ . is_err( ) ) ;
275
+
276
+ // A bundle with a min block number higher than the max block is invalid
277
+ assert ! ( send_bundle( & harness, 1 , Some ( 2 ) ) . await . is_err( ) ) ;
278
+
279
+ // A bundle with a min block number lower or equal to the current block is valid
280
+ assert ! ( send_bundle( & harness, next_valid_block, Some ( current_block) )
281
+ . await
282
+ . is_ok( ) ) ;
283
+ assert ! ( send_bundle( & harness, next_valid_block, Some ( 0 ) )
284
+ . await
285
+ . is_ok( ) ) ;
286
+
287
+ // A bundle with a min block equal to max block is valid
200
288
assert ! (
201
- send_bundle( & harness, next_valid_block + MAX_BLOCK_RANGE_BLOCKS + 1 )
289
+ send_bundle( & harness, next_valid_block, Some ( next_valid_block ) )
202
290
. await
203
- . is_err ( )
291
+ . is_ok ( )
204
292
) ;
205
293
206
294
Ok ( ( ) )
@@ -249,6 +337,7 @@ async fn revert_protection_check_transaction_receipt_status_message() -> eyre::R
249
337
. with_revert ( )
250
338
. with_bundle ( BundleOpts {
251
339
block_number_max : Some ( 3 ) ,
340
+ block_number_min : None ,
252
341
} )
253
342
. send ( )
254
343
. await ?;
0 commit comments