From 450dd9facb0db3b08cdd2af032c4e1b2ba59517f Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 18:07:55 +0300 Subject: [PATCH 01/13] Skeleton CLI binary --- Cargo.lock | 8 ++++++++ Cargo.toml | 1 + bin/cli/Cargo.toml | 24 ++++++++++++++++++++++++ bin/cli/src/main.rs | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 bin/cli/Cargo.toml create mode 100644 bin/cli/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index c35f1e807..49eb1fcb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1881,6 +1881,14 @@ dependencies = [ "tracing", ] +[[package]] +name = "citrea-cli" +version = "0.6.0" +dependencies = [ + "clap", + "tokio", +] + [[package]] name = "citrea-common" version = "0.6.0" diff --git a/Cargo.toml b/Cargo.toml index 1e98c3218..b65f5d9ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ # Citrea "bin/citrea", + "bin/cli", "crates/batch-prover", "crates/bitcoin-da", "crates/citrea-stf", diff --git a/bin/cli/Cargo.toml b/bin/cli/Cargo.toml new file mode 100644 index 000000000..5f3e3bd0e --- /dev/null +++ b/bin/cli/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "citrea-cli" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +publish = false +resolver = "2" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +# Citrea deps + +# Sovereign-SDK deps + +# 3rd-party deps +clap = { workspace = true } +tokio = { workspace = true } + +[[bin]] +name = "citrea-cli" +path = "src/main.rs" diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs new file mode 100644 index 000000000..820125778 --- /dev/null +++ b/bin/cli/src/main.rs @@ -0,0 +1,38 @@ +use std::path::PathBuf; + +use clap::{Parser, Subcommand}; + +#[derive(Parser)] +#[command(version, about, long_about = None)] +#[command(propagate_version = true)] +struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Prune database + Prune { + db_path: PathBuf, + }, + Rollback { + db_path: PathBuf, + }, +} + +#[tokio::main] +async fn main() { + let cli = Cli::parse(); + + // You can check for the existence of subcommands, and if found use their + // matches just as you would the top level cmd + match &cli.command { + Commands::Prune { db_path } => { + println!("Pruning stuff: {:?}", db_path); + } + Commands::Rollback { db_path } => { + println!("Rolling back stuff: {:?}", db_path); + } + } +} From 1a9203c135534b82005563443dedb1bc7329fa25 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 18:37:56 +0300 Subject: [PATCH 02/13] Setup subcommands & args --- Cargo.lock | 3 +++ bin/cli/Cargo.toml | 3 +++ bin/cli/src/main.rs | 23 +++++++++++++++++------ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 49eb1fcb9..525911b78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1885,7 +1885,10 @@ dependencies = [ name = "citrea-cli" version = "0.6.0" dependencies = [ + "anyhow", + "citrea-pruning", "clap", + "sov-db", "tokio", ] diff --git a/bin/cli/Cargo.toml b/bin/cli/Cargo.toml index 5f3e3bd0e..852d4c96d 100644 --- a/bin/cli/Cargo.toml +++ b/bin/cli/Cargo.toml @@ -12,10 +12,13 @@ resolver = "2" [dependencies] # Citrea deps +citrea-pruning = { path = "../../crates/pruning" } # Sovereign-SDK deps +sov-db = { path = "../../crates/sovereign-sdk/full-node/db/sov-db" } # 3rd-party deps +anyhow = { workspace = true } clap = { workspace = true } tokio = { workspace = true } diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs index 820125778..ef18cb94b 100644 --- a/bin/cli/src/main.rs +++ b/bin/cli/src/main.rs @@ -12,27 +12,38 @@ struct Cli { #[derive(Subcommand)] enum Commands { - /// Prune database + /// Prune old DB entries Prune { + /// The path of the database to prune + #[arg(long)] db_path: PathBuf, + /// The distance of the last pruned block to prune up to + #[arg(long)] + distance: u64, }, + /// Rollback the most recent N blocks Rollback { + /// The path of the database to prune + #[arg(long)] db_path: PathBuf, + /// The number of blocks to rollback + #[arg(long)] + blocks: u64, }, } #[tokio::main] -async fn main() { +async fn main() -> anyhow::Result<()> { let cli = Cli::parse(); // You can check for the existence of subcommands, and if found use their // matches just as you would the top level cmd match &cli.command { - Commands::Prune { db_path } => { - println!("Pruning stuff: {:?}", db_path); + Commands::Prune { db_path, distance } => { + println!("Pruning stuff: {:?}, distance: {}", db_path, distance); } - Commands::Rollback { db_path } => { - println!("Rolling back stuff: {:?}", db_path); + Commands::Rollback { db_path, blocks } => { + println!("Rolling back stuff: {:?}, blocks: {}", db_path, blocks); } } } From 752ba2373559e00ef40082a625b1b4379c9889f7 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 18:38:09 +0300 Subject: [PATCH 03/13] Add pruning subcommand --- bin/cli/src/commands/mod.rs | 1 + bin/cli/src/commands/prune.rs | 17 +++++++++++++++++ bin/cli/src/main.rs | 2 ++ 3 files changed, 20 insertions(+) create mode 100644 bin/cli/src/commands/mod.rs create mode 100644 bin/cli/src/commands/prune.rs diff --git a/bin/cli/src/commands/mod.rs b/bin/cli/src/commands/mod.rs new file mode 100644 index 000000000..b337405f7 --- /dev/null +++ b/bin/cli/src/commands/mod.rs @@ -0,0 +1 @@ +mod prune; diff --git a/bin/cli/src/commands/prune.rs b/bin/cli/src/commands/prune.rs new file mode 100644 index 000000000..2e6031fbb --- /dev/null +++ b/bin/cli/src/commands/prune.rs @@ -0,0 +1,17 @@ +use std::path::PathBuf; + +use citrea_pruning::{Pruner, PruningConfig}; +use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; +use sov_db::rocks_db_config::RocksdbConfig; + +pub(crate) fn prune(db_path: PathBuf, distance: u64) -> anyhow::Result<()> { + let config = PruningConfig { distance }; + + let rocksdb_config = RocksdbConfig::new(&db_path, None, None); + let ledger_db = LedgerDB::with_config(&rocksdb_config)?; + + let last_pruned_block = ledger_db.get_last_pruned_l2_height()?.unwrap_or(0); + let pruner = Pruner::new(config, last_pruned_block, l2_receiver, ledger_db)?; + + Ok(()) +} diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs index ef18cb94b..af5c690ab 100644 --- a/bin/cli/src/main.rs +++ b/bin/cli/src/main.rs @@ -2,6 +2,8 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; +mod commands; + #[derive(Parser)] #[command(version, about, long_about = None)] #[command(propagate_version = true)] From c96f9e8d506c92a865c0b1b358db188f436b870b Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 19:06:53 +0300 Subject: [PATCH 04/13] Refactor pruner into service & pruner --- bin/citrea/src/main.rs | 6 ++-- bin/citrea/src/rollup/mod.rs | 4 +-- crates/fullnode/src/lib.rs | 12 +++---- crates/pruning/src/lib.rs | 59 +++++++++++------------------------ crates/pruning/src/service.rs | 56 +++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 52 deletions(-) create mode 100644 crates/pruning/src/service.rs diff --git a/bin/citrea/src/main.rs b/bin/citrea/src/main.rs index ac649059f..2881d86f5 100644 --- a/bin/citrea/src/main.rs +++ b/bin/citrea/src/main.rs @@ -319,7 +319,7 @@ where }); } _ => { - let (mut full_node, l1_block_handler, pruner) = + let (mut full_node, l1_block_handler, pruner_service) = CitreaRollupBlueprint::create_full_node( &rollup_blueprint, genesis_config, @@ -352,9 +352,9 @@ where }); // Spawn pruner if configs are set - if let Some(pruner) = pruner { + if let Some(pruner_service) = pruner_service { task_manager.spawn(|cancellation_token| async move { - pruner.run(cancellation_token).await + pruner_service.run(cancellation_token).await }); } diff --git a/bin/citrea/src/rollup/mod.rs b/bin/citrea/src/rollup/mod.rs index 377ef9ee1..66cc6878e 100644 --- a/bin/citrea/src/rollup/mod.rs +++ b/bin/citrea/src/rollup/mod.rs @@ -11,7 +11,7 @@ use citrea_fullnode::CitreaFullnode; use citrea_light_client_prover::da_block_handler::L1BlockHandler as LightClientProverL1BlockHandler; use citrea_light_client_prover::runner::CitreaLightClientProver; use citrea_primitives::forks::get_forks; -use citrea_pruning::Pruner; +use citrea_pruning::PrunerService; use citrea_sequencer::CitreaSequencer; use jsonrpsee::RpcModule; use sov_db::ledger_db::migrations::{LedgerDBMigrator, Migrations}; @@ -203,7 +203,7 @@ pub trait CitreaRollupBlueprint: RollupBlueprint { StorageRootHash, LedgerDB, >, - Option>, + Option>, )> where ::Storage: NativeStorage, diff --git a/crates/fullnode/src/lib.rs b/crates/fullnode/src/lib.rs index 59a5be68d..c3dbcac99 100644 --- a/crates/fullnode/src/lib.rs +++ b/crates/fullnode/src/lib.rs @@ -6,7 +6,7 @@ use anyhow::Result; use borsh::{BorshDeserialize, BorshSerialize}; use citrea_common::cache::L1BlockCache; use citrea_common::{RollupPublicKeys, RunnerConfig}; -use citrea_pruning::Pruner; +use citrea_pruning::{Pruner, PrunerService}; use da_block_handler::L1BlockHandler; pub use runner::*; use serde::de::DeserializeOwned; @@ -42,7 +42,7 @@ pub fn build_services( ) -> Result<( CitreaFullnode, L1BlockHandler, - Option>, + Option>, )> where Da: DaService, @@ -60,13 +60,13 @@ where { let last_pruned_block = ledger_db.get_last_pruned_l2_height()?.unwrap_or(0); let pruner = runner_config.pruning_config.as_ref().map(|pruning_config| { - Pruner::::new( + let pruner = Pruner::::new( pruning_config.clone(), - last_pruned_block, - soft_confirmation_tx.subscribe(), ledger_db.clone(), storage_manager.get_native_db_handle(), - ) + ); + + PrunerService::new(pruner, last_pruned_block, soft_confirmation_tx.subscribe()) }); let runner = CitreaFullnode::new( diff --git a/crates/pruning/src/lib.rs b/crates/pruning/src/lib.rs index 350737639..0b70aab92 100644 --- a/crates/pruning/src/lib.rs +++ b/crates/pruning/src/lib.rs @@ -2,17 +2,16 @@ use std::sync::Arc; use futures::future; use serde::{Deserialize, Serialize}; +pub use service::*; use sov_db::ledger_db::SharedLedgerOps; -use tokio::select; -use tokio::sync::broadcast; -use tokio_util::sync::CancellationToken; -use tracing::{debug, error, info}; +use tracing::info; use crate::criteria::{Criteria, DistanceCriteria}; use crate::pruners::{prune_evm, prune_ledger, prune_native_db}; mod criteria; mod pruners; +mod service; #[cfg(test)] mod tests; @@ -33,10 +32,6 @@ pub struct Pruner where DB: SharedLedgerOps, { - /// The last block number which was pruned. - last_pruned_block: u64, - /// A channel receiver which gets notified of new L2 blocks. - l2_receiver: broadcast::Receiver, /// Access to ledger tables. ledger_db: DB, /// Access to native DB. @@ -49,26 +44,32 @@ impl Pruner where DB: SharedLedgerOps + Send + Sync + Clone + 'static, { - pub fn new( - config: PruningConfig, - last_pruned_block: u64, - l2_receiver: broadcast::Receiver, - ledger_db: DB, - native_db: Arc, - ) -> Self { + pub fn new(config: PruningConfig, ledger_db: DB, native_db: Arc) -> Self { // distance is the only criteria implemented at the moment. let criteria = Box::new(DistanceCriteria { distance: config.distance, }); Self { - last_pruned_block, - l2_receiver, ledger_db, native_db, criteria, } } + pub fn store_last_pruned_l2_height(&self, last_pruned_l2_height: u64) -> anyhow::Result<()> { + self.ledger_db + .set_last_pruned_l2_height(last_pruned_l2_height) + } + + pub(crate) fn should_prune( + &self, + last_pruned_l2_height: u64, + current_l2_height: u64, + ) -> Option { + self.criteria + .should_prune(last_pruned_l2_height, current_l2_height) + } + /// Prune everything pub async fn prune(&self, up_to_block: u64) { info!("Pruning up to L2 block: {}", up_to_block); @@ -87,28 +88,4 @@ where ]) .await; } - - pub async fn run(mut self, cancellation_token: CancellationToken) { - loop { - select! { - biased; - _ = cancellation_token.cancelled() => { - // Store the last pruned l2 height in ledger DB to be restored in the next initialization. - if let Err(e) = self.ledger_db.set_last_pruned_l2_height(self.last_pruned_block) { - error!("Failed to store last pruned L2 height {}: {:?}", self.last_pruned_block, e); - } - return; - } - current_l2_block = self.l2_receiver.recv() => { - if let Ok(current_l2_block) = current_l2_block { - debug!("Pruner received L2 {}, checking criteria", current_l2_block); - if let Some(up_to_block) = self.criteria.should_prune(self.last_pruned_block, current_l2_block) { - self.prune(up_to_block).await; - self.last_pruned_block = up_to_block; - } - } - }, - } - } - } } diff --git a/crates/pruning/src/service.rs b/crates/pruning/src/service.rs new file mode 100644 index 000000000..d2c1482b5 --- /dev/null +++ b/crates/pruning/src/service.rs @@ -0,0 +1,56 @@ +use sov_db::ledger_db::SharedLedgerOps; +use tokio::select; +use tokio::sync::broadcast; +use tokio_util::sync::CancellationToken; +use tracing::{debug, error}; + +use crate::Pruner; + +pub struct PrunerService { + pruner: Pruner, + /// The last block number which was pruned. + last_pruned_block: u64, + /// A channel receiver which gets notified of new L2 blocks. + l2_receiver: broadcast::Receiver, +} + +impl PrunerService +where + DB: SharedLedgerOps + Send + Sync + Clone + 'static, +{ + pub fn new( + pruner: Pruner, + last_pruned_block: u64, + l2_receiver: broadcast::Receiver, + ) -> Self { + Self { + pruner, + last_pruned_block, + l2_receiver, + } + } + + pub async fn run(mut self, cancellation_token: CancellationToken) { + loop { + select! { + biased; + _ = cancellation_token.cancelled() => { + // Store the last pruned l2 height in ledger DB to be restored in the next initialization. + if let Err(e) = self.pruner.store_last_pruned_l2_height(self.last_pruned_block) { + error!("Failed to store last pruned L2 height {}: {:?}", self.last_pruned_block, e); + } + return; + } + current_l2_block = self.l2_receiver.recv() => { + if let Ok(current_l2_block) = current_l2_block { + debug!("Pruner received L2 {}, checking criteria", current_l2_block); + if let Some(up_to_block) = self.pruner.should_prune(self.last_pruned_block, current_l2_block) { + self.pruner.prune(up_to_block).await; + self.last_pruned_block = up_to_block; + } + } + }, + } + } + } +} From 33ea57a31f783b10a2ab336ec3f7ca85ed720f32 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 21:12:28 +0300 Subject: [PATCH 05/13] Implement pruning command --- Cargo.lock | 3 +++ bin/cli/Cargo.toml | 3 +++ bin/cli/src/commands/mod.rs | 2 ++ bin/cli/src/commands/prune.rs | 25 ++++++++++++++++++++++--- bin/cli/src/main.rs | 9 ++++++++- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 525911b78..af6360bca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1889,7 +1889,10 @@ dependencies = [ "citrea-pruning", "clap", "sov-db", + "sov-prover-storage-manager", "tokio", + "tracing", + "tracing-subscriber 0.3.19", ] [[package]] diff --git a/bin/cli/Cargo.toml b/bin/cli/Cargo.toml index 852d4c96d..c06bc5b7d 100644 --- a/bin/cli/Cargo.toml +++ b/bin/cli/Cargo.toml @@ -16,11 +16,14 @@ citrea-pruning = { path = "../../crates/pruning" } # Sovereign-SDK deps sov-db = { path = "../../crates/sovereign-sdk/full-node/db/sov-db" } +sov-prover-storage-manager = { path = "../../crates/sovereign-sdk/full-node/sov-prover-storage-manager" } # 3rd-party deps anyhow = { workspace = true } clap = { workspace = true } tokio = { workspace = true } +tracing = { workspace = true } +tracing-subscriber = { workspace = true } [[bin]] name = "citrea-cli" diff --git a/bin/cli/src/commands/mod.rs b/bin/cli/src/commands/mod.rs index b337405f7..a889556ce 100644 --- a/bin/cli/src/commands/mod.rs +++ b/bin/cli/src/commands/mod.rs @@ -1 +1,3 @@ mod prune; + +pub(crate) use prune::*; diff --git a/bin/cli/src/commands/prune.rs b/bin/cli/src/commands/prune.rs index 2e6031fbb..532bfb6a4 100644 --- a/bin/cli/src/commands/prune.rs +++ b/bin/cli/src/commands/prune.rs @@ -1,17 +1,36 @@ use std::path::PathBuf; +use std::sync::Arc; use citrea_pruning::{Pruner, PruningConfig}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; +use sov_db::native_db::NativeDB; use sov_db::rocks_db_config::RocksdbConfig; +use sov_prover_storage_manager::SnapshotManager; +use tracing::{debug, info}; -pub(crate) fn prune(db_path: PathBuf, distance: u64) -> anyhow::Result<()> { +pub(crate) async fn prune(db_path: PathBuf, distance: u64) -> anyhow::Result<()> { + info!( + "Pruning DB at {} with pruning distance of {}", + db_path.display(), + distance + ); let config = PruningConfig { distance }; let rocksdb_config = RocksdbConfig::new(&db_path, None, None); let ledger_db = LedgerDB::with_config(&rocksdb_config)?; + let native_db = NativeDB::::setup_schema_db(&rocksdb_config)?; - let last_pruned_block = ledger_db.get_last_pruned_l2_height()?.unwrap_or(0); - let pruner = Pruner::new(config, last_pruned_block, l2_receiver, ledger_db)?; + let Some((soft_confirmation_number, _)) = ledger_db.get_head_soft_confirmation()? else { + return Ok(()); + }; + + debug!( + "Pruning up to latest soft confirmation number: {}, taking into consideration the configured distance of {}", + soft_confirmation_number.0, distance + ); + + let pruner = Pruner::new(config, ledger_db, Arc::new(native_db)); + pruner.prune(soft_confirmation_number.0).await; Ok(()) } diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs index af5c690ab..d99f0dd21 100644 --- a/bin/cli/src/main.rs +++ b/bin/cli/src/main.rs @@ -1,6 +1,9 @@ use std::path::PathBuf; use clap::{Parser, Subcommand}; +use tracing_subscriber::fmt; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::util::SubscriberInitExt; mod commands; @@ -36,16 +39,20 @@ enum Commands { #[tokio::main] async fn main() -> anyhow::Result<()> { + tracing_subscriber::registry().with(fmt::layer()).init(); + let cli = Cli::parse(); // You can check for the existence of subcommands, and if found use their // matches just as you would the top level cmd match &cli.command { Commands::Prune { db_path, distance } => { - println!("Pruning stuff: {:?}, distance: {}", db_path, distance); + commands::prune(db_path.clone(), *distance).await?; } Commands::Rollback { db_path, blocks } => { println!("Rolling back stuff: {:?}, blocks: {}", db_path, blocks); } } + + Ok(()) } From 31c651a08c61d8c17bc5e3170b6bf4190bee9657 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 21:22:43 +0300 Subject: [PATCH 06/13] Rename pruning to storage-ops --- Cargo.lock | 46 +++++++++---------- Cargo.toml | 2 +- bin/citrea/Cargo.toml | 2 +- bin/citrea/src/rollup/mod.rs | 2 +- bin/citrea/tests/e2e/mod.rs | 2 +- bin/citrea/tests/e2e/pruning.rs | 2 +- bin/citrea/tests/test_helpers/mod.rs | 2 +- bin/cli/Cargo.toml | 2 +- bin/cli/src/commands/prune.rs | 2 +- crates/common/Cargo.toml | 2 +- crates/common/src/config.rs | 2 +- crates/fullnode/Cargo.toml | 2 +- crates/fullnode/src/lib.rs | 2 +- crates/{pruning => storage-ops}/Cargo.toml | 2 +- .../{pruning => storage-ops}/src/criteria.rs | 0 crates/{pruning => storage-ops}/src/lib.rs | 0 .../src/pruners/evm.rs | 0 .../src/pruners/ledger.rs | 0 .../src/pruners/mod.rs | 0 .../src/pruners/native_db.rs | 0 .../{pruning => storage-ops}/src/service.rs | 0 crates/{pruning => storage-ops}/src/tests.rs | 0 22 files changed, 36 insertions(+), 36 deletions(-) rename crates/{pruning => storage-ops}/Cargo.toml (97%) rename crates/{pruning => storage-ops}/src/criteria.rs (100%) rename crates/{pruning => storage-ops}/src/lib.rs (100%) rename crates/{pruning => storage-ops}/src/pruners/evm.rs (100%) rename crates/{pruning => storage-ops}/src/pruners/ledger.rs (100%) rename crates/{pruning => storage-ops}/src/pruners/mod.rs (100%) rename crates/{pruning => storage-ops}/src/pruners/native_db.rs (100%) rename crates/{pruning => storage-ops}/src/service.rs (100%) rename crates/{pruning => storage-ops}/src/tests.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index af6360bca..af939c7ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1786,12 +1786,12 @@ dependencies = [ "citrea-fullnode", "citrea-light-client-prover", "citrea-primitives", - "citrea-pruning", "citrea-risc0-adapter", "citrea-risc0-batch-proof", "citrea-risc0-light-client", "citrea-sequencer", "citrea-stf", + "citrea-storage-ops", "clap", "ethereum-rpc", "futures", @@ -1886,7 +1886,7 @@ name = "citrea-cli" version = "0.6.0" dependencies = [ "anyhow", - "citrea-pruning", + "citrea-storage-ops", "clap", "sov-db", "sov-prover-storage-manager", @@ -1904,7 +1904,7 @@ dependencies = [ "backoff", "borsh", "citrea-primitives", - "citrea-pruning", + "citrea-storage-ops", "futures", "hex", "hyper", @@ -2021,7 +2021,7 @@ dependencies = [ "borsh", "citrea-common", "citrea-primitives", - "citrea-pruning", + "citrea-storage-ops", "futures", "hex", "jsonrpsee", @@ -2089,25 +2089,6 @@ dependencies = [ "sov-rollup-interface", ] -[[package]] -name = "citrea-pruning" -version = "0.6.0" -dependencies = [ - "anyhow", - "citrea-evm", - "citrea-primitives", - "futures", - "serde", - "sov-db", - "sov-modules-api", - "sov-prover-storage-manager", - "sov-schema-db", - "tempfile", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "citrea-risc0-adapter" version = "0.6.0" @@ -2228,6 +2209,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "citrea-storage-ops" +version = "0.6.0" +dependencies = [ + "anyhow", + "citrea-evm", + "citrea-primitives", + "futures", + "serde", + "sov-db", + "sov-modules-api", + "sov-prover-storage-manager", + "sov-schema-db", + "tempfile", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "clang-sys" version = "1.8.1" diff --git a/Cargo.toml b/Cargo.toml index b65f5d9ed..238b05493 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ members = [ "crates/light-client-prover", "crates/primitives", "crates/prover-services", - "crates/pruning", + "crates/storage-ops", "crates/risc0", "crates/sequencer", "crates/soft-confirmation-rule-enforcer", diff --git a/bin/citrea/Cargo.toml b/bin/citrea/Cargo.toml index fbcd6ff25..23c7a8aa4 100644 --- a/bin/citrea/Cargo.toml +++ b/bin/citrea/Cargo.toml @@ -19,13 +19,13 @@ citrea-common = { path = "../../crates/common" } citrea-fullnode = { path = "../../crates/fullnode" } citrea-light-client-prover = { path = "../../crates/light-client-prover", features = ["native"] } citrea-primitives = { path = "../../crates/primitives" } -citrea-pruning = { path = "../../crates/pruning" } citrea-risc0-adapter = { path = "../../crates/risc0", features = ["native"] } citrea-risc0-batch-proof = { path = "../../guests/risc0/batch-proof" } citrea-risc0-light-client = { path = "../../guests/risc0/light-client-proof" } citrea-sequencer = { path = "../../crates/sequencer" } # citrea-sp1 = { path = "../../crates/sp1", features = ["native"] } citrea-stf = { path = "../../crates/citrea-stf", features = ["native"] } +citrea-storage-ops = { path = "../../crates/storage-ops" } ethereum-rpc = { path = "../../crates/ethereum-rpc" } prover-services = { path = "../../crates/prover-services" } diff --git a/bin/citrea/src/rollup/mod.rs b/bin/citrea/src/rollup/mod.rs index 66cc6878e..beee2d5cd 100644 --- a/bin/citrea/src/rollup/mod.rs +++ b/bin/citrea/src/rollup/mod.rs @@ -11,8 +11,8 @@ use citrea_fullnode::CitreaFullnode; use citrea_light_client_prover::da_block_handler::L1BlockHandler as LightClientProverL1BlockHandler; use citrea_light_client_prover::runner::CitreaLightClientProver; use citrea_primitives::forks::get_forks; -use citrea_pruning::PrunerService; use citrea_sequencer::CitreaSequencer; +use citrea_storage_ops::PrunerService; use jsonrpsee::RpcModule; use sov_db::ledger_db::migrations::{LedgerDBMigrator, Migrations}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; diff --git a/bin/citrea/tests/e2e/mod.rs b/bin/citrea/tests/e2e/mod.rs index 058f5008a..c3eb52594 100644 --- a/bin/citrea/tests/e2e/mod.rs +++ b/bin/citrea/tests/e2e/mod.rs @@ -6,8 +6,8 @@ use alloy_primitives::{Address, U256}; use citrea_common::{BatchProverConfig, SequencerConfig}; use citrea_evm::smart_contracts::SimpleStorageContract; use citrea_primitives::forks::fork_from_block_number; -use citrea_pruning::PruningConfig; use citrea_stf::genesis_config::GenesisPaths; +use citrea_storage_ops::PruningConfig; use reth_primitives::BlockNumberOrTag; use sov_mock_da::{MockAddress, MockDaService}; use sov_rollup_interface::rpc::{LastVerifiedBatchProofResponse, SoftConfirmationStatus}; diff --git a/bin/citrea/tests/e2e/pruning.rs b/bin/citrea/tests/e2e/pruning.rs index ec34672be..8771ed5c4 100644 --- a/bin/citrea/tests/e2e/pruning.rs +++ b/bin/citrea/tests/e2e/pruning.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use alloy_primitives::Address; /// Testing if the sequencer and full node can handle system transactions correctly (the full node should have the same system transactions as the sequencer) -use citrea_pruning::PruningConfig; +use citrea_storage_ops::PruningConfig; use futures::FutureExt; use reth_primitives::BlockNumberOrTag; use sov_mock_da::{MockAddress, MockDaService}; diff --git a/bin/citrea/tests/test_helpers/mod.rs b/bin/citrea/tests/test_helpers/mod.rs index 14e1b7238..12fd959a0 100644 --- a/bin/citrea/tests/test_helpers/mod.rs +++ b/bin/citrea/tests/test_helpers/mod.rs @@ -14,8 +14,8 @@ use citrea_common::{ }; use citrea_light_client_prover::da_block_handler::StartVariant; use citrea_primitives::TEST_PRIVATE_KEY; -use citrea_pruning::PruningConfig; use citrea_stf::genesis_config::GenesisPaths; +use citrea_storage_ops::PruningConfig; use sov_db::ledger_db::SharedLedgerOps; use sov_db::rocks_db_config::RocksdbConfig; use sov_db::schema::tables::{ diff --git a/bin/cli/Cargo.toml b/bin/cli/Cargo.toml index c06bc5b7d..5ec7a8aa9 100644 --- a/bin/cli/Cargo.toml +++ b/bin/cli/Cargo.toml @@ -12,7 +12,7 @@ resolver = "2" [dependencies] # Citrea deps -citrea-pruning = { path = "../../crates/pruning" } +citrea-storage-ops = { path = "../../crates/storage-ops" } # Sovereign-SDK deps sov-db = { path = "../../crates/sovereign-sdk/full-node/db/sov-db" } diff --git a/bin/cli/src/commands/prune.rs b/bin/cli/src/commands/prune.rs index 532bfb6a4..fcfa5c01e 100644 --- a/bin/cli/src/commands/prune.rs +++ b/bin/cli/src/commands/prune.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::sync::Arc; -use citrea_pruning::{Pruner, PruningConfig}; +use citrea_storage_ops::{Pruner, PruningConfig}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; use sov_db::native_db::NativeDB; use sov_db::rocks_db_config::RocksdbConfig; diff --git a/crates/common/Cargo.toml b/crates/common/Cargo.toml index 5dd207ccc..3db8b12b8 100644 --- a/crates/common/Cargo.toml +++ b/crates/common/Cargo.toml @@ -41,7 +41,7 @@ sov-stf-runner = { path = "../sovereign-sdk/full-node/sov-stf-runner", features # Citrea citrea-primitives = { path = "../primitives/" } -citrea-pruning = { path = "../pruning" } +citrea-storage-ops = { path = "../storage-ops" } [dev-dependencies] sov-mock-da = { path = "../sovereign-sdk/adapters/mock-da", features = ["native"] } diff --git a/crates/common/src/config.rs b/crates/common/src/config.rs index 35258c95b..3be73b450 100644 --- a/crates/common/src/config.rs +++ b/crates/common/src/config.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; -use citrea_pruning::PruningConfig; +use citrea_storage_ops::PruningConfig; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sov_stf_runner::ProverGuestRunConfig; diff --git a/crates/fullnode/Cargo.toml b/crates/fullnode/Cargo.toml index 793d16238..7486a2f4b 100644 --- a/crates/fullnode/Cargo.toml +++ b/crates/fullnode/Cargo.toml @@ -12,7 +12,7 @@ repository.workspace = true # Citrea Deps citrea-common = { path = "../common" } citrea-primitives = { path = "../primitives" } -citrea-pruning = { path = "../pruning" } +citrea-storage-ops = { path = "../storage-ops" } # Sov SDK deps sov-db = { path = "../sovereign-sdk/full-node/db/sov-db" } diff --git a/crates/fullnode/src/lib.rs b/crates/fullnode/src/lib.rs index c3dbcac99..f59033007 100644 --- a/crates/fullnode/src/lib.rs +++ b/crates/fullnode/src/lib.rs @@ -6,7 +6,7 @@ use anyhow::Result; use borsh::{BorshDeserialize, BorshSerialize}; use citrea_common::cache::L1BlockCache; use citrea_common::{RollupPublicKeys, RunnerConfig}; -use citrea_pruning::{Pruner, PrunerService}; +use citrea_storage_ops::{Pruner, PrunerService}; use da_block_handler::L1BlockHandler; pub use runner::*; use serde::de::DeserializeOwned; diff --git a/crates/pruning/Cargo.toml b/crates/storage-ops/Cargo.toml similarity index 97% rename from crates/pruning/Cargo.toml rename to crates/storage-ops/Cargo.toml index fe1ce175f..604cd615e 100644 --- a/crates/pruning/Cargo.toml +++ b/crates/storage-ops/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "citrea-pruning" +name = "citrea-storage-ops" version.workspace = true authors.workspace = true edition.workspace = true diff --git a/crates/pruning/src/criteria.rs b/crates/storage-ops/src/criteria.rs similarity index 100% rename from crates/pruning/src/criteria.rs rename to crates/storage-ops/src/criteria.rs diff --git a/crates/pruning/src/lib.rs b/crates/storage-ops/src/lib.rs similarity index 100% rename from crates/pruning/src/lib.rs rename to crates/storage-ops/src/lib.rs diff --git a/crates/pruning/src/pruners/evm.rs b/crates/storage-ops/src/pruners/evm.rs similarity index 100% rename from crates/pruning/src/pruners/evm.rs rename to crates/storage-ops/src/pruners/evm.rs diff --git a/crates/pruning/src/pruners/ledger.rs b/crates/storage-ops/src/pruners/ledger.rs similarity index 100% rename from crates/pruning/src/pruners/ledger.rs rename to crates/storage-ops/src/pruners/ledger.rs diff --git a/crates/pruning/src/pruners/mod.rs b/crates/storage-ops/src/pruners/mod.rs similarity index 100% rename from crates/pruning/src/pruners/mod.rs rename to crates/storage-ops/src/pruners/mod.rs diff --git a/crates/pruning/src/pruners/native_db.rs b/crates/storage-ops/src/pruners/native_db.rs similarity index 100% rename from crates/pruning/src/pruners/native_db.rs rename to crates/storage-ops/src/pruners/native_db.rs diff --git a/crates/pruning/src/service.rs b/crates/storage-ops/src/service.rs similarity index 100% rename from crates/pruning/src/service.rs rename to crates/storage-ops/src/service.rs diff --git a/crates/pruning/src/tests.rs b/crates/storage-ops/src/tests.rs similarity index 100% rename from crates/pruning/src/tests.rs rename to crates/storage-ops/src/tests.rs From 9ed849b04352097dcbf8cb34bfcc8e1734989787 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Mon, 3 Feb 2025 21:33:55 +0300 Subject: [PATCH 07/13] Move pruning stuff into it's own module inside the crate --- bin/citrea/src/rollup/mod.rs | 2 +- bin/cli/src/commands/prune.rs | 2 +- crates/common/src/config.rs | 2 +- crates/fullnode/src/lib.rs | 2 +- crates/storage-ops/src/lib.rs | 90 +------------------ .../{pruners => pruning/components}/evm.rs | 0 .../{pruners => pruning/components}/ledger.rs | 0 .../{pruners => pruning/components}/mod.rs | 0 .../components}/native_db.rs | 0 .../storage-ops/src/{ => pruning}/criteria.rs | 0 crates/storage-ops/src/pruning/mod.rs | 89 ++++++++++++++++++ .../storage-ops/src/{ => pruning}/service.rs | 2 +- crates/storage-ops/src/tests.rs | 9 +- 13 files changed, 99 insertions(+), 99 deletions(-) rename crates/storage-ops/src/{pruners => pruning/components}/evm.rs (100%) rename crates/storage-ops/src/{pruners => pruning/components}/ledger.rs (100%) rename crates/storage-ops/src/{pruners => pruning/components}/mod.rs (100%) rename crates/storage-ops/src/{pruners => pruning/components}/native_db.rs (100%) rename crates/storage-ops/src/{ => pruning}/criteria.rs (100%) create mode 100644 crates/storage-ops/src/pruning/mod.rs rename crates/storage-ops/src/{ => pruning}/service.rs (99%) diff --git a/bin/citrea/src/rollup/mod.rs b/bin/citrea/src/rollup/mod.rs index beee2d5cd..fbea9088c 100644 --- a/bin/citrea/src/rollup/mod.rs +++ b/bin/citrea/src/rollup/mod.rs @@ -12,7 +12,7 @@ use citrea_light_client_prover::da_block_handler::L1BlockHandler as LightClientP use citrea_light_client_prover::runner::CitreaLightClientProver; use citrea_primitives::forks::get_forks; use citrea_sequencer::CitreaSequencer; -use citrea_storage_ops::PrunerService; +use citrea_storage_ops::pruning::PrunerService; use jsonrpsee::RpcModule; use sov_db::ledger_db::migrations::{LedgerDBMigrator, Migrations}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; diff --git a/bin/cli/src/commands/prune.rs b/bin/cli/src/commands/prune.rs index fcfa5c01e..4d8713c5a 100644 --- a/bin/cli/src/commands/prune.rs +++ b/bin/cli/src/commands/prune.rs @@ -1,7 +1,7 @@ use std::path::PathBuf; use std::sync::Arc; -use citrea_storage_ops::{Pruner, PruningConfig}; +use citrea_storage_ops::pruning::{Pruner, PruningConfig}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; use sov_db::native_db::NativeDB; use sov_db::rocks_db_config::RocksdbConfig; diff --git a/crates/common/src/config.rs b/crates/common/src/config.rs index 3be73b450..7cde57b7e 100644 --- a/crates/common/src/config.rs +++ b/crates/common/src/config.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; -use citrea_storage_ops::PruningConfig; +use citrea_storage_ops::pruning::PruningConfig; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use sov_stf_runner::ProverGuestRunConfig; diff --git a/crates/fullnode/src/lib.rs b/crates/fullnode/src/lib.rs index f59033007..82021b7ba 100644 --- a/crates/fullnode/src/lib.rs +++ b/crates/fullnode/src/lib.rs @@ -6,7 +6,7 @@ use anyhow::Result; use borsh::{BorshDeserialize, BorshSerialize}; use citrea_common::cache::L1BlockCache; use citrea_common::{RollupPublicKeys, RunnerConfig}; -use citrea_storage_ops::{Pruner, PrunerService}; +use citrea_storage_ops::pruning::{Pruner, PrunerService}; use da_block_handler::L1BlockHandler; pub use runner::*; use serde::de::DeserializeOwned; diff --git a/crates/storage-ops/src/lib.rs b/crates/storage-ops/src/lib.rs index 0b70aab92..3cc64d330 100644 --- a/crates/storage-ops/src/lib.rs +++ b/crates/storage-ops/src/lib.rs @@ -1,91 +1,3 @@ -use std::sync::Arc; - -use futures::future; -use serde::{Deserialize, Serialize}; -pub use service::*; -use sov_db::ledger_db::SharedLedgerOps; -use tracing::info; - -use crate::criteria::{Criteria, DistanceCriteria}; -use crate::pruners::{prune_evm, prune_ledger, prune_native_db}; - -mod criteria; -mod pruners; -mod service; +pub mod pruning; #[cfg(test)] mod tests; - -/// A configuration type to define the behaviour of the pruner. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] -pub struct PruningConfig { - /// Defines the number of blocks from the tip of the chain to remove. - pub distance: u64, -} - -impl Default for PruningConfig { - fn default() -> Self { - Self { distance: 256 } - } -} - -pub struct Pruner -where - DB: SharedLedgerOps, -{ - /// Access to ledger tables. - ledger_db: DB, - /// Access to native DB. - native_db: Arc, - /// Criteria to decide pruning - criteria: Box, -} - -impl Pruner -where - DB: SharedLedgerOps + Send + Sync + Clone + 'static, -{ - pub fn new(config: PruningConfig, ledger_db: DB, native_db: Arc) -> Self { - // distance is the only criteria implemented at the moment. - let criteria = Box::new(DistanceCriteria { - distance: config.distance, - }); - Self { - ledger_db, - native_db, - criteria, - } - } - - pub fn store_last_pruned_l2_height(&self, last_pruned_l2_height: u64) -> anyhow::Result<()> { - self.ledger_db - .set_last_pruned_l2_height(last_pruned_l2_height) - } - - pub(crate) fn should_prune( - &self, - last_pruned_l2_height: u64, - current_l2_height: u64, - ) -> Option { - self.criteria - .should_prune(last_pruned_l2_height, current_l2_height) - } - - /// Prune everything - pub async fn prune(&self, up_to_block: u64) { - info!("Pruning up to L2 block: {}", up_to_block); - let ledger_db = self.ledger_db.clone(); - let native_db = self.native_db.clone(); - let ledger_pruning_handle = - tokio::task::spawn_blocking(move || prune_ledger(ledger_db, up_to_block)); - let evm_pruning_handle = tokio::task::spawn_blocking(move || prune_evm(up_to_block)); - let native_db_pruning_handle = - tokio::task::spawn_blocking(move || prune_native_db(native_db, up_to_block)); - - future::join_all([ - ledger_pruning_handle, - evm_pruning_handle, - native_db_pruning_handle, - ]) - .await; - } -} diff --git a/crates/storage-ops/src/pruners/evm.rs b/crates/storage-ops/src/pruning/components/evm.rs similarity index 100% rename from crates/storage-ops/src/pruners/evm.rs rename to crates/storage-ops/src/pruning/components/evm.rs diff --git a/crates/storage-ops/src/pruners/ledger.rs b/crates/storage-ops/src/pruning/components/ledger.rs similarity index 100% rename from crates/storage-ops/src/pruners/ledger.rs rename to crates/storage-ops/src/pruning/components/ledger.rs diff --git a/crates/storage-ops/src/pruners/mod.rs b/crates/storage-ops/src/pruning/components/mod.rs similarity index 100% rename from crates/storage-ops/src/pruners/mod.rs rename to crates/storage-ops/src/pruning/components/mod.rs diff --git a/crates/storage-ops/src/pruners/native_db.rs b/crates/storage-ops/src/pruning/components/native_db.rs similarity index 100% rename from crates/storage-ops/src/pruners/native_db.rs rename to crates/storage-ops/src/pruning/components/native_db.rs diff --git a/crates/storage-ops/src/criteria.rs b/crates/storage-ops/src/pruning/criteria.rs similarity index 100% rename from crates/storage-ops/src/criteria.rs rename to crates/storage-ops/src/pruning/criteria.rs diff --git a/crates/storage-ops/src/pruning/mod.rs b/crates/storage-ops/src/pruning/mod.rs new file mode 100644 index 000000000..e515bb653 --- /dev/null +++ b/crates/storage-ops/src/pruning/mod.rs @@ -0,0 +1,89 @@ +use std::sync::Arc; + +use futures::future; +use serde::{Deserialize, Serialize}; +use sov_db::ledger_db::SharedLedgerOps; +use tracing::info; + +use self::components::{prune_evm, prune_ledger, prune_native_db}; +use self::criteria::{Criteria, DistanceCriteria}; +pub use self::service::*; + +pub(crate) mod components; +pub(crate) mod criteria; +pub(crate) mod service; + +/// A configuration type to define the behaviour of the pruner. +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub struct PruningConfig { + /// Defines the number of blocks from the tip of the chain to remove. + pub distance: u64, +} + +impl Default for PruningConfig { + fn default() -> Self { + Self { distance: 256 } + } +} + +pub struct Pruner +where + DB: SharedLedgerOps, +{ + /// Access to ledger tables. + ledger_db: DB, + /// Access to native DB. + native_db: Arc, + /// Criteria to decide pruning + criteria: Box, +} + +impl Pruner +where + DB: SharedLedgerOps + Send + Sync + Clone + 'static, +{ + pub fn new(config: PruningConfig, ledger_db: DB, native_db: Arc) -> Self { + // distance is the only criteria implemented at the moment. + let criteria = Box::new(DistanceCriteria { + distance: config.distance, + }); + Self { + ledger_db, + native_db, + criteria, + } + } + + pub fn store_last_pruned_l2_height(&self, last_pruned_l2_height: u64) -> anyhow::Result<()> { + self.ledger_db + .set_last_pruned_l2_height(last_pruned_l2_height) + } + + pub(crate) fn should_prune( + &self, + last_pruned_l2_height: u64, + current_l2_height: u64, + ) -> Option { + self.criteria + .should_prune(last_pruned_l2_height, current_l2_height) + } + + /// Prune everything + pub async fn prune(&self, up_to_block: u64) { + info!("Pruning up to L2 block: {}", up_to_block); + let ledger_db = self.ledger_db.clone(); + let native_db = self.native_db.clone(); + let ledger_pruning_handle = + tokio::task::spawn_blocking(move || prune_ledger(ledger_db, up_to_block)); + let evm_pruning_handle = tokio::task::spawn_blocking(move || prune_evm(up_to_block)); + let native_db_pruning_handle = + tokio::task::spawn_blocking(move || prune_native_db(native_db, up_to_block)); + + future::join_all([ + ledger_pruning_handle, + evm_pruning_handle, + native_db_pruning_handle, + ]) + .await; + } +} diff --git a/crates/storage-ops/src/service.rs b/crates/storage-ops/src/pruning/service.rs similarity index 99% rename from crates/storage-ops/src/service.rs rename to crates/storage-ops/src/pruning/service.rs index d2c1482b5..816415cfc 100644 --- a/crates/storage-ops/src/service.rs +++ b/crates/storage-ops/src/pruning/service.rs @@ -4,7 +4,7 @@ use tokio::sync::broadcast; use tokio_util::sync::CancellationToken; use tracing::{debug, error}; -use crate::Pruner; +use super::Pruner; pub struct PrunerService { pruner: Pruner, diff --git a/crates/storage-ops/src/tests.rs b/crates/storage-ops/src/tests.rs index 152a656f8..9b47b3679 100644 --- a/crates/storage-ops/src/tests.rs +++ b/crates/storage-ops/src/tests.rs @@ -9,8 +9,8 @@ use sov_prover_storage_manager::SnapshotManager; use tokio::sync::broadcast; use tokio_util::sync::CancellationToken; -use crate::criteria::{Criteria, DistanceCriteria}; -use crate::{Pruner, PruningConfig}; +use crate::pruning::criteria::{Criteria, DistanceCriteria}; +use crate::pruning::{Pruner, PrunerService, PruningConfig}; #[tokio::test(flavor = "multi_thread")] async fn test_pruner_simple_run() { @@ -23,13 +23,12 @@ async fn test_pruner_simple_run() { let native_db = NativeDB::::setup_schema_db(&rocksdb_config).unwrap(); let pruner = Pruner::new( PruningConfig { distance: 5 }, - 0, - receiver, ledger_db, Arc::new(native_db), ); + let pruner_service = PrunerService::new(pruner, 0, receiver); - tokio::spawn(pruner.run(cancellation_token.clone())); + tokio::spawn(pruner_service.run(cancellation_token.clone())); sleep(Duration::from_secs(1)); From c867814f7f9d69892e6d284cd2741d3444d42d9d Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Tue, 4 Feb 2025 10:31:06 +0300 Subject: [PATCH 08/13] Initial rollback implementation --- bin/cli/src/commands/mod.rs | 2 ++ bin/cli/src/commands/rollback.rs | 3 ++ bin/cli/src/main.rs | 4 +-- crates/storage-ops/src/lib.rs | 2 ++ crates/storage-ops/src/rollback/mod.rs | 12 ++++++++ crates/storage-ops/src/rollback/service.rs | 35 ++++++++++++++++++++++ 6 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 bin/cli/src/commands/rollback.rs create mode 100644 crates/storage-ops/src/rollback/mod.rs create mode 100644 crates/storage-ops/src/rollback/service.rs diff --git a/bin/cli/src/commands/mod.rs b/bin/cli/src/commands/mod.rs index a889556ce..302e743c4 100644 --- a/bin/cli/src/commands/mod.rs +++ b/bin/cli/src/commands/mod.rs @@ -1,3 +1,5 @@ mod prune; +mod rollback; pub(crate) use prune::*; +pub(crate) use rollback::*; diff --git a/bin/cli/src/commands/rollback.rs b/bin/cli/src/commands/rollback.rs new file mode 100644 index 000000000..da40db8f4 --- /dev/null +++ b/bin/cli/src/commands/rollback.rs @@ -0,0 +1,3 @@ +pub(crate) async fn rollback(_num_block: u32) -> anyhow::Result<()> { + Ok(()) +} diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs index d99f0dd21..75bb73fad 100644 --- a/bin/cli/src/main.rs +++ b/bin/cli/src/main.rs @@ -33,7 +33,7 @@ enum Commands { db_path: PathBuf, /// The number of blocks to rollback #[arg(long)] - blocks: u64, + blocks: u32, }, } @@ -50,7 +50,7 @@ async fn main() -> anyhow::Result<()> { commands::prune(db_path.clone(), *distance).await?; } Commands::Rollback { db_path, blocks } => { - println!("Rolling back stuff: {:?}, blocks: {}", db_path, blocks); + commands::rollback(*blocks).await?; } } diff --git a/crates/storage-ops/src/lib.rs b/crates/storage-ops/src/lib.rs index 3cc64d330..3f835e181 100644 --- a/crates/storage-ops/src/lib.rs +++ b/crates/storage-ops/src/lib.rs @@ -1,3 +1,5 @@ pub mod pruning; +pub mod rollback; + #[cfg(test)] mod tests; diff --git a/crates/storage-ops/src/rollback/mod.rs b/crates/storage-ops/src/rollback/mod.rs new file mode 100644 index 000000000..ee4888032 --- /dev/null +++ b/crates/storage-ops/src/rollback/mod.rs @@ -0,0 +1,12 @@ +pub mod service; + +pub struct Rollback {} + +impl Rollback { + /// Rollback the provided number of blocks + pub fn execute(&self, _num_blocks: u32) -> anyhow::Result<()> { + // Do something + + Ok(()) + } +} diff --git a/crates/storage-ops/src/rollback/service.rs b/crates/storage-ops/src/rollback/service.rs new file mode 100644 index 000000000..2b951d237 --- /dev/null +++ b/crates/storage-ops/src/rollback/service.rs @@ -0,0 +1,35 @@ +use tokio::select; +use tokio::sync::mpsc::Receiver; +use tokio_util::sync::CancellationToken; +use tracing::{error, info}; + +use super::Rollback; + +pub struct RollbackService { + rollback: Rollback, + receiver: Receiver, +} + +impl RollbackService { + pub fn new(rollback: Rollback, receiver: Receiver) -> Self { + Self { rollback, receiver } + } + + /// Run service to rollback when instructed to + pub async fn run(mut self, cancellation_token: CancellationToken) { + loop { + select! { + biased; + _ = cancellation_token.cancelled() => { + return; + }, + Some(num_blocks) = self.receiver.recv() => { + info!("Received signal to rollback {num_blocks} blocks"); + if let Err(e) = self.rollback.execute(num_blocks) { + error!("Could not rollback blocks: {:?}", e); + } + } + } + } + } +} From 296295092e355af97dc579894f665465946454f3 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Tue, 4 Feb 2025 15:39:32 +0300 Subject: [PATCH 09/13] Replace prune_evm with prune_state_Db --- crates/storage-ops/src/pruning/components/evm.rs | 10 ---------- .../src/pruning/components/{ledger.rs => ledger_db.rs} | 0 crates/storage-ops/src/pruning/components/mod.rs | 8 ++++---- crates/storage-ops/src/pruning/components/state_db.rs | 6 ++++++ crates/storage-ops/src/pruning/mod.rs | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) delete mode 100644 crates/storage-ops/src/pruning/components/evm.rs rename crates/storage-ops/src/pruning/components/{ledger.rs => ledger_db.rs} (100%) create mode 100644 crates/storage-ops/src/pruning/components/state_db.rs diff --git a/crates/storage-ops/src/pruning/components/evm.rs b/crates/storage-ops/src/pruning/components/evm.rs deleted file mode 100644 index af05397c7..000000000 --- a/crates/storage-ops/src/pruning/components/evm.rs +++ /dev/null @@ -1,10 +0,0 @@ -use citrea_evm::Evm; -use sov_modules_api::default_context::DefaultContext; -use tracing::debug; - -/// Prune evm -pub(crate) fn prune_evm(up_to_block: u64) { - debug!("Pruning EVM, up to L2 block {}", up_to_block); - let _evm = Evm::::default(); - // unimplemented!() -} diff --git a/crates/storage-ops/src/pruning/components/ledger.rs b/crates/storage-ops/src/pruning/components/ledger_db.rs similarity index 100% rename from crates/storage-ops/src/pruning/components/ledger.rs rename to crates/storage-ops/src/pruning/components/ledger_db.rs diff --git a/crates/storage-ops/src/pruning/components/mod.rs b/crates/storage-ops/src/pruning/components/mod.rs index c92186283..f1decd0dd 100644 --- a/crates/storage-ops/src/pruning/components/mod.rs +++ b/crates/storage-ops/src/pruning/components/mod.rs @@ -1,7 +1,7 @@ -mod evm; -mod ledger; +mod ledger_db; mod native_db; +mod state_db; -pub(crate) use evm::*; -pub(crate) use ledger::*; +pub(crate) use ledger_db::*; pub(crate) use native_db::*; +pub(crate) use state_db::*; diff --git a/crates/storage-ops/src/pruning/components/state_db.rs b/crates/storage-ops/src/pruning/components/state_db.rs new file mode 100644 index 000000000..1a22b10ad --- /dev/null +++ b/crates/storage-ops/src/pruning/components/state_db.rs @@ -0,0 +1,6 @@ +use std::sync::Arc; + +use tracing::{debug, error}; + +/// Prune state DB +pub(crate) fn prune_state_db(state_db: Arc, up_to_block: u64) {} diff --git a/crates/storage-ops/src/pruning/mod.rs b/crates/storage-ops/src/pruning/mod.rs index e515bb653..9c1c664b3 100644 --- a/crates/storage-ops/src/pruning/mod.rs +++ b/crates/storage-ops/src/pruning/mod.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Serialize}; use sov_db::ledger_db::SharedLedgerOps; use tracing::info; -use self::components::{prune_evm, prune_ledger, prune_native_db}; +use self::components::{prune_ledger, prune_native_db, prune_state_db}; use self::criteria::{Criteria, DistanceCriteria}; pub use self::service::*; From ea9dec2e674146ea4f9ed68125742cd2b6dde4a0 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Tue, 4 Feb 2025 15:40:00 +0300 Subject: [PATCH 10/13] Record stale nodes --- .../full-node/db/sov-db/src/schema/tables.rs | 8 +++++++- .../full-node/db/sov-db/src/state_db.rs | 15 +++++++++++++-- .../module-system/sov-state/src/prover_storage.rs | 10 +++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs index 154e2c4f3..6fe19056e 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/schema/tables.rs @@ -10,7 +10,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; -use jmt::storage::{NibblePath, Node, NodeKey}; +use jmt::storage::{NibblePath, Node, NodeKey, StaleNodeIndex}; use jmt::Version; use sov_rollup_interface::da::SequencerCommitment; use sov_rollup_interface::mmr::{MMRChunk, MMRNodeHash, Wtxid}; @@ -38,6 +38,7 @@ pub const STATE_TABLES: &[&str] = &[ KeyHashToKey::table_name(), JmtValues::table_name(), JmtNodes::table_name(), + StaleNodes::table_name(), ]; /// A list of all tables used by Sequencer LedgerDB @@ -372,6 +373,11 @@ define_table_without_codec!( (JmtNodes) NodeKey => Node ); +define_table_with_default_codec!( + /// The list of stale nodes in JMT + (StaleNodes) StaleNodeIndex => () +); + define_table_with_default_codec!( /// Light client proof data by l1 height (LightClientProofBySlotNumber) SlotNumber => StoredLightClientProof diff --git a/crates/sovereign-sdk/full-node/db/sov-db/src/state_db.rs b/crates/sovereign-sdk/full-node/db/sov-db/src/state_db.rs index 5e0883cb0..09610f157 100644 --- a/crates/sovereign-sdk/full-node/db/sov-db/src/state_db.rs +++ b/crates/sovereign-sdk/full-node/db/sov-db/src/state_db.rs @@ -1,12 +1,13 @@ +use std::collections::BTreeSet; use std::sync::{Arc, Mutex}; -use jmt::storage::{HasPreimage, TreeReader, TreeWriter}; +use jmt::storage::{HasPreimage, StaleNodeIndex, TreeReader, TreeWriter}; use jmt::{KeyHash, Version}; use sov_schema_db::snapshot::{DbSnapshot, QueryManager, ReadOnlyDbSnapshot}; use sov_schema_db::SchemaBatch; use crate::rocks_db_config::RocksdbConfig; -use crate::schema::tables::{JmtNodes, JmtValues, KeyHashToKey, STATE_TABLES}; +use crate::schema::tables::{JmtNodes, JmtValues, KeyHashToKey, StaleNodes, STATE_TABLES}; use crate::schema::types::StateKey; /// A typed wrapper around the db for storing rollup state. Internally, @@ -103,6 +104,16 @@ impl StateDB { } } + /// Record stale nodes in state + pub fn set_stale_nodes(&self, stale_nodes: &BTreeSet) -> anyhow::Result<()> { + let mut batch = SchemaBatch::new(); + for index in stale_nodes { + batch.put::(index, &())?; + } + self.db.write_many(batch)?; + Ok(()) + } + /// Increment the `next_version` counter by 1. pub fn inc_next_version(&self) { let mut version = self.next_version.lock().unwrap(); diff --git a/crates/sovereign-sdk/module-system/sov-state/src/prover_storage.rs b/crates/sovereign-sdk/module-system/sov-state/src/prover_storage.rs index e14c58a0b..fd6927f13 100644 --- a/crates/sovereign-sdk/module-system/sov-state/src/prover_storage.rs +++ b/crates/sovereign-sdk/module-system/sov-state/src/prover_storage.rs @@ -1,6 +1,7 @@ +use std::collections::BTreeSet; use std::sync::Arc; -use jmt::storage::{NodeBatch, TreeWriter}; +use jmt::storage::{NodeBatch, StaleNodeIndex, TreeWriter}; use jmt::{JellyfishMerkleTree, KeyHash, Version}; use sov_db::native_db::NativeDB; use sov_db::schema::{QueryManager, ReadOnlyDbSnapshot}; @@ -68,6 +69,7 @@ where pub struct ProverStateUpdate { pub(crate) node_batch: NodeBatch, pub key_preimages: Vec<(KeyHash, CacheKey)>, + pub stale_state: BTreeSet, } impl Storage for ProverStorage @@ -192,6 +194,7 @@ where let state_update = ProverStateUpdate { node_batch: tree_update.node_batch, key_preimages, + stale_state: tree_update.stale_node_index_batch, }; // We need the state diff to be calculated only inside zk context. @@ -250,6 +253,11 @@ where .write_node_batch(&state_update.node_batch) .expect("db write must succeed"); + // Write the stale state nodes which will be used by the pruner at a later stage for cleanup. + self.db + .set_stale_nodes(&state_update.stale_state) + .expect("db set stale nodes must succeed"); + // Finally, update our in-memory view of the current item numbers self.db.inc_next_version(); } From 303171a63ab69fa9735efd00d766cecad3510673 Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Tue, 4 Feb 2025 17:13:02 +0300 Subject: [PATCH 11/13] Implement state pruning iterator --- Cargo.lock | 1 + bin/cli/src/commands/prune.rs | 4 +- bin/cli/src/main.rs | 5 +- crates/fullnode/src/lib.rs | 1 + crates/storage-ops/Cargo.toml | 1 + .../src/pruning/components/state_db.rs | 87 ++++++++++++++++++- crates/storage-ops/src/pruning/mod.rs | 21 ++++- 7 files changed, 113 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af939c7ac..6a18d0fa1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2217,6 +2217,7 @@ dependencies = [ "citrea-evm", "citrea-primitives", "futures", + "jmt", "serde", "sov-db", "sov-modules-api", diff --git a/bin/cli/src/commands/prune.rs b/bin/cli/src/commands/prune.rs index 4d8713c5a..0107f0951 100644 --- a/bin/cli/src/commands/prune.rs +++ b/bin/cli/src/commands/prune.rs @@ -5,6 +5,7 @@ use citrea_storage_ops::pruning::{Pruner, PruningConfig}; use sov_db::ledger_db::{LedgerDB, SharedLedgerOps}; use sov_db::native_db::NativeDB; use sov_db::rocks_db_config::RocksdbConfig; +use sov_db::state_db::StateDB; use sov_prover_storage_manager::SnapshotManager; use tracing::{debug, info}; @@ -19,6 +20,7 @@ pub(crate) async fn prune(db_path: PathBuf, distance: u64) -> anyhow::Result<()> let rocksdb_config = RocksdbConfig::new(&db_path, None, None); let ledger_db = LedgerDB::with_config(&rocksdb_config)?; let native_db = NativeDB::::setup_schema_db(&rocksdb_config)?; + let state_db = StateDB::::setup_schema_db(&rocksdb_config)?; let Some((soft_confirmation_number, _)) = ledger_db.get_head_soft_confirmation()? else { return Ok(()); @@ -29,7 +31,7 @@ pub(crate) async fn prune(db_path: PathBuf, distance: u64) -> anyhow::Result<()> soft_confirmation_number.0, distance ); - let pruner = Pruner::new(config, ledger_db, Arc::new(native_db)); + let pruner = Pruner::new(config, ledger_db, Arc::new(state_db), Arc::new(native_db)); pruner.prune(soft_confirmation_number.0).await; Ok(()) diff --git a/bin/cli/src/main.rs b/bin/cli/src/main.rs index 75bb73fad..15e4fc1d0 100644 --- a/bin/cli/src/main.rs +++ b/bin/cli/src/main.rs @@ -49,7 +49,10 @@ async fn main() -> anyhow::Result<()> { Commands::Prune { db_path, distance } => { commands::prune(db_path.clone(), *distance).await?; } - Commands::Rollback { db_path, blocks } => { + Commands::Rollback { + db_path: _db_path, + blocks, + } => { commands::rollback(*blocks).await?; } } diff --git a/crates/fullnode/src/lib.rs b/crates/fullnode/src/lib.rs index 82021b7ba..15cc1e803 100644 --- a/crates/fullnode/src/lib.rs +++ b/crates/fullnode/src/lib.rs @@ -63,6 +63,7 @@ where let pruner = Pruner::::new( pruning_config.clone(), ledger_db.clone(), + storage_manager.get_state_db_handle(), storage_manager.get_native_db_handle(), ); diff --git a/crates/storage-ops/Cargo.toml b/crates/storage-ops/Cargo.toml index 604cd615e..95b4393fc 100644 --- a/crates/storage-ops/Cargo.toml +++ b/crates/storage-ops/Cargo.toml @@ -14,6 +14,7 @@ citrea-evm = { path = "../evm", features = ["native"] } citrea-primitives = { path = "../primitives" } # Sov SDK deps +jmt = { workspace = true } sov-db = { path = "../sovereign-sdk/full-node/db/sov-db" } sov-modules-api = { path = "../sovereign-sdk/module-system/sov-modules-api", default-features = false } sov-schema-db = { path = "../sovereign-sdk/full-node/db/sov-schema-db" } diff --git a/crates/storage-ops/src/pruning/components/state_db.rs b/crates/storage-ops/src/pruning/components/state_db.rs index 1a22b10ad..4fc371b7c 100644 --- a/crates/storage-ops/src/pruning/components/state_db.rs +++ b/crates/storage-ops/src/pruning/components/state_db.rs @@ -1,6 +1,89 @@ +use std::iter::Peekable; use std::sync::Arc; -use tracing::{debug, error}; +use jmt::storage::StaleNodeIndex; +use sov_db::schema::tables::{JmtNodes, StaleNodes}; +use sov_schema_db::{SchemaBatch, SchemaIterator, DB}; +use tracing::error; + +struct StaleNodeIndicesByVersionIterator<'a> { + inner: Peekable>, + up_to_version: u64, +} + +impl<'a> StaleNodeIndicesByVersionIterator<'a> { + fn new(db: &'a DB, up_to_version: u64) -> anyhow::Result { + let iter = db.iter::()?; + + Ok(Self { + inner: iter.peekable(), + up_to_version, + }) + } + + fn next_result(&mut self) -> anyhow::Result>> { + match self.inner.next().transpose()? { + None => Ok(None), + Some(iter_output) => { + let index = iter_output.key; + let version = index.stale_since_version; + if version > self.up_to_version { + return Ok(None); + } + + let mut indices = vec![index]; + while let Some(res) = self.inner.peek() { + if let Ok(iter_output_ref) = res { + let index_ref = iter_output_ref.key.clone(); + if index_ref.stale_since_version != version { + break; + } + } + + let iter_output = self.inner.next().transpose()?.expect("Should be Some."); + indices.push(iter_output.key); + } + + Ok(Some(indices)) + } + } + } +} + +impl<'a> Iterator for StaleNodeIndicesByVersionIterator<'a> { + type Item = anyhow::Result>; + + fn next(&mut self) -> Option { + self.next_result().transpose() + } +} /// Prune state DB -pub(crate) fn prune_state_db(state_db: Arc, up_to_block: u64) {} +pub(crate) fn prune_state_db(state_db: Arc, up_to_block: u64) { + let Ok(indicies) = StaleNodeIndicesByVersionIterator::new(&state_db, up_to_block + 1) else { + error!("Could not read stale nodes"); + return; + }; + + let indicies = indicies.into_iter().flatten().flatten().collect::>(); + + println!("Stale Indicies: {:#?}", indicies); + + if indicies.is_empty() { + return; + } + + let mut batch = SchemaBatch::new(); + for index in indicies { + if let Err(e) = batch.delete::(&index.node_key) { + error!( + "Could not add stale node to schema batch operation: {:?}", + e + ); + } + // batch.delete::(&index.node_key)?; + } + if let Err(e) = state_db.write_schemas(batch) { + error!("Could not delete state data: {:?}", e); + } +} diff --git a/crates/storage-ops/src/pruning/mod.rs b/crates/storage-ops/src/pruning/mod.rs index 9c1c664b3..8d3b3940a 100644 --- a/crates/storage-ops/src/pruning/mod.rs +++ b/crates/storage-ops/src/pruning/mod.rs @@ -34,6 +34,8 @@ where ledger_db: DB, /// Access to native DB. native_db: Arc, + /// Access to state DB. + state_db: Arc, /// Criteria to decide pruning criteria: Box, } @@ -42,13 +44,19 @@ impl Pruner where DB: SharedLedgerOps + Send + Sync + Clone + 'static, { - pub fn new(config: PruningConfig, ledger_db: DB, native_db: Arc) -> Self { + pub fn new( + config: PruningConfig, + ledger_db: DB, + state_db: Arc, + native_db: Arc, + ) -> Self { // distance is the only criteria implemented at the moment. let criteria = Box::new(DistanceCriteria { distance: config.distance, }); Self { ledger_db, + state_db, native_db, criteria, } @@ -72,16 +80,23 @@ where pub async fn prune(&self, up_to_block: u64) { info!("Pruning up to L2 block: {}", up_to_block); let ledger_db = self.ledger_db.clone(); + let native_db = self.native_db.clone(); + + let state_db = self.state_db.clone(); + let ledger_pruning_handle = tokio::task::spawn_blocking(move || prune_ledger(ledger_db, up_to_block)); - let evm_pruning_handle = tokio::task::spawn_blocking(move || prune_evm(up_to_block)); + + let state_db_pruning_handle = + tokio::task::spawn_blocking(move || prune_state_db(state_db, up_to_block)); + let native_db_pruning_handle = tokio::task::spawn_blocking(move || prune_native_db(native_db, up_to_block)); future::join_all([ ledger_pruning_handle, - evm_pruning_handle, + state_db_pruning_handle, native_db_pruning_handle, ]) .await; From f8c4da47724440cf84488b3ecb1d905c206b810e Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Tue, 4 Feb 2025 17:47:10 +0300 Subject: [PATCH 12/13] Pass state db --- bin/citrea/tests/e2e/mod.rs | 2 +- bin/citrea/tests/e2e/pruning.rs | 2 +- bin/citrea/tests/test_helpers/mod.rs | 2 +- crates/storage-ops/src/tests.rs | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/bin/citrea/tests/e2e/mod.rs b/bin/citrea/tests/e2e/mod.rs index c3eb52594..6163faaec 100644 --- a/bin/citrea/tests/e2e/mod.rs +++ b/bin/citrea/tests/e2e/mod.rs @@ -7,7 +7,7 @@ use citrea_common::{BatchProverConfig, SequencerConfig}; use citrea_evm::smart_contracts::SimpleStorageContract; use citrea_primitives::forks::fork_from_block_number; use citrea_stf::genesis_config::GenesisPaths; -use citrea_storage_ops::PruningConfig; +use citrea_storage_ops::pruning::PruningConfig; use reth_primitives::BlockNumberOrTag; use sov_mock_da::{MockAddress, MockDaService}; use sov_rollup_interface::rpc::{LastVerifiedBatchProofResponse, SoftConfirmationStatus}; diff --git a/bin/citrea/tests/e2e/pruning.rs b/bin/citrea/tests/e2e/pruning.rs index 8771ed5c4..8e73f8c96 100644 --- a/bin/citrea/tests/e2e/pruning.rs +++ b/bin/citrea/tests/e2e/pruning.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use alloy_primitives::Address; /// Testing if the sequencer and full node can handle system transactions correctly (the full node should have the same system transactions as the sequencer) -use citrea_storage_ops::PruningConfig; +use citrea_storage_ops::pruning::PruningConfig; use futures::FutureExt; use reth_primitives::BlockNumberOrTag; use sov_mock_da::{MockAddress, MockDaService}; diff --git a/bin/citrea/tests/test_helpers/mod.rs b/bin/citrea/tests/test_helpers/mod.rs index 12fd959a0..ea5ad7097 100644 --- a/bin/citrea/tests/test_helpers/mod.rs +++ b/bin/citrea/tests/test_helpers/mod.rs @@ -15,7 +15,7 @@ use citrea_common::{ use citrea_light_client_prover::da_block_handler::StartVariant; use citrea_primitives::TEST_PRIVATE_KEY; use citrea_stf::genesis_config::GenesisPaths; -use citrea_storage_ops::PruningConfig; +use citrea_storage_ops::pruning::PruningConfig; use sov_db::ledger_db::SharedLedgerOps; use sov_db::rocks_db_config::RocksdbConfig; use sov_db::schema::tables::{ diff --git a/crates/storage-ops/src/tests.rs b/crates/storage-ops/src/tests.rs index 9b47b3679..479018470 100644 --- a/crates/storage-ops/src/tests.rs +++ b/crates/storage-ops/src/tests.rs @@ -5,6 +5,7 @@ use std::time::Duration; use sov_db::ledger_db::LedgerDB; use sov_db::native_db::NativeDB; use sov_db::rocks_db_config::RocksdbConfig; +use sov_db::state_db::StateDB; use sov_prover_storage_manager::SnapshotManager; use tokio::sync::broadcast; use tokio_util::sync::CancellationToken; @@ -21,9 +22,11 @@ async fn test_pruner_simple_run() { let rocksdb_config = RocksdbConfig::new(tmpdir.path(), None, None); let ledger_db = LedgerDB::with_config(&rocksdb_config).unwrap(); let native_db = NativeDB::::setup_schema_db(&rocksdb_config).unwrap(); + let state_db = StateDB::::setup_schema_db(&rocksdb_config).unwrap(); let pruner = Pruner::new( PruningConfig { distance: 5 }, ledger_db, + Arc::new(state_db), Arc::new(native_db), ); let pruner_service = PrunerService::new(pruner, 0, receiver); From 9e98fef3c75dd6806e9c62b65dba9b9a5b5b396b Mon Sep 17 00:00:00 2001 From: Rakan Alhneiti Date: Tue, 4 Feb 2025 18:13:06 +0300 Subject: [PATCH 13/13] Finalize state db pruning implementation --- .../src/pruning/components/native_db.rs | 2 +- .../src/pruning/components/state_db.rs | 24 +++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/crates/storage-ops/src/pruning/components/native_db.rs b/crates/storage-ops/src/pruning/components/native_db.rs index fe93e2fbf..7de0e77a0 100644 --- a/crates/storage-ops/src/pruning/components/native_db.rs +++ b/crates/storage-ops/src/pruning/components/native_db.rs @@ -13,7 +13,7 @@ pub(crate) fn prune_native_db(native_db: Arc, up_to_block: u6 iter.seek_to_first(); - let mut counter = 1u32; + let mut counter = 0u32; let mut keys_to_delete = vec![]; while let Some(Ok(entry)) = iter.next() { let version = entry.key.1; diff --git a/crates/storage-ops/src/pruning/components/state_db.rs b/crates/storage-ops/src/pruning/components/state_db.rs index 4fc371b7c..b8f3d3c3b 100644 --- a/crates/storage-ops/src/pruning/components/state_db.rs +++ b/crates/storage-ops/src/pruning/components/state_db.rs @@ -4,7 +4,7 @@ use std::sync::Arc; use jmt::storage::StaleNodeIndex; use sov_db::schema::tables::{JmtNodes, StaleNodes}; use sov_schema_db::{SchemaBatch, SchemaIterator, DB}; -use tracing::error; +use tracing::{debug, error}; struct StaleNodeIndicesByVersionIterator<'a> { inner: Peekable>, @@ -13,7 +13,8 @@ struct StaleNodeIndicesByVersionIterator<'a> { impl<'a> StaleNodeIndicesByVersionIterator<'a> { fn new(db: &'a DB, up_to_version: u64) -> anyhow::Result { - let iter = db.iter::()?; + let mut iter = db.iter::()?; + iter.seek_to_first(); Ok(Self { inner: iter.peekable(), @@ -35,6 +36,7 @@ impl<'a> StaleNodeIndicesByVersionIterator<'a> { while let Some(res) = self.inner.peek() { if let Ok(iter_output_ref) = res { let index_ref = iter_output_ref.key.clone(); + if index_ref.stale_since_version != version { break; } @@ -60,6 +62,8 @@ impl<'a> Iterator for StaleNodeIndicesByVersionIterator<'a> { /// Prune state DB pub(crate) fn prune_state_db(state_db: Arc, up_to_block: u64) { + debug!("Pruning state DB, up to L2 block {}", up_to_block); + let Ok(indicies) = StaleNodeIndicesByVersionIterator::new(&state_db, up_to_block + 1) else { error!("Could not read stale nodes"); return; @@ -67,23 +71,33 @@ pub(crate) fn prune_state_db(state_db: Arc, up_to_block: u64) let indicies = indicies.into_iter().flatten().flatten().collect::>(); - println!("Stale Indicies: {:#?}", indicies); - if indicies.is_empty() { + debug!("State: Nothing to prune"); return; } + let count = indicies.len(); + let mut batch = SchemaBatch::new(); for index in indicies { if let Err(e) = batch.delete::(&index.node_key) { error!( - "Could not add stale node to schema batch operation: {:?}", + "Could not add JMT node deletion to schema batch operation: {:?}", e ); } // batch.delete::(&index.node_key)?; + if let Err(e) = batch.delete::(&index) { + error!( + "Could not add stale node deletion to schema batch operation: {:?}", + e + ); + } } + if let Err(e) = state_db.write_schemas(batch) { error!("Could not delete state data: {:?}", e); } + + debug!("Pruned {} state DB records", count); }