Skip to content

feat: l2 block data model update and reorg handling #95

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 7, 2025
5 changes: 4 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ scroll-alloy-provider = { git = "https://github.com/scroll-tech/reth.git", defau
scroll-alloy-rpc-types-engine = { git = "https://github.com/scroll-tech/reth.git", default-features = false }

# reth
reth-chainspec = { git = "https://github.com/scroll-tech/reth.git", default-features = false }
reth-e2e-test-utils = { git = "https://github.com/scroll-tech/reth.git" }
reth-eth-wire-types = { git = "https://github.com/scroll-tech/reth.git", default-features = false }
reth-network = { git = "https://github.com/scroll-tech/reth.git", default-features = false }
Expand All @@ -154,6 +155,7 @@ reth-provider = { git = "https://github.com/scroll-tech/reth.git", default-featu
reth-rpc-server-types = { git = "https://github.com/scroll-tech/reth.git" }
reth-tasks = { git = "https://github.com/scroll-tech/reth.git" }
reth-tokio-util = { git = "https://github.com/scroll-tech/reth.git", default-features = false }
reth-tracing = { git = "https://github.com/scroll-tech/reth.git", default-features = false }

# reth-scroll
reth-scroll-chainspec = { git = "https://github.com/scroll-tech/reth.git", default-features = false }
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ This repository is a modular Rust workspace for the Scroll rollup node. It is de
│ ├── primitives/
│ ├── providers/
│ ├── scroll-wire/
│ ├── signer/
│ ├── sequencer/
│ └── watcher/
├── Cargo.toml # Workspace manifest
Expand All @@ -51,6 +52,7 @@ This repository is a modular Rust workspace for the Scroll rollup node. It is de
- **crates/node/**: Node manager and orchestration logic.
- **crates/primitives/**: Shared primitive types (blocks, batches, attributes, etc.).
- **crates/providers/**: Abstractions for data providers (L1, beacon, block, etc.).
- **crates/signer/**: Implements signing logic for blocks.
- **crates/scroll-wire/**: Wire protocol definitions for Scroll-specific networking.
- **crates/sequencer/**: Sequencer logic for ordering and batching transactions.
- **crates/watcher/**: Monitors L1 chain state and handles reorgs and notifications.
Expand Down
4 changes: 2 additions & 2 deletions bin/rollup/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::{sync::Arc, time::Duration};
use alloy_provider::ProviderBuilder;
use alloy_rpc_client::RpcClient;
use alloy_transport::layers::RetryBackoffLayer;
use migration::MigratorTrait;
use reth_network::{config::NetworkMode, NetworkManager, PeersInfo};
use reth_node_api::TxTy;
use reth_node_builder::{components::NetworkBuilder, BuilderContext, FullNodeTypes};
Expand All @@ -25,6 +24,7 @@ use rollup_node_watcher::L1Watcher;
use scroll_alloy_provider::ScrollAuthEngineApiProvider;
use scroll_db::{Database, DatabaseConnectionProvider};
use scroll_engine::{EngineDriver, ForkchoiceState};
use scroll_migration::MigratorTrait;
use scroll_network::NetworkManager as ScrollNetworkManager;
use scroll_wire::{ProtocolHandler, ScrollWireConfig};
use tracing::info;
Expand Down Expand Up @@ -159,7 +159,7 @@ where
let db = Database::new(&database_path).await?;

// Run the database migrations
migration::Migrator::up(db.get_connection(), None).await?;
scroll_migration::Migrator::up(db.get_connection(), None).await?;

// Wrap the database in an Arc
let db = Arc::new(db);
Expand Down
32 changes: 22 additions & 10 deletions crates/database/db/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ mod test {
use arbitrary::{Arbitrary, Unstructured};
use futures::StreamExt;
use rand::Rng;
use rollup_node_primitives::{BatchCommitData, BatchInfo, BlockInfo, L1MessageEnvelope};
use rollup_node_primitives::{
BatchCommitData, BatchInfo, BlockInfo, L1MessageEnvelope, L2BlockInfoWithL1Messages,
};
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};

#[tokio::test]
Expand Down Expand Up @@ -137,7 +139,7 @@ mod test {
let db = setup_test_db().await;

// db should contain the seeded data after migration.
let data = db.get_block_data(0.into()).await.unwrap();
let data = db.get_l2_block_data_hint(0.into()).await.unwrap();
assert!(data.is_some());
}

Expand All @@ -154,13 +156,18 @@ mod test {
// Generate randoms BatchInfo and BlockInfo with increasing block numbers.
let mut block_number = 100;
let data = BatchCommitData { index: 100, ..Arbitrary::arbitrary(&mut u).unwrap() };
let batch_info = data.clone().into();
let batch_info: BatchInfo = data.clone().into();
db.insert_batch(data).await.unwrap();

for _ in 0..10 {
let block_info =
BlockInfo { number: block_number, hash: B256::arbitrary(&mut u).unwrap() };
db.insert_derived_block(block_info, batch_info).await.unwrap();
let block_info = L2BlockInfoWithL1Messages {
block_info: BlockInfo {
number: block_number,
hash: B256::arbitrary(&mut u).unwrap(),
},
l1_messages: vec![],
};
db.insert_block(block_info, batch_info.into()).await.unwrap();
block_number += 1;
}

Expand All @@ -183,7 +190,7 @@ mod test {
// Generate randoms BatchInfo and BlockInfo with increasing block numbers.
let mut block_number = 100;
let first_batch = BatchCommitData { index: 100, ..Arbitrary::arbitrary(&mut u).unwrap() };
let first_batch_info = first_batch.clone().into();
let first_batch_info: BatchInfo = first_batch.clone().into();

let second_batch = BatchCommitData { index: 250, ..Arbitrary::arbitrary(&mut u).unwrap() };
let second_batch_info: BatchInfo = second_batch.clone().into();
Expand All @@ -192,9 +199,14 @@ mod test {
db.insert_batch(second_batch).await.unwrap();

for _ in 0..10 {
let block_info =
BlockInfo { number: block_number, hash: B256::arbitrary(&mut u).unwrap() };
db.insert_derived_block(block_info, first_batch_info).await.unwrap();
let block_info = L2BlockInfoWithL1Messages {
block_info: BlockInfo {
number: block_number,
hash: B256::arbitrary(&mut u).unwrap(),
},
l1_messages: vec![],
};
db.insert_block(block_info, first_batch_info.into()).await.unwrap();
block_number += 1;
}

Expand Down
4 changes: 2 additions & 2 deletions crates/database/db/src/models/batch_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ pub struct Model {
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {
/// A one-to-many relation with the derived block table.
#[sea_orm(has_many = "super::derived_block::Entity")]
#[sea_orm(has_many = "super::l2_block::Entity")]
DerivedBlock,
}

impl Related<super::derived_block::Entity> for Entity {
impl Related<super::l2_block::Entity> for Entity {
fn to() -> RelationDef {
Relation::DerivedBlock.def()
}
Expand Down
13 changes: 9 additions & 4 deletions crates/database/db/src/models/l1_message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ use sea_orm::{entity::prelude::*, ActiveValue};
#[sea_orm(table_name = "l1_message")]
pub struct Model {
#[sea_orm(primary_key)]
queue_index: i64,
pub(crate) queue_index: i64,
queue_hash: Option<Vec<u8>>,
block_number: i64,
hash: Vec<u8>,
l1_block_number: i64,
gas_limit: String,
to: Vec<u8>,
value: Vec<u8>,
sender: Vec<u8>,
input: Vec<u8>,
pub(crate) l2_block_number: Option<i64>,
}

/// The relation for the L1 message model.
Expand All @@ -30,20 +32,23 @@ impl From<L1MessageEnvelope> for ActiveModel {
Self {
queue_index: ActiveValue::Set(value.transaction.queue_index as i64),
queue_hash: ActiveValue::Set(value.queue_hash.map(|q| q.to_vec())),
block_number: ActiveValue::Set(value.block_number as i64),
hash: ActiveValue::Set(value.transaction.tx_hash().to_vec()),
l1_block_number: ActiveValue::Set(value.l1_block_number as i64),
gas_limit: ActiveValue::Set(value.transaction.gas_limit.to_string()),
to: ActiveValue::Set(value.transaction.to.to_vec()),
value: ActiveValue::Set(value.transaction.value.to_le_bytes_vec()),
sender: ActiveValue::Set(value.transaction.sender.to_vec()),
input: ActiveValue::Set(value.transaction.input.to_vec()),
l2_block_number: ActiveValue::Set(value.l2_block_number.map(|b| b as i64)),
}
}
}

impl From<Model> for L1MessageEnvelope {
fn from(value: Model) -> Self {
Self {
block_number: value.block_number as u64,
l1_block_number: value.l1_block_number as u64,
l2_block_number: value.l2_block_number.map(|b| b as u64),
queue_hash: value.queue_hash.map(|q| B256::from_slice(&q)),
transaction: TxL1Message {
queue_index: value.queue_index as u64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ use sea_orm::{entity::prelude::*, ActiveValue};

/// A database model that represents a derived block.
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "derived_block")]
#[sea_orm(table_name = "l2_block")]
pub struct Model {
#[sea_orm(primary_key)]
block_number: i64,
block_hash: Vec<u8>,
batch_index: i64,
batch_hash: Vec<u8>,
batch_index: Option<i64>,
batch_hash: Option<Vec<u8>>,
}

impl Model {
Expand Down Expand Up @@ -42,17 +42,32 @@ impl Related<super::batch_commit::Entity> for Entity {
/// The active model behavior for the batch input model.
impl ActiveModelBehavior for ActiveModel {}

impl From<(BlockInfo, BatchInfo)> for ActiveModel {
fn from((block_info, batch_info): (BlockInfo, BatchInfo)) -> Self {
impl From<(BlockInfo, Option<BatchInfo>)> for ActiveModel {
fn from((block_info, batch_info): (BlockInfo, Option<BatchInfo>)) -> Self {
Self {
block_number: ActiveValue::Set(
block_info.number.try_into().expect("block number should fit in i64"),
),
block_hash: ActiveValue::Set(block_info.hash.to_vec()),
batch_index: ActiveValue::Set(
batch_info.index.try_into().expect("index should fit in i64"),
batch_info.map(|x| x.index.try_into().expect("index should fit in i64")),
),
batch_hash: ActiveValue::Set(batch_info.hash.to_vec()),
batch_hash: ActiveValue::Set(batch_info.map(|x| x.hash.to_vec())),
}
}
}

impl From<Model> for (BlockInfo, Option<BatchInfo>) {
fn from(value: Model) -> Self {
(
BlockInfo {
number: value.block_number as u64,
hash: B256::from_slice(&value.block_hash),
},
value.batch_hash.map(|b| BatchInfo {
index: value.batch_index.unwrap() as u64,
hash: B256::from_slice(&b),
}),
)
}
}
2 changes: 1 addition & 1 deletion crates/database/db/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pub mod batch_commit;

/// This module contains the derived block model.
pub mod derived_block;
pub mod l2_block;

/// This module contains the block data database model.
pub mod block_data;
Expand Down
Loading
Loading