Skip to content
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

feat(storage) L1BlockManager #552

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 12 additions & 1 deletion Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ members = [
"crates/state",
"crates/status",
"crates/storage",
"crates/macros",
"crates/sync",
"crates/tasks",
"crates/test-utils",
Expand Down Expand Up @@ -134,10 +135,13 @@ alloy-rpc-types-eth = { version = "0.4.2", default-features = false, features =
] }
alloy-serde = { version = "0.4.2", default-features = false }
alloy-sol-types = "0.8.0"
proc-macro2 = "1.0"
quote = "1.0"
revm = { version = "14.0.3", features = ["std"], default-features = false }
revm-primitives = { version = "10.0.0", features = [
"std",
], default-features = false }
syn = "2.0"

# reth itself:
reth = { git = "https://github.com/paradigmxyz/reth.git", rev = "v1.1.0" }
Expand Down
1 change: 1 addition & 0 deletions crates/db/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ parking_lot.workspace = true
serde.workspace = true
thiserror.workspace = true
tracing.workspace = true
strata-macros = { version = "0.1.0", path = "../macros" }

[features]
default = []
Expand Down
6 changes: 4 additions & 2 deletions crates/db/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use std::sync::Arc;

use borsh::{BorshDeserialize, BorshSerialize};
use strata_macros::gen_async_version;
use strata_mmr::CompactMmr;
use strata_primitives::{
l1::*,
Expand Down Expand Up @@ -43,6 +44,7 @@ pub trait Database {
}

/// Database interface to control our view of L1 data.
#[gen_async_version]
pub trait L1Database {
/// Atomically extends the chain with a new block, providing the manifest
/// and a list of transactions we find relevant. Returns error if
Expand Down Expand Up @@ -282,7 +284,7 @@ pub trait ProofDatabase {
/// Deletes a proof by its key.
///
/// Tries to delete a proof by its key, returning if it really
/// existed or not.
/// existed or not.
fn del_proof(&self, proof_key: ProofKey) -> DbResult<bool>;

/// Inserts dependencies for a given [`ProofContext`] into the database.
Expand All @@ -298,7 +300,7 @@ pub trait ProofDatabase {
/// Deletes dependencies for a given [`ProofContext`].
///
/// Tries to delete dependencies of by its context, returning if it really
/// existed or not.
/// existed or not.
fn del_proof_deps(&self, proof_context: ProofContext) -> DbResult<bool>;
}

Expand Down
12 changes: 12 additions & 0 deletions crates/macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "strata-macros"
version = "0.1.0"
edition = "2024"

[dependencies]
proc-macro2.workspace = true
quote.workspace = true
syn.workspace = true

[lib]
proc-macro = true
49 changes: 49 additions & 0 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{Attribute, ItemTrait, parse_macro_input};

#[proc_macro_attribute]
pub fn gen_async_version(_attr: TokenStream, item: TokenStream) -> TokenStream {
// Parse the input tokens into a syntax tree
let input = parse_macro_input!(item as ItemTrait);

// Extract the trait name
let trait_name = &input.ident;
let async_trait_name = syn::Ident::new(&format!("{}Async", trait_name), trait_name.span());

// Generate async methods
let async_methods = input.items.iter().filter_map(|item| {
if let syn::TraitItem::Fn(method) = item {
let sig = &method.sig;
let async_sig = syn::Signature {
asyncness: Some(Default::default()), // Add async keyword
..sig.clone()
};

let docs: Vec<&Attribute> = method
.attrs
.iter()
.filter(|attr| attr.path().is_ident("doc"))
.collect();

Some(quote! {
#(#docs)*
#async_sig;
})
} else {
None

Check warning on line 34 in crates/macros/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/macros/src/lib.rs#L34

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

// Generate the new async trait
let expanded = quote! {
#input

pub trait #async_trait_name {
#(#async_methods)*
}
};

// Convert the expanded code into a TokenStream and return it
TokenStream::from(expanded)
}
1 change: 1 addition & 0 deletions crates/storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ paste.workspace = true
threadpool.workspace = true
tokio.workspace = true
tracing.workspace = true
strata-mmr.workspace = true
124 changes: 124 additions & 0 deletions crates/storage/src/managers/l1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
use std::sync::Arc;

use strata_db::{
traits::{BlockStatus, Database, L1Database, L1DatabaseAsync},
DbResult,
};
use strata_mmr::CompactMmr;
use strata_primitives::{
buf::Buf32,
l1::{L1BlockManifest, L1TxRef},
};
use strata_state::{block::L2BlockBundle, header::L2Header, id::L2BlockId, l1::L1Tx};
use threadpool::ThreadPool;
use tokio::sync::oneshot::{self, error::RecvError};
use tracing::warn;

use crate::cache::{self, CacheTable};

/// Caching manager of L1 blocks in the block database.
pub struct L1BlockManager<DB>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the major reasons to have managers was to be free from these Db generics. The Ops construct was to facilitate this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What issues would arise from having this generic here if the compiler is going to infer it anyway?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have to pass it down through everything that wants to interact with the database / manager, which becomes cumbersome.

where
DB: L1Database + Sync + Send + 'static,
{
pool: ThreadPool,
db: Arc<DB>,
block_cache: CacheTable<L2BlockId, Option<L2BlockBundle>>,
}

impl<DB> L1BlockManager<DB>
where
DB: L1Database + Sync + Send + 'static,
{
pub fn new(pool: ThreadPool, db: Arc<DB>) -> Self {
Self {
pool,
db,
block_cache: CacheTable::new(64.try_into().unwrap()),
}
}

Check warning on line 39 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L33-L39

Added lines #L33 - L39 were not covered by tests
}

impl<DB> L1DatabaseAsync for L1BlockManager<DB>
where
DB: L1Database + Sync + Send + 'static,
{
async fn put_block_data(&self, idx: u64, mf: L1BlockManifest, txs: Vec<L1Tx>) -> DbResult<()> {
let db = self.db.clone();
self.pool
.spawn(move || db.put_block_data(idx, mf, txs))
.await
}

Check warning on line 51 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L46-L51

Added lines #L46 - L51 were not covered by tests

async fn put_mmr_checkpoint(&self, idx: u64, mmr: CompactMmr) -> DbResult<()> {
let db = self.db.clone();
self.pool
.spawn(move || db.put_mmr_checkpoint(idx, mmr))
.await
}

Check warning on line 58 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L53-L58

Added lines #L53 - L58 were not covered by tests

async fn revert_to_height(&self, idx: u64) -> DbResult<()> {
let db = self.db.clone();
self.pool.spawn(move || db.revert_to_height(idx)).await
}

Check warning on line 63 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L60-L63

Added lines #L60 - L63 were not covered by tests

async fn get_chain_tip(&self) -> DbResult<Option<u64>> {
let db = self.db.clone();
self.pool.spawn(move || db.get_chain_tip()).await
}

Check warning on line 68 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L65-L68

Added lines #L65 - L68 were not covered by tests

async fn get_block_manifest(&self, idx: u64) -> DbResult<Option<L1BlockManifest>> {
let db = self.db.clone();
self.pool.spawn(move || db.get_block_manifest(idx)).await
}

Check warning on line 73 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L70-L73

Added lines #L70 - L73 were not covered by tests

async fn get_blockid_range(&self, start_idx: u64, end_idx: u64) -> DbResult<Vec<Buf32>> {
let db = self.db.clone();
self.pool
.spawn(move || db.get_blockid_range(start_idx, end_idx))
.await
}

Check warning on line 80 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L75-L80

Added lines #L75 - L80 were not covered by tests

async fn get_block_txs(&self, idx: u64) -> DbResult<Option<Vec<L1TxRef>>> {
let db = self.db.clone();
self.pool.spawn(move || db.get_block_txs(idx)).await
}

Check warning on line 85 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L82-L85

Added lines #L82 - L85 were not covered by tests

async fn get_tx(&self, tx_ref: L1TxRef) -> DbResult<Option<L1Tx>> {
let db = self.db.clone();
self.pool.spawn(move || db.get_tx(tx_ref)).await
}

Check warning on line 90 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L87-L90

Added lines #L87 - L90 were not covered by tests

async fn get_last_mmr_to(&self, idx: u64) -> DbResult<Option<CompactMmr>> {
let db = self.db.clone();
self.pool.spawn(move || db.get_last_mmr_to(idx)).await
}

Check warning on line 95 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L92-L95

Added lines #L92 - L95 were not covered by tests

async fn get_txs_from(&self, start_idx: u64) -> DbResult<(Vec<L1Tx>, u64)> {
let db = self.db.clone();
self.pool.spawn(move || db.get_txs_from(start_idx)).await
}

Check warning on line 100 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L97-L100

Added lines #L97 - L100 were not covered by tests
}

trait ThreadPoolSpawn {
async fn spawn<T, F>(&self, func: F) -> T
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static;
}

impl ThreadPoolSpawn for ThreadPool {
async fn spawn<T, F>(&self, func: F) -> T
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
let (tx, rx) = oneshot::channel();
self.execute(move || {
if tx.send(func()).is_err() {
warn!("failed to send response")
}
});
rx.await.expect("Sender was dropped without sending")
}

Check warning on line 123 in crates/storage/src/managers/l1.rs

View check run for this annotation

Codecov / codecov/patch

crates/storage/src/managers/l1.rs#L111-L123

Added lines #L111 - L123 were not covered by tests
}
1 change: 1 addition & 0 deletions crates/storage/src/managers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod checkpoint;
pub mod l1;
pub mod l2;
Loading