Skip to content

Commit f8680a0

Browse files
feat: verify L1 message index (#241)
* feat: verify L1 message index * fix: propagate errors * fix: apply suggestions * fix: clippy --------- Co-authored-by: greg <[email protected]> Co-authored-by: Gregory Edison <[email protected]>
1 parent fd29f80 commit f8680a0

File tree

2 files changed

+55
-20
lines changed

2 files changed

+55
-20
lines changed

crates/database/db/src/db.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,46 @@ mod test {
298298
.unwrap()
299299
.unwrap();
300300
assert_eq!(l1_message_1, l1_message_1_from_db);
301+
let l1_message_2_from_db = db
302+
.get_l1_message_by_index(l1_message_2.transaction.queue_index)
303+
.await
304+
.unwrap()
305+
.unwrap();
306+
307+
assert_eq!(l1_message_2, l1_message_2_from_db);
308+
}
309+
310+
#[tokio::test]
311+
async fn test_database_duplicate_l1_index() {
312+
// Setup the test database.
313+
let db = setup_test_db().await;
314+
315+
// Generate unstructured bytes.
316+
let mut bytes = [0u8; 2048];
317+
rand::rng().fill(bytes.as_mut_slice());
318+
let mut u = Unstructured::new(&bytes);
319+
320+
// Generate 2 random L1Messages.
321+
let mut l1_message_1 = L1MessageEnvelope::arbitrary(&mut u).unwrap();
322+
let original_l1_message_1 = l1_message_1.clone();
323+
let l1_message_2 = L1MessageEnvelope::arbitrary(&mut u).unwrap();
324+
325+
// Insert the L1Messages into the database in a transaction.
326+
let tx = db.tx().await.unwrap();
327+
tx.insert_l1_message(l1_message_1.clone()).await.unwrap();
328+
tx.insert_l1_message(l1_message_2.clone()).await.unwrap();
329+
// Modify l1_block_number of l1_message_1 and attempt to insert again
330+
l1_message_1.l1_block_number = 1000;
331+
tx.insert_l1_message(l1_message_1.clone()).await.unwrap();
332+
tx.commit().await.unwrap();
333+
334+
// Check that the L1Messages are in the database.
335+
let l1_message_1_from_db = db
336+
.get_l1_message_by_index(l1_message_1.transaction.queue_index)
337+
.await
338+
.unwrap()
339+
.unwrap();
340+
assert_eq!(original_l1_message_1, l1_message_1_from_db);
301341
let l1_message_2_from_db = db
302342
.get_l1_message_by_index(l1_message_2.transaction.queue_index)
303343
.await

crates/database/db/src/operations.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rollup_node_primitives::{
99
use scroll_alloy_rpc_types_engine::BlockDataHint;
1010
use sea_orm::{
1111
sea_query::{Expr, OnConflict},
12-
ActiveModelTrait, ColumnTrait, Condition, EntityTrait, QueryFilter, QueryOrder, QuerySelect,
13-
Set,
12+
ActiveModelTrait, ColumnTrait, Condition, DbErr, EntityTrait, QueryFilter, QueryOrder,
13+
QuerySelect, Set,
1414
};
1515

1616
/// The [`DatabaseOperations`] trait provides methods for interacting with the database.
@@ -170,26 +170,21 @@ pub trait DatabaseOperations: DatabaseConnectionProvider {
170170

171171
/// Insert an [`L1MessageEnvelope`] into the database.
172172
async fn insert_l1_message(&self, l1_message: L1MessageEnvelope) -> Result<(), DatabaseError> {
173-
tracing::trace!(target: "scroll::db", queue_index = l1_message.transaction.queue_index, "Inserting L1 message into database.");
173+
let l1_index = l1_message.transaction.queue_index;
174+
tracing::trace!(target: "scroll::db", queue_index = l1_index, "Inserting L1 message into database.");
175+
174176
let l1_message: models::l1_message::ActiveModel = l1_message.into();
175-
models::l1_message::Entity::insert(l1_message)
176-
.on_conflict(
177-
OnConflict::column(models::l1_message::Column::QueueIndex)
178-
.update_columns(vec![
179-
models::l1_message::Column::QueueHash,
180-
models::l1_message::Column::Hash,
181-
models::l1_message::Column::L1BlockNumber,
182-
models::l1_message::Column::GasLimit,
183-
models::l1_message::Column::To,
184-
models::l1_message::Column::Value,
185-
models::l1_message::Column::Sender,
186-
models::l1_message::Column::Input,
187-
])
188-
.to_owned(),
189-
)
177+
let result = models::l1_message::Entity::insert(l1_message)
178+
.on_conflict_do_nothing()
190179
.exec(self.get_connection())
191-
.await?;
192-
Ok(())
180+
.await;
181+
182+
if matches!(result, Err(DbErr::RecordNotInserted)) {
183+
tracing::error!(target: "scroll::db", queue_index = l1_index, "L1 message already exists");
184+
Ok(())
185+
} else {
186+
Ok(result.map(|_| ())?)
187+
}
193188
}
194189

195190
/// Delete all [`L1MessageEnvelope`]s with a block number greater than the provided block

0 commit comments

Comments
 (0)