From b5c59963e19bb878f451829f86d0f36514af872a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksandar=20Terenti=C4=87?= Date: Thu, 15 Aug 2024 17:08:24 +0200 Subject: [PATCH] Enable memdb instead of rocks with feature flags --- .github/workflows/default.yml | 3 +- Cargo.toml | 2 +- client/Cargo.toml | 4 +-- client/src/main.rs | 36 +++++++++++++++-------- compatibility-tests/Cargo.toml | 4 +++ compatibility-tests/src/main.rs | 17 +++++++---- core/Cargo.toml | 4 +-- core/src/data.rs | 28 +++++------------- core/src/data/mem_db.rs | 5 ++++ core/src/data/rocks_db.rs | 5 ++++ core/src/maintenance.rs | 4 +-- core/src/network/p2p.rs | 32 ++++++++++++-------- core/src/network/p2p/client.rs | 2 +- core/src/network/p2p/configuration.rs | 10 ++++--- core/src/network/p2p/event_loop.rs | 17 ++--------- core/src/network/p2p/kad_mem_store.rs | 6 +--- core/src/network/p2p/kad_rocksdb_store.rs | 2 -- crawler/Cargo.toml | 6 +++- crawler/src/main.rs | 27 +++++++++++++---- 19 files changed, 121 insertions(+), 93 deletions(-) diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index b1b07ae96..db41eee31 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -62,8 +62,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - # TODO: Replace with "--benches --tests --all-features" when CI is fixed for other features - args: --workspace --benches --tests --features "default,crawl,kademlia-rocksdb" + args: --workspace --benches --tests --no-default-features env: RUSTFLAGS: "-C instrument-coverage" LLVM_PROFILE_FILE: "profile-%p-%m.profraw" diff --git a/Cargo.toml b/Cargo.toml index f4055cf22..d23a8aaaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,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 = { path = "./core" } anyhow = "1.0.71" async-std = { version = "1.12.0", features = ["attributes"] } diff --git a/client/Cargo.toml b/client/Cargo.toml index 0a244989c..caf711fdc 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -33,5 +33,5 @@ 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"] +default = ["rocksdb"] diff --git a/client/src/main.rs b/client/src/main.rs index 0659ac729..84c204d42 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -2,21 +2,22 @@ use crate::cli::CliOpts; use avail_core::AppId; +#[cfg(not(feature = "rocksdb"))] +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, MaintenanceConfig, MultiaddrConfig, RuntimeConfig, @@ -50,7 +51,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, @@ -92,6 +94,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, @@ -99,8 +108,7 @@ async fn run( &id_keys, false, shutdown.clone(), - #[cfg(feature = "kademlia-rocksdb")] - db.inner(), + store, ); spawn_in_span( @@ -409,7 +417,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(not(feature = "rocksdb"))] + let db = DB::default(); let client_id = db.get(ClientIdKey).unwrap_or_else(|| { let client_id = Uuid::new_v4(); diff --git a/compatibility-tests/Cargo.toml b/compatibility-tests/Cargo.toml index d4c7dc9a8..c4a8eb716 100644 --- a/compatibility-tests/Cargo.toml +++ b/compatibility-tests/Cargo.toml @@ -12,3 +12,7 @@ kate-recovery = { workspace = true } clap = { workspace = true } color-eyre = { workspace = true } tokio = { workspace = true } + +[features] +rocksdb = ["avail-light-core/rocksdb"] +default = ["rocksdb"] diff --git a/compatibility-tests/src/main.rs b/compatibility-tests/src/main.rs index efb08f608..eeb13a799 100644 --- a/compatibility-tests/src/main.rs +++ b/compatibility-tests/src/main.rs @@ -1,7 +1,8 @@ -use std::time::Duration; - +#[cfg(not(feature = "rocksdb"))] +use avail_light_core::data::MemoryDB as DB; +#[cfg(feature = "rocksdb")] +use avail_light_core::data::RocksDB as DB; use avail_light_core::{ - data::RocksDB, network::rpc::{ self, configuration::{ExponentialConfig, RPCConfig, RetryConfig}, @@ -9,8 +10,9 @@ use avail_light_core::{ shutdown::Controller, }; use clap::Parser; -use color_eyre::{eyre::Context, Result}; +use color_eyre::Result; use kate_recovery::matrix::Position; +use std::time::Duration; #[derive(Parser)] struct CommandArgs { @@ -25,8 +27,11 @@ async fn main() -> Result<()> { let command_args = CommandArgs::parse(); println!("Using URL: {}", command_args.url); println!("Using Path: {}", command_args.avail_path); - let db = RocksDB::open(&command_args.avail_path) - .wrap_err("API Compatibility Test could not initialize database")?; + + #[cfg(not(feature = "rocksdb"))] + let db = DB::default(); + #[cfg(feature = "rocksdb")] + let db = DB::open(&command_args.avail_path)?; let rpc_cfg = RPCConfig { full_node_ws: vec![command_args.url], diff --git a/core/Cargo.toml b/core/Cargo.toml index b16935dc4..621fa6314 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -41,7 +41,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" @@ -75,6 +75,6 @@ test-case = "3.2.1" [features] network-analysis = [] -kademlia-rocksdb = [] +rocksdb = ["dep:rocksdb"] crawl = [] default = [] diff --git a/core/src/data.rs b/core/src/data.rs index 78dc9d6e9..51299b1db 100644 --- a/core/src/data.rs +++ b/core/src/data.rs @@ -1,23 +1,23 @@ -use self::rocks_db::RocksDBKey; use crate::{ network::rpc::Node as RpcNode, types::{BlockRange, Uuid}, }; use avail_subxt::primitives::Header; use codec::{Decode, Encode}; -#[cfg(test)] -use mem_db::HashMapKey; use serde::{Deserialize, Serialize}; use sp_core::ed25519; mod keys; -#[cfg(test)] + +#[cfg(not(feature = "rocksdb"))] mod mem_db; -mod rocks_db; +#[cfg(not(feature = "rocksdb"))] +pub use mem_db::*; -#[cfg(test)] -pub use mem_db::MemoryDB; -pub use rocks_db::RocksDB; +#[cfg(feature = "rocksdb")] +mod rocks_db; +#[cfg(feature = "rocksdb")] +pub use rocks_db::*; /// Column family for application state pub const APP_STATE_CF: &str = "app_state_cf"; @@ -25,18 +25,6 @@ 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))] -/// Type of the database key which we can get from the custom key. -pub trait RecordKey: Into { - type Type: Serialize + for<'a> Deserialize<'a> + Encode + Decode; -} - -#[cfg(test)] -/// Type of the database key which we can get from the custom key. -pub trait RecordKey: Into + Into { - type Type: Serialize + for<'a> Deserialize<'a> + Encode + Decode; -} - 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/data/mem_db.rs b/core/src/data/mem_db.rs index 83aaa3396..2b674f2fd 100644 --- a/core/src/data/mem_db.rs +++ b/core/src/data/mem_db.rs @@ -13,6 +13,11 @@ pub struct MemoryDB { #[derive(Eq, Hash, PartialEq)] pub struct HashMapKey(pub String); +/// Type of the database key which we can get from the custom key. +pub trait RecordKey: Into { + type Type: Serialize + for<'a> Deserialize<'a> + Encode + Decode; +} + impl Default for MemoryDB { fn default() -> Self { MemoryDB { diff --git a/core/src/data/rocks_db.rs b/core/src/data/rocks_db.rs index e18cb101f..7edb22e08 100644 --- a/core/src/data/rocks_db.rs +++ b/core/src/data/rocks_db.rs @@ -16,6 +16,11 @@ pub struct RocksDB { #[derive(Eq, Hash, PartialEq)] pub struct RocksDBKey(Option<&'static str>, Vec); +/// Type of the database key which we can get from the custom key. +pub trait RecordKey: Into { + type Type: Serialize + for<'a> Deserialize<'a> + Encode + Decode; +} + impl RocksDBKey { fn app_state(key: &str) -> Self { Self(Some(APP_STATE_CF), key.as_bytes().to_vec()) 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 466476c9a..57cd2b34f 100644 --- a/core/src/network/p2p.rs +++ b/core/src/network/p2p.rs @@ -23,20 +23,31 @@ mod client; pub mod configuration; mod event_loop; mod kad_mem_providers; -#[cfg(not(feature = "kademlia-rocksdb"))] + +#[cfg(not(feature = "rocksdb"))] mod kad_mem_store; +#[cfg(feature = "rocksdb")] mod kad_rocksdb_store; + +#[cfg(not(feature = "rocksdb"))] +pub use kad_mem_store::MemoryStoreConfig; +#[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; +#[cfg(not(feature = "rocksdb"))] +pub type Store = kad_mem_store::MemoryStore; + 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"; @@ -122,11 +133,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)] @@ -310,7 +316,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); }; @@ -325,7 +331,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 a822b4bf8..23eff39d7 100644 --- a/core/src/network/p2p/client.rs +++ b/core/src/network/p2p/client.rs @@ -449,7 +449,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 10599c237..e5f66876f 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)] @@ -216,7 +217,7 @@ impl From<&LibP2PConfig> for kad::Config { } } -#[cfg(not(feature = "kademlia-rocksdb"))] +#[cfg(not(feature = "rocksdb"))] impl From<&LibP2PConfig> for MemoryStoreConfig { fn from(cfg: &LibP2PConfig) -> Self { MemoryStoreConfig { @@ -230,6 +231,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..b406b2626 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"] } clap.workspace = true color-eyre.workspace = true confy.workspace = true @@ -14,3 +14,7 @@ kate-recovery.workspace = true serde.workspace = true tokio.workspace = true tracing.workspace = true + +[features] +rocksdb = ["avail-light-core/rocksdb"] +default = ["rocksdb"] diff --git a/crawler/src/main.rs b/crawler/src/main.rs index 2f3809bd4..4e5da221a 100644 --- a/crawler/src/main.rs +++ b/crawler/src/main.rs @@ -1,7 +1,14 @@ +#[cfg(not(feature = "rocksdb"))] +use avail_light_core::data::MemoryDB as DB; +#[cfg(feature = "rocksdb")] +use avail_light_core::data::RocksDB as DB; use avail_light_core::{ crawl_client, - data::{Database, LatestHeaderKey, RocksDB}, - network::{p2p, rpc, Network}, + data::{Database, LatestHeaderKey}, + network::{ + p2p::{self, Store}, + rpc, Network, + }, shutdown::Controller, telemetry::{otlp, MetricCounter, Metrics}, types::{BlockVerified, KademliaMode}, @@ -50,14 +57,17 @@ pub async fn main() -> Result<()> { clean_db_state(&config.avail_path)?; }; - let db = RocksDB::open(&config.avail_path)?; + #[cfg(not(feature = "rocksdb"))] + let db = DB::default(); + #[cfg(feature = "rocksdb")] + let db = DB::open(&config.avail_path)?; let _ = spawn_in_span(run(config, db, shutdown)).await?; Ok(()) } -async fn run(config: Config, db: RocksDB, shutdown: Controller) -> Result<()> { +async fn run(config: Config, db: DB, shutdown: Controller) -> Result<()> { let version = clap::crate_version!(); info!("Running Avail Light Client Crawler v{version}"); info!("Using configuration: {config:?}"); @@ -87,6 +97,13 @@ 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( + p2p_peer_id, + (&config.libp2p).into(), + #[cfg(feature = "rocksdb")] + db.inner(), + ); + let p2p_event_loop = p2p::EventLoop::new( config.libp2p.clone(), version, @@ -94,7 +111,7 @@ async fn run(config: Config, db: RocksDB, shutdown: Controller) -> Resul &p2p_keypair, true, shutdown.clone(), - db.inner(), + store, ); spawn_in_span(