diff --git a/Cargo.toml b/Cargo.toml index f3735b6a1..3d2bb22df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ avail-core = { version = "0.6", git = "https://github.com/availproject/avail-cor avail-subxt = { version = "0.5", git = "https://github.com/availproject/avail.git", tag = "v2.1.0.0-rc1" } dusk-plonk = { git = "https://github.com/availproject/plonk.git", tag = "v0.12.0-polygon-2" } kate-recovery = { version = "0.9", git = "https://github.com/availproject/avail-core", tag = "node-v2100-rc1" } -avail-light-core = { version = "0.0.0", path = "./core" } +avail-light-core = { version = "0.0.0", path = "./core", default-features = false } anyhow = "1.0.71" async-std = { version = "1.12.0", features = ["attributes"] } diff --git a/client/Cargo.toml b/client/Cargo.toml index 0a244989c..98114ab30 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -33,5 +33,7 @@ test-case = "3.2.1" [features] network-analysis = ["avail-light-core/network-analysis"] -kademlia-rocksdb = ["avail-light-core/kademlia-rocksdb"] -default = ["kademlia-rocksdb"] +rocksdb = ["avail-light-core/rocksdb"] +memdb = ["avail-light-core/memdb"] +crawl = ["avail-light-core/crawl"] +default = ["memdb"] diff --git a/client/src/main.rs b/client/src/main.rs index d3a8ddc1d..fe1e96be5 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -2,21 +2,22 @@ use crate::cli::CliOpts; use avail_core::AppId; +#[cfg(feature = "memdb")] +use avail_light_core::data::MemoryDB as DB; +#[cfg(feature = "rocksdb")] +use avail_light_core::data::RocksDB as DB; use avail_light_core::{ api, consts::EXPECTED_SYSTEM_VERSION, - data::{IsFinalitySyncedKey, IsSyncedKey}, - network, - sync_client::SyncClient, - sync_finality::SyncFinality, -}; -use avail_light_core::{ - data::{ClientIdKey, Database, LatestHeaderKey, RocksDB}, + data::{ClientIdKey, Database, IsFinalitySyncedKey, IsSyncedKey, LatestHeaderKey}, network::{ - p2p::{self, BOOTSTRAP_LIST_EMPTY_MESSAGE}, + self, + p2p::{self, Store, BOOTSTRAP_LIST_EMPTY_MESSAGE}, rpc, Network, }, shutdown::Controller, + sync_client::SyncClient, + sync_finality::SyncFinality, telemetry::{self, MetricCounter, Metrics}, types::{ load_or_init_suri, IdentityConfig, KademliaMode, MaintenanceConfig, MultiaddrConfig, @@ -51,7 +52,8 @@ static GLOBAL: Jemalloc = Jemalloc; async fn run( cfg: RuntimeConfig, identity_cfg: IdentityConfig, - db: RocksDB, + + db: DB, shutdown: Controller, client_id: Uuid, execution_id: Uuid, @@ -99,6 +101,13 @@ async fn run( // Create sender channel for P2P event loop commands let (p2p_event_loop_sender, p2p_event_loop_receiver) = mpsc::unbounded_channel(); + let store = Store::with_config( + peer_id, + (&cfg.libp2p).into(), + #[cfg(feature = "rocksdb")] + db.inner(), + ); + let p2p_event_loop = p2p::EventLoop::new( cfg.libp2p.clone(), version, @@ -106,8 +115,7 @@ async fn run( &id_keys, cfg.is_fat_client(), shutdown.clone(), - #[cfg(feature = "kademlia-rocksdb")] - db.inner(), + store, ); spawn_in_span( @@ -338,7 +346,7 @@ async fn run( async fn run_fat( cfg: RuntimeConfig, identity_cfg: IdentityConfig, - db: RocksDB, + db: DB, shutdown: Controller, client_id: Uuid, execution_id: Uuid, @@ -384,6 +392,13 @@ async fn run_fat( // Create sender channel for P2P event loop commands let (p2p_event_loop_sender, p2p_event_loop_receiver) = mpsc::unbounded_channel(); + let store = Store::with_config( + peer_id, + (&cfg.libp2p).into(), + #[cfg(feature = "rocksdb")] + db.inner(), + ); + let p2p_event_loop = p2p::EventLoop::new( cfg.libp2p.clone(), version, @@ -391,8 +406,7 @@ async fn run_fat( &id_keys, cfg.is_fat_client(), shutdown.clone(), - #[cfg(feature = "kademlia-rocksdb")] - db.inner(), + store, ); spawn_in_span( @@ -613,7 +627,11 @@ pub async fn main() -> Result<()> { fs::remove_dir_all(&cfg.avail_path).wrap_err("Failed to remove local state directory")?; } - let db = RocksDB::open(&cfg.avail_path).expect("Avail Light could not initialize database"); + #[cfg(feature = "rocksdb")] + let db = DB::open(&cfg.avail_path).expect("Avail Light could not initialize database"); + + #[cfg(feature = "memdb")] + let db = DB::default(); let client_id = db.get(ClientIdKey).unwrap_or_else(|| { let client_id = Uuid::new_v4(); diff --git a/core/Cargo.toml b/core/Cargo.toml index c8b2dc057..718d067ee 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -40,7 +40,7 @@ num_cpus = "1.13.0" pcap = "1.1.0" rand = "0.8.4" rand_chacha = "0.3" -rocksdb = { version = "0.21.0", features = ["snappy", "multi-threaded-cf"] } +rocksdb = { version = "0.21.0", features = ["snappy", "multi-threaded-cf"], optional = true } semver = { workspace = true } serde = { workspace = true } serde_json = "1.0.68" @@ -74,6 +74,7 @@ test-case = "3.2.1" [features] network-analysis = [] -kademlia-rocksdb = [] +rocksdb = [ "dep:rocksdb" ] +memdb = [] crawl = [] -default = [] +default = [ "memdb" ] diff --git a/core/src/data.rs b/core/src/data.rs index 78dc9d6e9..525822699 100644 --- a/core/src/data.rs +++ b/core/src/data.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "rocksdb")] use self::rocks_db::RocksDBKey; use crate::{ network::rpc::Node as RpcNode, @@ -5,38 +6,42 @@ use crate::{ }; use avail_subxt::primitives::Header; use codec::{Decode, Encode}; -#[cfg(test)] +#[cfg(feature = "memdb")] use mem_db::HashMapKey; use serde::{Deserialize, Serialize}; use sp_core::ed25519; mod keys; -#[cfg(test)] -mod mem_db; -mod rocks_db; -#[cfg(test)] -pub use mem_db::MemoryDB; -pub use rocks_db::RocksDB; +#[cfg(all(feature = "rocksdb", feature = "memdb"))] +compile_error!("Features `rocksdb` and `memdb` cannot be enabled at the same time."); -/// Column family for application state -pub const APP_STATE_CF: &str = "app_state_cf"; - -/// Column family for Kademlia store -pub const KADEMLIA_STORE_CF: &str = "kademlia_store_cf"; - -#[cfg(not(test))] +#[cfg(feature = "memdb")] +mod mem_db; +#[cfg(feature = "memdb")] +pub use mem_db::MemoryDB; +#[cfg(feature = "memdb")] /// Type of the database key which we can get from the custom key. -pub trait RecordKey: Into { +pub trait RecordKey: Into { type Type: Serialize + for<'a> Deserialize<'a> + Encode + Decode; } -#[cfg(test)] +#[cfg(feature = "rocksdb")] +mod rocks_db; +#[cfg(feature = "rocksdb")] +pub use rocks_db::RocksDB; +#[cfg(feature = "rocksdb")] /// Type of the database key which we can get from the custom key. -pub trait RecordKey: Into + Into { +pub trait RecordKey: Into { type Type: Serialize + for<'a> Deserialize<'a> + Encode + Decode; } +/// Column family for application state +pub const APP_STATE_CF: &str = "app_state_cf"; + +/// Column family for Kademlia store +pub const KADEMLIA_STORE_CF: &str = "kademlia_store_cf"; + pub trait Database { /// Puts value for given key into database. /// Key is serialized into database key, value is serialized into type supported by database. diff --git a/core/src/maintenance.rs b/core/src/maintenance.rs index be2288bbb..943d76904 100644 --- a/core/src/maintenance.rs +++ b/core/src/maintenance.rs @@ -1,6 +1,6 @@ use color_eyre::{eyre::WrapErr, Result}; use std::sync::Arc; -#[cfg(not(feature = "kademlia-rocksdb"))] +#[cfg(not(feature = "rocksdb"))] use std::time::Instant; use tokio::sync::broadcast; use tracing::{debug, error, info}; @@ -18,7 +18,7 @@ pub async fn process_block( maintenance_config: MaintenanceConfig, metrics: &Arc, ) -> Result<()> { - #[cfg(not(feature = "kademlia-rocksdb"))] + #[cfg(not(feature = "rocksdb"))] if block_number % maintenance_config.pruning_interval == 0 { info!(block_number, "Pruning..."); match p2p_client.prune_expired_records(Instant::now()).await { diff --git a/core/src/network/p2p.rs b/core/src/network/p2p.rs index c5bf85d34..85dcdc57e 100644 --- a/core/src/network/p2p.rs +++ b/core/src/network/p2p.rs @@ -21,20 +21,30 @@ mod client; pub mod configuration; mod event_loop; mod kad_mem_providers; -#[cfg(not(feature = "kademlia-rocksdb"))] + +#[cfg(feature = "memdb")] mod kad_mem_store; +#[cfg(feature = "memdb")] +pub use kad_mem_store::MemoryStoreConfig; +#[cfg(feature = "memdb")] +pub type Store = kad_mem_store::MemoryStore; + +#[cfg(feature = "rocksdb")] mod kad_rocksdb_store; +#[cfg(feature = "rocksdb")] +pub use kad_rocksdb_store::ExpirationCompactionFilterFactory; +#[cfg(feature = "rocksdb")] +pub use kad_rocksdb_store::RocksDBStoreConfig; +#[cfg(feature = "rocksdb")] +pub type Store = kad_rocksdb_store::RocksDBStore; + use crate::{ - data::{Database, P2PKeypairKey, RocksDB}, + data::{Database, P2PKeypairKey}, types::SecretKey, }; pub use client::Client; pub use event_loop::EventLoop; pub use kad_mem_providers::ProvidersConfig; -#[cfg(not(feature = "kademlia-rocksdb"))] -pub use kad_mem_store::MemoryStoreConfig; -pub use kad_rocksdb_store::ExpirationCompactionFilterFactory; -pub use kad_rocksdb_store::RocksDBStoreConfig; use libp2p_allow_block_list as allow_block_list; const MINIMUM_SUPPORTED_BOOTSTRAP_VERSION: &str = "0.1.1"; @@ -120,11 +130,6 @@ pub enum QueryChannel { type Command = Box Result<(), Report> + Send>; -#[cfg(not(feature = "kademlia-rocksdb"))] -type Store = kad_mem_store::MemoryStore; -#[cfg(feature = "kademlia-rocksdb")] -type Store = kad_rocksdb_store::RocksDBStore; - // Behaviour struct is used to derive delegated Libp2p behaviour implementation #[derive(NetworkBehaviour)] #[behaviour(event_process = false)] @@ -302,7 +307,7 @@ pub fn is_multiaddr_global(address: &Multiaddr) -> bool { .any(|protocol| matches!(protocol, libp2p::multiaddr::Protocol::Ip4(ip) if is_global(ip))) } -fn get_or_init_keypair(cfg: &LibP2PConfig, db: RocksDB) -> Result { +fn get_or_init_keypair(cfg: &LibP2PConfig, db: impl Database) -> Result { if let Some(secret_key) = cfg.secret_key.as_ref() { return keypair(secret_key); }; @@ -317,7 +322,7 @@ fn get_or_init_keypair(cfg: &LibP2PConfig, db: RocksDB) -> Result Result<(identity::Keypair, PeerId)> { +pub fn identity(cfg: &LibP2PConfig, db: impl Database) -> Result<(identity::Keypair, PeerId)> { let keypair = get_or_init_keypair(cfg, db)?; let peer_id = PeerId::from(keypair.public()); Ok((keypair, peer_id)) diff --git a/core/src/network/p2p/client.rs b/core/src/network/p2p/client.rs index ea06dc4dc..d24e99a19 100644 --- a/core/src/network/p2p/client.rs +++ b/core/src/network/p2p/client.rs @@ -446,7 +446,7 @@ impl Client { pub async fn prune_expired_records(&self, now: Instant) -> Result { self.execute_sync(|response_sender| { - if cfg!(feature = "kademlia-rocksdb") { + if cfg!(feature = "rocksdb") { Box::new(move |_| { response_sender.send(Ok(0)).map_err(|e| { eyre!( diff --git a/core/src/network/p2p/configuration.rs b/core/src/network/p2p/configuration.rs index 750b44610..ba57ff267 100644 --- a/core/src/network/p2p/configuration.rs +++ b/core/src/network/p2p/configuration.rs @@ -1,4 +1,7 @@ -#[cfg(not(feature = "kademlia-rocksdb"))] +use super::ProvidersConfig; +#[cfg(feature = "rocksdb")] +use super::RocksDBStoreConfig; +#[cfg(not(feature = "rocksdb"))] use crate::network::p2p::MemoryStoreConfig; use crate::types::{duration_seconds_format, KademliaMode, MultiaddrConfig, SecretKey}; use libp2p::{kad, multiaddr::Protocol, Multiaddr}; @@ -10,8 +13,6 @@ use std::{ time::Duration, }; -use super::{ProvidersConfig, RocksDBStoreConfig}; - /// Libp2p AutoNAT configuration (see [RuntimeConfig] for details) #[derive(Clone, Serialize, Deserialize, Debug)] #[serde(default)] @@ -206,7 +207,7 @@ impl From<&LibP2PConfig> for kad::Config { } } -#[cfg(not(feature = "kademlia-rocksdb"))] +#[cfg(feature = "memdb")] impl From<&LibP2PConfig> for MemoryStoreConfig { fn from(cfg: &LibP2PConfig) -> Self { MemoryStoreConfig { @@ -220,6 +221,7 @@ impl From<&LibP2PConfig> for MemoryStoreConfig { } } +#[cfg(feature = "rocksdb")] impl From<&LibP2PConfig> for RocksDBStoreConfig { fn from(cfg: &LibP2PConfig) -> Self { RocksDBStoreConfig { diff --git a/core/src/network/p2p/event_loop.rs b/core/src/network/p2p/event_loop.rs index 3169a8a73..8a44a532a 100644 --- a/core/src/network/p2p/event_loop.rs +++ b/core/src/network/p2p/event_loop.rs @@ -29,7 +29,7 @@ use tracing::{debug, error, info, trace, warn}; use super::{ build_swarm, client::BlockStat, configuration::LibP2PConfig, Behaviour, BehaviourEvent, - Command, QueryChannel, + Command, QueryChannel, Store, }; use crate::{ network::p2p::{is_multiaddr_global, AgentVersion}, @@ -163,13 +163,7 @@ impl TryFrom for DHTKey { } } -#[cfg(not(feature = "kademlia-rocksdb"))] -type Store = super::kad_mem_store::MemoryStore; -#[cfg(feature = "kademlia-rocksdb")] -type Store = super::kad_rocksdb_store::RocksDBStore; - impl EventLoop { - #[allow(clippy::too_many_arguments)] pub async fn new( cfg: LibP2PConfig, version: &str, @@ -177,16 +171,9 @@ impl EventLoop { id_keys: &Keypair, is_fat_client: bool, shutdown: Controller, - #[cfg(feature = "kademlia-rocksdb")] db: Arc, + store: Store, ) -> Self { let bootstrap_interval = cfg.bootstrap_period; - let peer_id = id_keys.public().to_peer_id(); - let store = Store::with_config( - peer_id, - (&cfg).into(), - #[cfg(feature = "kademlia-rocksdb")] - db, - ); let swarm = build_swarm(&cfg, version, genesis_hash, id_keys, store) .await diff --git a/core/src/network/p2p/kad_mem_store.rs b/core/src/network/p2p/kad_mem_store.rs index 9ed2a76cd..b99cf9564 100644 --- a/core/src/network/p2p/kad_mem_store.rs +++ b/core/src/network/p2p/kad_mem_store.rs @@ -25,10 +25,8 @@ use libp2p::kad::{KBucketKey, ProviderRecord, Record, RecordKey}; use std::borrow::Cow; use std::collections::{hash_map, HashMap}; use std::iter; -use tracing::{instrument, Level}; - -#[cfg(not(feature = "kademlia-rocksdb"))] use tracing::trace; +use tracing::{instrument, Level}; /// In-memory implementation of a `RecordStore`. pub struct MemoryStore { @@ -63,7 +61,6 @@ impl Default for MemoryStoreConfig { } } -#[cfg(not(feature = "kademlia-rocksdb"))] impl MemoryStore { /// Creates a new `MemoryRecordStore` with a default configuration. pub fn new(local_id: PeerId) -> Self { @@ -162,7 +159,6 @@ impl RecordStore for MemoryStore { } } -#[cfg(not(feature = "kademlia-rocksdb"))] #[cfg(test)] mod tests { use std::time::{Duration, Instant}; diff --git a/core/src/network/p2p/kad_rocksdb_store.rs b/core/src/network/p2p/kad_rocksdb_store.rs index 9e5dde227..8ef9c53d4 100644 --- a/core/src/network/p2p/kad_rocksdb_store.rs +++ b/core/src/network/p2p/kad_rocksdb_store.rs @@ -12,7 +12,6 @@ use std::iter; use std::sync::Arc; use std::time::{Duration, Instant}; use tracing::{error, instrument, Level}; -#[cfg(feature = "kademlia-rocksdb")] use {rocksdb::WriteBatch, tracing::info}; #[derive(Serialize, Deserialize, Encode, Decode, Clone)] @@ -92,7 +91,6 @@ impl Default for RocksDBStoreConfig { } } -#[cfg(feature = "kademlia-rocksdb")] impl RocksDBStore { /// Creates a new `RocksDBRecordStore` with the given configuration. pub fn with_config(local_id: PeerId, config: RocksDBStoreConfig, db: Arc) -> Self { diff --git a/crawler/Cargo.toml b/crawler/Cargo.toml index 63e51798c..cdeaa617a 100644 --- a/crawler/Cargo.toml +++ b/crawler/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" repository.workspace = true [dependencies] -avail-light-core = { workspace = true, features = ["crawl", "kademlia-rocksdb"] } +avail-light-core = { workspace = true, features = ["crawl", "rocksdb"] } clap.workspace = true color-eyre.workspace = true confy.workspace = true diff --git a/crawler/src/main.rs b/crawler/src/main.rs index e6179e272..671ea788e 100644 --- a/crawler/src/main.rs +++ b/crawler/src/main.rs @@ -87,6 +87,8 @@ async fn run(config: Config, db: RocksDB, shutdown: Controller) -> Resul let (p2p_event_loop_sender, p2p_event_loop_receiver) = mpsc::unbounded_channel(); + let store = Store::with_config(peer_id, (&cfg.libp2p).into(), db.inner()); + let p2p_event_loop = p2p::EventLoop::new( config.libp2p.clone(), version, @@ -94,7 +96,7 @@ async fn run(config: Config, db: RocksDB, shutdown: Controller) -> Resul &p2p_keypair, true, shutdown.clone(), - db.inner(), + store, ); spawn_in_span(