@@ -636,6 +636,19 @@ impl<
636636 compute_l1_message_queue_hash ( & database, & l1_message, l1_v2_message_queue_start_index)
637637 . await ?;
638638 let l1_message = L1MessageEnvelope :: new ( l1_message, l1_block_number, None , queue_hash) ;
639+
640+ // Perform a consistency check to ensure the previous L1 message exists in the database.
641+ if l1_message. transaction . queue_index > 0 &&
642+ database
643+ . get_l1_message_by_index ( l1_message. transaction . queue_index - 1 )
644+ . await ?
645+ . is_none ( )
646+ {
647+ return Err ( ChainOrchestratorError :: L1MessageQueueGap (
648+ l1_message. transaction . queue_index ,
649+ ) )
650+ }
651+
639652 database. insert_l1_message ( l1_message) . await ?;
640653 Ok ( Some ( event) )
641654 }
@@ -648,6 +661,11 @@ impl<
648661 let txn = database. tx ( ) . await ?;
649662 let prev_batch_index = batch. index - 1 ;
650663
664+ // Perform a consistency check to ensure the previous commit batch exists in the database.
665+ if txn. get_batch_by_index ( prev_batch_index) . await ?. is_none ( ) {
666+ return Err ( ChainOrchestratorError :: BatchCommitGap ( batch. index ) )
667+ }
668+
651669 // remove any batches with an index greater than the previous batch.
652670 let affected = txn. delete_batches_gt_batch_index ( prev_batch_index) . await ?;
653671
@@ -1152,24 +1170,28 @@ mod test {
11521170 rand:: rng ( ) . fill ( bytes. as_mut_slice ( ) ) ;
11531171 let mut u = Unstructured :: new ( & bytes) ;
11541172
1155- let batch_commit = BatchCommitData :: arbitrary ( & mut u) . unwrap ( ) ;
1156- chain_orchestrator
1157- . handle_l1_notification ( L1Notification :: BatchCommit ( batch_commit. clone ( ) ) ) ;
1173+ // Insert a batch commit in the database to satisfy the chain orchestrator consistency
1174+ // checks
1175+ let batch_0 = BatchCommitData { index : 0 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ;
1176+ db. insert_batch ( batch_0) . await . unwrap ( ) ;
1177+
1178+ let batch_1 = BatchCommitData { index : 1 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ;
1179+ chain_orchestrator. handle_l1_notification ( L1Notification :: BatchCommit ( batch_1. clone ( ) ) ) ;
11581180
11591181 let event = chain_orchestrator. next ( ) . await . unwrap ( ) . unwrap ( ) ;
11601182
11611183 // Verify the event structure
11621184 match event {
11631185 ChainOrchestratorEvent :: BatchCommitIndexed { batch_info, safe_head, .. } => {
1164- assert_eq ! ( batch_info. index, batch_commit . index) ;
1165- assert_eq ! ( batch_info. hash, batch_commit . hash) ;
1186+ assert_eq ! ( batch_info. index, batch_1 . index) ;
1187+ assert_eq ! ( batch_info. hash, batch_1 . hash) ;
11661188 assert_eq ! ( safe_head, None ) ; // No safe head since no batch revert
11671189 }
11681190 _ => panic ! ( "Expected BatchCommitIndexed event" ) ,
11691191 }
11701192
1171- let batch_commit_result = db. get_batch_by_index ( batch_commit . index ) . await . unwrap ( ) . unwrap ( ) ;
1172- assert_eq ! ( batch_commit , batch_commit_result) ;
1193+ let batch_commit_result = db. get_batch_by_index ( batch_1 . index ) . await . unwrap ( ) . unwrap ( ) ;
1194+ assert_eq ! ( batch_1 , batch_commit_result) ;
11731195 }
11741196
11751197 #[ tokio:: test]
@@ -1182,6 +1204,15 @@ mod test {
11821204 rand:: rng ( ) . fill ( bytes. as_mut_slice ( ) ) ;
11831205 let mut u = Unstructured :: new ( & bytes) ;
11841206
1207+ // Insert batch 0 into the database to satisfy the consistency conditions in the chain
1208+ // orchestrator
1209+ let batch_0 = BatchCommitData {
1210+ index : 99 ,
1211+ calldata : Arc :: new ( vec ! [ ] . into ( ) ) ,
1212+ ..Arbitrary :: arbitrary ( & mut u) . unwrap ( )
1213+ } ;
1214+ db. insert_batch ( batch_0) . await . unwrap ( ) ;
1215+
11851216 // Create sequential batches
11861217 let batch_1 = BatchCommitData {
11871218 index : 100 ,
@@ -1305,22 +1336,33 @@ mod test {
13051336 rand:: rng ( ) . fill ( bytes. as_mut_slice ( ) ) ;
13061337 let mut u = Unstructured :: new ( & bytes) ;
13071338
1308- let message = TxL1Message {
1339+ // Insert an initial message in the database to satisfy the consistency checks in the chain
1340+ // orchestrator.
1341+ let message_0 = L1MessageEnvelope {
1342+ transaction : TxL1Message {
1343+ queue_index : TEST_L1_MESSAGE_QUEUE_INDEX_BOUNDARY - 2 ,
1344+ ..Arbitrary :: arbitrary ( & mut u) . unwrap ( )
1345+ } ,
1346+ ..Arbitrary :: arbitrary ( & mut u) . unwrap ( )
1347+ } ;
1348+ db. insert_l1_message ( message_0) . await . unwrap ( ) ;
1349+
1350+ let message_1 = TxL1Message {
13091351 queue_index : TEST_L1_MESSAGE_QUEUE_INDEX_BOUNDARY - 1 ,
13101352 ..Arbitrary :: arbitrary ( & mut u) . unwrap ( )
13111353 } ;
13121354 let block_number = u64:: arbitrary ( & mut u) . unwrap ( ) ;
13131355 chain_orchestrator. handle_l1_notification ( L1Notification :: L1Message {
1314- message : message . clone ( ) ,
1356+ message : message_1 . clone ( ) ,
13151357 block_number,
13161358 block_timestamp : 0 ,
13171359 } ) ;
13181360
13191361 let _ = chain_orchestrator. next ( ) . await ;
13201362
13211363 let l1_message_result =
1322- db. get_l1_message_by_index ( message . queue_index ) . await . unwrap ( ) . unwrap ( ) ;
1323- let l1_message = L1MessageEnvelope :: new ( message , block_number, None , None ) ;
1364+ db. get_l1_message_by_index ( message_1 . queue_index ) . await . unwrap ( ) . unwrap ( ) ;
1365+ let l1_message = L1MessageEnvelope :: new ( message_1 , block_number, None , None ) ;
13241366
13251367 assert_eq ! ( l1_message, l1_message_result) ;
13261368 }
@@ -1330,6 +1372,19 @@ mod test {
13301372 // Instantiate chain orchestrator and db
13311373 let ( mut chain_orchestrator, db) = setup_test_chain_orchestrator ( ) . await ;
13321374
1375+ // Insert the previous l1 message in the database to satisfy the chain orchestrator
1376+ // consistency checks.
1377+ let message = L1MessageEnvelope {
1378+ transaction : TxL1Message {
1379+ queue_index : TEST_L1_MESSAGE_QUEUE_INDEX_BOUNDARY - 1 ,
1380+ ..Default :: default ( )
1381+ } ,
1382+ l1_block_number : 1475587 ,
1383+ l2_block_number : None ,
1384+ queue_hash : None ,
1385+ } ;
1386+ db. insert_l1_message ( message) . await . unwrap ( ) ;
1387+
13331388 // insert the previous L1 message in database.
13341389 chain_orchestrator. handle_l1_notification ( L1Notification :: L1Message {
13351390 message : TxL1Message {
@@ -1377,29 +1432,45 @@ mod test {
13771432 rand:: rng ( ) . fill ( bytes. as_mut_slice ( ) ) ;
13781433 let mut u = Unstructured :: new ( & bytes) ;
13791434
1435+ // Insert batch 0 into the database to satisfy the consistency checks in the chain
1436+ // orchestrator
1437+ let batch_0 =
1438+ BatchCommitData { index : 0 , block_number : 0 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ;
1439+ db. insert_batch ( batch_0) . await . unwrap ( ) ;
1440+
1441+ // Insert l1 message into the database to satisfy the consistency checks in the chain
1442+ // orchestrator
1443+ let l1_message = L1MessageEnvelope {
1444+ queue_hash : None ,
1445+ l1_block_number : 0 ,
1446+ l2_block_number : None ,
1447+ transaction : TxL1Message { queue_index : 0 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ,
1448+ } ;
1449+ db. insert_l1_message ( l1_message) . await . unwrap ( ) ;
1450+
13801451 // Generate a 3 random batch inputs and set their block numbers
13811452 let mut batch_commit_block_1 = BatchCommitData :: arbitrary ( & mut u) . unwrap ( ) ;
13821453 batch_commit_block_1. block_number = 1 ;
13831454 batch_commit_block_1. index = 1 ;
13841455 let batch_commit_block_1 = batch_commit_block_1;
13851456
1386- let mut batch_commit_block_20 = BatchCommitData :: arbitrary ( & mut u) . unwrap ( ) ;
1387- batch_commit_block_20 . block_number = 20 ;
1388- batch_commit_block_20 . index = 20 ;
1389- let batch_commit_block_20 = batch_commit_block_20 ;
1457+ let mut batch_commit_block_2 = BatchCommitData :: arbitrary ( & mut u) . unwrap ( ) ;
1458+ batch_commit_block_2 . block_number = 2 ;
1459+ batch_commit_block_2 . index = 2 ;
1460+ let batch_commit_block_2 = batch_commit_block_2 ;
13901461
1391- let mut batch_commit_block_30 = BatchCommitData :: arbitrary ( & mut u) . unwrap ( ) ;
1392- batch_commit_block_30 . block_number = 30 ;
1393- batch_commit_block_30 . index = 30 ;
1394- let batch_commit_block_30 = batch_commit_block_30 ;
1462+ let mut batch_commit_block_3 = BatchCommitData :: arbitrary ( & mut u) . unwrap ( ) ;
1463+ batch_commit_block_3 . block_number = 3 ;
1464+ batch_commit_block_3 . index = 3 ;
1465+ let batch_commit_block_3 = batch_commit_block_3 ;
13951466
13961467 // Index batch inputs
13971468 chain_orchestrator
13981469 . handle_l1_notification ( L1Notification :: BatchCommit ( batch_commit_block_1. clone ( ) ) ) ;
13991470 chain_orchestrator
1400- . handle_l1_notification ( L1Notification :: BatchCommit ( batch_commit_block_20 . clone ( ) ) ) ;
1471+ . handle_l1_notification ( L1Notification :: BatchCommit ( batch_commit_block_2 . clone ( ) ) ) ;
14011472 chain_orchestrator
1402- . handle_l1_notification ( L1Notification :: BatchCommit ( batch_commit_block_30 . clone ( ) ) ) ;
1473+ . handle_l1_notification ( L1Notification :: BatchCommit ( batch_commit_block_3 . clone ( ) ) ) ;
14031474
14041475 // Generate 3 random L1 messages and set their block numbers
14051476 let l1_message_block_1 = L1MessageEnvelope {
@@ -1408,15 +1479,15 @@ mod test {
14081479 l2_block_number : None ,
14091480 transaction : TxL1Message { queue_index : 1 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ,
14101481 } ;
1411- let l1_message_block_20 = L1MessageEnvelope {
1482+ let l1_message_block_2 = L1MessageEnvelope {
14121483 queue_hash : None ,
1413- l1_block_number : 20 ,
1484+ l1_block_number : 2 ,
14141485 l2_block_number : None ,
14151486 transaction : TxL1Message { queue_index : 2 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ,
14161487 } ;
1417- let l1_message_block_30 = L1MessageEnvelope {
1488+ let l1_message_block_3 = L1MessageEnvelope {
14181489 queue_hash : None ,
1419- l1_block_number : 30 ,
1490+ l1_block_number : 3 ,
14201491 l2_block_number : None ,
14211492 transaction : TxL1Message { queue_index : 3 , ..Arbitrary :: arbitrary ( & mut u) . unwrap ( ) } ,
14221493 } ;
@@ -1428,18 +1499,18 @@ mod test {
14281499 block_timestamp : 0 ,
14291500 } ) ;
14301501 chain_orchestrator. handle_l1_notification ( L1Notification :: L1Message {
1431- message : l1_message_block_20 . clone ( ) . transaction ,
1432- block_number : l1_message_block_20 . clone ( ) . l1_block_number ,
1502+ message : l1_message_block_2 . clone ( ) . transaction ,
1503+ block_number : l1_message_block_2 . clone ( ) . l1_block_number ,
14331504 block_timestamp : 0 ,
14341505 } ) ;
14351506 chain_orchestrator. handle_l1_notification ( L1Notification :: L1Message {
1436- message : l1_message_block_30 . clone ( ) . transaction ,
1437- block_number : l1_message_block_30 . clone ( ) . l1_block_number ,
1507+ message : l1_message_block_3 . clone ( ) . transaction ,
1508+ block_number : l1_message_block_3 . clone ( ) . l1_block_number ,
14381509 block_timestamp : 0 ,
14391510 } ) ;
14401511
1441- // Reorg at block 20
1442- chain_orchestrator. handle_l1_notification ( L1Notification :: Reorg ( 20 ) ) ;
1512+ // Reorg at block 2
1513+ chain_orchestrator. handle_l1_notification ( L1Notification :: Reorg ( 2 ) ) ;
14431514
14441515 for _ in 0 ..7 {
14451516 chain_orchestrator. next ( ) . await . unwrap ( ) . unwrap ( ) ;
@@ -1451,7 +1522,7 @@ mod test {
14511522
14521523 assert_eq ! ( 3 , batch_commits. len( ) ) ;
14531524 assert ! ( batch_commits. contains( & batch_commit_block_1) ) ;
1454- assert ! ( batch_commits. contains( & batch_commit_block_20 ) ) ;
1525+ assert ! ( batch_commits. contains( & batch_commit_block_2 ) ) ;
14551526
14561527 // check that the L1 message at block 30 is deleted
14571528 let l1_messages = db
@@ -1461,9 +1532,9 @@ mod test {
14611532 . map ( |res| res. unwrap ( ) )
14621533 . collect :: < Vec < _ > > ( )
14631534 . await ;
1464- assert_eq ! ( 2 , l1_messages. len( ) ) ;
1535+ assert_eq ! ( 3 , l1_messages. len( ) ) ;
14651536 assert ! ( l1_messages. contains( & l1_message_block_1) ) ;
1466- assert ! ( l1_messages. contains( & l1_message_block_20 ) ) ;
1537+ assert ! ( l1_messages. contains( & l1_message_block_2 ) ) ;
14671538 }
14681539
14691540 // We ignore this test for now as it requires a more complex setup which leverages an L2 node
0 commit comments