Skip to content

Commit 24582e4

Browse files
feat(rpc): Modify getL1Message* rpc to acces L1MesageKey (#378)
* feat(rpc): Modify getL1Message* rpc to acces L1MesageKey * fix: add serialization tests --------- Co-authored-by: frisitano <[email protected]>
1 parent f64369c commit 24582e4

File tree

9 files changed

+125
-24
lines changed

9 files changed

+125
-24
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/chain-orchestrator/src/handle/command.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use reth_network_api::FullNetwork;
44
use reth_scroll_node::ScrollNetworkPrimitives;
55
use reth_tokio_util::EventStream;
66
use rollup_node_primitives::{BlockInfo, L1MessageEnvelope};
7+
use scroll_db::L1MessageKey;
78
use scroll_network::ScrollNetworkHandle;
89
use tokio::sync::oneshot;
910

@@ -35,5 +36,5 @@ pub enum ChainOrchestratorCommand<N: FullNetwork<Primitives = ScrollNetworkPrimi
3536
#[derive(Debug)]
3637
pub enum DatabaseQuery {
3738
/// Get L1 message by its index.
38-
GetL1MessageByIndex(u64, oneshot::Sender<Option<L1MessageEnvelope>>),
39+
GetL1MessageByKey(L1MessageKey, oneshot::Sender<Option<L1MessageEnvelope>>),
3940
}

crates/chain-orchestrator/src/handle/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use reth_network_api::FullNetwork;
66
use reth_scroll_node::ScrollNetworkPrimitives;
77
use reth_tokio_util::EventStream;
88
use rollup_node_primitives::{BlockInfo, L1MessageEnvelope};
9+
use scroll_db::L1MessageKey;
910
use scroll_network::ScrollNetworkHandle;
1011
use tokio::sync::{mpsc, oneshot};
1112
use tracing::error;
@@ -91,13 +92,13 @@ impl<N: FullNetwork<Primitives = ScrollNetworkPrimitives>> ChainOrchestratorHand
9192
}
9293

9394
/// Get an L1 message by its index.
94-
pub async fn get_l1_message_by_index(
95+
pub async fn get_l1_message_by_key(
9596
&self,
96-
index: u64,
97+
key: L1MessageKey,
9798
) -> Result<Option<L1MessageEnvelope>, oneshot::error::RecvError> {
9899
let (tx, rx) = oneshot::channel();
99100
self.send_command(ChainOrchestratorCommand::DatabaseQuery(
100-
DatabaseQuery::GetL1MessageByIndex(index, tx),
101+
DatabaseQuery::GetL1MessageByKey(key, tx),
101102
));
102103
rx.await
103104
}

crates/chain-orchestrator/src/lib.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -379,12 +379,9 @@ impl<
379379
}
380380
}
381381
ChainOrchestratorCommand::DatabaseQuery(query) => match query {
382-
DatabaseQuery::GetL1MessageByIndex(index, sender) => {
383-
let l1_message = self
384-
.database
385-
.get_n_l1_messages(Some(L1MessageKey::from_queue_index(index)), 1)
386-
.await?
387-
.pop();
382+
DatabaseQuery::GetL1MessageByKey(l1_message_key, sender) => {
383+
let l1_message =
384+
self.database.get_n_l1_messages(Some(l1_message_key), 1).await?.pop();
388385
let _ = sender.send(l1_message);
389386
}
390387
},

crates/database/db/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ futures.workspace = true
2828
metrics.workspace = true
2929
metrics-derive.workspace = true
3030
sea-orm = { workspace = true, features = ["sqlx-sqlite", "runtime-tokio-native-tls", "macros"] }
31+
serde.workspace = true
3132
serde_json.workspace = true
3233
tempfile = { version = "3.20.0", optional = true }
3334
thiserror.workspace = true

crates/database/db/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub use models::*;
1616

1717
mod operations;
1818
pub use operations::{
19-
DatabaseReadOperations, DatabaseWriteOperations, L1MessageKey, NotIncludedStart, UnwindResult,
19+
DatabaseReadOperations, DatabaseWriteOperations, L1MessageKey, NotIncludedKey, UnwindResult,
2020
};
2121

2222
pub use sea_orm::EntityTrait;

crates/database/db/src/operations.rs

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ impl<T: WriteConnectionProvider + ?Sized + Sync> DatabaseWriteOperations for T {
388388
let Some((block_info, batch_info)) =
389389
self.get_latest_safe_l2_info().await?.filter(|(block_info, _)| block_info.number > 0)
390390
else {
391-
return Ok((None, None))
391+
return Ok((None, None));
392392
};
393393
let batch = self.get_batch_by_index(batch_info.index).await?.expect("batch must exist");
394394
Ok((Some(block_info), Some(batch.block_number.saturating_add(1))))
@@ -864,7 +864,7 @@ impl<T: ReadConnectionProvider + Sync + ?Sized> DatabaseReadOperations for T {
864864
// Provides a stream over all L1 messages with increasing queue index starting that have
865865
// not been included in an L2 block and have a block number less than or equal to the
866866
// finalized L1 block number (they have been finalized on L1).
867-
Some(L1MessageKey::NotIncluded(NotIncludedStart::FinalizedWithBlockDepth(depth))) => {
867+
Some(L1MessageKey::NotIncluded(NotIncludedKey::FinalizedWithBlockDepth(depth))) => {
868868
// Lookup the finalized L1 block number.
869869
let finalized_block_number = self.get_finalized_l1_block_number().await?;
870870

@@ -898,7 +898,7 @@ impl<T: ReadConnectionProvider + Sync + ?Sized> DatabaseReadOperations for T {
898898
// included in an L2 block and have a block number less than or equal to the
899899
// latest L1 block number minus the provided depth (they have been sufficiently deep
900900
// on L1 to be considered safe to include - reorg risk is low).
901-
Some(L1MessageKey::NotIncluded(NotIncludedStart::BlockDepth(depth))) => {
901+
Some(L1MessageKey::NotIncluded(NotIncludedKey::BlockDepth(depth))) => {
902902
// Lookup the latest L1 block number.
903903
let latest_block_number = self.get_latest_l1_block_number().await?;
904904

@@ -1055,7 +1055,8 @@ impl<T: ReadConnectionProvider + Sync + ?Sized> DatabaseReadOperations for T {
10551055
/// A key for an L1 message stored in the database.
10561056
///
10571057
/// It can either be the queue index, queue hash or the transaction hash.
1058-
#[derive(Debug, Clone, PartialEq, Eq)]
1058+
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1059+
#[serde(rename_all = "camelCase")]
10591060
pub enum L1MessageKey {
10601061
/// The queue index of the message.
10611062
QueueIndex(u64),
@@ -1066,7 +1067,7 @@ pub enum L1MessageKey {
10661067
/// Start from the first message for the provided block number.
10671068
BlockNumber(u64),
10681069
/// Start from messages that have not been included in a block yet.
1069-
NotIncluded(NotIncludedStart),
1070+
NotIncluded(NotIncludedKey),
10701071
}
10711072

10721073
impl L1MessageKey {
@@ -1093,13 +1094,15 @@ impl L1MessageKey {
10931094

10941095
/// This type defines where to start when fetching L1 messages that have not been included in a
10951096
/// block yet.
1096-
#[derive(Debug, Clone, PartialEq, Eq)]
1097-
pub enum NotIncludedStart {
1097+
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1098+
pub enum NotIncludedKey {
10981099
/// Start from finalized messages that have not been included in a block yet and have a L1
10991100
/// block number that is a specified number of blocks below the current finalized L1 block
11001101
/// number.
1102+
#[serde(rename = "notIncludedFinalizedWithBlockDepth")]
11011103
FinalizedWithBlockDepth(u64),
11021104
/// Start from unfinalized messages that are included in L1 blocks at a specific depth.
1105+
#[serde(rename = "notIncludedBlockDepth")]
11031106
BlockDepth(u64),
11041107
}
11051108

@@ -1115,10 +1118,10 @@ impl fmt::Display for L1MessageKey {
11151118
Self::TransactionHash(hash) => write!(f, "TransactionHash({hash:#x})"),
11161119
Self::BlockNumber(number) => write!(f, "BlockNumber({number})"),
11171120
Self::NotIncluded(start) => match start {
1118-
NotIncludedStart::FinalizedWithBlockDepth(depth) => {
1121+
NotIncludedKey::FinalizedWithBlockDepth(depth) => {
11191122
write!(f, "NotIncluded(Finalized:{depth})")
11201123
}
1121-
NotIncludedStart::BlockDepth(depth) => {
1124+
NotIncludedKey::BlockDepth(depth) => {
11221125
write!(f, "NotIncluded(BlockDepth({depth}))")
11231126
}
11241127
},
@@ -1139,3 +1142,71 @@ pub struct UnwindResult {
11391142
/// The L2 safe block info after the unwind. This is only populated if the L2 safe has reorged.
11401143
pub l2_safe_block_info: Option<BlockInfo>,
11411144
}
1145+
1146+
mod tests {
1147+
1148+
#[test]
1149+
fn test_l1_message_key_serialization() {
1150+
use crate::{L1MessageKey, NotIncludedKey};
1151+
use alloy_primitives::B256;
1152+
use std::str::FromStr;
1153+
1154+
// Test for `L1MessageKey::QueueIndex`
1155+
let key = L1MessageKey::QueueIndex(42);
1156+
let json = serde_json::to_string(&key).unwrap();
1157+
let decoded: L1MessageKey = serde_json::from_str(&json).unwrap();
1158+
assert_eq!(key, decoded);
1159+
1160+
// Test for `L1MessageKey::TransactionHash`
1161+
let key = L1MessageKey::TransactionHash(
1162+
B256::from_str("0xa46f0b1dbe17b3d0d86fa70cef4a23dca5efcd35858998cc8c53140d01429746")
1163+
.unwrap(),
1164+
);
1165+
let json = serde_json::to_string(&key).unwrap();
1166+
let decoded: L1MessageKey = serde_json::from_str(&json).unwrap();
1167+
assert_eq!(key, decoded);
1168+
1169+
// Test for `L1MessageKey::NotIncluded`
1170+
let key = L1MessageKey::NotIncluded(NotIncludedKey::FinalizedWithBlockDepth(100));
1171+
let json = serde_json::to_string(&key).unwrap();
1172+
let decoded: L1MessageKey = serde_json::from_str(&json).unwrap();
1173+
assert_eq!(key, decoded);
1174+
}
1175+
1176+
#[test]
1177+
fn test_l1_message_key_manual_serialization() {
1178+
use crate::{L1MessageKey, NotIncludedKey};
1179+
use alloy_primitives::B256;
1180+
use std::str::FromStr;
1181+
1182+
// Test for `L1MessageKey::QueueIndex`
1183+
let json_string_queue_index = r#"{"queueIndex":42}"#;
1184+
let decoded_queue_index: L1MessageKey =
1185+
serde_json::from_str(json_string_queue_index).unwrap();
1186+
assert_eq!(decoded_queue_index, L1MessageKey::QueueIndex(42));
1187+
1188+
// Test for `L1MessageKey::TransactionHash`
1189+
let json_string_transaction_hash = r#"{"transactionHash":"0xa46f0b1dbe17b3d0d86fa70cef4a23dca5efcd35858998cc8c53140d01429746"}"#;
1190+
let decoded_transaction_hash: L1MessageKey =
1191+
serde_json::from_str(json_string_transaction_hash).unwrap();
1192+
assert_eq!(
1193+
decoded_transaction_hash,
1194+
L1MessageKey::TransactionHash(
1195+
B256::from_str(
1196+
"0xa46f0b1dbe17b3d0d86fa70cef4a23dca5efcd35858998cc8c53140d01429746"
1197+
)
1198+
.unwrap()
1199+
)
1200+
);
1201+
1202+
// Test for `L1MessageKey::NotIncluded`
1203+
let json_string_not_included_key =
1204+
r#"{"notIncluded":{"notIncludedFinalizedWithBlockDepth":100}}"#;
1205+
let decoded_not_included_key: L1MessageKey =
1206+
serde_json::from_str(json_string_not_included_key).unwrap();
1207+
assert_eq!(
1208+
decoded_not_included_key,
1209+
L1MessageKey::NotIncluded(NotIncludedKey::FinalizedWithBlockDepth(100))
1210+
);
1211+
}
1212+
}

crates/node/src/add_ons/rpc.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use reth_network_api::FullNetwork;
88
use reth_scroll_node::ScrollNetworkPrimitives;
99
use rollup_node_chain_orchestrator::{ChainOrchestratorHandle, ChainOrchestratorStatus};
1010
use rollup_node_primitives::L1MessageEnvelope;
11+
use scroll_db::L1MessageKey;
1112
use tokio::sync::{oneshot, Mutex, OnceCell};
1213

1314
/// RPC extension for rollup node management operations.
@@ -84,6 +85,13 @@ pub trait RollupNodeExtApi {
8485
/// Returns the L1 message by index.
8586
#[method(name = "getL1MessageByIndex")]
8687
async fn get_l1_message_by_index(&self, index: u64) -> RpcResult<Option<L1MessageEnvelope>>;
88+
89+
/// Returns the L1 message by key.
90+
#[method(name = "getL1MessageByKey")]
91+
async fn get_l1_message_by_key(
92+
&self,
93+
l1_message_key: L1MessageKey,
94+
) -> RpcResult<Option<L1MessageEnvelope>>;
8795
}
8896

8997
#[async_trait]
@@ -154,12 +162,33 @@ where
154162
)
155163
})?;
156164

157-
handle.get_l1_message_by_index(index).await.map_err(|e| {
165+
handle.get_l1_message_by_key(L1MessageKey::from_queue_index(index)).await.map_err(|e| {
158166
ErrorObjectOwned::owned(
159167
error::INTERNAL_ERROR_CODE,
160168
format!("Failed to get L1 message by index: {}", e),
161169
None::<()>,
162170
)
163171
})
164172
}
173+
174+
async fn get_l1_message_by_key(
175+
&self,
176+
l1_message_key: L1MessageKey,
177+
) -> RpcResult<Option<L1MessageEnvelope>> {
178+
let handle = self.rollup_manager_handle().await.map_err(|e| {
179+
ErrorObjectOwned::owned(
180+
error::INTERNAL_ERROR_CODE,
181+
format!("Failed to get rollup manager handle: {}", e),
182+
None::<()>,
183+
)
184+
})?;
185+
186+
handle.get_l1_message_by_key(l1_message_key).await.map_err(|e| {
187+
ErrorObjectOwned::owned(
188+
error::INTERNAL_ERROR_CODE,
189+
format!("Failed to get L1 message by key: {}", e),
190+
None::<()>,
191+
)
192+
})
193+
}
165194
}

crates/sequencer/src/config.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use alloy_primitives::Address;
2-
use scroll_db::{L1MessageKey, NotIncludedStart};
2+
use scroll_db::{L1MessageKey, NotIncludedKey};
33
use std::{fmt, str::FromStr, sync::Arc};
44

55
/// Configuration for the sequencer.
@@ -82,10 +82,10 @@ impl From<L1MessageInclusionMode> for L1MessageKey {
8282
fn from(mode: L1MessageInclusionMode) -> Self {
8383
match mode {
8484
L1MessageInclusionMode::FinalizedWithBlockDepth(depth) => {
85-
Self::NotIncluded(NotIncludedStart::FinalizedWithBlockDepth(depth))
85+
Self::NotIncluded(NotIncludedKey::FinalizedWithBlockDepth(depth))
8686
}
8787
L1MessageInclusionMode::BlockDepth(depth) => {
88-
Self::NotIncluded(NotIncludedStart::BlockDepth(depth))
88+
Self::NotIncluded(NotIncludedKey::BlockDepth(depth))
8989
}
9090
}
9191
}

0 commit comments

Comments
 (0)