diff --git a/bin/node/testing/src/bench.rs b/bin/node/testing/src/bench.rs index 3bc31c6e414a6..a6f65b86a0e27 100644 --- a/bin/node/testing/src/bench.rs +++ b/bin/node/testing/src/bench.rs @@ -410,8 +410,10 @@ impl BenchDb { let db_config = sc_client_db::DatabaseSettings { state_cache_size: 16*1024*1024, state_cache_child_ratio: Some((0, 100)), - pruning: PruningMode::ArchiveAll, + state_pruning: PruningMode::ArchiveAll, source: database_type.into_settings(dir.into()), + keep_blocks: sc_client_db::KeepBlocks::All, + transaction_storage: sc_client_db::TransactionStorageMode::BlockBody, }; let task_executor = TaskExecutor::new(); diff --git a/client/cli/src/config.rs b/client/cli/src/config.rs index 017d2b421683f..854e73ae78125 100644 --- a/client/cli/src/config.rs +++ b/client/cli/src/config.rs @@ -32,7 +32,7 @@ use sc_service::config::{ NodeKeyConfig, OffchainWorkerConfig, PrometheusConfig, PruningMode, Role, RpcMethods, TaskExecutor, TelemetryEndpoints, TransactionPoolOptions, WasmExecutionMethod, }; -use sc_service::{ChainSpec, TracingReceiver}; +use sc_service::{ChainSpec, TracingReceiver, KeepBlocks, TransactionStorageMode }; use std::net::SocketAddr; use std::path::PathBuf; @@ -203,6 +203,13 @@ pub trait CliConfiguration: Sized { .unwrap_or_default()) } + /// Get the database transaction storage scheme. + fn database_transaction_storage(&self) -> Result { + Ok(self.database_params() + .map(|x| x.transaction_storage()) + .unwrap_or(TransactionStorageMode::BlockBody)) + } + /// Get the database backend variant. /// /// By default this is retrieved from `DatabaseParams` if it is available. Otherwise its `None`. @@ -244,16 +251,26 @@ pub trait CliConfiguration: Sized { Ok(Default::default()) } - /// Get the pruning mode. + /// Get the state pruning mode. /// /// By default this is retrieved from `PruningMode` if it is available. Otherwise its /// `PruningMode::default()`. - fn pruning(&self, unsafe_pruning: bool, role: &Role) -> Result { + fn state_pruning(&self, unsafe_pruning: bool, role: &Role) -> Result { self.pruning_params() - .map(|x| x.pruning(unsafe_pruning, role)) + .map(|x| x.state_pruning(unsafe_pruning, role)) .unwrap_or_else(|| Ok(Default::default())) } + /// Get the block pruning mode. + /// + /// By default this is retrieved from `block_pruning` if it is available. Otherwise its + /// `KeepBlocks::All`. + fn keep_blocks(&self) -> Result { + self.pruning_params() + .map(|x| x.keep_blocks()) + .unwrap_or_else(|| Ok(KeepBlocks::All)) + } + /// Get the chain ID (string). /// /// By default this is retrieved from `SharedParams`. @@ -493,7 +510,9 @@ pub trait CliConfiguration: Sized { database: self.database_config(&config_dir, database_cache_size, database)?, state_cache_size: self.state_cache_size()?, state_cache_child_ratio: self.state_cache_child_ratio()?, - pruning: self.pruning(unsafe_pruning, &role)?, + state_pruning: self.state_pruning(unsafe_pruning, &role)?, + keep_blocks: self.keep_blocks()?, + transaction_storage: self.database_transaction_storage()?, wasm_method: self.wasm_method()?, wasm_runtime_overrides: self.wasm_runtime_overrides(), execution_strategies: self.execution_strategies(is_dev, is_validator)?, diff --git a/client/cli/src/params/database_params.rs b/client/cli/src/params/database_params.rs index 21529f65a56b0..23d2adc07f9de 100644 --- a/client/cli/src/params/database_params.rs +++ b/client/cli/src/params/database_params.rs @@ -18,6 +18,7 @@ use crate::arg_enums::Database; use structopt::StructOpt; +use sc_service::TransactionStorageMode; /// Parameters for block import. #[derive(Debug, StructOpt)] @@ -34,6 +35,15 @@ pub struct DatabaseParams { /// Limit the memory the database cache can use. #[structopt(long = "db-cache", value_name = "MiB")] pub database_cache_size: Option, + + /// Enable storage chain mode + /// + /// This changes the storage format for blocks bodys. + /// If this is enabled, each transaction is stored separately in the + /// transaction database column and is only referenced by hash + /// in the block body column. + #[structopt(long)] + pub storage_chain: bool, } impl DatabaseParams { @@ -46,4 +56,13 @@ impl DatabaseParams { pub fn database_cache_size(&self) -> Option { self.database_cache_size } + + /// Transaction storage scheme. + pub fn transaction_storage(&self) -> TransactionStorageMode { + if self.storage_chain { + TransactionStorageMode::StorageChain + } else { + TransactionStorageMode::BlockBody + } + } } diff --git a/client/cli/src/params/pruning_params.rs b/client/cli/src/params/pruning_params.rs index 80118cafd8769..467ca253531f1 100644 --- a/client/cli/src/params/pruning_params.rs +++ b/client/cli/src/params/pruning_params.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::error; -use sc_service::{PruningMode, Role}; +use sc_service::{PruningMode, Role, KeepBlocks}; use structopt::StructOpt; /// Parameters to define the pruning mode @@ -30,11 +30,16 @@ pub struct PruningParams { /// 256 blocks. #[structopt(long = "pruning", value_name = "PRUNING_MODE")] pub pruning: Option, + /// Specify the number of finalized blocks to keep in the database. + /// + /// Default is to keep all blocks. + #[structopt(long, value_name = "COUNT")] + pub keep_blocks: Option, } impl PruningParams { /// Get the pruning value from the parameters - pub fn pruning(&self, unsafe_pruning: bool, role: &Role) -> error::Result { + pub fn state_pruning(&self, unsafe_pruning: bool, role: &Role) -> error::Result { // by default we disable pruning if the node is an authority (i.e. // `ArchiveAll`), otherwise we keep state for the last 256 blocks. if the // node is an authority and pruning is enabled explicitly, then we error @@ -58,4 +63,12 @@ impl PruningParams { } }) } + + /// Get the block pruning value from the parameters + pub fn keep_blocks(&self) -> error::Result { + Ok(match self.keep_blocks { + Some(n) => KeepBlocks::Some(n), + None => KeepBlocks::All, + }) + } } diff --git a/client/db/src/lib.rs b/client/db/src/lib.rs index e3b94b03c87d8..3fc95d5cdf975 100644 --- a/client/db/src/lib.rs +++ b/client/db/src/lib.rs @@ -66,7 +66,7 @@ use codec::{Decode, Encode}; use hash_db::Prefix; use sp_trie::{MemoryDB, PrefixedMemoryDB, prefixed_key}; use sp_database::Transaction; -use sp_core::ChangesTrieConfiguration; +use sp_core::{Hasher, ChangesTrieConfiguration}; use sp_core::offchain::storage::{OffchainOverlayedChange, OffchainOverlayedChanges}; use sp_core::storage::{well_known_keys, ChildInfo}; use sp_arithmetic::traits::Saturating; @@ -264,10 +264,33 @@ pub struct DatabaseSettings { pub state_cache_size: usize, /// Ratio of cache size dedicated to child tries. pub state_cache_child_ratio: Option<(usize, usize)>, - /// Pruning mode. - pub pruning: PruningMode, + /// State pruning mode. + pub state_pruning: PruningMode, /// Where to find the database. pub source: DatabaseSettingsSrc, + /// Block pruning mode. + pub keep_blocks: KeepBlocks, + /// Block body/Transaction storage scheme. + pub transaction_storage: TransactionStorageMode, +} + +/// Block pruning settings. +#[derive(Debug, Clone, Copy)] +pub enum KeepBlocks { + /// Keep full block history. + All, + /// Keep N recent finalized blocks. + Some(u32), +} + +/// Block body storage scheme. +#[derive(Debug, Clone, Copy)] +pub enum TransactionStorageMode { + /// Store block body as an encoded list of full transactions in the BODY column + BlockBody, + /// Store a list of hashes in the BODY column and each transaction individually + /// in the TRANSACTION column. + StorageChain, } /// Where to find the database.. @@ -334,6 +357,8 @@ pub(crate) mod columns { /// Offchain workers local storage pub const OFFCHAIN: u32 = 9; pub const CACHE: u32 = 10; + /// Transactions + pub const TRANSACTION: u32 = 11; } struct PendingBlock { @@ -372,10 +397,14 @@ pub struct BlockchainDb { leaves: RwLock>>, header_metadata_cache: Arc>, header_cache: Mutex>>, + transaction_storage: TransactionStorageMode, } impl BlockchainDb { - fn new(db: Arc>) -> ClientResult { + fn new( + db: Arc>, + transaction_storage: TransactionStorageMode + ) -> ClientResult { let meta = read_meta::(&*db, columns::HEADER)?; let leaves = LeafSet::read_from_db(&*db, columns::META, meta_keys::LEAF_PREFIX)?; Ok(BlockchainDb { @@ -384,6 +413,7 @@ impl BlockchainDb { meta: Arc::new(RwLock::new(meta)), header_metadata_cache: Arc::new(HeaderMetadataCache::default()), header_cache: Default::default(), + transaction_storage, }) } @@ -418,6 +448,20 @@ impl BlockchainDb { header.digest().log(DigestItem::as_changes_trie_root) .cloned())) } + + fn extrinsic(&self, hash: &Block::Hash) -> ClientResult> { + match self.db.get(columns::TRANSACTION, hash.as_ref()) { + Some(ex) => { + match Decode::decode(&mut &ex[..]) { + Ok(ex) => Ok(Some(ex)), + Err(err) => Err(sp_blockchain::Error::Backend( + format!("Error decoding extrinsic {}: {}", hash, err) + )), + } + }, + None => Ok(None), + } + } } impl sc_client_api::blockchain::HeaderBackend for BlockchainDb { @@ -476,11 +520,30 @@ impl sc_client_api::blockchain::HeaderBackend for Blockcha impl sc_client_api::blockchain::Backend for BlockchainDb { fn body(&self, id: BlockId) -> ClientResult>> { match read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, id)? { - Some(body) => match Decode::decode(&mut &body[..]) { - Ok(body) => Ok(Some(body)), - Err(err) => return Err(sp_blockchain::Error::Backend( - format!("Error decoding body: {}", err) - )), + Some(body) => { + match self.transaction_storage { + TransactionStorageMode::BlockBody => match Decode::decode(&mut &body[..]) { + Ok(body) => Ok(Some(body)), + Err(err) => return Err(sp_blockchain::Error::Backend( + format!("Error decoding body: {}", err) + )), + }, + TransactionStorageMode::StorageChain => { + match Vec::::decode(&mut &body[..]) { + Ok(hashes) => { + let extrinsics: ClientResult> = hashes.into_iter().map( + |h| self.extrinsic(&h) .and_then(|maybe_ex| maybe_ex.ok_or_else( + || sp_blockchain::Error::Backend( + format!("Missing transaction: {}", h)))) + ).collect(); + Ok(Some(extrinsics?)) + } + Err(err) => return Err(sp_blockchain::Error::Backend( + format!("Error decoding body list: {}", err) + )), + } + } + } } None => Ok(None), } @@ -855,6 +918,8 @@ pub struct Backend { shared_cache: SharedCache, import_lock: Arc>, is_archive: bool, + keep_blocks: KeepBlocks, + transaction_storage: TransactionStorageMode, io_stats: FrozenForDuration<(kvdb::IoStats, StateUsageInfo)>, state_usage: Arc, } @@ -871,13 +936,29 @@ impl Backend { /// Create new memory-backed client backend for tests. #[cfg(any(test, feature = "test-helpers"))] pub fn new_test(keep_blocks: u32, canonicalization_delay: u64) -> Self { + Self::new_test_with_tx_storage( + keep_blocks, + canonicalization_delay, + TransactionStorageMode::BlockBody, + ) + } + + /// Create new memory-backed client backend for tests. + #[cfg(any(test, feature = "test-helpers"))] + fn new_test_with_tx_storage( + keep_blocks: u32, + canonicalization_delay: u64, + transaction_storage: TransactionStorageMode, + ) -> Self { let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS); let db = sp_database::as_database(db); let db_setting = DatabaseSettings { state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - pruning: PruningMode::keep_blocks(keep_blocks), + state_pruning: PruningMode::keep_blocks(keep_blocks), source: DatabaseSettingsSrc::Custom(db), + keep_blocks: KeepBlocks::Some(keep_blocks), + transaction_storage, }; Self::new(db_setting, canonicalization_delay).expect("failed to create test-db") @@ -888,12 +969,12 @@ impl Backend { canonicalization_delay: u64, config: &DatabaseSettings, ) -> ClientResult { - let is_archive_pruning = config.pruning.is_archive(); - let blockchain = BlockchainDb::new(db.clone())?; + let is_archive_pruning = config.state_pruning.is_archive(); + let blockchain = BlockchainDb::new(db.clone(), config.transaction_storage.clone())?; let meta = blockchain.meta.clone(); let map_e = |e: sc_state_db::Error| sp_blockchain::Error::from_state_db(e); let state_db: StateDb<_, _> = StateDb::new( - config.pruning.clone(), + config.state_pruning.clone(), !config.source.supports_ref_counting(), &StateMetaDb(&*db), ).map_err(map_e)?; @@ -933,6 +1014,8 @@ impl Backend { is_archive: is_archive_pruning, io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)), state_usage: Arc::new(StateUsageStats::new()), + keep_blocks: config.keep_blocks.clone(), + transaction_storage: config.transaction_storage.clone(), }) } @@ -1140,7 +1223,21 @@ impl Backend { transaction.set_from_vec(columns::HEADER, &lookup_key, pending_block.header.encode()); if let Some(body) = &pending_block.body { - transaction.set_from_vec(columns::BODY, &lookup_key, body.encode()); + match self.transaction_storage { + TransactionStorageMode::BlockBody => { + transaction.set_from_vec(columns::BODY, &lookup_key, body.encode()); + }, + TransactionStorageMode::StorageChain => { + let mut hashes = Vec::with_capacity(body.len()); + for extrinsic in body { + let extrinsic = extrinsic.encode(); + let hash = HashFor::::hash(&extrinsic); + transaction.set(columns::TRANSACTION, &hash.as_ref(), &extrinsic); + hashes.push(hash); + } + transaction.set_from_vec(columns::BODY, &lookup_key, hashes.encode()); + }, + } } if let Some(justification) = pending_block.justification { transaction.set_from_vec(columns::JUSTIFICATION, &lookup_key, justification.encode()); @@ -1391,6 +1488,7 @@ impl Backend { } } + self.prune_blocks(transaction, f_num)?; let new_displaced = self.blockchain.leaves.write().finalize_height(f_num); match displaced { x @ &mut None => *x = Some(new_displaced), @@ -1399,6 +1497,50 @@ impl Backend { Ok(()) } + + fn prune_blocks( + &self, + transaction: &mut Transaction, + finalized: NumberFor, + ) -> ClientResult<()> { + if let KeepBlocks::Some(keep_blocks) = self.keep_blocks { + // Always keep the last finalized block + let keep = std::cmp::max(keep_blocks, 1); + if finalized < keep.into() { + return Ok(()) + } + let number = finalized.saturating_sub(keep.into()); + match read_db(&*self.storage.db, columns::KEY_LOOKUP, columns::BODY, BlockId::::number(number))? { + Some(body) => { + debug!(target: "db", "Removing block #{}", number); + utils::remove_from_db( + transaction, + &*self.storage.db, + columns::KEY_LOOKUP, + columns::BODY, + BlockId::::number(number), + )?; + match self.transaction_storage { + TransactionStorageMode::BlockBody => {}, + TransactionStorageMode::StorageChain => { + match Vec::::decode(&mut &body[..]) { + Ok(hashes) => { + for h in hashes { + transaction.remove(columns::TRANSACTION, h.as_ref()); + } + } + Err(err) => return Err(sp_blockchain::Error::Backend( + format!("Error decoding body list: {}", err) + )), + } + } + } + } + None => return Ok(()), + } + } + Ok(()) + } } fn apply_state_commit(transaction: &mut Transaction, commit: sc_state_db::CommitSet>) { @@ -1804,6 +1946,17 @@ pub(crate) mod tests { parent_hash: H256, changes: Option, Vec)>>, extrinsics_root: H256, + ) -> H256 { + insert_block(backend, number, parent_hash, changes, extrinsics_root, Vec::new()) + } + + pub fn insert_block( + backend: &Backend, + number: u64, + parent_hash: H256, + changes: Option, Vec)>>, + extrinsics_root: H256, + body: Vec>, ) -> H256 { use sp_runtime::testing::Digest; @@ -1830,7 +1983,7 @@ pub(crate) mod tests { }; let mut op = backend.begin_operation().unwrap(); backend.begin_state_operation(&mut op, block_id).unwrap(); - op.set_block_data(header, Some(Vec::new()), None, NewBlockState::Best).unwrap(); + op.set_block_data(header, Some(body), None, NewBlockState::Best).unwrap(); op.update_changes_trie((changes_trie_update, ChangesTrieCacheAction::Clear)).unwrap(); backend.commit_operation(op).unwrap(); @@ -1882,8 +2035,10 @@ pub(crate) mod tests { let backend = Backend::::new(DatabaseSettings { state_cache_size: 16777216, state_cache_child_ratio: Some((50, 100)), - pruning: PruningMode::keep_blocks(1), + state_pruning: PruningMode::keep_blocks(1), source: DatabaseSettingsSrc::Custom(backing), + keep_blocks: KeepBlocks::All, + transaction_storage: TransactionStorageMode::BlockBody, }, 0).unwrap(); assert_eq!(backend.blockchain().info().best_number, 9); for i in 0..10 { @@ -2427,4 +2582,33 @@ pub(crate) mod tests { assert_eq!(cht_root_1, cht_root_2); assert_eq!(cht_root_2, cht_root_3); } + + #[test] + fn prune_blocks_on_finalize() { + for storage in &[TransactionStorageMode::BlockBody, TransactionStorageMode::StorageChain] { + let backend = Backend::::new_test_with_tx_storage(2, 0, *storage); + let mut blocks = Vec::new(); + let mut prev_hash = Default::default(); + for i in 0 .. 5 { + let hash = insert_block(&backend, i, prev_hash, None, Default::default(), vec![i.into()]); + blocks.push(hash); + prev_hash = hash; + } + + { + let mut op = backend.begin_operation().unwrap(); + backend.begin_state_operation(&mut op, BlockId::Hash(blocks[4])).unwrap(); + for i in 1 .. 5 { + op.mark_finalized(BlockId::Hash(blocks[i]), None).unwrap(); + } + backend.commit_operation(op).unwrap(); + } + let bc = backend.blockchain(); + assert_eq!(None, bc.body(BlockId::hash(blocks[0])).unwrap()); + assert_eq!(None, bc.body(BlockId::hash(blocks[1])).unwrap()); + assert_eq!(None, bc.body(BlockId::hash(blocks[2])).unwrap()); + assert_eq!(Some(vec![3.into()]), bc.body(BlockId::hash(blocks[3])).unwrap()); + assert_eq!(Some(vec![4.into()]), bc.body(BlockId::hash(blocks[4])).unwrap()); + } + } } diff --git a/client/db/src/upgrade.rs b/client/db/src/upgrade.rs index e87b11b69660c..b6e49edba1978 100644 --- a/client/db/src/upgrade.rs +++ b/client/db/src/upgrade.rs @@ -24,21 +24,26 @@ use std::path::{Path, PathBuf}; use sp_runtime::traits::Block as BlockT; use crate::utils::DatabaseType; +use kvdb_rocksdb::{Database, DatabaseConfig}; /// Version file name. const VERSION_FILE_NAME: &'static str = "db_version"; /// Current db version. -const CURRENT_VERSION: u32 = 1; +const CURRENT_VERSION: u32 = 2; + +/// Number of columns in v1. +const V1_NUM_COLUMNS: u32 = 11; /// Upgrade database to current version. -pub fn upgrade_db(db_path: &Path, _db_type: DatabaseType) -> sp_blockchain::Result<()> { +pub fn upgrade_db(db_path: &Path, db_type: DatabaseType) -> sp_blockchain::Result<()> { let is_empty = db_path.read_dir().map_or(true, |mut d| d.next().is_none()); if !is_empty { let db_version = current_version(db_path)?; match db_version { 0 => Err(sp_blockchain::Error::Backend(format!("Unsupported database version: {}", db_version)))?, - 1 => (), + 1 => migrate_1_to_2::(db_path, db_type)?, + CURRENT_VERSION => (), _ => Err(sp_blockchain::Error::Backend(format!("Future database version: {}", db_version)))?, } } @@ -46,6 +51,16 @@ pub fn upgrade_db(db_path: &Path, _db_type: DatabaseType) -> sp_b update_version(db_path) } +/// Migration from version1 to version2: +/// 1) the number of columns has changed from 11 to 12; +/// 2) transactions column is added; +fn migrate_1_to_2(db_path: &Path, _db_type: DatabaseType) -> sp_blockchain::Result<()> { + let db_path = db_path.to_str() + .ok_or_else(|| sp_blockchain::Error::Backend("Invalid database path".into()))?; + let db_cfg = DatabaseConfig::with_columns(V1_NUM_COLUMNS); + let db = Database::open(&db_cfg, db_path).map_err(db_err)?; + db.add_column().map_err(db_err) +} /// Reads current database version from the file at given path. /// If the file does not exist returns 0. @@ -87,7 +102,7 @@ fn version_file_path(path: &Path) -> PathBuf { #[cfg(test)] mod tests { use sc_state_db::PruningMode; - use crate::{DatabaseSettings, DatabaseSettingsSrc}; + use crate::{DatabaseSettings, DatabaseSettingsSrc, KeepBlocks, TransactionStorageMode}; use crate::tests::Block; use super::*; @@ -103,8 +118,10 @@ mod tests { crate::utils::open_database::(&DatabaseSettings { state_cache_size: 0, state_cache_child_ratio: None, - pruning: PruningMode::ArchiveAll, + state_pruning: PruningMode::ArchiveAll, source: DatabaseSettingsSrc::RocksDb { path: db_path.to_owned(), cache_size: 128 }, + keep_blocks: KeepBlocks::All, + transaction_storage: TransactionStorageMode::BlockBody, }, DatabaseType::Full).map(|_| ()) } @@ -122,4 +139,15 @@ mod tests { open_database(db_dir.path()).unwrap(); assert_eq!(current_version(db_dir.path()).unwrap(), CURRENT_VERSION); } + + #[test] + fn upgrade_from_1_to_2_works() { + for version_from_file in &[None, Some(1)] { + let db_dir = tempfile::TempDir::new().unwrap(); + let db_path = db_dir.path(); + create_db(db_path, *version_from_file); + open_database(db_path).unwrap(); + assert_eq!(current_version(db_path).unwrap(), CURRENT_VERSION); + } + } } diff --git a/client/db/src/utils.rs b/client/db/src/utils.rs index dfc1e945b3a4c..baea6aab69fa0 100644 --- a/client/db/src/utils.rs +++ b/client/db/src/utils.rs @@ -37,7 +37,7 @@ use crate::{DatabaseSettings, DatabaseSettingsSrc, Database, DbHash}; /// Number of columns in the db. Must be the same for both full && light dbs. /// Otherwise RocksDb will fail to open database && check its type. #[cfg(any(feature = "with-kvdb-rocksdb", feature = "with-parity-db", feature = "test-helpers", test))] -pub const NUM_COLUMNS: u32 = 11; +pub const NUM_COLUMNS: u32 = 12; /// Meta column. The set of keys in the column is shared by full && light storages. pub const COLUMN_META: u32 = 0; @@ -327,6 +327,23 @@ pub fn read_db( }) } +/// Remove database column entry for the given block. +pub fn remove_from_db( + transaction: &mut Transaction, + db: &dyn Database, + col_index: u32, + col: u32, + id: BlockId, +) -> sp_blockchain::Result<()> +where + Block: BlockT, +{ + block_id_to_lookup_key(db, col_index, id).and_then(|key| match key { + Some(key) => Ok(transaction.remove(col, key.as_ref())), + None => Ok(()), + }) +} + /// Read a header from the database. pub fn read_header( db: &dyn Database, diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index e3476e625ca55..bac5191f0ccae 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -326,8 +326,10 @@ pub fn new_full_parts( state_cache_size: config.state_cache_size, state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), - pruning: config.pruning.clone(), + state_pruning: config.state_pruning.clone(), source: config.database.clone(), + keep_blocks: config.keep_blocks.clone(), + transaction_storage: config.transaction_storage.clone(), }; let extensions = sc_client_api::execution_extensions::ExecutionExtensions::new( @@ -384,8 +386,10 @@ pub fn new_light_parts( state_cache_size: config.state_cache_size, state_cache_child_ratio: config.state_cache_child_ratio.map(|v| (v, 100)), - pruning: config.pruning.clone(), + state_pruning: config.state_pruning.clone(), source: config.database.clone(), + keep_blocks: config.keep_blocks.clone(), + transaction_storage: config.transaction_storage.clone(), }; sc_client_db::light::LightStorage::new(db_settings)? }; diff --git a/client/service/src/config.rs b/client/service/src/config.rs index e253ed97ff3a5..5197aa655b249 100644 --- a/client/service/src/config.rs +++ b/client/service/src/config.rs @@ -18,7 +18,10 @@ //! Service configuration. -pub use sc_client_db::{Database, PruningMode, DatabaseSettingsSrc as DatabaseConfig}; +pub use sc_client_db::{ + Database, PruningMode, DatabaseSettingsSrc as DatabaseConfig, + KeepBlocks, TransactionStorageMode +}; pub use sc_network::Multiaddr; pub use sc_network::config::{ExtTransport, MultiaddrWithPeerId, NetworkConfiguration, Role, NodeKeyConfig}; pub use sc_executor::WasmExecutionMethod; @@ -58,8 +61,12 @@ pub struct Configuration { pub state_cache_size: usize, /// Size in percent of cache size dedicated to child tries pub state_cache_child_ratio: Option, - /// Pruning settings. - pub pruning: PruningMode, + /// State pruning settings. + pub state_pruning: PruningMode, + /// Number of blocks to keep in the db. + pub keep_blocks: KeepBlocks, + /// Transaction storage scheme. + pub transaction_storage: TransactionStorageMode, /// Chain configuration. pub chain_spec: Box, /// Wasm execution method. diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 8b26b1a75ddf8..df1cd47db0f7e 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -60,6 +60,7 @@ pub use self::builder::{ }; pub use config::{ BasePath, Configuration, DatabaseConfig, PruningMode, Role, RpcMethods, TaskExecutor, TaskType, + KeepBlocks, TransactionStorageMode, }; pub use sc_chain_spec::{ ChainSpec, GenericChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension, diff --git a/client/service/test/src/client/mod.rs b/client/service/test/src/client/mod.rs index 6bb09981107a0..9712e84e60496 100644 --- a/client/service/test/src/client/mod.rs +++ b/client/service/test/src/client/mod.rs @@ -31,7 +31,9 @@ use substrate_test_runtime_client::{ use sc_client_api::{ StorageProvider, BlockBackend, in_mem, BlockchainEvents, }; -use sc_client_db::{Backend, DatabaseSettings, DatabaseSettingsSrc, PruningMode}; +use sc_client_db::{ + Backend, DatabaseSettings, DatabaseSettingsSrc, PruningMode, KeepBlocks, TransactionStorageMode +}; use sc_block_builder::BlockBuilderProvider; use sc_service::client::{self, Client, LocalCallExecutor, new_in_mem}; use sp_runtime::traits::{ @@ -1275,7 +1277,9 @@ fn doesnt_import_blocks_that_revert_finality() { DatabaseSettings { state_cache_size: 1 << 20, state_cache_child_ratio: None, - pruning: PruningMode::ArchiveAll, + state_pruning: PruningMode::ArchiveAll, + keep_blocks: KeepBlocks::All, + transaction_storage: TransactionStorageMode::BlockBody, source: DatabaseSettingsSrc::RocksDb { path: tmp.path().into(), cache_size: 1024, @@ -1476,7 +1480,9 @@ fn returns_status_for_pruned_blocks() { DatabaseSettings { state_cache_size: 1 << 20, state_cache_child_ratio: None, - pruning: PruningMode::keep_blocks(1), + state_pruning: PruningMode::keep_blocks(1), + keep_blocks: KeepBlocks::All, + transaction_storage: TransactionStorageMode::BlockBody, source: DatabaseSettingsSrc::RocksDb { path: tmp.path().into(), cache_size: 1024, diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index c30246e91ca05..bd4f325908b0a 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -35,6 +35,7 @@ use sc_service::{ GenericChainSpec, ChainSpecExtension, Configuration, + KeepBlocks, TransactionStorageMode, config::{BasePath, DatabaseConfig, KeystoreConfig}, RuntimeGenesis, Role, @@ -250,7 +251,9 @@ fn node_config