Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
57fe112
feat: added reth dependency to create db table
sadiq1971 May 14, 2025
f4a1fd6
added storage crate for supervisor
sadiq1971 May 14, 2025
4d50280
removed unused imports
sadiq1971 May 14, 2025
ff3a19d
defined schema for log storage
sadiq1971 May 15, 2025
28fa0e8
merged main
sadiq1971 May 15, 2025
15312c7
added space
sadiq1971 May 15, 2025
49d1349
lint fixed
sadiq1971 May 15, 2025
226af96
Merge branch 'main' into sa/feat/log-storage
dhyaniarun1993 May 16, 2025
b2f29ad
refactoring
dhyaniarun1993 May 16, 2025
eb3ef5e
added executing message to log entry
sadiq1971 May 16, 2025
433d36e
doc fixed
sadiq1971 May 16, 2025
7ab59ad
Merge branch 'main' of github.com:op-rs/kona into sa/feat/log-storage
sadiq1971 May 16, 2025
19afcbb
minor fixes
dhyaniarun1993 May 16, 2025
dda9760
Merge branch 'main' into sa/feat/log-storage
dhyaniarun1993 May 16, 2025
2de12ec
test cases added
dhyaniarun1993 May 16, 2025
d6e2388
Merge branch 'main' into sa/feat/log-storage
dhyaniarun1993 May 16, 2025
01cc5f6
lintfix
dhyaniarun1993 May 16, 2025
f12e7a3
main merged and conflict resolved
dhyaniarun1993 May 19, 2025
f17f9aa
block schema updated and test cases added
dhyaniarun1993 May 19, 2025
5483329
lintfix
dhyaniarun1993 May 19, 2025
2177686
feat: derivation table schema added
dhyaniarun1993 May 19, 2025
e4b3210
table added for source to derived block
dhyaniarun1993 May 19, 2025
c092a1a
minor fixes
dhyaniarun1993 May 19, 2025
5c816d8
blockHeader -> blockRef
dhyaniarun1993 May 19, 2025
249558f
lintfix
dhyaniarun1993 May 19, 2025
bc3d120
typo fixes
dhyaniarun1993 May 19, 2025
644f020
deny setting updated
dhyaniarun1993 May 19, 2025
932cd99
Merge branch 'sa/feat/log-storage' into feat/derivation-schema
dhyaniarun1993 May 19, 2025
2ec942c
testcase fixes
dhyaniarun1993 May 19, 2025
3eed5a4
main merged and conflict resolved
dhyaniarun1993 May 19, 2025
4b3057e
rust doc fixes
dhyaniarun1993 May 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/supervisor/storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ alloy-primitives = { workspace = true, features = ["map", "rlp", "serde", "rand"

# Misc
serde = { workspace = true, features = ["derive"] }
derive_more.workspace = true
bytes = { workspace = true }
modular-bitfield = { workspace = true }

Expand Down
87 changes: 87 additions & 0 deletions crates/supervisor/storage/src/models/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! Common model types used across various storage tables.

use derive_more::{Deref, DerefMut};
use reth_codecs::Compact;
use serde::{Deserialize, Serialize};

/// Wrapper for `Vec<u64>` to represent a list of numbers.
// todo: add support for Vec<64> in table
#[derive(
Deref, DerefMut, Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Compact,
)]
pub struct U64List(pub Vec<u64>);

#[cfg(test)]
mod tests {
use super::*;
use reth_codecs::Compact;

#[test]
fn test_u64list_compact_empty() {
let original_list = U64List(Vec::new());

let mut buffer = Vec::new();
let bytes_written = original_list.to_compact(&mut buffer);

assert_eq!(
bytes_written,
buffer.len(),
"Bytes written should match buffer length for empty list"

Check warning on line 29 in crates/supervisor/storage/src/models/common.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/common.rs#L29

Added line #L29 was not covered by tests
);
let (deserialized_list, remaining_buf) = U64List::from_compact(&buffer, bytes_written);

assert_eq!(
original_list, deserialized_list,
"Original and deserialized empty lists should be equal"

Check warning on line 35 in crates/supervisor/storage/src/models/common.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/common.rs#L35

Added line #L35 was not covered by tests
);
assert!(
remaining_buf.is_empty(),
"Remaining buffer should be empty after deserialization of empty list"

Check warning on line 39 in crates/supervisor/storage/src/models/common.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/common.rs#L39

Added line #L39 was not covered by tests
);
}

#[test]
fn test_u64list_compact_with_data() {
let original_list = U64List(vec![10, 20, 30, 40, 50]);

let mut buffer = Vec::new();
let bytes_written = original_list.to_compact(&mut buffer);

assert_eq!(
bytes_written,
buffer.len(),
"Bytes written should match buffer length for list with data"

Check warning on line 53 in crates/supervisor/storage/src/models/common.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/common.rs#L53

Added line #L53 was not covered by tests
);
let (deserialized_list, remaining_buf) = U64List::from_compact(&buffer, bytes_written);

assert_eq!(
original_list, deserialized_list,
"Original and deserialized lists with data should be equal"

Check warning on line 59 in crates/supervisor/storage/src/models/common.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/common.rs#L59

Added line #L59 was not covered by tests
);
assert!(
remaining_buf.is_empty(),
"Remaining buffer should be empty after deserialization of list with data"

Check warning on line 63 in crates/supervisor/storage/src/models/common.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/common.rs#L63

Added line #L63 was not covered by tests
);
}

#[test]
fn test_u64list_deref() {
let list = U64List(vec![1, 2, 3]);
assert_eq!(list.len(), 3);
assert_eq!(list[0], 1);
assert!(!list.is_empty());
}

#[test]
fn test_u64list_deref_mut() {
let mut list = U64List(vec![1, 2, 3]);
list.push(4);
assert_eq!(list.0, vec![1, 2, 3, 4]);

list.sort();
assert_eq!(list.0, vec![1, 2, 3, 4]);

list.clear();
assert!(list.is_empty());
}
}
77 changes: 77 additions & 0 deletions crates/supervisor/storage/src/models/derivation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//! Models for storing blockchain derivation in the database.
//!
//! This module defines the data structure and schema used for tracking
//! how blocks are derived from source. This is particularly relevant
//! in rollup contexts, such as linking an L2 block to its originating L1 block.

use super::BlockRef;
use reth_codecs::Compact;
use serde::{Deserialize, Serialize};

/// Represents a pair of blocks where one block [`derived`](`Self::derived`) is derived
/// from another [`source`](`Self::source`).
///
/// This structure is used to track the lineage of blocks where L2 blocks are derived from L1
/// blocks. It stores the [`BlockRef`] information for both the source and the derived blocks.
/// It is stored as value in the [`DerivedBlocks`](`crate::models::DerivedBlocks`) table.
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct DerivedBlockPair {
/// The block that was derived from the [`source`](`Self::source`) block.
pub derived: BlockRef,
/// The source block from which the [`derived`](`Self::derived`) block was created.
pub source: BlockRef,
}

impl Compact for DerivedBlockPair {
fn to_compact<B: bytes::BufMut + AsMut<[u8]>>(&self, buf: &mut B) -> usize {
let mut bytes_written = 0;
bytes_written += self.derived.to_compact(buf);
bytes_written += self.source.to_compact(buf);
bytes_written
}

fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
let (derived, remaining_buf) = BlockRef::from_compact(buf, buf.len());
let (source, final_remaining_buf) =
BlockRef::from_compact(remaining_buf, remaining_buf.len());
(Self { derived, source }, final_remaining_buf)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::models::BlockRef;
use alloy_primitives::B256;
use reth_codecs::Compact;

fn test_b256(val: u8) -> B256 {
let mut val_bytes = [0u8; 32];
val_bytes[0] = val;
let b256_from_val = B256::from(val_bytes);
B256::random() ^ b256_from_val
}

#[test]
fn test_derived_block_pair_compact_roundtrip() {
let source_ref =
BlockRef { number: 100, hash: test_b256(1), parent_hash: test_b256(2), time: 1000 };
let derived_ref =
BlockRef { number: 200, hash: test_b256(3), parent_hash: test_b256(4), time: 1010 };

let original_pair = DerivedBlockPair { source: source_ref, derived: derived_ref };

let mut buffer = Vec::new();
let bytes_written = original_pair.to_compact(&mut buffer);

assert_eq!(bytes_written, buffer.len(), "Bytes written should match buffer length");
let (deserialized_pair, remaining_buf) =
DerivedBlockPair::from_compact(&buffer, bytes_written);

assert_eq!(
original_pair, deserialized_pair,
"Original and deserialized pairs should be equal"

Check warning on line 73 in crates/supervisor/storage/src/models/derivation.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/derivation.rs#L73

Added line #L73 was not covered by tests
);
assert!(remaining_buf.is_empty(), "Remaining buffer should be empty after deserialization");
}
}
85 changes: 84 additions & 1 deletion crates/supervisor/storage/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,16 @@

mod log;
pub use log::{ExecutingMessageEntry, LogEntry};

mod block;
pub use block::BlockRef;

mod derivation;
pub use derivation::DerivedBlockPair;

mod common;
pub use common::U64List;

/// Implements [`reth_db_api::table::Compress`] and [`reth_db_api::table::Decompress`] traits for
/// types that implement [`reth_codecs::Compact`].
///
Expand Down Expand Up @@ -50,7 +57,7 @@
}

// Implement compression logic for all value types stored in tables
impl_compression_for_compact!(BlockRef, LogEntry);
impl_compression_for_compact!(BlockRef, LogEntry, DerivedBlockPair, U64List);

tables! {
Comment thread
dhyaniarun1993 marked this conversation as resolved.
/// A dup-sorted table that stores all logs emitted in a given block, sorted by their index.
Expand All @@ -69,6 +76,22 @@
type Key = u64;
type Value = BlockRef;
}

/// A table mapping a derived block number to its corresponding source and derived block reference.
/// - Key: `u64` — derived block number
/// - Value: [`DerivedBlockPair`] — pair of source and derived block reference
table DerivedBlocks {
type Key = u64;
type Value = DerivedBlockPair;
}

/// A table mapping a source block number to a list of its derived block numbers.
/// - Key: `u64` — source block number
/// - Value: [`U64List`] — list of derived block numbers
table SourceToDerivedBlockNumbers {
type Key = u64;
type Value = U64List;
}
}
Comment thread
dhyaniarun1993 marked this conversation as resolved.

#[cfg(test)]
Expand Down Expand Up @@ -129,4 +152,64 @@
let decompressed = LogEntry::decompress(&compressed_buf).unwrap();
assert_eq!(original, decompressed);
}

#[test]
fn test_derived_block_pair_compression_decompression() {
let source_ref =
BlockRef { number: 100, hash: test_b256(6), parent_hash: test_b256(7), time: 1000 };
let derived_ref = BlockRef {
number: 200,
hash: test_b256(8),
parent_hash: test_b256(8), // Link to source
time: 1010,
};

let original_pair = DerivedBlockPair { source: source_ref, derived: derived_ref };

let mut compressed_buf = Vec::new();
original_pair.compress_to_buf(&mut compressed_buf);

assert!(!compressed_buf.is_empty(), "Buffer should not be empty after compression");

let decompressed_pair = DerivedBlockPair::decompress(&compressed_buf).unwrap();
assert_eq!(
original_pair, decompressed_pair,
"Original and deserialized pairs should be equal"

Check warning on line 177 in crates/supervisor/storage/src/models/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/mod.rs#L177

Added line #L177 was not covered by tests
);
}

#[test]
fn test_u64list_compression_decompression_empty() {
let original_list = U64List(Vec::new());

let mut compressed_buf = Vec::new();
original_list.compress_to_buf(&mut compressed_buf);

// For an empty list, the compact representation might also be empty or very small.
// The primary check is that deserialization works and results in an empty list.
let decompressed_list = U64List::decompress(&compressed_buf).unwrap();
assert_eq!(
original_list, decompressed_list,
"Original and deserialized empty U64List should be equal"

Check warning on line 193 in crates/supervisor/storage/src/models/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/mod.rs#L193

Added line #L193 was not covered by tests
);
}

#[test]
fn test_u64list_compression_decompression_with_data() {
let original_list = U64List(vec![10, 20, 30, 40, 50]);

let mut compressed_buf = Vec::new();
original_list.compress_to_buf(&mut compressed_buf);

assert!(
!compressed_buf.is_empty(),
"Buffer should not be empty after compression of U64List with data"

Check warning on line 206 in crates/supervisor/storage/src/models/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/mod.rs#L206

Added line #L206 was not covered by tests
);

let decompressed_list = U64List::decompress(&compressed_buf).unwrap();
assert_eq!(
original_list, decompressed_list,
"Original and deserialized U64List with data should be equal"

Check warning on line 212 in crates/supervisor/storage/src/models/mod.rs

View check run for this annotation

Codecov / codecov/patch

crates/supervisor/storage/src/models/mod.rs#L212

Added line #L212 was not covered by tests
);
}
}
Loading