Skip to main content

sc_client_db/
lib.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Client backend that is backed by a database.
20//!
21//! # Canonicality vs. Finality
22//!
23//! Finality indicates that a block will not be reverted, according to the consensus algorithm,
24//! while canonicality indicates that the block may be reverted, but we will be unable to do so,
25//! having discarded heavy state that will allow a chain reorganization.
26//!
27//! Finality implies canonicality but not vice-versa.
28
29#![warn(missing_docs)]
30
31pub mod offchain;
32
33pub mod bench;
34
35mod children;
36mod parity_db;
37mod pinned_blocks_cache;
38mod record_stats_state;
39mod stats;
40#[cfg(any(feature = "rocksdb", test))]
41mod upgrade;
42mod utils;
43
44use linked_hash_map::LinkedHashMap;
45use log::{debug, trace, warn};
46use parking_lot::{Mutex, RwLock};
47use prometheus_endpoint::Registry;
48use std::{
49	collections::{HashMap, HashSet},
50	io,
51	path::{Path, PathBuf},
52	sync::Arc,
53};
54
55use crate::{
56	pinned_blocks_cache::PinnedBlocksCache,
57	record_stats_state::RecordStatsState,
58	stats::StateUsageStats,
59	utils::{meta_keys, read_db, read_meta, remove_from_db, DatabaseType, Meta},
60};
61use codec::{Decode, Encode};
62use hash_db::Prefix;
63use sc_client_api::{
64	backend::NewBlockState,
65	blockchain::{BlockGap, BlockGapType},
66	leaves::{FinalizationOutcome, LeafSet},
67	utils::is_descendent_of,
68	IoInfo, MemoryInfo, MemorySize, TrieCacheContext, UsageInfo,
69};
70use sc_state_db::{IsPruned, LastCanonicalized, StateDb};
71use sp_arithmetic::traits::Saturating;
72use sp_blockchain::{
73	Backend as _, CachedHeaderMetadata, DisplacedLeavesAfterFinalization, Error as ClientError,
74	HeaderBackend, HeaderMetadata, HeaderMetadataCache, Result as ClientResult,
75};
76use sp_core::{
77	offchain::OffchainOverlayedChange,
78	storage::{well_known_keys, ChildInfo},
79};
80use sp_database::Transaction;
81use sp_runtime::{
82	generic::BlockId,
83	traits::{
84		Block as BlockT, Hash, HashingFor, Header as HeaderT, NumberFor, One, SaturatedConversion,
85		Zero,
86	},
87	Justification, Justifications, StateVersion, Storage,
88};
89use sp_state_machine::{
90	backend::{AsTrieBackend, Backend as StateBackend},
91	BackendTransaction, ChildStorageCollection, DBValue, IndexOperation, IterArgs,
92	OffchainChangesCollection, StateMachineStats, StorageCollection, StorageIterator, StorageKey,
93	StorageValue, UsageInfo as StateUsageInfo,
94};
95use sp_trie::{cache::SharedTrieCache, prefixed_key, MemoryDB, MerkleValue, PrefixedMemoryDB};
96use utils::BLOCK_GAP_CURRENT_VERSION;
97
98// Re-export the Database trait so that one can pass an implementation of it.
99pub use sc_state_db::PruningMode;
100pub use sp_database::Database;
101
102pub use bench::BenchmarkingState;
103
104const CACHE_HEADERS: usize = 8;
105
106/// DB-backed patricia trie state, transaction type is an overlay of changes to commit.
107pub type DbState<H> = sp_state_machine::TrieBackend<Arc<dyn sp_state_machine::Storage<H>>, H>;
108
109/// Builder for [`DbState`].
110pub type DbStateBuilder<Hasher> =
111	sp_state_machine::TrieBackendBuilder<Arc<dyn sp_state_machine::Storage<Hasher>>, Hasher>;
112
113/// Length of a [`DbHash`].
114const DB_HASH_LEN: usize = 32;
115
116/// Hash type that this backend uses for the database.
117pub type DbHash = sp_core::H256;
118
119/// An extrinsic entry in the database.
120#[derive(Debug, Encode, Decode)]
121enum DbExtrinsic<B: BlockT> {
122	/// Extrinsic that contains indexed data.
123	Indexed {
124		/// Hash of the indexed part.
125		hash: DbHash,
126		/// Extrinsic header.
127		header: Vec<u8>,
128	},
129	/// Complete extrinsic data.
130	Full(B::Extrinsic),
131}
132
133/// A reference tracking state.
134///
135/// It makes sure that the hash we are using stays pinned in storage
136/// until this structure is dropped.
137pub struct RefTrackingState<Block: BlockT> {
138	state: DbState<HashingFor<Block>>,
139	storage: Arc<StorageDb<Block>>,
140	parent_hash: Option<Block::Hash>,
141}
142
143impl<B: BlockT> RefTrackingState<B> {
144	fn new(
145		state: DbState<HashingFor<B>>,
146		storage: Arc<StorageDb<B>>,
147		parent_hash: Option<B::Hash>,
148	) -> Self {
149		RefTrackingState { state, parent_hash, storage }
150	}
151}
152
153impl<B: BlockT> Drop for RefTrackingState<B> {
154	fn drop(&mut self) {
155		if let Some(hash) = &self.parent_hash {
156			self.storage.state_db.unpin(hash);
157		}
158	}
159}
160
161impl<Block: BlockT> std::fmt::Debug for RefTrackingState<Block> {
162	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163		write!(f, "Block {:?}", self.parent_hash)
164	}
165}
166
167/// A raw iterator over the `RefTrackingState`.
168pub struct RawIter<B: BlockT> {
169	inner: <DbState<HashingFor<B>> as StateBackend<HashingFor<B>>>::RawIter,
170}
171
172impl<B: BlockT> StorageIterator<HashingFor<B>> for RawIter<B> {
173	type Backend = RefTrackingState<B>;
174	type Error = <DbState<HashingFor<B>> as StateBackend<HashingFor<B>>>::Error;
175
176	fn next_key(&mut self, backend: &Self::Backend) -> Option<Result<StorageKey, Self::Error>> {
177		self.inner.next_key(&backend.state)
178	}
179
180	fn next_pair(
181		&mut self,
182		backend: &Self::Backend,
183	) -> Option<Result<(StorageKey, StorageValue), Self::Error>> {
184		self.inner.next_pair(&backend.state)
185	}
186
187	fn was_complete(&self) -> bool {
188		self.inner.was_complete()
189	}
190}
191
192impl<B: BlockT> StateBackend<HashingFor<B>> for RefTrackingState<B> {
193	type Error = <DbState<HashingFor<B>> as StateBackend<HashingFor<B>>>::Error;
194	type TrieBackendStorage =
195		<DbState<HashingFor<B>> as StateBackend<HashingFor<B>>>::TrieBackendStorage;
196	type RawIter = RawIter<B>;
197
198	fn storage(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
199		self.state.storage(key)
200	}
201
202	fn storage_hash(&self, key: &[u8]) -> Result<Option<B::Hash>, Self::Error> {
203		self.state.storage_hash(key)
204	}
205
206	fn child_storage(
207		&self,
208		child_info: &ChildInfo,
209		key: &[u8],
210	) -> Result<Option<Vec<u8>>, Self::Error> {
211		self.state.child_storage(child_info, key)
212	}
213
214	fn child_storage_hash(
215		&self,
216		child_info: &ChildInfo,
217		key: &[u8],
218	) -> Result<Option<B::Hash>, Self::Error> {
219		self.state.child_storage_hash(child_info, key)
220	}
221
222	fn closest_merkle_value(
223		&self,
224		key: &[u8],
225	) -> Result<Option<MerkleValue<B::Hash>>, Self::Error> {
226		self.state.closest_merkle_value(key)
227	}
228
229	fn child_closest_merkle_value(
230		&self,
231		child_info: &ChildInfo,
232		key: &[u8],
233	) -> Result<Option<MerkleValue<B::Hash>>, Self::Error> {
234		self.state.child_closest_merkle_value(child_info, key)
235	}
236
237	fn exists_storage(&self, key: &[u8]) -> Result<bool, Self::Error> {
238		self.state.exists_storage(key)
239	}
240
241	fn exists_child_storage(
242		&self,
243		child_info: &ChildInfo,
244		key: &[u8],
245	) -> Result<bool, Self::Error> {
246		self.state.exists_child_storage(child_info, key)
247	}
248
249	fn next_storage_key(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
250		self.state.next_storage_key(key)
251	}
252
253	fn next_child_storage_key(
254		&self,
255		child_info: &ChildInfo,
256		key: &[u8],
257	) -> Result<Option<Vec<u8>>, Self::Error> {
258		self.state.next_child_storage_key(child_info, key)
259	}
260
261	fn storage_root<'a>(
262		&self,
263		delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
264		state_version: StateVersion,
265	) -> (B::Hash, BackendTransaction<HashingFor<B>>) {
266		self.state.storage_root(delta, state_version)
267	}
268
269	fn child_storage_root<'a>(
270		&self,
271		child_info: &ChildInfo,
272		delta: impl Iterator<Item = (&'a [u8], Option<&'a [u8]>)>,
273		state_version: StateVersion,
274	) -> (B::Hash, bool, BackendTransaction<HashingFor<B>>) {
275		self.state.child_storage_root(child_info, delta, state_version)
276	}
277
278	fn raw_iter(&self, args: IterArgs) -> Result<Self::RawIter, Self::Error> {
279		self.state.raw_iter(args).map(|inner| RawIter { inner })
280	}
281
282	fn register_overlay_stats(&self, stats: &StateMachineStats) {
283		self.state.register_overlay_stats(stats);
284	}
285
286	fn usage_info(&self) -> StateUsageInfo {
287		self.state.usage_info()
288	}
289}
290
291impl<B: BlockT> AsTrieBackend<HashingFor<B>> for RefTrackingState<B> {
292	type TrieBackendStorage =
293		<DbState<HashingFor<B>> as StateBackend<HashingFor<B>>>::TrieBackendStorage;
294
295	fn as_trie_backend(
296		&self,
297	) -> &sp_state_machine::TrieBackend<Self::TrieBackendStorage, HashingFor<B>> {
298		&self.state.as_trie_backend()
299	}
300}
301
302/// Database settings.
303pub struct DatabaseSettings {
304	/// The maximum trie cache size in bytes.
305	///
306	/// If `None` is given, the cache is disabled.
307	pub trie_cache_maximum_size: Option<usize>,
308	/// Requested state pruning mode.
309	pub state_pruning: Option<PruningMode>,
310	/// Where to find the database.
311	pub source: DatabaseSource,
312	/// Block pruning mode.
313	///
314	/// NOTE: only finalized blocks are subject for removal!
315	pub blocks_pruning: BlocksPruning,
316
317	/// Prometheus metrics registry.
318	pub metrics_registry: Option<Registry>,
319}
320
321/// Block pruning settings.
322#[derive(Debug, Clone, Copy, PartialEq)]
323pub enum BlocksPruning {
324	/// Keep full block history, of every block that was ever imported.
325	KeepAll,
326	/// Keep full finalized block history.
327	KeepFinalized,
328	/// Keep N recent finalized blocks.
329	Some(u32),
330}
331
332impl BlocksPruning {
333	/// True if this is an archive pruning mode (either KeepAll or KeepFinalized).
334	pub fn is_archive(&self) -> bool {
335		match *self {
336			BlocksPruning::KeepAll | BlocksPruning::KeepFinalized => true,
337			BlocksPruning::Some(_) => false,
338		}
339	}
340}
341
342/// Where to find the database..
343#[derive(Debug, Clone)]
344pub enum DatabaseSource {
345	/// Check given path, and see if there is an existing database there. If it's either `RocksDb`
346	/// or `ParityDb`, use it. If there is none, create a new instance of `ParityDb`.
347	Auto {
348		/// Path to the paritydb database.
349		paritydb_path: PathBuf,
350		/// Path to the rocksdb database.
351		rocksdb_path: PathBuf,
352		/// Cache size in MiB. Used only by `RocksDb` variant of `DatabaseSource`.
353		cache_size: usize,
354	},
355	/// Load a RocksDB database from a given path. Recommended for most uses.
356	#[cfg(feature = "rocksdb")]
357	RocksDb {
358		/// Path to the database.
359		path: PathBuf,
360		/// Cache size in MiB.
361		cache_size: usize,
362	},
363
364	/// Load a ParityDb database from a given path.
365	ParityDb {
366		/// Path to the database.
367		path: PathBuf,
368	},
369
370	/// Use a custom already-open database.
371	Custom {
372		/// the handle to the custom storage
373		db: Arc<dyn Database<DbHash>>,
374
375		/// if set, the `create` flag will be required to open such datasource
376		require_create_flag: bool,
377	},
378}
379
380impl DatabaseSource {
381	/// Return path for databases that are stored on disk.
382	pub fn path(&self) -> Option<&Path> {
383		match self {
384			// as per https://github.com/paritytech/substrate/pull/9500#discussion_r684312550
385			//
386			// IIUC this is needed for polkadot to create its own dbs, so until it can use parity db
387			// I would think rocksdb, but later parity-db.
388			DatabaseSource::Auto { paritydb_path, .. } => Some(paritydb_path),
389			#[cfg(feature = "rocksdb")]
390			DatabaseSource::RocksDb { path, .. } => Some(path),
391			DatabaseSource::ParityDb { path } => Some(path),
392			DatabaseSource::Custom { .. } => None,
393		}
394	}
395
396	/// Set path for databases that are stored on disk.
397	pub fn set_path(&mut self, p: &Path) -> bool {
398		match self {
399			DatabaseSource::Auto { ref mut paritydb_path, .. } => {
400				*paritydb_path = p.into();
401				true
402			},
403			#[cfg(feature = "rocksdb")]
404			DatabaseSource::RocksDb { ref mut path, .. } => {
405				*path = p.into();
406				true
407			},
408			DatabaseSource::ParityDb { ref mut path } => {
409				*path = p.into();
410				true
411			},
412			DatabaseSource::Custom { .. } => false,
413		}
414	}
415}
416
417impl std::fmt::Display for DatabaseSource {
418	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
419		let name = match self {
420			DatabaseSource::Auto { .. } => "Auto",
421			#[cfg(feature = "rocksdb")]
422			DatabaseSource::RocksDb { .. } => "RocksDb",
423			DatabaseSource::ParityDb { .. } => "ParityDb",
424			DatabaseSource::Custom { .. } => "Custom",
425		};
426		write!(f, "{}", name)
427	}
428}
429
430pub(crate) mod columns {
431	pub const META: u32 = crate::utils::COLUMN_META;
432	pub const STATE: u32 = 1;
433	pub const STATE_META: u32 = 2;
434	/// maps hashes to lookup keys and numbers to canon hashes.
435	pub const KEY_LOOKUP: u32 = 3;
436	pub const HEADER: u32 = 4;
437	pub const BODY: u32 = 5;
438	pub const JUSTIFICATIONS: u32 = 6;
439	pub const AUX: u32 = 8;
440	/// Offchain workers local storage
441	pub const OFFCHAIN: u32 = 9;
442	/// Transactions
443	pub const TRANSACTION: u32 = 11;
444	pub const BODY_INDEX: u32 = 12;
445}
446
447struct PendingBlock<Block: BlockT> {
448	header: Block::Header,
449	justifications: Option<Justifications>,
450	body: Option<Vec<Block::Extrinsic>>,
451	indexed_body: Option<Vec<Vec<u8>>>,
452	leaf_state: NewBlockState,
453}
454
455// wrapper that implements trait required for state_db
456#[derive(Clone)]
457struct StateMetaDb(Arc<dyn Database<DbHash>>);
458
459impl sc_state_db::MetaDb for StateMetaDb {
460	type Error = sp_database::error::DatabaseError;
461
462	fn get_meta(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
463		Ok(self.0.get(columns::STATE_META, key))
464	}
465}
466
467struct MetaUpdate<Block: BlockT> {
468	pub hash: Block::Hash,
469	pub number: NumberFor<Block>,
470	pub is_best: bool,
471	pub is_finalized: bool,
472	pub with_state: bool,
473}
474
475fn cache_header<Hash: std::cmp::Eq + std::hash::Hash, Header>(
476	cache: &mut LinkedHashMap<Hash, Option<Header>>,
477	hash: Hash,
478	header: Option<Header>,
479) {
480	cache.insert(hash, header);
481	while cache.len() > CACHE_HEADERS {
482		cache.pop_front();
483	}
484}
485
486/// Block database
487pub struct BlockchainDb<Block: BlockT> {
488	db: Arc<dyn Database<DbHash>>,
489	meta: Arc<RwLock<Meta<NumberFor<Block>, Block::Hash>>>,
490	leaves: RwLock<LeafSet<Block::Hash, NumberFor<Block>>>,
491	header_metadata_cache: Arc<HeaderMetadataCache<Block>>,
492	header_cache: Mutex<LinkedHashMap<Block::Hash, Option<Block::Header>>>,
493	pinned_blocks_cache: Arc<RwLock<PinnedBlocksCache<Block>>>,
494}
495
496impl<Block: BlockT> BlockchainDb<Block> {
497	fn new(db: Arc<dyn Database<DbHash>>) -> ClientResult<Self> {
498		let meta = read_meta::<Block>(&*db, columns::HEADER)?;
499		let leaves = LeafSet::read_from_db(&*db, columns::META, meta_keys::LEAF_PREFIX)?;
500		Ok(BlockchainDb {
501			db,
502			leaves: RwLock::new(leaves),
503			meta: Arc::new(RwLock::new(meta)),
504			header_metadata_cache: Arc::new(HeaderMetadataCache::default()),
505			header_cache: Default::default(),
506			pinned_blocks_cache: Arc::new(RwLock::new(PinnedBlocksCache::new())),
507		})
508	}
509
510	fn update_meta(&self, update: MetaUpdate<Block>) {
511		let MetaUpdate { hash, number, is_best, is_finalized, with_state } = update;
512		let mut meta = self.meta.write();
513		if number.is_zero() {
514			meta.genesis_hash = hash;
515		}
516
517		if is_best {
518			meta.best_number = number;
519			meta.best_hash = hash;
520		}
521
522		if is_finalized {
523			if with_state {
524				meta.finalized_state = Some((hash, number));
525			}
526			meta.finalized_number = number;
527			meta.finalized_hash = hash;
528		}
529	}
530
531	fn update_block_gap(&self, gap: Option<BlockGap<NumberFor<Block>>>) {
532		let mut meta = self.meta.write();
533		meta.block_gap = gap;
534	}
535
536	/// Empty the cache of pinned items.
537	fn clear_pinning_cache(&self) {
538		self.pinned_blocks_cache.write().clear();
539	}
540
541	/// Load a justification into the cache of pinned items.
542	/// Reference count of the item will not be increased. Use this
543	/// to load values for items into the cache which have already been pinned.
544	fn insert_justifications_if_pinned(&self, hash: Block::Hash, justification: Justification) {
545		let mut cache = self.pinned_blocks_cache.write();
546		if !cache.contains(hash) {
547			return;
548		}
549
550		let justifications = Justifications::from(justification);
551		cache.insert_justifications(hash, Some(justifications));
552	}
553
554	/// Load a justification from the db into the cache of pinned items.
555	/// Reference count of the item will not be increased. Use this
556	/// to load values for items into the cache which have already been pinned.
557	fn insert_persisted_justifications_if_pinned(&self, hash: Block::Hash) -> ClientResult<()> {
558		let mut cache = self.pinned_blocks_cache.write();
559		if !cache.contains(hash) {
560			return Ok(());
561		}
562
563		let justifications = self.justifications_uncached(hash)?;
564		cache.insert_justifications(hash, justifications);
565		Ok(())
566	}
567
568	/// Load a block body from the db into the cache of pinned items.
569	/// Reference count of the item will not be increased. Use this
570	/// to load values for items items into the cache which have already been pinned.
571	fn insert_persisted_body_if_pinned(&self, hash: Block::Hash) -> ClientResult<()> {
572		let mut cache = self.pinned_blocks_cache.write();
573		if !cache.contains(hash) {
574			return Ok(());
575		}
576
577		let body = self.body_uncached(hash)?;
578		cache.insert_body(hash, body);
579		Ok(())
580	}
581
582	/// Bump reference count for pinned item.
583	fn bump_ref(&self, hash: Block::Hash) {
584		self.pinned_blocks_cache.write().pin(hash);
585	}
586
587	/// Decrease reference count for pinned item and remove if reference count is 0.
588	fn unpin(&self, hash: Block::Hash) {
589		self.pinned_blocks_cache.write().unpin(hash);
590	}
591
592	fn justifications_uncached(&self, hash: Block::Hash) -> ClientResult<Option<Justifications>> {
593		match read_db(
594			&*self.db,
595			columns::KEY_LOOKUP,
596			columns::JUSTIFICATIONS,
597			BlockId::<Block>::Hash(hash),
598		)? {
599			Some(justifications) => match Decode::decode(&mut &justifications[..]) {
600				Ok(justifications) => Ok(Some(justifications)),
601				Err(err) =>
602					return Err(sp_blockchain::Error::Backend(format!(
603						"Error decoding justifications: {err}"
604					))),
605			},
606			None => Ok(None),
607		}
608	}
609
610	fn body_uncached(&self, hash: Block::Hash) -> ClientResult<Option<Vec<Block::Extrinsic>>> {
611		if let Some(body) =
612			read_db(&*self.db, columns::KEY_LOOKUP, columns::BODY, BlockId::Hash::<Block>(hash))?
613		{
614			// Plain body
615			match Decode::decode(&mut &body[..]) {
616				Ok(body) => return Ok(Some(body)),
617				Err(err) =>
618					return Err(sp_blockchain::Error::Backend(format!("Error decoding body: {err}"))),
619			}
620		}
621
622		if let Some(index) = read_db(
623			&*self.db,
624			columns::KEY_LOOKUP,
625			columns::BODY_INDEX,
626			BlockId::Hash::<Block>(hash),
627		)? {
628			match Vec::<DbExtrinsic<Block>>::decode(&mut &index[..]) {
629				Ok(index) => {
630					let mut body = Vec::new();
631					for ex in index {
632						match ex {
633							DbExtrinsic::Indexed { hash, header } => {
634								match self.db.get(columns::TRANSACTION, hash.as_ref()) {
635									Some(t) => {
636										let mut input =
637											utils::join_input(header.as_ref(), t.as_ref());
638										let ex = Block::Extrinsic::decode(&mut input).map_err(
639											|err| {
640												sp_blockchain::Error::Backend(format!(
641													"Error decoding indexed extrinsic: {err}"
642												))
643											},
644										)?;
645										body.push(ex);
646									},
647									None =>
648										return Err(sp_blockchain::Error::Backend(format!(
649											"Missing indexed transaction {hash:?}"
650										))),
651								};
652							},
653							DbExtrinsic::Full(ex) => {
654								body.push(ex);
655							},
656						}
657					}
658					return Ok(Some(body));
659				},
660				Err(err) =>
661					return Err(sp_blockchain::Error::Backend(format!(
662						"Error decoding body list: {err}",
663					))),
664			}
665		}
666		Ok(None)
667	}
668}
669
670impl<Block: BlockT> sc_client_api::blockchain::HeaderBackend<Block> for BlockchainDb<Block> {
671	fn header(&self, hash: Block::Hash) -> ClientResult<Option<Block::Header>> {
672		let mut cache = self.header_cache.lock();
673		if let Some(result) = cache.get_refresh(&hash) {
674			return Ok(result.clone());
675		}
676		let header = utils::read_header(
677			&*self.db,
678			columns::KEY_LOOKUP,
679			columns::HEADER,
680			BlockId::<Block>::Hash(hash),
681		)?;
682		cache_header(&mut cache, hash, header.clone());
683		Ok(header)
684	}
685
686	fn info(&self) -> sc_client_api::blockchain::Info<Block> {
687		let meta = self.meta.read();
688		sc_client_api::blockchain::Info {
689			best_hash: meta.best_hash,
690			best_number: meta.best_number,
691			genesis_hash: meta.genesis_hash,
692			finalized_hash: meta.finalized_hash,
693			finalized_number: meta.finalized_number,
694			finalized_state: meta.finalized_state,
695			number_leaves: self.leaves.read().count(),
696			block_gap: meta.block_gap,
697		}
698	}
699
700	fn status(&self, hash: Block::Hash) -> ClientResult<sc_client_api::blockchain::BlockStatus> {
701		match self.header(hash)?.is_some() {
702			true => Ok(sc_client_api::blockchain::BlockStatus::InChain),
703			false => Ok(sc_client_api::blockchain::BlockStatus::Unknown),
704		}
705	}
706
707	fn number(&self, hash: Block::Hash) -> ClientResult<Option<NumberFor<Block>>> {
708		Ok(self.header_metadata(hash).ok().map(|header_metadata| header_metadata.number))
709	}
710
711	fn hash(&self, number: NumberFor<Block>) -> ClientResult<Option<Block::Hash>> {
712		Ok(utils::read_header::<Block>(
713			&*self.db,
714			columns::KEY_LOOKUP,
715			columns::HEADER,
716			BlockId::Number(number),
717		)?
718		.map(|header| header.hash()))
719	}
720}
721
722impl<Block: BlockT> sc_client_api::blockchain::Backend<Block> for BlockchainDb<Block> {
723	fn body(&self, hash: Block::Hash) -> ClientResult<Option<Vec<Block::Extrinsic>>> {
724		let cache = self.pinned_blocks_cache.read();
725		if let Some(result) = cache.body(&hash) {
726			return Ok(result.clone());
727		}
728
729		self.body_uncached(hash)
730	}
731
732	fn justifications(&self, hash: Block::Hash) -> ClientResult<Option<Justifications>> {
733		let cache = self.pinned_blocks_cache.read();
734		if let Some(result) = cache.justifications(&hash) {
735			return Ok(result.clone());
736		}
737
738		self.justifications_uncached(hash)
739	}
740
741	fn last_finalized(&self) -> ClientResult<Block::Hash> {
742		Ok(self.meta.read().finalized_hash)
743	}
744
745	fn leaves(&self) -> ClientResult<Vec<Block::Hash>> {
746		Ok(self.leaves.read().hashes())
747	}
748
749	fn children(&self, parent_hash: Block::Hash) -> ClientResult<Vec<Block::Hash>> {
750		children::read_children(&*self.db, columns::META, meta_keys::CHILDREN_PREFIX, parent_hash)
751	}
752
753	fn indexed_transaction(&self, hash: Block::Hash) -> ClientResult<Option<Vec<u8>>> {
754		Ok(self.db.get(columns::TRANSACTION, hash.as_ref()))
755	}
756
757	fn has_indexed_transaction(&self, hash: Block::Hash) -> ClientResult<bool> {
758		Ok(self.db.contains(columns::TRANSACTION, hash.as_ref()))
759	}
760
761	fn block_indexed_body(&self, hash: Block::Hash) -> ClientResult<Option<Vec<Vec<u8>>>> {
762		let body = match read_db(
763			&*self.db,
764			columns::KEY_LOOKUP,
765			columns::BODY_INDEX,
766			BlockId::<Block>::Hash(hash),
767		)? {
768			Some(body) => body,
769			None => return Ok(None),
770		};
771		match Vec::<DbExtrinsic<Block>>::decode(&mut &body[..]) {
772			Ok(index) => {
773				let mut transactions = Vec::new();
774				for ex in index.into_iter() {
775					if let DbExtrinsic::Indexed { hash, .. } = ex {
776						match self.db.get(columns::TRANSACTION, hash.as_ref()) {
777							Some(t) => transactions.push(t),
778							None =>
779								return Err(sp_blockchain::Error::Backend(format!(
780									"Missing indexed transaction {hash:?}",
781								))),
782						}
783					}
784				}
785				Ok(Some(transactions))
786			},
787			Err(err) =>
788				Err(sp_blockchain::Error::Backend(format!("Error decoding body list: {err}"))),
789		}
790	}
791}
792
793impl<Block: BlockT> HeaderMetadata<Block> for BlockchainDb<Block> {
794	type Error = sp_blockchain::Error;
795
796	fn header_metadata(
797		&self,
798		hash: Block::Hash,
799	) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
800		self.header_metadata_cache.header_metadata(hash).map_or_else(
801			|| {
802				self.header(hash)?
803					.map(|header| {
804						let header_metadata = CachedHeaderMetadata::from(&header);
805						self.header_metadata_cache
806							.insert_header_metadata(header_metadata.hash, header_metadata.clone());
807						header_metadata
808					})
809					.ok_or_else(|| {
810						ClientError::UnknownBlock(format!(
811							"Header was not found in the database: {hash:?}",
812						))
813					})
814			},
815			Ok,
816		)
817	}
818
819	fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata<Block>) {
820		self.header_metadata_cache.insert_header_metadata(hash, metadata)
821	}
822
823	fn remove_header_metadata(&self, hash: Block::Hash) {
824		self.header_cache.lock().remove(&hash);
825		self.header_metadata_cache.remove_header_metadata(hash);
826	}
827}
828
829/// Database transaction
830pub struct BlockImportOperation<Block: BlockT> {
831	old_state: RecordStatsState<RefTrackingState<Block>, Block>,
832	db_updates: PrefixedMemoryDB<HashingFor<Block>>,
833	storage_updates: StorageCollection,
834	child_storage_updates: ChildStorageCollection,
835	offchain_storage_updates: OffchainChangesCollection,
836	pending_block: Option<PendingBlock<Block>>,
837	aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
838	finalized_blocks: Vec<(Block::Hash, Option<Justification>)>,
839	set_head: Option<Block::Hash>,
840	commit_state: bool,
841	create_gap: bool,
842	reset_storage: bool,
843	index_ops: Vec<IndexOperation>,
844}
845
846impl<Block: BlockT> BlockImportOperation<Block> {
847	fn apply_offchain(&mut self, transaction: &mut Transaction<DbHash>) {
848		let mut count = 0;
849		for ((prefix, key), value_operation) in self.offchain_storage_updates.drain(..) {
850			count += 1;
851			let key = crate::offchain::concatenate_prefix_and_key(&prefix, &key);
852			match value_operation {
853				OffchainOverlayedChange::SetValue(val) =>
854					transaction.set_from_vec(columns::OFFCHAIN, &key, val),
855				OffchainOverlayedChange::Remove => transaction.remove(columns::OFFCHAIN, &key),
856			}
857		}
858
859		if count > 0 {
860			log::debug!(target: "sc_offchain", "Applied {count} offchain indexing changes.");
861		}
862	}
863
864	fn apply_aux(&mut self, transaction: &mut Transaction<DbHash>) {
865		for (key, maybe_val) in self.aux_ops.drain(..) {
866			match maybe_val {
867				Some(val) => transaction.set_from_vec(columns::AUX, &key, val),
868				None => transaction.remove(columns::AUX, &key),
869			}
870		}
871	}
872
873	fn apply_new_state(
874		&mut self,
875		storage: Storage,
876		state_version: StateVersion,
877	) -> ClientResult<Block::Hash> {
878		if storage.top.keys().any(|k| well_known_keys::is_child_storage_key(k)) {
879			return Err(sp_blockchain::Error::InvalidState);
880		}
881
882		let child_delta = storage.children_default.values().map(|child_content| {
883			(
884				&child_content.child_info,
885				child_content.data.iter().map(|(k, v)| (&k[..], Some(&v[..]))),
886			)
887		});
888
889		let (root, transaction) = self.old_state.full_storage_root(
890			storage.top.iter().map(|(k, v)| (&k[..], Some(&v[..]))),
891			child_delta,
892			state_version,
893		);
894
895		self.db_updates = transaction;
896		Ok(root)
897	}
898}
899
900impl<Block: BlockT> sc_client_api::backend::BlockImportOperation<Block>
901	for BlockImportOperation<Block>
902{
903	type State = RecordStatsState<RefTrackingState<Block>, Block>;
904
905	fn state(&self) -> ClientResult<Option<&Self::State>> {
906		Ok(Some(&self.old_state))
907	}
908
909	fn set_block_data(
910		&mut self,
911		header: Block::Header,
912		body: Option<Vec<Block::Extrinsic>>,
913		indexed_body: Option<Vec<Vec<u8>>>,
914		justifications: Option<Justifications>,
915		leaf_state: NewBlockState,
916	) -> ClientResult<()> {
917		assert!(self.pending_block.is_none(), "Only one block per operation is allowed");
918		self.pending_block =
919			Some(PendingBlock { header, body, indexed_body, justifications, leaf_state });
920		Ok(())
921	}
922
923	fn update_db_storage(
924		&mut self,
925		update: PrefixedMemoryDB<HashingFor<Block>>,
926	) -> ClientResult<()> {
927		self.db_updates = update;
928		Ok(())
929	}
930
931	fn reset_storage(
932		&mut self,
933		storage: Storage,
934		state_version: StateVersion,
935	) -> ClientResult<Block::Hash> {
936		let root = self.apply_new_state(storage, state_version)?;
937		self.commit_state = true;
938		self.reset_storage = true;
939		Ok(root)
940	}
941
942	fn set_genesis_state(
943		&mut self,
944		storage: Storage,
945		commit: bool,
946		state_version: StateVersion,
947	) -> ClientResult<Block::Hash> {
948		let root = self.apply_new_state(storage, state_version)?;
949		self.commit_state = commit;
950		Ok(root)
951	}
952
953	fn insert_aux<I>(&mut self, ops: I) -> ClientResult<()>
954	where
955		I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>,
956	{
957		self.aux_ops.append(&mut ops.into_iter().collect());
958		Ok(())
959	}
960
961	fn update_storage(
962		&mut self,
963		update: StorageCollection,
964		child_update: ChildStorageCollection,
965	) -> ClientResult<()> {
966		self.storage_updates = update;
967		self.child_storage_updates = child_update;
968		Ok(())
969	}
970
971	fn update_offchain_storage(
972		&mut self,
973		offchain_update: OffchainChangesCollection,
974	) -> ClientResult<()> {
975		self.offchain_storage_updates = offchain_update;
976		Ok(())
977	}
978
979	fn mark_finalized(
980		&mut self,
981		block: Block::Hash,
982		justification: Option<Justification>,
983	) -> ClientResult<()> {
984		self.finalized_blocks.push((block, justification));
985		Ok(())
986	}
987
988	fn mark_head(&mut self, hash: Block::Hash) -> ClientResult<()> {
989		assert!(self.set_head.is_none(), "Only one set head per operation is allowed");
990		self.set_head = Some(hash);
991		Ok(())
992	}
993
994	fn update_transaction_index(&mut self, index_ops: Vec<IndexOperation>) -> ClientResult<()> {
995		self.index_ops = index_ops;
996		Ok(())
997	}
998
999	fn set_create_gap(&mut self, create_gap: bool) {
1000		self.create_gap = create_gap;
1001	}
1002}
1003
1004struct StorageDb<Block: BlockT> {
1005	pub db: Arc<dyn Database<DbHash>>,
1006	pub state_db: StateDb<Block::Hash, Vec<u8>, StateMetaDb>,
1007	prefix_keys: bool,
1008}
1009
1010impl<Block: BlockT> sp_state_machine::Storage<HashingFor<Block>> for StorageDb<Block> {
1011	fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result<Option<DBValue>, String> {
1012		if self.prefix_keys {
1013			let key = prefixed_key::<HashingFor<Block>>(key, prefix);
1014			self.state_db.get(&key, self)
1015		} else {
1016			self.state_db.get(key.as_ref(), self)
1017		}
1018		.map_err(|e| format!("Database backend error: {e:?}"))
1019	}
1020}
1021
1022impl<Block: BlockT> sc_state_db::NodeDb for StorageDb<Block> {
1023	type Error = io::Error;
1024	type Key = [u8];
1025
1026	fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Self::Error> {
1027		Ok(self.db.get(columns::STATE, key))
1028	}
1029}
1030
1031struct DbGenesisStorage<Block: BlockT> {
1032	root: Block::Hash,
1033	storage: PrefixedMemoryDB<HashingFor<Block>>,
1034}
1035
1036impl<Block: BlockT> DbGenesisStorage<Block> {
1037	pub fn new(root: Block::Hash, storage: PrefixedMemoryDB<HashingFor<Block>>) -> Self {
1038		DbGenesisStorage { root, storage }
1039	}
1040}
1041
1042impl<Block: BlockT> sp_state_machine::Storage<HashingFor<Block>> for DbGenesisStorage<Block> {
1043	fn get(&self, key: &Block::Hash, prefix: Prefix) -> Result<Option<DBValue>, String> {
1044		use hash_db::HashDB;
1045		Ok(self.storage.get(key, prefix))
1046	}
1047}
1048
1049struct EmptyStorage<Block: BlockT>(pub Block::Hash);
1050
1051impl<Block: BlockT> EmptyStorage<Block> {
1052	pub fn new() -> Self {
1053		let mut root = Block::Hash::default();
1054		let mut mdb = MemoryDB::<HashingFor<Block>>::default();
1055		// both triedbmut are the same on empty storage.
1056		sp_trie::trie_types::TrieDBMutBuilderV1::<HashingFor<Block>>::new(&mut mdb, &mut root)
1057			.build();
1058		EmptyStorage(root)
1059	}
1060}
1061
1062impl<Block: BlockT> sp_state_machine::Storage<HashingFor<Block>> for EmptyStorage<Block> {
1063	fn get(&self, _key: &Block::Hash, _prefix: Prefix) -> Result<Option<DBValue>, String> {
1064		Ok(None)
1065	}
1066}
1067
1068/// Frozen `value` at time `at`.
1069///
1070/// Used as inner structure under lock in `FrozenForDuration`.
1071struct Frozen<T: Clone> {
1072	at: std::time::Instant,
1073	value: Option<T>,
1074}
1075
1076/// Some value frozen for period of time.
1077///
1078/// If time `duration` not passed since the value was instantiated,
1079/// current frozen value is returned. Otherwise, you have to provide
1080/// a new value which will be again frozen for `duration`.
1081pub(crate) struct FrozenForDuration<T: Clone> {
1082	duration: std::time::Duration,
1083	value: parking_lot::Mutex<Frozen<T>>,
1084}
1085
1086impl<T: Clone> FrozenForDuration<T> {
1087	fn new(duration: std::time::Duration) -> Self {
1088		Self { duration, value: Frozen { at: std::time::Instant::now(), value: None }.into() }
1089	}
1090
1091	fn take_or_else<F>(&self, f: F) -> T
1092	where
1093		F: FnOnce() -> T,
1094	{
1095		let mut lock = self.value.lock();
1096		let now = std::time::Instant::now();
1097		if now.saturating_duration_since(lock.at) > self.duration || lock.value.is_none() {
1098			let new_value = f();
1099			lock.at = now;
1100			lock.value = Some(new_value.clone());
1101			new_value
1102		} else {
1103			lock.value.as_ref().expect("Checked with in branch above; qed").clone()
1104		}
1105	}
1106}
1107
1108/// Disk backend.
1109///
1110/// Disk backend keeps data in a key-value store. In archive mode, trie nodes are kept from all
1111/// blocks. Otherwise, trie nodes are kept only from some recent blocks.
1112pub struct Backend<Block: BlockT> {
1113	storage: Arc<StorageDb<Block>>,
1114	offchain_storage: offchain::LocalStorage,
1115	blockchain: BlockchainDb<Block>,
1116	canonicalization_delay: u64,
1117	import_lock: Arc<RwLock<()>>,
1118	is_archive: bool,
1119	blocks_pruning: BlocksPruning,
1120	io_stats: FrozenForDuration<(kvdb::IoStats, StateUsageInfo)>,
1121	state_usage: Arc<StateUsageStats>,
1122	genesis_state: RwLock<Option<Arc<DbGenesisStorage<Block>>>>,
1123	shared_trie_cache: Option<sp_trie::cache::SharedTrieCache<HashingFor<Block>>>,
1124}
1125
1126impl<Block: BlockT> Backend<Block> {
1127	/// Create a new instance of database backend.
1128	///
1129	/// The pruning window is how old a block must be before the state is pruned.
1130	pub fn new(db_config: DatabaseSettings, canonicalization_delay: u64) -> ClientResult<Self> {
1131		use utils::OpenDbError;
1132
1133		let db_source = &db_config.source;
1134
1135		let (needs_init, db) =
1136			match crate::utils::open_database::<Block>(db_source, DatabaseType::Full, false) {
1137				Ok(db) => (false, db),
1138				Err(OpenDbError::DoesNotExist) => {
1139					let db =
1140						crate::utils::open_database::<Block>(db_source, DatabaseType::Full, true)?;
1141					(true, db)
1142				},
1143				Err(as_is) => return Err(as_is.into()),
1144			};
1145
1146		Self::from_database(db as Arc<_>, canonicalization_delay, &db_config, needs_init)
1147	}
1148
1149	/// Reset the shared trie cache.
1150	pub fn reset_trie_cache(&self) {
1151		if let Some(cache) = &self.shared_trie_cache {
1152			cache.reset();
1153		}
1154	}
1155
1156	/// Create new memory-backed client backend for tests.
1157	#[cfg(any(test, feature = "test-helpers"))]
1158	pub fn new_test(blocks_pruning: u32, canonicalization_delay: u64) -> Self {
1159		Self::new_test_with_tx_storage(BlocksPruning::Some(blocks_pruning), canonicalization_delay)
1160	}
1161
1162	/// Create new memory-backed client backend for tests.
1163	#[cfg(any(test, feature = "test-helpers"))]
1164	pub fn new_test_with_tx_storage(
1165		blocks_pruning: BlocksPruning,
1166		canonicalization_delay: u64,
1167	) -> Self {
1168		let db = kvdb_memorydb::create(crate::utils::NUM_COLUMNS);
1169		let db = sp_database::as_database(db);
1170		let state_pruning = match blocks_pruning {
1171			BlocksPruning::KeepAll => PruningMode::ArchiveAll,
1172			BlocksPruning::KeepFinalized => PruningMode::ArchiveCanonical,
1173			BlocksPruning::Some(n) => PruningMode::blocks_pruning(n),
1174		};
1175		let db_setting = DatabaseSettings {
1176			trie_cache_maximum_size: Some(16 * 1024 * 1024),
1177			state_pruning: Some(state_pruning),
1178			source: DatabaseSource::Custom { db, require_create_flag: true },
1179			blocks_pruning,
1180			metrics_registry: None,
1181		};
1182
1183		Self::new(db_setting, canonicalization_delay).expect("failed to create test-db")
1184	}
1185
1186	/// Expose the Database that is used by this backend.
1187	/// The second argument is the Column that stores the State.
1188	///
1189	/// Should only be needed for benchmarking.
1190	#[cfg(feature = "runtime-benchmarks")]
1191	pub fn expose_db(&self) -> (Arc<dyn sp_database::Database<DbHash>>, sp_database::ColumnId) {
1192		(self.storage.db.clone(), columns::STATE)
1193	}
1194
1195	/// Expose the Storage that is used by this backend.
1196	///
1197	/// Should only be needed for benchmarking.
1198	#[cfg(feature = "runtime-benchmarks")]
1199	pub fn expose_storage(&self) -> Arc<dyn sp_state_machine::Storage<HashingFor<Block>>> {
1200		self.storage.clone()
1201	}
1202
1203	/// Expose the shared trie cache that is used by this backend.
1204	///
1205	/// Should only be needed for benchmarking.
1206	#[cfg(feature = "runtime-benchmarks")]
1207	pub fn expose_shared_trie_cache(
1208		&self,
1209	) -> Option<sp_trie::cache::SharedTrieCache<HashingFor<Block>>> {
1210		self.shared_trie_cache.clone()
1211	}
1212
1213	fn from_database(
1214		db: Arc<dyn Database<DbHash>>,
1215		canonicalization_delay: u64,
1216		config: &DatabaseSettings,
1217		should_init: bool,
1218	) -> ClientResult<Self> {
1219		let mut db_init_transaction = Transaction::new();
1220
1221		let requested_state_pruning = config.state_pruning.clone();
1222		let state_meta_db = StateMetaDb(db.clone());
1223		let map_e = sp_blockchain::Error::from_state_db;
1224
1225		let (state_db_init_commit_set, state_db) = StateDb::open(
1226			state_meta_db,
1227			requested_state_pruning,
1228			!db.supports_ref_counting(),
1229			should_init,
1230		)
1231		.map_err(map_e)?;
1232
1233		apply_state_commit(&mut db_init_transaction, state_db_init_commit_set);
1234
1235		let state_pruning_used = state_db.pruning_mode();
1236		let is_archive_pruning = state_pruning_used.is_archive();
1237		let blockchain = BlockchainDb::new(db.clone())?;
1238
1239		let storage_db =
1240			StorageDb { db: db.clone(), state_db, prefix_keys: !db.supports_ref_counting() };
1241
1242		let offchain_storage = offchain::LocalStorage::new(db.clone());
1243
1244		let shared_trie_cache = config.trie_cache_maximum_size.map(|maximum_size| {
1245			let system_memory = sysinfo::System::new_all();
1246			let used_memory = system_memory.used_memory();
1247			let total_memory = system_memory.total_memory();
1248
1249			debug!("Initializing shared trie cache with size {} bytes, {}% of total memory", maximum_size, (maximum_size as f64 / total_memory as f64 * 100.0));
1250			if maximum_size as u64 > total_memory - used_memory {
1251				warn!(
1252					"Not enough memory to initialize shared trie cache. Cache size: {} bytes. System memory: used {} bytes, total {} bytes",
1253					maximum_size, used_memory, total_memory,
1254				);
1255			}
1256
1257			SharedTrieCache::new(sp_trie::cache::CacheSize::new(maximum_size), config.metrics_registry.as_ref())
1258		});
1259
1260		let backend = Backend {
1261			storage: Arc::new(storage_db),
1262			offchain_storage,
1263			blockchain,
1264			canonicalization_delay,
1265			import_lock: Default::default(),
1266			is_archive: is_archive_pruning,
1267			io_stats: FrozenForDuration::new(std::time::Duration::from_secs(1)),
1268			state_usage: Arc::new(StateUsageStats::new()),
1269			blocks_pruning: config.blocks_pruning,
1270			genesis_state: RwLock::new(None),
1271			shared_trie_cache,
1272		};
1273
1274		// Older DB versions have no last state key. Check if the state is available and set it.
1275		let info = backend.blockchain.info();
1276		if info.finalized_state.is_none() &&
1277			info.finalized_hash != Default::default() &&
1278			sc_client_api::Backend::have_state_at(
1279				&backend,
1280				info.finalized_hash,
1281				info.finalized_number,
1282			) {
1283			backend.blockchain.update_meta(MetaUpdate {
1284				hash: info.finalized_hash,
1285				number: info.finalized_number,
1286				is_best: info.finalized_hash == info.best_hash,
1287				is_finalized: true,
1288				with_state: true,
1289			});
1290		}
1291
1292		// Non archive nodes cannot fill the missing block gap with bodies.
1293		// If the gap is present, it means that every restart will try to fill the gap:
1294		// - a block request is made for each and every block in the gap
1295		// - the request is fulfilled putting pressure on the network and other nodes
1296		// - upon receiving the block, the block cannot be executed since the state
1297		//  of the parent block might have been discarded
1298		// - then the sync engine closes the gap in memory, but never in DB.
1299		//
1300		// This leads to inefficient syncing and high CPU usage on every restart. To mitigate this,
1301		// remove the gap from the DB if we detect it and the current node is not an archive.
1302		match (backend.is_archive, info.block_gap) {
1303			(false, Some(gap)) if matches!(gap.gap_type, BlockGapType::MissingBody) => {
1304				warn!(
1305					"Detected a missing body gap for non-archive nodes. Removing the gap={:?}",
1306					gap
1307				);
1308
1309				db_init_transaction.remove(columns::META, meta_keys::BLOCK_GAP);
1310				db_init_transaction.remove(columns::META, meta_keys::BLOCK_GAP_VERSION);
1311				backend.blockchain.update_block_gap(None);
1312			},
1313			_ => {},
1314		}
1315
1316		db.commit(db_init_transaction)?;
1317
1318		Ok(backend)
1319	}
1320
1321	/// Handle setting head within a transaction. `route_to` should be the last
1322	/// block that existed in the database. `best_to` should be the best block
1323	/// to be set.
1324	///
1325	/// In the case where the new best block is a block to be imported, `route_to`
1326	/// should be the parent of `best_to`. In the case where we set an existing block
1327	/// to be best, `route_to` should equal to `best_to`.
1328	fn set_head_with_transaction(
1329		&self,
1330		transaction: &mut Transaction<DbHash>,
1331		route_to: Block::Hash,
1332		best_to: (NumberFor<Block>, Block::Hash),
1333	) -> ClientResult<(Vec<Block::Hash>, Vec<Block::Hash>)> {
1334		let mut enacted = Vec::default();
1335		let mut retracted = Vec::default();
1336
1337		let (best_number, best_hash) = best_to;
1338
1339		let meta = self.blockchain.meta.read();
1340
1341		if meta.best_number.saturating_sub(best_number).saturated_into::<u64>() >
1342			self.canonicalization_delay
1343		{
1344			return Err(sp_blockchain::Error::SetHeadTooOld);
1345		}
1346
1347		let parent_exists =
1348			self.blockchain.status(route_to)? == sp_blockchain::BlockStatus::InChain;
1349
1350		// Cannot find tree route with empty DB or when imported a detached block.
1351		if meta.best_hash != Default::default() && parent_exists {
1352			let tree_route = sp_blockchain::tree_route(&self.blockchain, meta.best_hash, route_to)?;
1353
1354			// uncanonicalize: check safety violations and ensure the numbers no longer
1355			// point to these block hashes in the key mapping.
1356			for r in tree_route.retracted() {
1357				if r.hash == meta.finalized_hash {
1358					warn!(
1359						"Potential safety failure: reverting finalized block {:?}",
1360						(&r.number, &r.hash)
1361					);
1362
1363					return Err(sp_blockchain::Error::NotInFinalizedChain);
1364				}
1365
1366				retracted.push(r.hash);
1367				utils::remove_number_to_key_mapping(transaction, columns::KEY_LOOKUP, r.number)?;
1368			}
1369
1370			// canonicalize: set the number lookup to map to this block's hash.
1371			for e in tree_route.enacted() {
1372				enacted.push(e.hash);
1373				utils::insert_number_to_key_mapping(
1374					transaction,
1375					columns::KEY_LOOKUP,
1376					e.number,
1377					e.hash,
1378				)?;
1379			}
1380		}
1381
1382		let lookup_key = utils::number_and_hash_to_lookup_key(best_number, &best_hash)?;
1383		transaction.set_from_vec(columns::META, meta_keys::BEST_BLOCK, lookup_key);
1384		utils::insert_number_to_key_mapping(
1385			transaction,
1386			columns::KEY_LOOKUP,
1387			best_number,
1388			best_hash,
1389		)?;
1390
1391		Ok((enacted, retracted))
1392	}
1393
1394	fn ensure_sequential_finalization(
1395		&self,
1396		header: &Block::Header,
1397		last_finalized: Option<Block::Hash>,
1398	) -> ClientResult<()> {
1399		let last_finalized =
1400			last_finalized.unwrap_or_else(|| self.blockchain.meta.read().finalized_hash);
1401		if last_finalized != self.blockchain.meta.read().genesis_hash &&
1402			*header.parent_hash() != last_finalized
1403		{
1404			return Err(sp_blockchain::Error::NonSequentialFinalization(format!(
1405				"Last finalized {last_finalized:?} not parent of {:?}",
1406				header.hash()
1407			)));
1408		}
1409		Ok(())
1410	}
1411
1412	/// `remove_displaced` can be set to `false` if this is not the last of many subsequent calls
1413	/// for performance reasons.
1414	fn finalize_block_with_transaction(
1415		&self,
1416		transaction: &mut Transaction<DbHash>,
1417		hash: Block::Hash,
1418		header: &Block::Header,
1419		last_finalized: Option<Block::Hash>,
1420		justification: Option<Justification>,
1421		current_transaction_justifications: &mut HashMap<Block::Hash, Justification>,
1422		remove_displaced: bool,
1423	) -> ClientResult<MetaUpdate<Block>> {
1424		// TODO: ensure best chain contains this block.
1425		let number = *header.number();
1426		self.ensure_sequential_finalization(header, last_finalized)?;
1427		let with_state = sc_client_api::Backend::have_state_at(self, hash, number);
1428
1429		self.note_finalized(
1430			transaction,
1431			header,
1432			hash,
1433			with_state,
1434			current_transaction_justifications,
1435			remove_displaced,
1436		)?;
1437
1438		if let Some(justification) = justification {
1439			transaction.set_from_vec(
1440				columns::JUSTIFICATIONS,
1441				&utils::number_and_hash_to_lookup_key(number, hash)?,
1442				Justifications::from(justification.clone()).encode(),
1443			);
1444			current_transaction_justifications.insert(hash, justification);
1445		}
1446		Ok(MetaUpdate { hash, number, is_best: false, is_finalized: true, with_state })
1447	}
1448
1449	// performs forced canonicalization with a delay after importing a non-finalized block.
1450	fn force_delayed_canonicalize(
1451		&self,
1452		transaction: &mut Transaction<DbHash>,
1453	) -> ClientResult<()> {
1454		let best_canonical = match self.storage.state_db.last_canonicalized() {
1455			LastCanonicalized::None => 0,
1456			LastCanonicalized::Block(b) => b,
1457			// Nothing needs to be done when canonicalization is not happening.
1458			LastCanonicalized::NotCanonicalizing => return Ok(()),
1459		};
1460
1461		let info = self.blockchain.info();
1462		let best_number: u64 = self.blockchain.info().best_number.saturated_into();
1463
1464		for to_canonicalize in
1465			best_canonical + 1..=best_number.saturating_sub(self.canonicalization_delay)
1466		{
1467			let hash_to_canonicalize = sc_client_api::blockchain::HeaderBackend::hash(
1468				&self.blockchain,
1469				to_canonicalize.saturated_into(),
1470			)?
1471			.ok_or_else(|| {
1472				let best_hash = info.best_hash;
1473
1474				sp_blockchain::Error::Backend(format!(
1475					"Can't canonicalize missing block number #{to_canonicalize} when for best block {best_hash:?} (#{best_number})",
1476				))
1477			})?;
1478
1479			if !sc_client_api::Backend::have_state_at(
1480				self,
1481				hash_to_canonicalize,
1482				to_canonicalize.saturated_into(),
1483			) {
1484				return Ok(());
1485			}
1486
1487			trace!(target: "db", "Canonicalize block #{to_canonicalize} ({hash_to_canonicalize:?})");
1488			let commit = self.storage.state_db.canonicalize_block(&hash_to_canonicalize).map_err(
1489				sp_blockchain::Error::from_state_db::<
1490					sc_state_db::Error<sp_database::error::DatabaseError>,
1491				>,
1492			)?;
1493			apply_state_commit(transaction, commit);
1494		}
1495
1496		Ok(())
1497	}
1498
1499	fn try_commit_operation(&self, mut operation: BlockImportOperation<Block>) -> ClientResult<()> {
1500		let mut transaction = Transaction::new();
1501
1502		operation.apply_aux(&mut transaction);
1503		operation.apply_offchain(&mut transaction);
1504
1505		let mut meta_updates = Vec::with_capacity(operation.finalized_blocks.len());
1506		let (best_num, mut last_finalized_hash, mut last_finalized_num, mut block_gap) = {
1507			let meta = self.blockchain.meta.read();
1508			(meta.best_number, meta.finalized_hash, meta.finalized_number, meta.block_gap)
1509		};
1510
1511		let mut block_gap_updated = false;
1512
1513		let mut current_transaction_justifications: HashMap<Block::Hash, Justification> =
1514			HashMap::new();
1515		let mut finalized_blocks = operation.finalized_blocks.into_iter().peekable();
1516		while let Some((block_hash, justification)) = finalized_blocks.next() {
1517			let block_header = self.blockchain.expect_header(block_hash)?;
1518			meta_updates.push(self.finalize_block_with_transaction(
1519				&mut transaction,
1520				block_hash,
1521				&block_header,
1522				Some(last_finalized_hash),
1523				justification,
1524				&mut current_transaction_justifications,
1525				finalized_blocks.peek().is_none(),
1526			)?);
1527			last_finalized_hash = block_hash;
1528			last_finalized_num = *block_header.number();
1529		}
1530
1531		let imported = if let Some(pending_block) = operation.pending_block {
1532			let hash = pending_block.header.hash();
1533
1534			let parent_hash = *pending_block.header.parent_hash();
1535			let number = *pending_block.header.number();
1536			let highest_leaf = self
1537				.blockchain
1538				.leaves
1539				.read()
1540				.highest_leaf()
1541				.map(|(n, _)| n)
1542				.unwrap_or(Zero::zero());
1543			let existing_header = number <= highest_leaf && self.blockchain.header(hash)?.is_some();
1544			let existing_body = pending_block.body.is_some();
1545
1546			// blocks are keyed by number + hash.
1547			let lookup_key = utils::number_and_hash_to_lookup_key(number, hash)?;
1548
1549			if pending_block.leaf_state.is_best() {
1550				self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))?;
1551			};
1552
1553			utils::insert_hash_to_key_mapping(&mut transaction, columns::KEY_LOOKUP, number, hash)?;
1554
1555			transaction.set_from_vec(columns::HEADER, &lookup_key, pending_block.header.encode());
1556			if let Some(body) = pending_block.body {
1557				// If we have any index operations we save block in the new format with indexed
1558				// extrinsic headers Otherwise we save the body as a single blob.
1559				if operation.index_ops.is_empty() {
1560					transaction.set_from_vec(columns::BODY, &lookup_key, body.encode());
1561				} else {
1562					let body =
1563						apply_index_ops::<Block>(&mut transaction, body, operation.index_ops);
1564					transaction.set_from_vec(columns::BODY_INDEX, &lookup_key, body);
1565				}
1566			}
1567			if let Some(body) = pending_block.indexed_body {
1568				apply_indexed_body::<Block>(&mut transaction, body);
1569			}
1570			if let Some(justifications) = pending_block.justifications {
1571				transaction.set_from_vec(
1572					columns::JUSTIFICATIONS,
1573					&lookup_key,
1574					justifications.encode(),
1575				);
1576			}
1577
1578			if number.is_zero() {
1579				transaction.set(columns::META, meta_keys::GENESIS_HASH, hash.as_ref());
1580
1581				if operation.commit_state {
1582					transaction.set_from_vec(columns::META, meta_keys::FINALIZED_STATE, lookup_key);
1583				} else {
1584					// When we don't want to commit the genesis state, we still preserve it in
1585					// memory to bootstrap consensus. It is queried for an initial list of
1586					// authorities, etc.
1587					*self.genesis_state.write() = Some(Arc::new(DbGenesisStorage::new(
1588						*pending_block.header.state_root(),
1589						operation.db_updates.clone(),
1590					)));
1591				}
1592			}
1593
1594			let finalized = if operation.commit_state {
1595				let mut changeset: sc_state_db::ChangeSet<Vec<u8>> =
1596					sc_state_db::ChangeSet::default();
1597				let mut ops: u64 = 0;
1598				let mut bytes: u64 = 0;
1599				let mut removal: u64 = 0;
1600				let mut bytes_removal: u64 = 0;
1601				for (mut key, (val, rc)) in operation.db_updates.drain() {
1602					self.storage.db.sanitize_key(&mut key);
1603					if rc > 0 {
1604						ops += 1;
1605						bytes += key.len() as u64 + val.len() as u64;
1606						if rc == 1 {
1607							changeset.inserted.push((key, val.to_vec()));
1608						} else {
1609							changeset.inserted.push((key.clone(), val.to_vec()));
1610							for _ in 0..rc - 1 {
1611								changeset.inserted.push((key.clone(), Default::default()));
1612							}
1613						}
1614					} else if rc < 0 {
1615						removal += 1;
1616						bytes_removal += key.len() as u64;
1617						if rc == -1 {
1618							changeset.deleted.push(key);
1619						} else {
1620							for _ in 0..-rc {
1621								changeset.deleted.push(key.clone());
1622							}
1623						}
1624					}
1625				}
1626				self.state_usage.tally_writes_nodes(ops, bytes);
1627				self.state_usage.tally_removed_nodes(removal, bytes_removal);
1628
1629				let mut ops: u64 = 0;
1630				let mut bytes: u64 = 0;
1631				for (key, value) in operation
1632					.storage_updates
1633					.iter()
1634					.chain(operation.child_storage_updates.iter().flat_map(|(_, s)| s.iter()))
1635				{
1636					ops += 1;
1637					bytes += key.len() as u64;
1638					if let Some(v) = value.as_ref() {
1639						bytes += v.len() as u64;
1640					}
1641				}
1642				self.state_usage.tally_writes(ops, bytes);
1643				let number_u64 = number.saturated_into::<u64>();
1644				let commit = self
1645					.storage
1646					.state_db
1647					.insert_block(&hash, number_u64, pending_block.header.parent_hash(), changeset)
1648					.map_err(|e: sc_state_db::Error<sp_database::error::DatabaseError>| {
1649						sp_blockchain::Error::from_state_db(e)
1650					})?;
1651				apply_state_commit(&mut transaction, commit);
1652				if number <= last_finalized_num {
1653					// Canonicalize in the db when re-importing existing blocks with state.
1654					let commit = self.storage.state_db.canonicalize_block(&hash).map_err(
1655						sp_blockchain::Error::from_state_db::<
1656							sc_state_db::Error<sp_database::error::DatabaseError>,
1657						>,
1658					)?;
1659					apply_state_commit(&mut transaction, commit);
1660					meta_updates.push(MetaUpdate {
1661						hash,
1662						number,
1663						is_best: false,
1664						is_finalized: true,
1665						with_state: true,
1666					});
1667				}
1668
1669				// Check if need to finalize. Genesis is always finalized instantly.
1670				let finalized = number_u64 == 0 || pending_block.leaf_state.is_final();
1671				finalized
1672			} else {
1673				(number.is_zero() && last_finalized_num.is_zero()) ||
1674					pending_block.leaf_state.is_final()
1675			};
1676
1677			let header = &pending_block.header;
1678			let is_best = pending_block.leaf_state.is_best();
1679			debug!(
1680				target: "db",
1681				"DB Commit {hash:?} ({number}), best={is_best}, state={}, existing={existing_header}, finalized={finalized}",
1682				operation.commit_state,
1683			);
1684
1685			self.state_usage.merge_sm(operation.old_state.usage_info());
1686
1687			// release state reference so that it can be finalized
1688			// VERY IMPORTANT
1689			drop(operation.old_state);
1690
1691			if finalized {
1692				// TODO: ensure best chain contains this block.
1693				self.ensure_sequential_finalization(header, Some(last_finalized_hash))?;
1694				let mut current_transaction_justifications = HashMap::new();
1695				self.note_finalized(
1696					&mut transaction,
1697					header,
1698					hash,
1699					operation.commit_state,
1700					&mut current_transaction_justifications,
1701					true,
1702				)?;
1703			} else {
1704				// canonicalize blocks which are old enough, regardless of finality.
1705				self.force_delayed_canonicalize(&mut transaction)?
1706			}
1707
1708			if !existing_header {
1709				// Add a new leaf if the block has the potential to be finalized.
1710				if number > last_finalized_num || last_finalized_num.is_zero() {
1711					let mut leaves = self.blockchain.leaves.write();
1712					leaves.import(hash, number, parent_hash);
1713					leaves.prepare_transaction(
1714						&mut transaction,
1715						columns::META,
1716						meta_keys::LEAF_PREFIX,
1717					);
1718				}
1719
1720				let mut children = children::read_children(
1721					&*self.storage.db,
1722					columns::META,
1723					meta_keys::CHILDREN_PREFIX,
1724					parent_hash,
1725				)?;
1726				if !children.contains(&hash) {
1727					children.push(hash);
1728					children::write_children(
1729						&mut transaction,
1730						columns::META,
1731						meta_keys::CHILDREN_PREFIX,
1732						parent_hash,
1733						children,
1734					);
1735				}
1736			}
1737
1738			let should_check_block_gap = !existing_header || !existing_body;
1739
1740			if should_check_block_gap {
1741				let insert_new_gap =
1742					|transaction: &mut Transaction<DbHash>,
1743					 new_gap: BlockGap<NumberFor<Block>>,
1744					 block_gap: &mut Option<BlockGap<NumberFor<Block>>>| {
1745						transaction.set(columns::META, meta_keys::BLOCK_GAP, &new_gap.encode());
1746						transaction.set(
1747							columns::META,
1748							meta_keys::BLOCK_GAP_VERSION,
1749							&BLOCK_GAP_CURRENT_VERSION.encode(),
1750						);
1751						block_gap.replace(new_gap);
1752					};
1753
1754				if let Some(mut gap) = block_gap {
1755					match gap.gap_type {
1756						BlockGapType::MissingHeaderAndBody =>
1757							if number == gap.start {
1758								gap.start += One::one();
1759								utils::insert_number_to_key_mapping(
1760									&mut transaction,
1761									columns::KEY_LOOKUP,
1762									number,
1763									hash,
1764								)?;
1765								if gap.start > gap.end {
1766									transaction.remove(columns::META, meta_keys::BLOCK_GAP);
1767									transaction.remove(columns::META, meta_keys::BLOCK_GAP_VERSION);
1768									block_gap = None;
1769									debug!(target: "db", "Removed block gap.");
1770								} else {
1771									insert_new_gap(&mut transaction, gap, &mut block_gap);
1772									debug!(target: "db", "Update block gap. {block_gap:?}");
1773								}
1774								block_gap_updated = true;
1775							},
1776						BlockGapType::MissingBody => {
1777							// Gap increased when syncing the header chain during fast sync.
1778							if number == gap.end + One::one() && !existing_body {
1779								gap.end += One::one();
1780								utils::insert_number_to_key_mapping(
1781									&mut transaction,
1782									columns::KEY_LOOKUP,
1783									number,
1784									hash,
1785								)?;
1786								insert_new_gap(&mut transaction, gap, &mut block_gap);
1787								debug!(target: "db", "Update block gap. {block_gap:?}");
1788								block_gap_updated = true;
1789							// Gap decreased when downloading the full blocks.
1790							} else if number == gap.start && existing_body {
1791								gap.start += One::one();
1792								if gap.start > gap.end {
1793									transaction.remove(columns::META, meta_keys::BLOCK_GAP);
1794									transaction.remove(columns::META, meta_keys::BLOCK_GAP_VERSION);
1795									block_gap = None;
1796									debug!(target: "db", "Removed block gap.");
1797								} else {
1798									insert_new_gap(&mut transaction, gap, &mut block_gap);
1799									debug!(target: "db", "Update block gap. {block_gap:?}");
1800								}
1801								block_gap_updated = true;
1802							}
1803						},
1804					}
1805				} else if operation.create_gap {
1806					if number > best_num + One::one() &&
1807						self.blockchain.header(parent_hash)?.is_none()
1808					{
1809						let gap = BlockGap {
1810							start: best_num + One::one(),
1811							end: number - One::one(),
1812							gap_type: BlockGapType::MissingHeaderAndBody,
1813						};
1814						insert_new_gap(&mut transaction, gap, &mut block_gap);
1815						block_gap_updated = true;
1816						debug!(target: "db", "Detected block gap (warp sync) {block_gap:?}");
1817					} else if number == best_num + One::one() &&
1818						self.blockchain.header(parent_hash)?.is_some() &&
1819						!existing_body
1820					{
1821						let gap = BlockGap {
1822							start: number,
1823							end: number,
1824							gap_type: BlockGapType::MissingBody,
1825						};
1826						insert_new_gap(&mut transaction, gap, &mut block_gap);
1827						block_gap_updated = true;
1828						debug!(target: "db", "Detected block gap (fast sync) {block_gap:?}");
1829					}
1830				}
1831			}
1832
1833			meta_updates.push(MetaUpdate {
1834				hash,
1835				number,
1836				is_best: pending_block.leaf_state.is_best(),
1837				is_finalized: finalized,
1838				with_state: operation.commit_state,
1839			});
1840			Some((pending_block.header, hash))
1841		} else {
1842			None
1843		};
1844
1845		if let Some(set_head) = operation.set_head {
1846			if let Some(header) =
1847				sc_client_api::blockchain::HeaderBackend::header(&self.blockchain, set_head)?
1848			{
1849				let number = header.number();
1850				let hash = header.hash();
1851
1852				self.set_head_with_transaction(&mut transaction, hash, (*number, hash))?;
1853
1854				meta_updates.push(MetaUpdate {
1855					hash,
1856					number: *number,
1857					is_best: true,
1858					is_finalized: false,
1859					with_state: false,
1860				});
1861			} else {
1862				return Err(sp_blockchain::Error::UnknownBlock(format!(
1863					"Cannot set head {set_head:?}",
1864				)));
1865			}
1866		}
1867
1868		self.storage.db.commit(transaction)?;
1869
1870		// `reset_storage == true` means the entire state got replaced.
1871		// In this case we optimize the `STATE` column to improve read performance.
1872		if operation.reset_storage {
1873			if let Err(e) = self.storage.db.optimize_db_col(columns::STATE) {
1874				warn!(target: "db", "Failed to optimize database after state import: {e:?}");
1875			}
1876		}
1877
1878		// Apply all in-memory state changes.
1879		// Code beyond this point can't fail.
1880
1881		if let Some((header, hash)) = imported {
1882			trace!(target: "db", "DB Commit done {hash:?}");
1883			let header_metadata = CachedHeaderMetadata::from(&header);
1884			self.blockchain.insert_header_metadata(header_metadata.hash, header_metadata);
1885			cache_header(&mut self.blockchain.header_cache.lock(), hash, Some(header));
1886		}
1887
1888		for m in meta_updates {
1889			self.blockchain.update_meta(m);
1890		}
1891		if block_gap_updated {
1892			self.blockchain.update_block_gap(block_gap);
1893		}
1894
1895		Ok(())
1896	}
1897
1898	// Write stuff to a transaction after a new block is finalized. This canonicalizes finalized
1899	// blocks. Fails if called with a block which was not a child of the last finalized block.
1900	/// `remove_displaced` can be set to `false` if this is not the last of many subsequent calls
1901	/// for performance reasons.
1902	fn note_finalized(
1903		&self,
1904		transaction: &mut Transaction<DbHash>,
1905		f_header: &Block::Header,
1906		f_hash: Block::Hash,
1907		with_state: bool,
1908		current_transaction_justifications: &mut HashMap<Block::Hash, Justification>,
1909		remove_displaced: bool,
1910	) -> ClientResult<()> {
1911		let f_num = *f_header.number();
1912
1913		let lookup_key = utils::number_and_hash_to_lookup_key(f_num, f_hash)?;
1914		if with_state {
1915			transaction.set_from_vec(columns::META, meta_keys::FINALIZED_STATE, lookup_key.clone());
1916		}
1917		transaction.set_from_vec(columns::META, meta_keys::FINALIZED_BLOCK, lookup_key);
1918
1919		let requires_canonicalization = match self.storage.state_db.last_canonicalized() {
1920			LastCanonicalized::None => true,
1921			LastCanonicalized::Block(b) => f_num.saturated_into::<u64>() > b,
1922			LastCanonicalized::NotCanonicalizing => false,
1923		};
1924
1925		if requires_canonicalization && sc_client_api::Backend::have_state_at(self, f_hash, f_num) {
1926			let commit = self.storage.state_db.canonicalize_block(&f_hash).map_err(
1927				sp_blockchain::Error::from_state_db::<
1928					sc_state_db::Error<sp_database::error::DatabaseError>,
1929				>,
1930			)?;
1931			apply_state_commit(transaction, commit);
1932		}
1933
1934		if remove_displaced {
1935			let new_displaced = self.blockchain.displaced_leaves_after_finalizing(
1936				f_hash,
1937				f_num,
1938				*f_header.parent_hash(),
1939			)?;
1940
1941			self.blockchain.leaves.write().remove_displaced_leaves(FinalizationOutcome::new(
1942				new_displaced.displaced_leaves.iter().copied(),
1943			));
1944
1945			if !matches!(self.blocks_pruning, BlocksPruning::KeepAll) {
1946				self.prune_displaced_branches(transaction, &new_displaced)?;
1947			}
1948		}
1949
1950		self.prune_blocks(transaction, f_num, current_transaction_justifications)?;
1951
1952		Ok(())
1953	}
1954
1955	fn prune_blocks(
1956		&self,
1957		transaction: &mut Transaction<DbHash>,
1958		finalized_number: NumberFor<Block>,
1959		current_transaction_justifications: &mut HashMap<Block::Hash, Justification>,
1960	) -> ClientResult<()> {
1961		if let BlocksPruning::Some(blocks_pruning) = self.blocks_pruning {
1962			// Always keep the last finalized block
1963			let keep = std::cmp::max(blocks_pruning, 1);
1964			if finalized_number >= keep.into() {
1965				let number = finalized_number.saturating_sub(keep.into());
1966
1967				// Before we prune a block, check if it is pinned
1968				if let Some(hash) = self.blockchain.hash(number)? {
1969					self.blockchain.insert_persisted_body_if_pinned(hash)?;
1970
1971					// If the block was finalized in this transaction, it will not be in the db
1972					// yet.
1973					if let Some(justification) = current_transaction_justifications.remove(&hash) {
1974						self.blockchain.insert_justifications_if_pinned(hash, justification);
1975					} else {
1976						self.blockchain.insert_persisted_justifications_if_pinned(hash)?;
1977					}
1978				};
1979
1980				self.prune_block(transaction, BlockId::<Block>::number(number))?;
1981			}
1982		}
1983		Ok(())
1984	}
1985
1986	fn prune_displaced_branches(
1987		&self,
1988		transaction: &mut Transaction<DbHash>,
1989		displaced: &DisplacedLeavesAfterFinalization<Block>,
1990	) -> ClientResult<()> {
1991		// Discard all blocks from displaced branches
1992		for &hash in displaced.displaced_blocks.iter() {
1993			self.blockchain.insert_persisted_body_if_pinned(hash)?;
1994			self.prune_block(transaction, BlockId::<Block>::hash(hash))?;
1995		}
1996		Ok(())
1997	}
1998
1999	fn prune_block(
2000		&self,
2001		transaction: &mut Transaction<DbHash>,
2002		id: BlockId<Block>,
2003	) -> ClientResult<()> {
2004		debug!(target: "db", "Removing block #{id}");
2005		utils::remove_from_db(
2006			transaction,
2007			&*self.storage.db,
2008			columns::KEY_LOOKUP,
2009			columns::BODY,
2010			id,
2011		)?;
2012		utils::remove_from_db(
2013			transaction,
2014			&*self.storage.db,
2015			columns::KEY_LOOKUP,
2016			columns::JUSTIFICATIONS,
2017			id,
2018		)?;
2019		if let Some(index) =
2020			read_db(&*self.storage.db, columns::KEY_LOOKUP, columns::BODY_INDEX, id)?
2021		{
2022			utils::remove_from_db(
2023				transaction,
2024				&*self.storage.db,
2025				columns::KEY_LOOKUP,
2026				columns::BODY_INDEX,
2027				id,
2028			)?;
2029			match Vec::<DbExtrinsic<Block>>::decode(&mut &index[..]) {
2030				Ok(index) =>
2031					for ex in index {
2032						if let DbExtrinsic::Indexed { hash, .. } = ex {
2033							transaction.release(columns::TRANSACTION, hash);
2034						}
2035					},
2036				Err(err) =>
2037					return Err(sp_blockchain::Error::Backend(format!(
2038						"Error decoding body list: {err}",
2039					))),
2040			}
2041		}
2042		Ok(())
2043	}
2044
2045	fn empty_state(&self) -> RecordStatsState<RefTrackingState<Block>, Block> {
2046		let root = EmptyStorage::<Block>::new().0; // Empty trie
2047		let db_state = DbStateBuilder::<HashingFor<Block>>::new(self.storage.clone(), root)
2048			.with_optional_cache(self.shared_trie_cache.as_ref().map(|c| c.local_cache_untrusted()))
2049			.build();
2050		let state = RefTrackingState::new(db_state, self.storage.clone(), None);
2051		RecordStatsState::new(state, None, self.state_usage.clone())
2052	}
2053}
2054
2055fn apply_state_commit(
2056	transaction: &mut Transaction<DbHash>,
2057	commit: sc_state_db::CommitSet<Vec<u8>>,
2058) {
2059	for (key, val) in commit.data.inserted.into_iter() {
2060		transaction.set_from_vec(columns::STATE, &key[..], val);
2061	}
2062	for key in commit.data.deleted.into_iter() {
2063		transaction.remove(columns::STATE, &key[..]);
2064	}
2065	for (key, val) in commit.meta.inserted.into_iter() {
2066		transaction.set_from_vec(columns::STATE_META, &key[..], val);
2067	}
2068	for key in commit.meta.deleted.into_iter() {
2069		transaction.remove(columns::STATE_META, &key[..]);
2070	}
2071}
2072
2073fn apply_index_ops<Block: BlockT>(
2074	transaction: &mut Transaction<DbHash>,
2075	body: Vec<Block::Extrinsic>,
2076	ops: Vec<IndexOperation>,
2077) -> Vec<u8> {
2078	let mut extrinsic_index: Vec<DbExtrinsic<Block>> = Vec::with_capacity(body.len());
2079	let mut index_map = HashMap::new();
2080	let mut renewed_map = HashMap::new();
2081	for op in ops {
2082		match op {
2083			IndexOperation::Insert { extrinsic, hash, size } => {
2084				index_map.insert(extrinsic, (hash, size));
2085			},
2086			IndexOperation::Renew { extrinsic, hash } => {
2087				renewed_map.insert(extrinsic, DbHash::from_slice(hash.as_ref()));
2088			},
2089		}
2090	}
2091	for (index, extrinsic) in body.into_iter().enumerate() {
2092		let db_extrinsic = if let Some(hash) = renewed_map.get(&(index as u32)) {
2093			// Bump ref counter
2094			let extrinsic = extrinsic.encode();
2095			transaction.reference(columns::TRANSACTION, DbHash::from_slice(hash.as_ref()));
2096			DbExtrinsic::Indexed { hash: *hash, header: extrinsic }
2097		} else {
2098			match index_map.get(&(index as u32)) {
2099				Some((hash, size)) => {
2100					let encoded = extrinsic.encode();
2101					if *size as usize <= encoded.len() {
2102						let offset = encoded.len() - *size as usize;
2103						transaction.store(
2104							columns::TRANSACTION,
2105							DbHash::from_slice(hash.as_ref()),
2106							encoded[offset..].to_vec(),
2107						);
2108						DbExtrinsic::Indexed {
2109							hash: DbHash::from_slice(hash.as_ref()),
2110							header: encoded[..offset].to_vec(),
2111						}
2112					} else {
2113						// Invalid indexed slice. Just store full data and don't index anything.
2114						DbExtrinsic::Full(extrinsic)
2115					}
2116				},
2117				_ => DbExtrinsic::Full(extrinsic),
2118			}
2119		};
2120		extrinsic_index.push(db_extrinsic);
2121	}
2122	debug!(
2123		target: "db",
2124		"DB transaction index: {} inserted, {} renewed, {} full",
2125		index_map.len(),
2126		renewed_map.len(),
2127		extrinsic_index.len() - index_map.len() - renewed_map.len(),
2128	);
2129	extrinsic_index.encode()
2130}
2131
2132fn apply_indexed_body<Block: BlockT>(transaction: &mut Transaction<DbHash>, body: Vec<Vec<u8>>) {
2133	for extrinsic in body {
2134		let hash = sp_runtime::traits::BlakeTwo256::hash(&extrinsic);
2135		transaction.store(columns::TRANSACTION, DbHash::from_slice(hash.as_ref()), extrinsic);
2136	}
2137}
2138
2139impl<Block> sc_client_api::backend::AuxStore for Backend<Block>
2140where
2141	Block: BlockT,
2142{
2143	fn insert_aux<
2144		'a,
2145		'b: 'a,
2146		'c: 'a,
2147		I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
2148		D: IntoIterator<Item = &'a &'b [u8]>,
2149	>(
2150		&self,
2151		insert: I,
2152		delete: D,
2153	) -> ClientResult<()> {
2154		let mut transaction = Transaction::new();
2155		for (k, v) in insert {
2156			transaction.set(columns::AUX, k, v);
2157		}
2158		for k in delete {
2159			transaction.remove(columns::AUX, k);
2160		}
2161		self.storage.db.commit(transaction)?;
2162		Ok(())
2163	}
2164
2165	fn get_aux(&self, key: &[u8]) -> ClientResult<Option<Vec<u8>>> {
2166		Ok(self.storage.db.get(columns::AUX, key))
2167	}
2168}
2169
2170impl<Block: BlockT> sc_client_api::backend::Backend<Block> for Backend<Block> {
2171	type BlockImportOperation = BlockImportOperation<Block>;
2172	type Blockchain = BlockchainDb<Block>;
2173	type State = RecordStatsState<RefTrackingState<Block>, Block>;
2174	type OffchainStorage = offchain::LocalStorage;
2175
2176	fn begin_operation(&self) -> ClientResult<Self::BlockImportOperation> {
2177		Ok(BlockImportOperation {
2178			pending_block: None,
2179			old_state: self.empty_state(),
2180			db_updates: PrefixedMemoryDB::default(),
2181			storage_updates: Default::default(),
2182			child_storage_updates: Default::default(),
2183			offchain_storage_updates: Default::default(),
2184			aux_ops: Vec::new(),
2185			finalized_blocks: Vec::new(),
2186			set_head: None,
2187			commit_state: false,
2188			create_gap: true,
2189			reset_storage: false,
2190			index_ops: Default::default(),
2191		})
2192	}
2193
2194	fn begin_state_operation(
2195		&self,
2196		operation: &mut Self::BlockImportOperation,
2197		block: Block::Hash,
2198	) -> ClientResult<()> {
2199		if block == Default::default() {
2200			operation.old_state = self.empty_state();
2201		} else {
2202			operation.old_state = self.state_at(block, TrieCacheContext::Untrusted)?;
2203		}
2204
2205		operation.commit_state = true;
2206		Ok(())
2207	}
2208
2209	fn commit_operation(&self, operation: Self::BlockImportOperation) -> ClientResult<()> {
2210		let usage = operation.old_state.usage_info();
2211		self.state_usage.merge_sm(usage);
2212
2213		if let Err(e) = self.try_commit_operation(operation) {
2214			let state_meta_db = StateMetaDb(self.storage.db.clone());
2215			self.storage
2216				.state_db
2217				.reset(state_meta_db)
2218				.map_err(sp_blockchain::Error::from_state_db)?;
2219			self.blockchain.clear_pinning_cache();
2220			Err(e)
2221		} else {
2222			self.storage.state_db.sync();
2223			Ok(())
2224		}
2225	}
2226
2227	fn finalize_block(
2228		&self,
2229		hash: Block::Hash,
2230		justification: Option<Justification>,
2231	) -> ClientResult<()> {
2232		let mut transaction = Transaction::new();
2233		let header = self.blockchain.expect_header(hash)?;
2234
2235		let mut current_transaction_justifications = HashMap::new();
2236		let m = self.finalize_block_with_transaction(
2237			&mut transaction,
2238			hash,
2239			&header,
2240			None,
2241			justification,
2242			&mut current_transaction_justifications,
2243			true,
2244		)?;
2245
2246		self.storage.db.commit(transaction)?;
2247		self.blockchain.update_meta(m);
2248		Ok(())
2249	}
2250
2251	fn append_justification(
2252		&self,
2253		hash: Block::Hash,
2254		justification: Justification,
2255	) -> ClientResult<()> {
2256		let mut transaction: Transaction<DbHash> = Transaction::new();
2257		let header = self.blockchain.expect_header(hash)?;
2258		let number = *header.number();
2259
2260		// Check if the block is finalized first.
2261		let is_descendent_of = is_descendent_of(&self.blockchain, None);
2262		let last_finalized = self.blockchain.last_finalized()?;
2263
2264		// We can do a quick check first, before doing a proper but more expensive check
2265		if number > self.blockchain.info().finalized_number ||
2266			(hash != last_finalized && !is_descendent_of(&hash, &last_finalized)?)
2267		{
2268			return Err(ClientError::NotInFinalizedChain);
2269		}
2270
2271		let justifications = if let Some(mut stored_justifications) =
2272			self.blockchain.justifications(hash)?
2273		{
2274			if !stored_justifications.append(justification) {
2275				return Err(ClientError::BadJustification("Duplicate consensus engine ID".into()));
2276			}
2277			stored_justifications
2278		} else {
2279			Justifications::from(justification)
2280		};
2281
2282		transaction.set_from_vec(
2283			columns::JUSTIFICATIONS,
2284			&utils::number_and_hash_to_lookup_key(number, hash)?,
2285			justifications.encode(),
2286		);
2287
2288		self.storage.db.commit(transaction)?;
2289
2290		Ok(())
2291	}
2292
2293	fn offchain_storage(&self) -> Option<Self::OffchainStorage> {
2294		Some(self.offchain_storage.clone())
2295	}
2296
2297	fn usage_info(&self) -> Option<UsageInfo> {
2298		let (io_stats, state_stats) = self.io_stats.take_or_else(|| {
2299			(
2300				// TODO: implement DB stats and cache size retrieval
2301				kvdb::IoStats::empty(),
2302				self.state_usage.take(),
2303			)
2304		});
2305		let database_cache = MemorySize::from_bytes(0);
2306		let state_cache = MemorySize::from_bytes(
2307			self.shared_trie_cache.as_ref().map_or(0, |c| c.used_memory_size()),
2308		);
2309
2310		Some(UsageInfo {
2311			memory: MemoryInfo { state_cache, database_cache },
2312			io: IoInfo {
2313				transactions: io_stats.transactions,
2314				bytes_read: io_stats.bytes_read,
2315				bytes_written: io_stats.bytes_written,
2316				writes: io_stats.writes,
2317				reads: io_stats.reads,
2318				average_transaction_size: io_stats.avg_transaction_size() as u64,
2319				state_reads: state_stats.reads.ops,
2320				state_writes: state_stats.writes.ops,
2321				state_writes_cache: state_stats.overlay_writes.ops,
2322				state_reads_cache: state_stats.cache_reads.ops,
2323				state_writes_nodes: state_stats.nodes_writes.ops,
2324			},
2325		})
2326	}
2327
2328	fn revert(
2329		&self,
2330		n: NumberFor<Block>,
2331		revert_finalized: bool,
2332	) -> ClientResult<(NumberFor<Block>, HashSet<Block::Hash>)> {
2333		let mut reverted_finalized = HashSet::new();
2334
2335		let info = self.blockchain.info();
2336
2337		let highest_leaf = self
2338			.blockchain
2339			.leaves
2340			.read()
2341			.highest_leaf()
2342			.and_then(|(n, h)| h.last().map(|h| (n, *h)));
2343
2344		let best_number = info.best_number;
2345		let best_hash = info.best_hash;
2346
2347		let finalized = info.finalized_number;
2348
2349		let revertible = best_number - finalized;
2350		let n = if !revert_finalized && revertible < n { revertible } else { n };
2351
2352		let (n, mut number_to_revert, mut hash_to_revert) = match highest_leaf {
2353			Some((l_n, l_h)) => (n + (l_n - best_number), l_n, l_h),
2354			None => (n, best_number, best_hash),
2355		};
2356
2357		let mut revert_blocks = || -> ClientResult<NumberFor<Block>> {
2358			for c in 0..n.saturated_into::<u64>() {
2359				if number_to_revert.is_zero() {
2360					return Ok(c.saturated_into::<NumberFor<Block>>());
2361				}
2362				let mut transaction = Transaction::new();
2363				let removed = self.blockchain.header(hash_to_revert)?.ok_or_else(|| {
2364					sp_blockchain::Error::UnknownBlock(format!(
2365						"Error reverting to {hash_to_revert}. Block header not found.",
2366					))
2367				})?;
2368				let removed_hash = hash_to_revert;
2369
2370				let prev_number = number_to_revert.saturating_sub(One::one());
2371				let prev_hash =
2372					if prev_number == best_number { best_hash } else { *removed.parent_hash() };
2373
2374				if !self.have_state_at(prev_hash, prev_number) {
2375					return Ok(c.saturated_into::<NumberFor<Block>>());
2376				}
2377
2378				match self.storage.state_db.revert_one() {
2379					Some(commit) => {
2380						apply_state_commit(&mut transaction, commit);
2381
2382						number_to_revert = prev_number;
2383						hash_to_revert = prev_hash;
2384
2385						let update_finalized = number_to_revert < finalized;
2386
2387						let key = utils::number_and_hash_to_lookup_key(
2388							number_to_revert,
2389							&hash_to_revert,
2390						)?;
2391						if update_finalized {
2392							transaction.set_from_vec(
2393								columns::META,
2394								meta_keys::FINALIZED_BLOCK,
2395								key.clone(),
2396							);
2397
2398							reverted_finalized.insert(removed_hash);
2399							if let Some((hash, _)) = self.blockchain.info().finalized_state {
2400								if hash == hash_to_revert {
2401									if !number_to_revert.is_zero() &&
2402										self.have_state_at(prev_hash, prev_number)
2403									{
2404										let lookup_key = utils::number_and_hash_to_lookup_key(
2405											prev_number,
2406											prev_hash,
2407										)?;
2408										transaction.set_from_vec(
2409											columns::META,
2410											meta_keys::FINALIZED_STATE,
2411											lookup_key,
2412										);
2413									} else {
2414										transaction
2415											.remove(columns::META, meta_keys::FINALIZED_STATE);
2416									}
2417								}
2418							}
2419						}
2420
2421						transaction.set_from_vec(columns::META, meta_keys::BEST_BLOCK, key);
2422						transaction.remove(columns::KEY_LOOKUP, removed_hash.as_ref());
2423						children::remove_children(
2424							&mut transaction,
2425							columns::META,
2426							meta_keys::CHILDREN_PREFIX,
2427							hash_to_revert,
2428						);
2429						self.prune_block(&mut transaction, BlockId::Hash(removed_hash))?;
2430						remove_from_db::<Block>(
2431							&mut transaction,
2432							&*self.storage.db,
2433							columns::KEY_LOOKUP,
2434							columns::HEADER,
2435							BlockId::Hash(removed_hash),
2436						)?;
2437
2438						self.storage.db.commit(transaction)?;
2439
2440						// Clean the cache
2441						self.blockchain.remove_header_metadata(removed_hash);
2442
2443						let is_best = number_to_revert < best_number;
2444
2445						self.blockchain.update_meta(MetaUpdate {
2446							hash: hash_to_revert,
2447							number: number_to_revert,
2448							is_best,
2449							is_finalized: update_finalized,
2450							with_state: false,
2451						});
2452					},
2453					None => return Ok(c.saturated_into::<NumberFor<Block>>()),
2454				}
2455			}
2456
2457			Ok(n)
2458		};
2459
2460		let reverted = revert_blocks()?;
2461
2462		let revert_leaves = || -> ClientResult<()> {
2463			let mut transaction = Transaction::new();
2464			let mut leaves = self.blockchain.leaves.write();
2465
2466			leaves.revert(hash_to_revert, number_to_revert).into_iter().try_for_each(
2467				|(h, _)| {
2468					self.blockchain.remove_header_metadata(h);
2469					transaction.remove(columns::KEY_LOOKUP, h.as_ref());
2470
2471					self.prune_block(&mut transaction, BlockId::Hash(h))?;
2472					remove_from_db::<Block>(
2473						&mut transaction,
2474						&*self.storage.db,
2475						columns::KEY_LOOKUP,
2476						columns::HEADER,
2477						BlockId::Hash(h),
2478					)?;
2479
2480					Ok::<_, ClientError>(())
2481				},
2482			)?;
2483			leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX);
2484			self.storage.db.commit(transaction)?;
2485
2486			Ok(())
2487		};
2488
2489		revert_leaves()?;
2490
2491		Ok((reverted, reverted_finalized))
2492	}
2493
2494	fn remove_leaf_block(&self, hash: Block::Hash) -> ClientResult<()> {
2495		let best_hash = self.blockchain.info().best_hash;
2496
2497		if best_hash == hash {
2498			return Err(sp_blockchain::Error::Backend(format!("Can't remove best block {hash:?}")));
2499		}
2500
2501		let hdr = self.blockchain.header_metadata(hash)?;
2502		if !self.have_state_at(hash, hdr.number) {
2503			return Err(sp_blockchain::Error::UnknownBlock(format!(
2504				"State already discarded for {hash:?}",
2505			)));
2506		}
2507
2508		let mut leaves = self.blockchain.leaves.write();
2509		if !leaves.contains(hdr.number, hash) {
2510			return Err(sp_blockchain::Error::Backend(format!(
2511				"Can't remove non-leaf block {hash:?}",
2512			)));
2513		}
2514
2515		let mut transaction = Transaction::new();
2516		if let Some(commit) = self.storage.state_db.remove(&hash) {
2517			apply_state_commit(&mut transaction, commit);
2518		}
2519		transaction.remove(columns::KEY_LOOKUP, hash.as_ref());
2520
2521		let children: Vec<_> = self
2522			.blockchain()
2523			.children(hdr.parent)?
2524			.into_iter()
2525			.filter(|child_hash| *child_hash != hash)
2526			.collect();
2527		let parent_leaf = if children.is_empty() {
2528			children::remove_children(
2529				&mut transaction,
2530				columns::META,
2531				meta_keys::CHILDREN_PREFIX,
2532				hdr.parent,
2533			);
2534			Some(hdr.parent)
2535		} else {
2536			children::write_children(
2537				&mut transaction,
2538				columns::META,
2539				meta_keys::CHILDREN_PREFIX,
2540				hdr.parent,
2541				children,
2542			);
2543			None
2544		};
2545
2546		let remove_outcome = leaves.remove(hash, hdr.number, parent_leaf);
2547		leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX);
2548		if let Err(e) = self.storage.db.commit(transaction) {
2549			if let Some(outcome) = remove_outcome {
2550				leaves.undo().undo_remove(outcome);
2551			}
2552			return Err(e.into());
2553		}
2554		self.blockchain().remove_header_metadata(hash);
2555		Ok(())
2556	}
2557
2558	fn blockchain(&self) -> &BlockchainDb<Block> {
2559		&self.blockchain
2560	}
2561
2562	fn state_at(
2563		&self,
2564		hash: Block::Hash,
2565		trie_cache_context: TrieCacheContext,
2566	) -> ClientResult<Self::State> {
2567		if hash == self.blockchain.meta.read().genesis_hash {
2568			if let Some(genesis_state) = &*self.genesis_state.read() {
2569				let root = genesis_state.root;
2570				let db_state =
2571					DbStateBuilder::<HashingFor<Block>>::new(genesis_state.clone(), root)
2572						.with_optional_cache(self.shared_trie_cache.as_ref().map(|c| {
2573							if matches!(trie_cache_context, TrieCacheContext::Trusted) {
2574								c.local_cache_trusted()
2575							} else {
2576								c.local_cache_untrusted()
2577							}
2578						}))
2579						.build();
2580
2581				let state = RefTrackingState::new(db_state, self.storage.clone(), None);
2582				return Ok(RecordStatsState::new(state, None, self.state_usage.clone()));
2583			}
2584		}
2585
2586		match self.blockchain.header_metadata(hash) {
2587			Ok(ref hdr) => {
2588				let hint = || {
2589					sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref())
2590						.unwrap_or(None)
2591						.is_some()
2592				};
2593
2594				if let Ok(()) =
2595					self.storage.state_db.pin(&hash, hdr.number.saturated_into::<u64>(), hint)
2596				{
2597					let root = hdr.state_root;
2598					let db_state =
2599						DbStateBuilder::<HashingFor<Block>>::new(self.storage.clone(), root)
2600							.with_optional_cache(self.shared_trie_cache.as_ref().map(|c| {
2601								if matches!(trie_cache_context, TrieCacheContext::Trusted) {
2602									c.local_cache_trusted()
2603								} else {
2604									c.local_cache_untrusted()
2605								}
2606							}))
2607							.build();
2608					let state = RefTrackingState::new(db_state, self.storage.clone(), Some(hash));
2609					Ok(RecordStatsState::new(state, Some(hash), self.state_usage.clone()))
2610				} else {
2611					Err(sp_blockchain::Error::UnknownBlock(format!(
2612						"State already discarded for {hash:?}",
2613					)))
2614				}
2615			},
2616			Err(e) => Err(e),
2617		}
2618	}
2619
2620	fn have_state_at(&self, hash: Block::Hash, number: NumberFor<Block>) -> bool {
2621		if self.is_archive {
2622			match self.blockchain.header_metadata(hash) {
2623				Ok(header) => sp_state_machine::Storage::get(
2624					self.storage.as_ref(),
2625					&header.state_root,
2626					(&[], None),
2627				)
2628				.unwrap_or(None)
2629				.is_some(),
2630				_ => false,
2631			}
2632		} else {
2633			match self.storage.state_db.is_pruned(&hash, number.saturated_into::<u64>()) {
2634				IsPruned::Pruned => false,
2635				IsPruned::NotPruned => true,
2636				IsPruned::MaybePruned => match self.blockchain.header_metadata(hash) {
2637					Ok(header) => sp_state_machine::Storage::get(
2638						self.storage.as_ref(),
2639						&header.state_root,
2640						(&[], None),
2641					)
2642					.unwrap_or(None)
2643					.is_some(),
2644					_ => false,
2645				},
2646			}
2647		}
2648	}
2649
2650	fn get_import_lock(&self) -> &RwLock<()> {
2651		&self.import_lock
2652	}
2653
2654	fn requires_full_sync(&self) -> bool {
2655		matches!(
2656			self.storage.state_db.pruning_mode(),
2657			PruningMode::ArchiveAll | PruningMode::ArchiveCanonical
2658		)
2659	}
2660
2661	fn pin_block(&self, hash: <Block as BlockT>::Hash) -> sp_blockchain::Result<()> {
2662		let hint = || {
2663			let header_metadata = self.blockchain.header_metadata(hash);
2664			header_metadata
2665				.map(|hdr| {
2666					sc_state_db::NodeDb::get(self.storage.as_ref(), hdr.state_root.as_ref())
2667						.unwrap_or(None)
2668						.is_some()
2669				})
2670				.unwrap_or(false)
2671		};
2672
2673		if let Some(number) = self.blockchain.number(hash)? {
2674			self.storage.state_db.pin(&hash, number.saturated_into::<u64>(), hint).map_err(
2675				|_| {
2676					sp_blockchain::Error::UnknownBlock(format!(
2677						"Unable to pin: state already discarded for `{hash:?}`",
2678					))
2679				},
2680			)?;
2681		} else {
2682			return Err(ClientError::UnknownBlock(format!(
2683				"Can not pin block with hash `{hash:?}`. Block not found.",
2684			)));
2685		}
2686
2687		if self.blocks_pruning != BlocksPruning::KeepAll {
2688			// Only increase reference count for this hash. Value is loaded once we prune.
2689			self.blockchain.bump_ref(hash);
2690		}
2691		Ok(())
2692	}
2693
2694	fn unpin_block(&self, hash: <Block as BlockT>::Hash) {
2695		self.storage.state_db.unpin(&hash);
2696
2697		if self.blocks_pruning != BlocksPruning::KeepAll {
2698			self.blockchain.unpin(hash);
2699		}
2700	}
2701}
2702
2703impl<Block: BlockT> sc_client_api::backend::LocalBackend<Block> for Backend<Block> {}
2704
2705#[cfg(test)]
2706pub(crate) mod tests {
2707	use super::*;
2708	use crate::{columns, utils::number_and_hash_to_lookup_key};
2709	use hash_db::{HashDB, EMPTY_PREFIX};
2710	use sc_client_api::{
2711		backend::{Backend as BTrait, BlockImportOperation as Op},
2712		blockchain::Backend as BLBTrait,
2713	};
2714	use sp_blockchain::{lowest_common_ancestor, tree_route};
2715	use sp_core::H256;
2716	use sp_runtime::{
2717		testing::{Block as RawBlock, Header, MockCallU64, TestXt},
2718		traits::{BlakeTwo256, Hash},
2719		ConsensusEngineId, StateVersion,
2720	};
2721
2722	const CONS0_ENGINE_ID: ConsensusEngineId = *b"CON0";
2723	const CONS1_ENGINE_ID: ConsensusEngineId = *b"CON1";
2724
2725	type UncheckedXt = TestXt<MockCallU64, ()>;
2726	pub(crate) type Block = RawBlock<UncheckedXt>;
2727
2728	pub fn insert_header(
2729		backend: &Backend<Block>,
2730		number: u64,
2731		parent_hash: H256,
2732		changes: Option<Vec<(Vec<u8>, Vec<u8>)>>,
2733		extrinsics_root: H256,
2734	) -> H256 {
2735		insert_block(backend, number, parent_hash, changes, extrinsics_root, Vec::new(), None)
2736			.unwrap()
2737	}
2738
2739	pub fn insert_block(
2740		backend: &Backend<Block>,
2741		number: u64,
2742		parent_hash: H256,
2743		_changes: Option<Vec<(Vec<u8>, Vec<u8>)>>,
2744		extrinsics_root: H256,
2745		body: Vec<UncheckedXt>,
2746		transaction_index: Option<Vec<IndexOperation>>,
2747	) -> Result<H256, sp_blockchain::Error> {
2748		use sp_runtime::testing::Digest;
2749
2750		let digest = Digest::default();
2751		let mut header =
2752			Header { number, parent_hash, state_root: Default::default(), digest, extrinsics_root };
2753
2754		let block_hash = if number == 0 { Default::default() } else { parent_hash };
2755		let mut op = backend.begin_operation().unwrap();
2756		backend.begin_state_operation(&mut op, block_hash).unwrap();
2757		if let Some(index) = transaction_index {
2758			op.update_transaction_index(index).unwrap();
2759		}
2760
2761		// Insert some fake data to ensure that the block can be found in the state column.
2762		let (root, overlay) = op.old_state.storage_root(
2763			vec![(block_hash.as_ref(), Some(block_hash.as_ref()))].into_iter(),
2764			StateVersion::V1,
2765		);
2766		op.update_db_storage(overlay).unwrap();
2767		header.state_root = root.into();
2768
2769		op.set_block_data(header.clone(), Some(body), None, None, NewBlockState::Best)
2770			.unwrap();
2771
2772		backend.commit_operation(op)?;
2773
2774		Ok(header.hash())
2775	}
2776
2777	pub fn insert_disconnected_header(
2778		backend: &Backend<Block>,
2779		number: u64,
2780		parent_hash: H256,
2781		extrinsics_root: H256,
2782		best: bool,
2783	) -> H256 {
2784		use sp_runtime::testing::Digest;
2785
2786		let digest = Digest::default();
2787		let header =
2788			Header { number, parent_hash, state_root: Default::default(), digest, extrinsics_root };
2789
2790		let mut op = backend.begin_operation().unwrap();
2791
2792		op.set_block_data(
2793			header.clone(),
2794			Some(vec![]),
2795			None,
2796			None,
2797			if best { NewBlockState::Best } else { NewBlockState::Normal },
2798		)
2799		.unwrap();
2800
2801		backend.commit_operation(op).unwrap();
2802
2803		header.hash()
2804	}
2805
2806	pub fn insert_header_no_head(
2807		backend: &Backend<Block>,
2808		number: u64,
2809		parent_hash: H256,
2810		extrinsics_root: H256,
2811	) -> H256 {
2812		use sp_runtime::testing::Digest;
2813
2814		let digest = Digest::default();
2815		let mut header =
2816			Header { number, parent_hash, state_root: Default::default(), digest, extrinsics_root };
2817		let mut op = backend.begin_operation().unwrap();
2818
2819		let root = backend
2820			.state_at(parent_hash, TrieCacheContext::Untrusted)
2821			.unwrap_or_else(|_| {
2822				if parent_hash == Default::default() {
2823					backend.empty_state()
2824				} else {
2825					panic!("Unknown block: {parent_hash:?}")
2826				}
2827			})
2828			.storage_root(
2829				vec![(parent_hash.as_ref(), Some(parent_hash.as_ref()))].into_iter(),
2830				StateVersion::V1,
2831			)
2832			.0;
2833		header.state_root = root.into();
2834
2835		op.set_block_data(header.clone(), None, None, None, NewBlockState::Normal)
2836			.unwrap();
2837		backend.commit_operation(op).unwrap();
2838
2839		header.hash()
2840	}
2841
2842	#[test]
2843	fn block_hash_inserted_correctly() {
2844		let backing = {
2845			let db = Backend::<Block>::new_test(1, 0);
2846			for i in 0..10 {
2847				assert!(db.blockchain().hash(i).unwrap().is_none());
2848
2849				{
2850					let hash = if i == 0 {
2851						Default::default()
2852					} else {
2853						db.blockchain.hash(i - 1).unwrap().unwrap()
2854					};
2855
2856					let mut op = db.begin_operation().unwrap();
2857					db.begin_state_operation(&mut op, hash).unwrap();
2858					let header = Header {
2859						number: i,
2860						parent_hash: hash,
2861						state_root: Default::default(),
2862						digest: Default::default(),
2863						extrinsics_root: Default::default(),
2864					};
2865
2866					op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best)
2867						.unwrap();
2868					db.commit_operation(op).unwrap();
2869				}
2870
2871				assert!(db.blockchain().hash(i).unwrap().is_some())
2872			}
2873			db.storage.db.clone()
2874		};
2875
2876		let backend = Backend::<Block>::new(
2877			DatabaseSettings {
2878				trie_cache_maximum_size: Some(16 * 1024 * 1024),
2879				state_pruning: Some(PruningMode::blocks_pruning(1)),
2880				source: DatabaseSource::Custom { db: backing, require_create_flag: false },
2881				blocks_pruning: BlocksPruning::KeepFinalized,
2882				metrics_registry: None,
2883			},
2884			0,
2885		)
2886		.unwrap();
2887		assert_eq!(backend.blockchain().info().best_number, 9);
2888		for i in 0..10 {
2889			assert!(backend.blockchain().hash(i).unwrap().is_some())
2890		}
2891	}
2892
2893	#[test]
2894	fn set_state_data() {
2895		set_state_data_inner(StateVersion::V0);
2896		set_state_data_inner(StateVersion::V1);
2897	}
2898	fn set_state_data_inner(state_version: StateVersion) {
2899		let db = Backend::<Block>::new_test(2, 0);
2900		let hash = {
2901			let mut op = db.begin_operation().unwrap();
2902			let mut header = Header {
2903				number: 0,
2904				parent_hash: Default::default(),
2905				state_root: Default::default(),
2906				digest: Default::default(),
2907				extrinsics_root: Default::default(),
2908			};
2909
2910			let storage = vec![(vec![1, 3, 5], vec![2, 4, 6]), (vec![1, 2, 3], vec![9, 9, 9])];
2911
2912			header.state_root = op
2913				.old_state
2914				.storage_root(storage.iter().map(|(x, y)| (&x[..], Some(&y[..]))), state_version)
2915				.0
2916				.into();
2917			let hash = header.hash();
2918
2919			op.reset_storage(
2920				Storage {
2921					top: storage.into_iter().collect(),
2922					children_default: Default::default(),
2923				},
2924				state_version,
2925			)
2926			.unwrap();
2927			op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best)
2928				.unwrap();
2929
2930			db.commit_operation(op).unwrap();
2931
2932			let state = db.state_at(hash, TrieCacheContext::Untrusted).unwrap();
2933
2934			assert_eq!(state.storage(&[1, 3, 5]).unwrap(), Some(vec![2, 4, 6]));
2935			assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9]));
2936			assert_eq!(state.storage(&[5, 5, 5]).unwrap(), None);
2937
2938			hash
2939		};
2940
2941		{
2942			let mut op = db.begin_operation().unwrap();
2943			db.begin_state_operation(&mut op, hash).unwrap();
2944			let mut header = Header {
2945				number: 1,
2946				parent_hash: hash,
2947				state_root: Default::default(),
2948				digest: Default::default(),
2949				extrinsics_root: Default::default(),
2950			};
2951
2952			let storage = vec![(vec![1, 3, 5], None), (vec![5, 5, 5], Some(vec![4, 5, 6]))];
2953
2954			let (root, overlay) = op.old_state.storage_root(
2955				storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))),
2956				state_version,
2957			);
2958			op.update_db_storage(overlay).unwrap();
2959			header.state_root = root.into();
2960
2961			op.update_storage(storage, Vec::new()).unwrap();
2962			op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best)
2963				.unwrap();
2964
2965			db.commit_operation(op).unwrap();
2966
2967			let state = db.state_at(header.hash(), TrieCacheContext::Untrusted).unwrap();
2968
2969			assert_eq!(state.storage(&[1, 3, 5]).unwrap(), None);
2970			assert_eq!(state.storage(&[1, 2, 3]).unwrap(), Some(vec![9, 9, 9]));
2971			assert_eq!(state.storage(&[5, 5, 5]).unwrap(), Some(vec![4, 5, 6]));
2972		}
2973	}
2974
2975	#[test]
2976	fn delete_only_when_negative_rc() {
2977		sp_tracing::try_init_simple();
2978		let state_version = StateVersion::default();
2979		let key;
2980		let backend = Backend::<Block>::new_test(1, 0);
2981
2982		let hash = {
2983			let mut op = backend.begin_operation().unwrap();
2984			backend.begin_state_operation(&mut op, Default::default()).unwrap();
2985			let mut header = Header {
2986				number: 0,
2987				parent_hash: Default::default(),
2988				state_root: Default::default(),
2989				digest: Default::default(),
2990				extrinsics_root: Default::default(),
2991			};
2992
2993			header.state_root =
2994				op.old_state.storage_root(std::iter::empty(), state_version).0.into();
2995			let hash = header.hash();
2996
2997			op.reset_storage(
2998				Storage { top: Default::default(), children_default: Default::default() },
2999				state_version,
3000			)
3001			.unwrap();
3002
3003			key = op.db_updates.insert(EMPTY_PREFIX, b"hello");
3004			op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best)
3005				.unwrap();
3006
3007			backend.commit_operation(op).unwrap();
3008			assert_eq!(
3009				backend
3010					.storage
3011					.db
3012					.get(columns::STATE, &sp_trie::prefixed_key::<BlakeTwo256>(&key, EMPTY_PREFIX))
3013					.unwrap(),
3014				&b"hello"[..]
3015			);
3016			hash
3017		};
3018
3019		let hashof1 = {
3020			let mut op = backend.begin_operation().unwrap();
3021			backend.begin_state_operation(&mut op, hash).unwrap();
3022			let mut header = Header {
3023				number: 1,
3024				parent_hash: hash,
3025				state_root: Default::default(),
3026				digest: Default::default(),
3027				extrinsics_root: Default::default(),
3028			};
3029
3030			let storage: Vec<(_, _)> = vec![];
3031
3032			header.state_root = op
3033				.old_state
3034				.storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version)
3035				.0
3036				.into();
3037			let hash = header.hash();
3038
3039			op.db_updates.insert(EMPTY_PREFIX, b"hello");
3040			op.db_updates.remove(&key, EMPTY_PREFIX);
3041			op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best)
3042				.unwrap();
3043
3044			backend.commit_operation(op).unwrap();
3045			assert_eq!(
3046				backend
3047					.storage
3048					.db
3049					.get(columns::STATE, &sp_trie::prefixed_key::<BlakeTwo256>(&key, EMPTY_PREFIX))
3050					.unwrap(),
3051				&b"hello"[..]
3052			);
3053			hash
3054		};
3055
3056		let hashof2 = {
3057			let mut op = backend.begin_operation().unwrap();
3058			backend.begin_state_operation(&mut op, hashof1).unwrap();
3059			let mut header = Header {
3060				number: 2,
3061				parent_hash: hashof1,
3062				state_root: Default::default(),
3063				digest: Default::default(),
3064				extrinsics_root: Default::default(),
3065			};
3066
3067			let storage: Vec<(_, _)> = vec![];
3068
3069			header.state_root = op
3070				.old_state
3071				.storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version)
3072				.0
3073				.into();
3074			let hash = header.hash();
3075
3076			op.db_updates.remove(&key, EMPTY_PREFIX);
3077			op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best)
3078				.unwrap();
3079
3080			backend.commit_operation(op).unwrap();
3081
3082			assert!(backend
3083				.storage
3084				.db
3085				.get(columns::STATE, &sp_trie::prefixed_key::<BlakeTwo256>(&key, EMPTY_PREFIX))
3086				.is_some());
3087			hash
3088		};
3089
3090		let hashof3 = {
3091			let mut op = backend.begin_operation().unwrap();
3092			backend.begin_state_operation(&mut op, hashof2).unwrap();
3093			let mut header = Header {
3094				number: 3,
3095				parent_hash: hashof2,
3096				state_root: Default::default(),
3097				digest: Default::default(),
3098				extrinsics_root: Default::default(),
3099			};
3100
3101			let storage: Vec<(_, _)> = vec![];
3102
3103			header.state_root = op
3104				.old_state
3105				.storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version)
3106				.0
3107				.into();
3108			let hash = header.hash();
3109
3110			op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best)
3111				.unwrap();
3112
3113			backend.commit_operation(op).unwrap();
3114			hash
3115		};
3116
3117		let hashof4 = {
3118			let mut op = backend.begin_operation().unwrap();
3119			backend.begin_state_operation(&mut op, hashof3).unwrap();
3120			let mut header = Header {
3121				number: 4,
3122				parent_hash: hashof3,
3123				state_root: Default::default(),
3124				digest: Default::default(),
3125				extrinsics_root: Default::default(),
3126			};
3127
3128			let storage: Vec<(_, _)> = vec![];
3129
3130			header.state_root = op
3131				.old_state
3132				.storage_root(storage.iter().cloned().map(|(x, y)| (x, Some(y))), state_version)
3133				.0
3134				.into();
3135			let hash = header.hash();
3136
3137			op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Best)
3138				.unwrap();
3139
3140			backend.commit_operation(op).unwrap();
3141			assert!(backend
3142				.storage
3143				.db
3144				.get(columns::STATE, &sp_trie::prefixed_key::<BlakeTwo256>(&key, EMPTY_PREFIX))
3145				.is_none());
3146			hash
3147		};
3148
3149		backend.finalize_block(hashof1, None).unwrap();
3150		backend.finalize_block(hashof2, None).unwrap();
3151		backend.finalize_block(hashof3, None).unwrap();
3152		backend.finalize_block(hashof4, None).unwrap();
3153		assert!(backend
3154			.storage
3155			.db
3156			.get(columns::STATE, &sp_trie::prefixed_key::<BlakeTwo256>(&key, EMPTY_PREFIX))
3157			.is_none());
3158	}
3159
3160	#[test]
3161	fn tree_route_works() {
3162		let backend = Backend::<Block>::new_test(1000, 100);
3163		let blockchain = backend.blockchain();
3164		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3165
3166		// fork from genesis: 3 prong.
3167		let a1 = insert_header(&backend, 1, block0, None, Default::default());
3168		let a2 = insert_header(&backend, 2, a1, None, Default::default());
3169		let a3 = insert_header(&backend, 3, a2, None, Default::default());
3170
3171		// fork from genesis: 2 prong.
3172		let b1 = insert_header(&backend, 1, block0, None, H256::from([1; 32]));
3173		let b2 = insert_header(&backend, 2, b1, None, Default::default());
3174
3175		{
3176			let tree_route = tree_route(blockchain, a1, a1).unwrap();
3177
3178			assert_eq!(tree_route.common_block().hash, a1);
3179			assert!(tree_route.retracted().is_empty());
3180			assert!(tree_route.enacted().is_empty());
3181		}
3182
3183		{
3184			let tree_route = tree_route(blockchain, a3, b2).unwrap();
3185
3186			assert_eq!(tree_route.common_block().hash, block0);
3187			assert_eq!(
3188				tree_route.retracted().iter().map(|r| r.hash).collect::<Vec<_>>(),
3189				vec![a3, a2, a1]
3190			);
3191			assert_eq!(
3192				tree_route.enacted().iter().map(|r| r.hash).collect::<Vec<_>>(),
3193				vec![b1, b2]
3194			);
3195		}
3196
3197		{
3198			let tree_route = tree_route(blockchain, a1, a3).unwrap();
3199
3200			assert_eq!(tree_route.common_block().hash, a1);
3201			assert!(tree_route.retracted().is_empty());
3202			assert_eq!(
3203				tree_route.enacted().iter().map(|r| r.hash).collect::<Vec<_>>(),
3204				vec![a2, a3]
3205			);
3206		}
3207
3208		{
3209			let tree_route = tree_route(blockchain, a3, a1).unwrap();
3210
3211			assert_eq!(tree_route.common_block().hash, a1);
3212			assert_eq!(
3213				tree_route.retracted().iter().map(|r| r.hash).collect::<Vec<_>>(),
3214				vec![a3, a2]
3215			);
3216			assert!(tree_route.enacted().is_empty());
3217		}
3218
3219		{
3220			let tree_route = tree_route(blockchain, a2, a2).unwrap();
3221
3222			assert_eq!(tree_route.common_block().hash, a2);
3223			assert!(tree_route.retracted().is_empty());
3224			assert!(tree_route.enacted().is_empty());
3225		}
3226	}
3227
3228	#[test]
3229	fn tree_route_child() {
3230		let backend = Backend::<Block>::new_test(1000, 100);
3231		let blockchain = backend.blockchain();
3232
3233		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3234		let block1 = insert_header(&backend, 1, block0, None, Default::default());
3235
3236		{
3237			let tree_route = tree_route(blockchain, block0, block1).unwrap();
3238
3239			assert_eq!(tree_route.common_block().hash, block0);
3240			assert!(tree_route.retracted().is_empty());
3241			assert_eq!(
3242				tree_route.enacted().iter().map(|r| r.hash).collect::<Vec<_>>(),
3243				vec![block1]
3244			);
3245		}
3246	}
3247
3248	#[test]
3249	fn lowest_common_ancestor_works() {
3250		let backend = Backend::<Block>::new_test(1000, 100);
3251		let blockchain = backend.blockchain();
3252		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3253
3254		// fork from genesis: 3 prong.
3255		let a1 = insert_header(&backend, 1, block0, None, Default::default());
3256		let a2 = insert_header(&backend, 2, a1, None, Default::default());
3257		let a3 = insert_header(&backend, 3, a2, None, Default::default());
3258
3259		// fork from genesis: 2 prong.
3260		let b1 = insert_header(&backend, 1, block0, None, H256::from([1; 32]));
3261		let b2 = insert_header(&backend, 2, b1, None, Default::default());
3262
3263		{
3264			let lca = lowest_common_ancestor(blockchain, a3, b2).unwrap();
3265
3266			assert_eq!(lca.hash, block0);
3267			assert_eq!(lca.number, 0);
3268		}
3269
3270		{
3271			let lca = lowest_common_ancestor(blockchain, a1, a3).unwrap();
3272
3273			assert_eq!(lca.hash, a1);
3274			assert_eq!(lca.number, 1);
3275		}
3276
3277		{
3278			let lca = lowest_common_ancestor(blockchain, a3, a1).unwrap();
3279
3280			assert_eq!(lca.hash, a1);
3281			assert_eq!(lca.number, 1);
3282		}
3283
3284		{
3285			let lca = lowest_common_ancestor(blockchain, a2, a3).unwrap();
3286
3287			assert_eq!(lca.hash, a2);
3288			assert_eq!(lca.number, 2);
3289		}
3290
3291		{
3292			let lca = lowest_common_ancestor(blockchain, a2, a1).unwrap();
3293
3294			assert_eq!(lca.hash, a1);
3295			assert_eq!(lca.number, 1);
3296		}
3297
3298		{
3299			let lca = lowest_common_ancestor(blockchain, a2, a2).unwrap();
3300
3301			assert_eq!(lca.hash, a2);
3302			assert_eq!(lca.number, 2);
3303		}
3304	}
3305
3306	#[test]
3307	fn displaced_leaves_after_finalizing_works_with_disconnect() {
3308		// In this test we will create a situation that can typically happen after warp sync.
3309		// The situation looks like this:
3310		// g -> <unimported> -> a3 -> a4
3311		// Basically there is a gap of unimported blocks at some point in the chain.
3312		let backend = Backend::<Block>::new_test(1000, 100);
3313		let blockchain = backend.blockchain();
3314		let genesis_number = 0;
3315		let genesis_hash =
3316			insert_header(&backend, genesis_number, Default::default(), None, Default::default());
3317
3318		let a3_number = 3;
3319		let a3_hash = insert_disconnected_header(
3320			&backend,
3321			a3_number,
3322			H256::from([200; 32]),
3323			H256::from([1; 32]),
3324			true,
3325		);
3326
3327		let a4_number = 4;
3328		let a4_hash =
3329			insert_disconnected_header(&backend, a4_number, a3_hash, H256::from([2; 32]), true);
3330		{
3331			let displaced = blockchain
3332				.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([200; 32]))
3333				.unwrap();
3334			assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, genesis_hash]);
3335			assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]);
3336			assert_eq!(displaced.displaced_blocks, vec![]);
3337		}
3338
3339		{
3340			let displaced = blockchain
3341				.displaced_leaves_after_finalizing(a4_hash, a4_number, a3_hash)
3342				.unwrap();
3343			assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, genesis_hash]);
3344			assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]);
3345			assert_eq!(displaced.displaced_blocks, vec![]);
3346		}
3347
3348		// Import block a1 which has the genesis block as parent.
3349		// g -> a1 -> <unimported> -> a3(f) -> a4
3350		let a1_number = 1;
3351		let a1_hash = insert_disconnected_header(
3352			&backend,
3353			a1_number,
3354			genesis_hash,
3355			H256::from([123; 32]),
3356			false,
3357		);
3358		{
3359			let displaced = blockchain
3360				.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([2; 32]))
3361				.unwrap();
3362			assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, a1_hash]);
3363			assert_eq!(displaced.displaced_leaves, vec![]);
3364			assert_eq!(displaced.displaced_blocks, vec![]);
3365		}
3366
3367		// Import block b1 which has the genesis block as parent.
3368		// g -> a1 -> <unimported> -> a3(f) -> a4
3369		//  \-> b1
3370		let b1_number = 1;
3371		let b1_hash = insert_disconnected_header(
3372			&backend,
3373			b1_number,
3374			genesis_hash,
3375			H256::from([124; 32]),
3376			false,
3377		);
3378		{
3379			let displaced = blockchain
3380				.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([2; 32]))
3381				.unwrap();
3382			assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, a1_hash, b1_hash]);
3383			assert_eq!(displaced.displaced_leaves, vec![]);
3384			assert_eq!(displaced.displaced_blocks, vec![]);
3385		}
3386
3387		// If branch of b blocks is higher in number than a branch, we
3388		// should still not prune disconnected leafs.
3389		// g -> a1 -> <unimported> -> a3(f) -> a4
3390		//  \-> b1 -> b2 ----------> b3 ----> b4 -> b5
3391		let b2_number = 2;
3392		let b2_hash =
3393			insert_disconnected_header(&backend, b2_number, b1_hash, H256::from([40; 32]), false);
3394		let b3_number = 3;
3395		let b3_hash =
3396			insert_disconnected_header(&backend, b3_number, b2_hash, H256::from([41; 32]), false);
3397		let b4_number = 4;
3398		let b4_hash =
3399			insert_disconnected_header(&backend, b4_number, b3_hash, H256::from([42; 32]), false);
3400		let b5_number = 5;
3401		let b5_hash =
3402			insert_disconnected_header(&backend, b5_number, b4_hash, H256::from([43; 32]), false);
3403		{
3404			let displaced = blockchain
3405				.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([2; 32]))
3406				.unwrap();
3407			assert_eq!(blockchain.leaves().unwrap(), vec![b5_hash, a4_hash, a1_hash]);
3408			assert_eq!(displaced.displaced_leaves, vec![]);
3409			assert_eq!(displaced.displaced_blocks, vec![]);
3410		}
3411
3412		// Even though there is a disconnect, diplace should still detect
3413		// branches above the block gap.
3414		//                              /-> c4
3415		// g -> a1 -> <unimported> -> a3 -> a4(f)
3416		//  \-> b1 -> b2 ----------> b3 -> b4 -> b5
3417		let c4_number = 4;
3418		let c4_hash =
3419			insert_disconnected_header(&backend, c4_number, a3_hash, H256::from([44; 32]), false);
3420		{
3421			let displaced = blockchain
3422				.displaced_leaves_after_finalizing(a4_hash, a4_number, a3_hash)
3423				.unwrap();
3424			assert_eq!(blockchain.leaves().unwrap(), vec![b5_hash, a4_hash, c4_hash, a1_hash]);
3425			assert_eq!(displaced.displaced_leaves, vec![(c4_number, c4_hash)]);
3426			assert_eq!(displaced.displaced_blocks, vec![c4_hash]);
3427		}
3428	}
3429	#[test]
3430	fn displaced_leaves_after_finalizing_works() {
3431		let backend = Backend::<Block>::new_test(1000, 100);
3432		let blockchain = backend.blockchain();
3433		let genesis_number = 0;
3434		let genesis_hash =
3435			insert_header(&backend, genesis_number, Default::default(), None, Default::default());
3436
3437		// fork from genesis: 3 prong.
3438		// block 0 -> a1 -> a2 -> a3
3439		//        \
3440		//         -> b1 -> b2 -> c1 -> c2
3441		//              \
3442		//               -> d1 -> d2
3443		let a1_number = 1;
3444		let a1_hash = insert_header(&backend, a1_number, genesis_hash, None, Default::default());
3445		let a2_number = 2;
3446		let a2_hash = insert_header(&backend, a2_number, a1_hash, None, Default::default());
3447		let a3_number = 3;
3448		let a3_hash = insert_header(&backend, a3_number, a2_hash, None, Default::default());
3449
3450		{
3451			let displaced = blockchain
3452				.displaced_leaves_after_finalizing(genesis_hash, genesis_number, Default::default())
3453				.unwrap();
3454			assert_eq!(displaced.displaced_leaves, vec![]);
3455			assert_eq!(displaced.displaced_blocks, vec![]);
3456		}
3457		{
3458			let displaced_a1 = blockchain
3459				.displaced_leaves_after_finalizing(a1_hash, a1_number, genesis_hash)
3460				.unwrap();
3461			assert_eq!(displaced_a1.displaced_leaves, vec![]);
3462			assert_eq!(displaced_a1.displaced_blocks, vec![]);
3463
3464			let displaced_a2 = blockchain
3465				.displaced_leaves_after_finalizing(a2_hash, a2_number, a1_hash)
3466				.unwrap();
3467			assert_eq!(displaced_a2.displaced_leaves, vec![]);
3468			assert_eq!(displaced_a2.displaced_blocks, vec![]);
3469
3470			let displaced_a3 = blockchain
3471				.displaced_leaves_after_finalizing(a3_hash, a3_number, a2_hash)
3472				.unwrap();
3473			assert_eq!(displaced_a3.displaced_leaves, vec![]);
3474			assert_eq!(displaced_a3.displaced_blocks, vec![]);
3475		}
3476		{
3477			// Finalized block is above leaves and not imported yet.
3478			// We will not be able to make a connection,
3479			// nothing can be marked as displaced.
3480			let displaced = blockchain
3481				.displaced_leaves_after_finalizing(H256::from([57; 32]), 10, H256::from([56; 32]))
3482				.unwrap();
3483			assert_eq!(displaced.displaced_leaves, vec![]);
3484			assert_eq!(displaced.displaced_blocks, vec![]);
3485		}
3486
3487		// fork from genesis: 2 prong.
3488		let b1_number = 1;
3489		let b1_hash = insert_header(&backend, b1_number, genesis_hash, None, H256::from([1; 32]));
3490		let b2_number = 2;
3491		let b2_hash = insert_header(&backend, b2_number, b1_hash, None, Default::default());
3492
3493		// fork from b2.
3494		let c1_number = 3;
3495		let c1_hash = insert_header(&backend, c1_number, b2_hash, None, H256::from([2; 32]));
3496		let c2_number = 4;
3497		let c2_hash = insert_header(&backend, c2_number, c1_hash, None, Default::default());
3498
3499		// fork from b1.
3500		let d1_number = 2;
3501		let d1_hash = insert_header(&backend, d1_number, b1_hash, None, H256::from([3; 32]));
3502		let d2_number = 3;
3503		let d2_hash = insert_header(&backend, d2_number, d1_hash, None, Default::default());
3504
3505		{
3506			let displaced_a1 = blockchain
3507				.displaced_leaves_after_finalizing(a1_hash, a1_number, genesis_hash)
3508				.unwrap();
3509			assert_eq!(
3510				displaced_a1.displaced_leaves,
3511				vec![(c2_number, c2_hash), (d2_number, d2_hash)]
3512			);
3513			let mut displaced_blocks = vec![b1_hash, b2_hash, c1_hash, c2_hash, d1_hash, d2_hash];
3514			displaced_blocks.sort();
3515			assert_eq!(displaced_a1.displaced_blocks, displaced_blocks);
3516
3517			let displaced_a2 = blockchain
3518				.displaced_leaves_after_finalizing(a2_hash, a2_number, a1_hash)
3519				.unwrap();
3520			assert_eq!(displaced_a1.displaced_leaves, displaced_a2.displaced_leaves);
3521			assert_eq!(displaced_a1.displaced_blocks, displaced_a2.displaced_blocks);
3522
3523			let displaced_a3 = blockchain
3524				.displaced_leaves_after_finalizing(a3_hash, a3_number, a2_hash)
3525				.unwrap();
3526			assert_eq!(displaced_a1.displaced_leaves, displaced_a3.displaced_leaves);
3527			assert_eq!(displaced_a1.displaced_blocks, displaced_a3.displaced_blocks);
3528		}
3529		{
3530			let displaced = blockchain
3531				.displaced_leaves_after_finalizing(b1_hash, b1_number, genesis_hash)
3532				.unwrap();
3533			assert_eq!(displaced.displaced_leaves, vec![(a3_number, a3_hash)]);
3534			let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash];
3535			displaced_blocks.sort();
3536			assert_eq!(displaced.displaced_blocks, displaced_blocks);
3537		}
3538		{
3539			let displaced = blockchain
3540				.displaced_leaves_after_finalizing(b2_hash, b2_number, b1_hash)
3541				.unwrap();
3542			assert_eq!(
3543				displaced.displaced_leaves,
3544				vec![(a3_number, a3_hash), (d2_number, d2_hash)]
3545			);
3546			let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash, d1_hash, d2_hash];
3547			displaced_blocks.sort();
3548			assert_eq!(displaced.displaced_blocks, displaced_blocks);
3549		}
3550		{
3551			let displaced = blockchain
3552				.displaced_leaves_after_finalizing(c2_hash, c2_number, c1_hash)
3553				.unwrap();
3554			assert_eq!(
3555				displaced.displaced_leaves,
3556				vec![(a3_number, a3_hash), (d2_number, d2_hash)]
3557			);
3558			let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash, d1_hash, d2_hash];
3559			displaced_blocks.sort();
3560			assert_eq!(displaced.displaced_blocks, displaced_blocks);
3561		}
3562	}
3563
3564	#[test]
3565	fn test_tree_route_regression() {
3566		// NOTE: this is a test for a regression introduced in #3665, the result
3567		// of tree_route would be erroneously computed, since it was taking into
3568		// account the `ancestor` in `CachedHeaderMetadata` for the comparison.
3569		// in this test we simulate the same behavior with the side-effect
3570		// triggering the issue being eviction of a previously fetched record
3571		// from the cache, therefore this test is dependent on the LRU cache
3572		// size for header metadata, which is currently set to 5000 elements.
3573		let backend = Backend::<Block>::new_test(10000, 10000);
3574		let blockchain = backend.blockchain();
3575
3576		let genesis = insert_header(&backend, 0, Default::default(), None, Default::default());
3577
3578		let block100 = (1..=100).fold(genesis, |parent, n| {
3579			insert_header(&backend, n, parent, None, Default::default())
3580		});
3581
3582		let block7000 = (101..=7000).fold(block100, |parent, n| {
3583			insert_header(&backend, n, parent, None, Default::default())
3584		});
3585
3586		// This will cause the ancestor of `block100` to be set to `genesis` as a side-effect.
3587		lowest_common_ancestor(blockchain, genesis, block100).unwrap();
3588
3589		// While traversing the tree we will have to do 6900 calls to
3590		// `header_metadata`, which will make sure we will exhaust our cache
3591		// which only takes 5000 elements. In particular, the `CachedHeaderMetadata` struct for
3592		// block #100 will be evicted and will get a new value (with ancestor set to its parent).
3593		let tree_route = tree_route(blockchain, block100, block7000).unwrap();
3594
3595		assert!(tree_route.retracted().is_empty());
3596	}
3597
3598	#[test]
3599	fn test_leaves_with_complex_block_tree() {
3600		let backend: Arc<Backend<substrate_test_runtime_client::runtime::Block>> =
3601			Arc::new(Backend::new_test(20, 20));
3602		substrate_test_runtime_client::trait_tests::test_leaves_for_backend(backend);
3603	}
3604
3605	#[test]
3606	fn test_children_with_complex_block_tree() {
3607		let backend: Arc<Backend<substrate_test_runtime_client::runtime::Block>> =
3608			Arc::new(Backend::new_test(20, 20));
3609		substrate_test_runtime_client::trait_tests::test_children_for_backend(backend);
3610	}
3611
3612	#[test]
3613	fn test_blockchain_query_by_number_gets_canonical() {
3614		let backend: Arc<Backend<substrate_test_runtime_client::runtime::Block>> =
3615			Arc::new(Backend::new_test(20, 20));
3616		substrate_test_runtime_client::trait_tests::test_blockchain_query_by_number_gets_canonical(
3617			backend,
3618		);
3619	}
3620
3621	#[test]
3622	fn test_leaves_pruned_on_finality() {
3623		//   / 1b - 2b - 3b
3624		// 0 - 1a - 2a
3625		//   \ 1c
3626		let backend: Backend<Block> = Backend::new_test(10, 10);
3627		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3628
3629		let block1_a = insert_header(&backend, 1, block0, None, Default::default());
3630		let block1_b = insert_header(&backend, 1, block0, None, [1; 32].into());
3631		let block1_c = insert_header(&backend, 1, block0, None, [2; 32].into());
3632
3633		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block1_a, block1_b, block1_c]);
3634
3635		let block2_a = insert_header(&backend, 2, block1_a, None, Default::default());
3636		let block2_b = insert_header(&backend, 2, block1_b, None, Default::default());
3637
3638		let block3_b = insert_header(&backend, 3, block2_b, None, [3; 32].into());
3639
3640		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block3_b, block2_a, block1_c]);
3641
3642		backend.finalize_block(block1_a, None).unwrap();
3643		backend.finalize_block(block2_a, None).unwrap();
3644
3645		// All leaves are pruned that are known to not belong to canonical branch
3646		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]);
3647	}
3648
3649	#[test]
3650	fn test_aux() {
3651		let backend: Backend<substrate_test_runtime_client::runtime::Block> =
3652			Backend::new_test(0, 0);
3653		assert!(backend.get_aux(b"test").unwrap().is_none());
3654		backend.insert_aux(&[(&b"test"[..], &b"hello"[..])], &[]).unwrap();
3655		assert_eq!(b"hello", &backend.get_aux(b"test").unwrap().unwrap()[..]);
3656		backend.insert_aux(&[], &[&b"test"[..]]).unwrap();
3657		assert!(backend.get_aux(b"test").unwrap().is_none());
3658	}
3659
3660	#[test]
3661	fn test_finalize_block_with_justification() {
3662		use sc_client_api::blockchain::Backend as BlockChainBackend;
3663
3664		let backend = Backend::<Block>::new_test(10, 10);
3665
3666		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3667		let block1 = insert_header(&backend, 1, block0, None, Default::default());
3668
3669		let justification = Some((CONS0_ENGINE_ID, vec![1, 2, 3]));
3670		backend.finalize_block(block1, justification.clone()).unwrap();
3671
3672		assert_eq!(
3673			backend.blockchain().justifications(block1).unwrap(),
3674			justification.map(Justifications::from),
3675		);
3676	}
3677
3678	#[test]
3679	fn test_append_justification_to_finalized_block() {
3680		use sc_client_api::blockchain::Backend as BlockChainBackend;
3681
3682		let backend = Backend::<Block>::new_test(10, 10);
3683
3684		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3685		let block1 = insert_header(&backend, 1, block0, None, Default::default());
3686
3687		let just0 = (CONS0_ENGINE_ID, vec![1, 2, 3]);
3688		backend.finalize_block(block1, Some(just0.clone().into())).unwrap();
3689
3690		let just1 = (CONS1_ENGINE_ID, vec![4, 5]);
3691		backend.append_justification(block1, just1.clone()).unwrap();
3692
3693		let just2 = (CONS1_ENGINE_ID, vec![6, 7]);
3694		assert!(matches!(
3695			backend.append_justification(block1, just2),
3696			Err(ClientError::BadJustification(_))
3697		));
3698
3699		let justifications = {
3700			let mut just = Justifications::from(just0);
3701			just.append(just1);
3702			just
3703		};
3704		assert_eq!(backend.blockchain().justifications(block1).unwrap(), Some(justifications),);
3705	}
3706
3707	#[test]
3708	fn test_finalize_multiple_blocks_in_single_op() {
3709		let backend = Backend::<Block>::new_test(10, 10);
3710
3711		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3712		let block1 = insert_header(&backend, 1, block0, None, Default::default());
3713		let block2 = insert_header(&backend, 2, block1, None, Default::default());
3714		let block3 = insert_header(&backend, 3, block2, None, Default::default());
3715		let block4 = insert_header(&backend, 4, block3, None, Default::default());
3716		{
3717			let mut op = backend.begin_operation().unwrap();
3718			backend.begin_state_operation(&mut op, block0).unwrap();
3719			op.mark_finalized(block1, None).unwrap();
3720			op.mark_finalized(block2, None).unwrap();
3721			backend.commit_operation(op).unwrap();
3722		}
3723		{
3724			let mut op = backend.begin_operation().unwrap();
3725			backend.begin_state_operation(&mut op, block2).unwrap();
3726			op.mark_finalized(block3, None).unwrap();
3727			op.mark_finalized(block4, None).unwrap();
3728			backend.commit_operation(op).unwrap();
3729		}
3730	}
3731
3732	#[test]
3733	fn storage_hash_is_cached_correctly() {
3734		let state_version = StateVersion::default();
3735		let backend = Backend::<Block>::new_test(10, 10);
3736
3737		let hash0 = {
3738			let mut op = backend.begin_operation().unwrap();
3739			backend.begin_state_operation(&mut op, Default::default()).unwrap();
3740			let mut header = Header {
3741				number: 0,
3742				parent_hash: Default::default(),
3743				state_root: Default::default(),
3744				digest: Default::default(),
3745				extrinsics_root: Default::default(),
3746			};
3747
3748			let storage = vec![(b"test".to_vec(), b"test".to_vec())];
3749
3750			header.state_root = op
3751				.old_state
3752				.storage_root(storage.iter().map(|(x, y)| (&x[..], Some(&y[..]))), state_version)
3753				.0
3754				.into();
3755			let hash = header.hash();
3756
3757			op.reset_storage(
3758				Storage {
3759					top: storage.into_iter().collect(),
3760					children_default: Default::default(),
3761				},
3762				state_version,
3763			)
3764			.unwrap();
3765			op.set_block_data(header.clone(), Some(vec![]), None, None, NewBlockState::Best)
3766				.unwrap();
3767
3768			backend.commit_operation(op).unwrap();
3769
3770			hash
3771		};
3772
3773		let block0_hash = backend
3774			.state_at(hash0, TrieCacheContext::Untrusted)
3775			.unwrap()
3776			.storage_hash(&b"test"[..])
3777			.unwrap();
3778
3779		let hash1 = {
3780			let mut op = backend.begin_operation().unwrap();
3781			backend.begin_state_operation(&mut op, hash0).unwrap();
3782			let mut header = Header {
3783				number: 1,
3784				parent_hash: hash0,
3785				state_root: Default::default(),
3786				digest: Default::default(),
3787				extrinsics_root: Default::default(),
3788			};
3789
3790			let storage = vec![(b"test".to_vec(), Some(b"test2".to_vec()))];
3791
3792			let (root, overlay) = op.old_state.storage_root(
3793				storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))),
3794				state_version,
3795			);
3796			op.update_db_storage(overlay).unwrap();
3797			header.state_root = root.into();
3798			let hash = header.hash();
3799
3800			op.update_storage(storage, Vec::new()).unwrap();
3801			op.set_block_data(header, Some(vec![]), None, None, NewBlockState::Normal)
3802				.unwrap();
3803
3804			backend.commit_operation(op).unwrap();
3805
3806			hash
3807		};
3808
3809		{
3810			let header = backend.blockchain().header(hash1).unwrap().unwrap();
3811			let mut op = backend.begin_operation().unwrap();
3812			op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap();
3813			backend.commit_operation(op).unwrap();
3814		}
3815
3816		let block1_hash = backend
3817			.state_at(hash1, TrieCacheContext::Untrusted)
3818			.unwrap()
3819			.storage_hash(&b"test"[..])
3820			.unwrap();
3821
3822		assert_ne!(block0_hash, block1_hash);
3823	}
3824
3825	#[test]
3826	fn test_finalize_non_sequential() {
3827		let backend = Backend::<Block>::new_test(10, 10);
3828
3829		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
3830		let block1 = insert_header(&backend, 1, block0, None, Default::default());
3831		let block2 = insert_header(&backend, 2, block1, None, Default::default());
3832		{
3833			let mut op = backend.begin_operation().unwrap();
3834			backend.begin_state_operation(&mut op, block0).unwrap();
3835			op.mark_finalized(block2, None).unwrap();
3836			backend.commit_operation(op).unwrap_err();
3837		}
3838	}
3839
3840	#[test]
3841	fn prune_blocks_on_finalize() {
3842		let pruning_modes =
3843			vec![BlocksPruning::Some(2), BlocksPruning::KeepFinalized, BlocksPruning::KeepAll];
3844
3845		for pruning_mode in pruning_modes {
3846			let backend = Backend::<Block>::new_test_with_tx_storage(pruning_mode, 0);
3847			let mut blocks = Vec::new();
3848			let mut prev_hash = Default::default();
3849			for i in 0..5 {
3850				let hash = insert_block(
3851					&backend,
3852					i,
3853					prev_hash,
3854					None,
3855					Default::default(),
3856					vec![UncheckedXt::new_transaction(i.into(), ())],
3857					None,
3858				)
3859				.unwrap();
3860				blocks.push(hash);
3861				prev_hash = hash;
3862			}
3863
3864			{
3865				let mut op = backend.begin_operation().unwrap();
3866				backend.begin_state_operation(&mut op, blocks[4]).unwrap();
3867				for i in 1..5 {
3868					op.mark_finalized(blocks[i], None).unwrap();
3869				}
3870				backend.commit_operation(op).unwrap();
3871			}
3872			let bc = backend.blockchain();
3873
3874			if matches!(pruning_mode, BlocksPruning::Some(_)) {
3875				assert_eq!(None, bc.body(blocks[0]).unwrap());
3876				assert_eq!(None, bc.body(blocks[1]).unwrap());
3877				assert_eq!(None, bc.body(blocks[2]).unwrap());
3878				assert_eq!(
3879					Some(vec![UncheckedXt::new_transaction(3.into(), ())]),
3880					bc.body(blocks[3]).unwrap()
3881				);
3882				assert_eq!(
3883					Some(vec![UncheckedXt::new_transaction(4.into(), ())]),
3884					bc.body(blocks[4]).unwrap()
3885				);
3886			} else {
3887				for i in 0..5 {
3888					assert_eq!(
3889						Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]),
3890						bc.body(blocks[i]).unwrap()
3891					);
3892				}
3893			}
3894		}
3895	}
3896
3897	#[test]
3898	fn prune_blocks_on_finalize_with_fork() {
3899		sp_tracing::try_init_simple();
3900
3901		let pruning_modes =
3902			vec![BlocksPruning::Some(2), BlocksPruning::KeepFinalized, BlocksPruning::KeepAll];
3903
3904		for pruning in pruning_modes {
3905			let backend = Backend::<Block>::new_test_with_tx_storage(pruning, 10);
3906			let mut blocks = Vec::new();
3907			let mut prev_hash = Default::default();
3908			for i in 0..5 {
3909				let hash = insert_block(
3910					&backend,
3911					i,
3912					prev_hash,
3913					None,
3914					Default::default(),
3915					vec![UncheckedXt::new_transaction(i.into(), ())],
3916					None,
3917				)
3918				.unwrap();
3919				blocks.push(hash);
3920				prev_hash = hash;
3921			}
3922
3923			// insert a fork at block 2
3924			let fork_hash_root = insert_block(
3925				&backend,
3926				2,
3927				blocks[1],
3928				None,
3929				H256::random(),
3930				vec![UncheckedXt::new_transaction(2.into(), ())],
3931				None,
3932			)
3933			.unwrap();
3934			insert_block(
3935				&backend,
3936				3,
3937				fork_hash_root,
3938				None,
3939				H256::random(),
3940				vec![
3941					UncheckedXt::new_transaction(3.into(), ()),
3942					UncheckedXt::new_transaction(11.into(), ()),
3943				],
3944				None,
3945			)
3946			.unwrap();
3947			let mut op = backend.begin_operation().unwrap();
3948			backend.begin_state_operation(&mut op, blocks[4]).unwrap();
3949			op.mark_head(blocks[4]).unwrap();
3950			backend.commit_operation(op).unwrap();
3951
3952			let bc = backend.blockchain();
3953			assert_eq!(
3954				Some(vec![UncheckedXt::new_transaction(2.into(), ())]),
3955				bc.body(fork_hash_root).unwrap()
3956			);
3957
3958			for i in 1..5 {
3959				let mut op = backend.begin_operation().unwrap();
3960				backend.begin_state_operation(&mut op, blocks[4]).unwrap();
3961				op.mark_finalized(blocks[i], None).unwrap();
3962				backend.commit_operation(op).unwrap();
3963			}
3964
3965			if matches!(pruning, BlocksPruning::Some(_)) {
3966				assert_eq!(None, bc.body(blocks[0]).unwrap());
3967				assert_eq!(None, bc.body(blocks[1]).unwrap());
3968				assert_eq!(None, bc.body(blocks[2]).unwrap());
3969
3970				assert_eq!(
3971					Some(vec![UncheckedXt::new_transaction(3.into(), ())]),
3972					bc.body(blocks[3]).unwrap()
3973				);
3974				assert_eq!(
3975					Some(vec![UncheckedXt::new_transaction(4.into(), ())]),
3976					bc.body(blocks[4]).unwrap()
3977				);
3978			} else {
3979				for i in 0..5 {
3980					assert_eq!(
3981						Some(vec![UncheckedXt::new_transaction((i as u64).into(), ())]),
3982						bc.body(blocks[i]).unwrap()
3983					);
3984				}
3985			}
3986
3987			if matches!(pruning, BlocksPruning::KeepAll) {
3988				assert_eq!(
3989					Some(vec![UncheckedXt::new_transaction(2.into(), ())]),
3990					bc.body(fork_hash_root).unwrap()
3991				);
3992			} else {
3993				assert_eq!(None, bc.body(fork_hash_root).unwrap());
3994			}
3995
3996			assert_eq!(bc.info().best_number, 4);
3997			for i in 0..5 {
3998				assert!(bc.hash(i).unwrap().is_some());
3999			}
4000		}
4001	}
4002
4003	#[test]
4004	fn prune_blocks_on_finalize_and_reorg() {
4005		//	0 - 1b
4006		//	\ - 1a - 2a - 3a
4007		//	     \ - 2b
4008
4009		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(10), 10);
4010
4011		let make_block = |index, parent, val: u64| {
4012			insert_block(
4013				&backend,
4014				index,
4015				parent,
4016				None,
4017				H256::random(),
4018				vec![UncheckedXt::new_transaction(val.into(), ())],
4019				None,
4020			)
4021			.unwrap()
4022		};
4023
4024		let block_0 = make_block(0, Default::default(), 0x00);
4025		let block_1a = make_block(1, block_0, 0x1a);
4026		let block_1b = make_block(1, block_0, 0x1b);
4027		let block_2a = make_block(2, block_1a, 0x2a);
4028		let block_2b = make_block(2, block_1a, 0x2b);
4029		let block_3a = make_block(3, block_2a, 0x3a);
4030
4031		// Make sure 1b is head
4032		let mut op = backend.begin_operation().unwrap();
4033		backend.begin_state_operation(&mut op, block_0).unwrap();
4034		op.mark_head(block_1b).unwrap();
4035		backend.commit_operation(op).unwrap();
4036
4037		// Finalize 3a
4038		let mut op = backend.begin_operation().unwrap();
4039		backend.begin_state_operation(&mut op, block_0).unwrap();
4040		op.mark_head(block_3a).unwrap();
4041		op.mark_finalized(block_1a, None).unwrap();
4042		op.mark_finalized(block_2a, None).unwrap();
4043		op.mark_finalized(block_3a, None).unwrap();
4044		backend.commit_operation(op).unwrap();
4045
4046		let bc = backend.blockchain();
4047		assert_eq!(None, bc.body(block_1b).unwrap());
4048		assert_eq!(None, bc.body(block_2b).unwrap());
4049		assert_eq!(
4050			Some(vec![UncheckedXt::new_transaction(0x00.into(), ())]),
4051			bc.body(block_0).unwrap()
4052		);
4053		assert_eq!(
4054			Some(vec![UncheckedXt::new_transaction(0x1a.into(), ())]),
4055			bc.body(block_1a).unwrap()
4056		);
4057		assert_eq!(
4058			Some(vec![UncheckedXt::new_transaction(0x2a.into(), ())]),
4059			bc.body(block_2a).unwrap()
4060		);
4061		assert_eq!(
4062			Some(vec![UncheckedXt::new_transaction(0x3a.into(), ())]),
4063			bc.body(block_3a).unwrap()
4064		);
4065	}
4066
4067	#[test]
4068	fn indexed_data_block_body() {
4069		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(1), 10);
4070
4071		let x0 = UncheckedXt::new_transaction(0.into(), ()).encode();
4072		let x1 = UncheckedXt::new_transaction(1.into(), ()).encode();
4073		let x0_hash = <HashingFor<Block> as sp_core::Hasher>::hash(&x0[1..]);
4074		let x1_hash = <HashingFor<Block> as sp_core::Hasher>::hash(&x1[1..]);
4075		let index = vec![
4076			IndexOperation::Insert {
4077				extrinsic: 0,
4078				hash: x0_hash.as_ref().to_vec(),
4079				size: (x0.len() - 1) as u32,
4080			},
4081			IndexOperation::Insert {
4082				extrinsic: 1,
4083				hash: x1_hash.as_ref().to_vec(),
4084				size: (x1.len() - 1) as u32,
4085			},
4086		];
4087		let hash = insert_block(
4088			&backend,
4089			0,
4090			Default::default(),
4091			None,
4092			Default::default(),
4093			vec![
4094				UncheckedXt::new_transaction(0.into(), ()),
4095				UncheckedXt::new_transaction(1.into(), ()),
4096			],
4097			Some(index),
4098		)
4099		.unwrap();
4100		let bc = backend.blockchain();
4101		assert_eq!(bc.indexed_transaction(x0_hash).unwrap().unwrap(), &x0[1..]);
4102		assert_eq!(bc.indexed_transaction(x1_hash).unwrap().unwrap(), &x1[1..]);
4103
4104		let hashof0 = bc.info().genesis_hash;
4105		// Push one more blocks and make sure block is pruned and transaction index is cleared.
4106		let block1 =
4107			insert_block(&backend, 1, hash, None, Default::default(), vec![], None).unwrap();
4108		backend.finalize_block(block1, None).unwrap();
4109		assert_eq!(bc.body(hashof0).unwrap(), None);
4110		assert_eq!(bc.indexed_transaction(x0_hash).unwrap(), None);
4111		assert_eq!(bc.indexed_transaction(x1_hash).unwrap(), None);
4112	}
4113
4114	#[test]
4115	fn index_invalid_size() {
4116		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(1), 10);
4117
4118		let x0 = UncheckedXt::new_transaction(0.into(), ()).encode();
4119		let x1 = UncheckedXt::new_transaction(1.into(), ()).encode();
4120
4121		let x0_hash = <HashingFor<Block> as sp_core::Hasher>::hash(&x0[..]);
4122		let x1_hash = <HashingFor<Block> as sp_core::Hasher>::hash(&x1[..]);
4123		let index = vec![
4124			IndexOperation::Insert {
4125				extrinsic: 0,
4126				hash: x0_hash.as_ref().to_vec(),
4127				size: (x0.len()) as u32,
4128			},
4129			IndexOperation::Insert {
4130				extrinsic: 1,
4131				hash: x1_hash.as_ref().to_vec(),
4132				size: (x1.len() + 1) as u32,
4133			},
4134		];
4135		insert_block(
4136			&backend,
4137			0,
4138			Default::default(),
4139			None,
4140			Default::default(),
4141			vec![
4142				UncheckedXt::new_transaction(0.into(), ()),
4143				UncheckedXt::new_transaction(1.into(), ()),
4144			],
4145			Some(index),
4146		)
4147		.unwrap();
4148		let bc = backend.blockchain();
4149		assert_eq!(bc.indexed_transaction(x0_hash).unwrap().unwrap(), &x0[..]);
4150		assert_eq!(bc.indexed_transaction(x1_hash).unwrap(), None);
4151	}
4152
4153	#[test]
4154	fn renew_transaction_storage() {
4155		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(2), 10);
4156		let mut blocks = Vec::new();
4157		let mut prev_hash = Default::default();
4158		let x1 = UncheckedXt::new_transaction(0.into(), ()).encode();
4159		let x1_hash = <HashingFor<Block> as sp_core::Hasher>::hash(&x1[1..]);
4160		for i in 0..10 {
4161			let mut index = Vec::new();
4162			if i == 0 {
4163				index.push(IndexOperation::Insert {
4164					extrinsic: 0,
4165					hash: x1_hash.as_ref().to_vec(),
4166					size: (x1.len() - 1) as u32,
4167				});
4168			} else if i < 5 {
4169				// keep renewing 1st
4170				index.push(IndexOperation::Renew { extrinsic: 0, hash: x1_hash.as_ref().to_vec() });
4171			} // else stop renewing
4172			let hash = insert_block(
4173				&backend,
4174				i,
4175				prev_hash,
4176				None,
4177				Default::default(),
4178				vec![UncheckedXt::new_transaction(i.into(), ())],
4179				Some(index),
4180			)
4181			.unwrap();
4182			blocks.push(hash);
4183			prev_hash = hash;
4184		}
4185
4186		for i in 1..10 {
4187			let mut op = backend.begin_operation().unwrap();
4188			backend.begin_state_operation(&mut op, blocks[4]).unwrap();
4189			op.mark_finalized(blocks[i], None).unwrap();
4190			backend.commit_operation(op).unwrap();
4191			let bc = backend.blockchain();
4192			if i < 6 {
4193				assert!(bc.indexed_transaction(x1_hash).unwrap().is_some());
4194			} else {
4195				assert!(bc.indexed_transaction(x1_hash).unwrap().is_none());
4196			}
4197		}
4198	}
4199
4200	#[test]
4201	fn remove_leaf_block_works() {
4202		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(2), 10);
4203		let mut blocks = Vec::new();
4204		let mut prev_hash = Default::default();
4205		for i in 0..2 {
4206			let hash = insert_block(
4207				&backend,
4208				i,
4209				prev_hash,
4210				None,
4211				Default::default(),
4212				vec![UncheckedXt::new_transaction(i.into(), ())],
4213				None,
4214			)
4215			.unwrap();
4216			blocks.push(hash);
4217			prev_hash = hash;
4218		}
4219
4220		for i in 0..2 {
4221			let hash = insert_block(
4222				&backend,
4223				2,
4224				blocks[1],
4225				None,
4226				sp_core::H256::random(),
4227				vec![UncheckedXt::new_transaction(i.into(), ())],
4228				None,
4229			)
4230			.unwrap();
4231			blocks.push(hash);
4232		}
4233
4234		// insert a fork at block 1, which becomes best block
4235		let best_hash = insert_block(
4236			&backend,
4237			1,
4238			blocks[0],
4239			None,
4240			sp_core::H256::random(),
4241			vec![UncheckedXt::new_transaction(42.into(), ())],
4242			None,
4243		)
4244		.unwrap();
4245
4246		assert_eq!(backend.blockchain().info().best_hash, best_hash);
4247		assert!(backend.remove_leaf_block(best_hash).is_err());
4248
4249		assert_eq!(backend.blockchain().leaves().unwrap(), vec![blocks[2], blocks[3], best_hash]);
4250		assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![blocks[2], blocks[3]]);
4251
4252		assert!(backend.have_state_at(blocks[3], 2));
4253		assert!(backend.blockchain().header(blocks[3]).unwrap().is_some());
4254		backend.remove_leaf_block(blocks[3]).unwrap();
4255		assert!(!backend.have_state_at(blocks[3], 2));
4256		assert!(backend.blockchain().header(blocks[3]).unwrap().is_none());
4257		assert_eq!(backend.blockchain().leaves().unwrap(), vec![blocks[2], best_hash]);
4258		assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![blocks[2]]);
4259
4260		assert!(backend.have_state_at(blocks[2], 2));
4261		assert!(backend.blockchain().header(blocks[2]).unwrap().is_some());
4262		backend.remove_leaf_block(blocks[2]).unwrap();
4263		assert!(!backend.have_state_at(blocks[2], 2));
4264		assert!(backend.blockchain().header(blocks[2]).unwrap().is_none());
4265		assert_eq!(backend.blockchain().leaves().unwrap(), vec![best_hash, blocks[1]]);
4266		assert_eq!(backend.blockchain().children(blocks[1]).unwrap(), vec![]);
4267
4268		assert!(backend.have_state_at(blocks[1], 1));
4269		assert!(backend.blockchain().header(blocks[1]).unwrap().is_some());
4270		backend.remove_leaf_block(blocks[1]).unwrap();
4271		assert!(!backend.have_state_at(blocks[1], 1));
4272		assert!(backend.blockchain().header(blocks[1]).unwrap().is_none());
4273		assert_eq!(backend.blockchain().leaves().unwrap(), vec![best_hash]);
4274		assert_eq!(backend.blockchain().children(blocks[0]).unwrap(), vec![best_hash]);
4275	}
4276
4277	#[test]
4278	fn test_import_existing_block_as_new_head() {
4279		let backend: Backend<Block> = Backend::new_test(10, 3);
4280		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
4281		let block1 = insert_header(&backend, 1, block0, None, Default::default());
4282		let block2 = insert_header(&backend, 2, block1, None, Default::default());
4283		let block3 = insert_header(&backend, 3, block2, None, Default::default());
4284		let block4 = insert_header(&backend, 4, block3, None, Default::default());
4285		let block5 = insert_header(&backend, 5, block4, None, Default::default());
4286		assert_eq!(backend.blockchain().info().best_hash, block5);
4287
4288		// Insert 1 as best again. This should fail because canonicalization_delay == 3 and best ==
4289		// 5
4290		let header = Header {
4291			number: 1,
4292			parent_hash: block0,
4293			state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1),
4294			digest: Default::default(),
4295			extrinsics_root: Default::default(),
4296		};
4297		let mut op = backend.begin_operation().unwrap();
4298		op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap();
4299		assert!(matches!(backend.commit_operation(op), Err(sp_blockchain::Error::SetHeadTooOld)));
4300
4301		// Insert 2 as best again.
4302		let header = backend.blockchain().header(block2).unwrap().unwrap();
4303		let mut op = backend.begin_operation().unwrap();
4304		op.set_block_data(header, None, None, None, NewBlockState::Best).unwrap();
4305		backend.commit_operation(op).unwrap();
4306		assert_eq!(backend.blockchain().info().best_hash, block2);
4307	}
4308
4309	#[test]
4310	fn test_import_existing_block_as_final() {
4311		let backend: Backend<Block> = Backend::new_test(10, 10);
4312		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
4313		let block1 = insert_header(&backend, 1, block0, None, Default::default());
4314		let _block2 = insert_header(&backend, 2, block1, None, Default::default());
4315		// Genesis is auto finalized, the rest are not.
4316		assert_eq!(backend.blockchain().info().finalized_hash, block0);
4317
4318		// Insert 1 as final again.
4319		let header = backend.blockchain().header(block1).unwrap().unwrap();
4320
4321		let mut op = backend.begin_operation().unwrap();
4322		op.set_block_data(header, None, None, None, NewBlockState::Final).unwrap();
4323		backend.commit_operation(op).unwrap();
4324
4325		assert_eq!(backend.blockchain().info().finalized_hash, block1);
4326	}
4327
4328	#[test]
4329	fn test_import_existing_state_fails() {
4330		let backend: Backend<Block> = Backend::new_test(10, 10);
4331		let genesis =
4332			insert_block(&backend, 0, Default::default(), None, Default::default(), vec![], None)
4333				.unwrap();
4334
4335		insert_block(&backend, 1, genesis, None, Default::default(), vec![], None).unwrap();
4336		let err = insert_block(&backend, 1, genesis, None, Default::default(), vec![], None)
4337			.err()
4338			.unwrap();
4339		match err {
4340			sp_blockchain::Error::StateDatabase(m) if m == "Block already exists" => (),
4341			e @ _ => panic!("Unexpected error {:?}", e),
4342		}
4343	}
4344
4345	#[test]
4346	fn test_leaves_not_created_for_ancient_blocks() {
4347		let backend: Backend<Block> = Backend::new_test(10, 10);
4348		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
4349
4350		let block1_a = insert_header(&backend, 1, block0, None, Default::default());
4351		let block2_a = insert_header(&backend, 2, block1_a, None, Default::default());
4352		backend.finalize_block(block1_a, None).unwrap();
4353		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]);
4354
4355		// Insert a fork prior to finalization point. Leave should not be created.
4356		insert_header_no_head(&backend, 1, block0, [1; 32].into());
4357		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2_a]);
4358	}
4359
4360	#[test]
4361	fn revert_non_best_blocks() {
4362		let backend = Backend::<Block>::new_test(10, 10);
4363
4364		let genesis =
4365			insert_block(&backend, 0, Default::default(), None, Default::default(), vec![], None)
4366				.unwrap();
4367
4368		let block1 =
4369			insert_block(&backend, 1, genesis, None, Default::default(), vec![], None).unwrap();
4370
4371		let block2 =
4372			insert_block(&backend, 2, block1, None, Default::default(), vec![], None).unwrap();
4373
4374		let block3 = {
4375			let mut op = backend.begin_operation().unwrap();
4376			backend.begin_state_operation(&mut op, block1).unwrap();
4377			let header = Header {
4378				number: 3,
4379				parent_hash: block2,
4380				state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1),
4381				digest: Default::default(),
4382				extrinsics_root: Default::default(),
4383			};
4384
4385			op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal)
4386				.unwrap();
4387
4388			backend.commit_operation(op).unwrap();
4389
4390			header.hash()
4391		};
4392
4393		let block4 = {
4394			let mut op = backend.begin_operation().unwrap();
4395			backend.begin_state_operation(&mut op, block2).unwrap();
4396			let header = Header {
4397				number: 4,
4398				parent_hash: block3,
4399				state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1),
4400				digest: Default::default(),
4401				extrinsics_root: Default::default(),
4402			};
4403
4404			op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal)
4405				.unwrap();
4406
4407			backend.commit_operation(op).unwrap();
4408
4409			header.hash()
4410		};
4411
4412		let block3_fork = {
4413			let mut op = backend.begin_operation().unwrap();
4414			backend.begin_state_operation(&mut op, block2).unwrap();
4415			let header = Header {
4416				number: 3,
4417				parent_hash: block2,
4418				state_root: BlakeTwo256::trie_root(Vec::new(), StateVersion::V1),
4419				digest: Default::default(),
4420				extrinsics_root: H256::from_low_u64_le(42),
4421			};
4422
4423			op.set_block_data(header.clone(), Some(Vec::new()), None, None, NewBlockState::Normal)
4424				.unwrap();
4425
4426			backend.commit_operation(op).unwrap();
4427
4428			header.hash()
4429		};
4430
4431		assert!(backend.have_state_at(block1, 1));
4432		assert!(backend.have_state_at(block2, 2));
4433		assert!(backend.have_state_at(block3, 3));
4434		assert!(backend.have_state_at(block4, 4));
4435		assert!(backend.have_state_at(block3_fork, 3));
4436
4437		assert_eq!(backend.blockchain.leaves().unwrap(), vec![block4, block3_fork]);
4438		assert_eq!(4, backend.blockchain.leaves.read().highest_leaf().unwrap().0);
4439
4440		assert_eq!(3, backend.revert(1, false).unwrap().0);
4441
4442		assert!(backend.have_state_at(block1, 1));
4443
4444		let ensure_pruned = |hash, number: u32| {
4445			assert_eq!(
4446				backend.blockchain.status(hash).unwrap(),
4447				sc_client_api::blockchain::BlockStatus::Unknown
4448			);
4449			assert!(
4450				backend
4451					.blockchain
4452					.db
4453					.get(columns::BODY, &number_and_hash_to_lookup_key(number, hash).unwrap())
4454					.is_none(),
4455				"{number}"
4456			);
4457			assert!(
4458				backend
4459					.blockchain
4460					.db
4461					.get(columns::HEADER, &number_and_hash_to_lookup_key(number, hash).unwrap())
4462					.is_none(),
4463				"{number}"
4464			);
4465		};
4466
4467		ensure_pruned(block2, 2);
4468		ensure_pruned(block3, 3);
4469		ensure_pruned(block4, 4);
4470		ensure_pruned(block3_fork, 3);
4471
4472		assert_eq!(backend.blockchain.leaves().unwrap(), vec![block1]);
4473		assert_eq!(1, backend.blockchain.leaves.read().highest_leaf().unwrap().0);
4474	}
4475
4476	#[test]
4477	fn revert_finalized_blocks() {
4478		let pruning_modes = [BlocksPruning::Some(10), BlocksPruning::KeepAll];
4479
4480		// we will create a chain with 11 blocks, finalize block #8 and then
4481		// attempt to revert 5 blocks.
4482		for pruning_mode in pruning_modes {
4483			let backend = Backend::<Block>::new_test_with_tx_storage(pruning_mode, 1);
4484
4485			let mut parent = Default::default();
4486			for i in 0..=10 {
4487				parent = insert_block(&backend, i, parent, None, Default::default(), vec![], None)
4488					.unwrap();
4489			}
4490
4491			assert_eq!(backend.blockchain().info().best_number, 10);
4492
4493			let block8 = backend.blockchain().hash(8).unwrap().unwrap();
4494			backend.finalize_block(block8, None).unwrap();
4495			backend.revert(5, true).unwrap();
4496
4497			match pruning_mode {
4498				// we can only revert to blocks for which we have state, if pruning is enabled
4499				// then the last state available will be that of the latest finalized block
4500				BlocksPruning::Some(_) => {
4501					assert_eq!(backend.blockchain().info().finalized_number, 8)
4502				},
4503				// otherwise if we're not doing state pruning we can revert past finalized blocks
4504				_ => assert_eq!(backend.blockchain().info().finalized_number, 5),
4505			}
4506		}
4507	}
4508
4509	#[test]
4510	fn test_no_duplicated_leaves_allowed() {
4511		let backend: Backend<Block> = Backend::new_test(10, 10);
4512		let block0 = insert_header(&backend, 0, Default::default(), None, Default::default());
4513		let block1 = insert_header(&backend, 1, block0, None, Default::default());
4514		// Add block 2 not as the best block
4515		let block2 = insert_header_no_head(&backend, 2, block1, Default::default());
4516		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2]);
4517		assert_eq!(backend.blockchain().info().best_hash, block1);
4518
4519		// Add block 2 as the best block
4520		let block2 = insert_header(&backend, 2, block1, None, Default::default());
4521		assert_eq!(backend.blockchain().leaves().unwrap(), vec![block2]);
4522		assert_eq!(backend.blockchain().info().best_hash, block2);
4523	}
4524
4525	#[test]
4526	fn force_delayed_canonicalize_waiting_for_blocks_to_be_finalized() {
4527		let pruning_modes =
4528			[BlocksPruning::Some(10), BlocksPruning::KeepAll, BlocksPruning::KeepFinalized];
4529
4530		for pruning_mode in pruning_modes {
4531			eprintln!("Running with pruning mode: {:?}", pruning_mode);
4532
4533			let backend = Backend::<Block>::new_test_with_tx_storage(pruning_mode, 1);
4534
4535			let genesis = insert_block(
4536				&backend,
4537				0,
4538				Default::default(),
4539				None,
4540				Default::default(),
4541				vec![],
4542				None,
4543			)
4544			.unwrap();
4545
4546			let block1 = {
4547				let mut op = backend.begin_operation().unwrap();
4548				backend.begin_state_operation(&mut op, genesis).unwrap();
4549				let mut header = Header {
4550					number: 1,
4551					parent_hash: genesis,
4552					state_root: Default::default(),
4553					digest: Default::default(),
4554					extrinsics_root: Default::default(),
4555				};
4556
4557				let storage = vec![(vec![1, 3, 5], None), (vec![5, 5, 5], Some(vec![4, 5, 6]))];
4558
4559				let (root, overlay) = op.old_state.storage_root(
4560					storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))),
4561					StateVersion::V1,
4562				);
4563				op.update_db_storage(overlay).unwrap();
4564				header.state_root = root.into();
4565
4566				op.update_storage(storage, Vec::new()).unwrap();
4567
4568				op.set_block_data(
4569					header.clone(),
4570					Some(Vec::new()),
4571					None,
4572					None,
4573					NewBlockState::Normal,
4574				)
4575				.unwrap();
4576
4577				backend.commit_operation(op).unwrap();
4578
4579				header.hash()
4580			};
4581
4582			if matches!(pruning_mode, BlocksPruning::Some(_)) {
4583				assert_eq!(
4584					LastCanonicalized::Block(0),
4585					backend.storage.state_db.last_canonicalized()
4586				);
4587			}
4588
4589			// This should not trigger any forced canonicalization as we didn't have imported any
4590			// best block by now.
4591			let block2 = {
4592				let mut op = backend.begin_operation().unwrap();
4593				backend.begin_state_operation(&mut op, block1).unwrap();
4594				let mut header = Header {
4595					number: 2,
4596					parent_hash: block1,
4597					state_root: Default::default(),
4598					digest: Default::default(),
4599					extrinsics_root: Default::default(),
4600				};
4601
4602				let storage = vec![(vec![5, 5, 5], Some(vec![4, 5, 6, 2]))];
4603
4604				let (root, overlay) = op.old_state.storage_root(
4605					storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))),
4606					StateVersion::V1,
4607				);
4608				op.update_db_storage(overlay).unwrap();
4609				header.state_root = root.into();
4610
4611				op.update_storage(storage, Vec::new()).unwrap();
4612
4613				op.set_block_data(
4614					header.clone(),
4615					Some(Vec::new()),
4616					None,
4617					None,
4618					NewBlockState::Normal,
4619				)
4620				.unwrap();
4621
4622				backend.commit_operation(op).unwrap();
4623
4624				header.hash()
4625			};
4626
4627			if matches!(pruning_mode, BlocksPruning::Some(_)) {
4628				assert_eq!(
4629					LastCanonicalized::Block(0),
4630					backend.storage.state_db.last_canonicalized()
4631				);
4632			}
4633
4634			// This should also not trigger it yet, because we import a best block, but the best
4635			// block from the POV of the db is still at `0`.
4636			let block3 = {
4637				let mut op = backend.begin_operation().unwrap();
4638				backend.begin_state_operation(&mut op, block2).unwrap();
4639				let mut header = Header {
4640					number: 3,
4641					parent_hash: block2,
4642					state_root: Default::default(),
4643					digest: Default::default(),
4644					extrinsics_root: Default::default(),
4645				};
4646
4647				let storage = vec![(vec![5, 5, 5], Some(vec![4, 5, 6, 3]))];
4648
4649				let (root, overlay) = op.old_state.storage_root(
4650					storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))),
4651					StateVersion::V1,
4652				);
4653				op.update_db_storage(overlay).unwrap();
4654				header.state_root = root.into();
4655
4656				op.update_storage(storage, Vec::new()).unwrap();
4657
4658				op.set_block_data(
4659					header.clone(),
4660					Some(Vec::new()),
4661					None,
4662					None,
4663					NewBlockState::Best,
4664				)
4665				.unwrap();
4666
4667				backend.commit_operation(op).unwrap();
4668
4669				header.hash()
4670			};
4671
4672			// Now it should kick in.
4673			let block4 = {
4674				let mut op = backend.begin_operation().unwrap();
4675				backend.begin_state_operation(&mut op, block3).unwrap();
4676				let mut header = Header {
4677					number: 4,
4678					parent_hash: block3,
4679					state_root: Default::default(),
4680					digest: Default::default(),
4681					extrinsics_root: Default::default(),
4682				};
4683
4684				let storage = vec![(vec![5, 5, 5], Some(vec![4, 5, 6, 4]))];
4685
4686				let (root, overlay) = op.old_state.storage_root(
4687					storage.iter().map(|(k, v)| (k.as_slice(), v.as_ref().map(|v| &v[..]))),
4688					StateVersion::V1,
4689				);
4690				op.update_db_storage(overlay).unwrap();
4691				header.state_root = root.into();
4692
4693				op.update_storage(storage, Vec::new()).unwrap();
4694
4695				op.set_block_data(
4696					header.clone(),
4697					Some(Vec::new()),
4698					None,
4699					None,
4700					NewBlockState::Best,
4701				)
4702				.unwrap();
4703
4704				backend.commit_operation(op).unwrap();
4705
4706				header.hash()
4707			};
4708
4709			if matches!(pruning_mode, BlocksPruning::Some(_)) {
4710				assert_eq!(
4711					LastCanonicalized::Block(2),
4712					backend.storage.state_db.last_canonicalized()
4713				);
4714			}
4715
4716			assert_eq!(block1, backend.blockchain().hash(1).unwrap().unwrap());
4717			assert_eq!(block2, backend.blockchain().hash(2).unwrap().unwrap());
4718			assert_eq!(block3, backend.blockchain().hash(3).unwrap().unwrap());
4719			assert_eq!(block4, backend.blockchain().hash(4).unwrap().unwrap());
4720		}
4721	}
4722
4723	#[test]
4724	fn test_pinned_blocks_on_finalize() {
4725		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(1), 10);
4726		let mut blocks = Vec::new();
4727		let mut prev_hash = Default::default();
4728
4729		let build_justification = |i: u64| ([0, 0, 0, 0], vec![i.try_into().unwrap()]);
4730		// Block tree:
4731		//   0 -> 1 -> 2 -> 3 -> 4
4732		for i in 0..5 {
4733			let hash = insert_block(
4734				&backend,
4735				i,
4736				prev_hash,
4737				None,
4738				Default::default(),
4739				vec![UncheckedXt::new_transaction(i.into(), ())],
4740				None,
4741			)
4742			.unwrap();
4743			blocks.push(hash);
4744			// Avoid block pruning.
4745			backend.pin_block(blocks[i as usize]).unwrap();
4746
4747			prev_hash = hash;
4748		}
4749
4750		let bc = backend.blockchain();
4751
4752		// Check that we can properly access values when there is reference count
4753		// but no value.
4754		assert_eq!(
4755			Some(vec![UncheckedXt::new_transaction(1.into(), ())]),
4756			bc.body(blocks[1]).unwrap()
4757		);
4758
4759		// Block 1 gets pinned three times
4760		backend.pin_block(blocks[1]).unwrap();
4761		backend.pin_block(blocks[1]).unwrap();
4762
4763		// Finalize all blocks. This will trigger pruning.
4764		let mut op = backend.begin_operation().unwrap();
4765		backend.begin_state_operation(&mut op, blocks[4]).unwrap();
4766		for i in 1..5 {
4767			op.mark_finalized(blocks[i], Some(build_justification(i.try_into().unwrap())))
4768				.unwrap();
4769		}
4770		backend.commit_operation(op).unwrap();
4771
4772		// Block 0, 1, 2, 3 are pinned, so all values should be cached.
4773		// Block 4 is inside the pruning window, its value is in db.
4774		assert_eq!(
4775			Some(vec![UncheckedXt::new_transaction(0.into(), ())]),
4776			bc.body(blocks[0]).unwrap()
4777		);
4778
4779		assert_eq!(
4780			Some(vec![UncheckedXt::new_transaction(1.into(), ())]),
4781			bc.body(blocks[1]).unwrap()
4782		);
4783		assert_eq!(
4784			Some(Justifications::from(build_justification(1))),
4785			bc.justifications(blocks[1]).unwrap()
4786		);
4787
4788		assert_eq!(
4789			Some(vec![UncheckedXt::new_transaction(2.into(), ())]),
4790			bc.body(blocks[2]).unwrap()
4791		);
4792		assert_eq!(
4793			Some(Justifications::from(build_justification(2))),
4794			bc.justifications(blocks[2]).unwrap()
4795		);
4796
4797		assert_eq!(
4798			Some(vec![UncheckedXt::new_transaction(3.into(), ())]),
4799			bc.body(blocks[3]).unwrap()
4800		);
4801		assert_eq!(
4802			Some(Justifications::from(build_justification(3))),
4803			bc.justifications(blocks[3]).unwrap()
4804		);
4805
4806		assert_eq!(
4807			Some(vec![UncheckedXt::new_transaction(4.into(), ())]),
4808			bc.body(blocks[4]).unwrap()
4809		);
4810		assert_eq!(
4811			Some(Justifications::from(build_justification(4))),
4812			bc.justifications(blocks[4]).unwrap()
4813		);
4814
4815		// Unpin all blocks. Values should be removed from cache.
4816		for block in &blocks {
4817			backend.unpin_block(*block);
4818		}
4819
4820		assert!(bc.body(blocks[0]).unwrap().is_none());
4821		// Block 1 was pinned twice, we expect it to be still cached
4822		assert!(bc.body(blocks[1]).unwrap().is_some());
4823		assert!(bc.justifications(blocks[1]).unwrap().is_some());
4824		// Headers should also be available while pinned
4825		assert!(bc.header(blocks[1]).ok().flatten().is_some());
4826		assert!(bc.body(blocks[2]).unwrap().is_none());
4827		assert!(bc.justifications(blocks[2]).unwrap().is_none());
4828		assert!(bc.body(blocks[3]).unwrap().is_none());
4829		assert!(bc.justifications(blocks[3]).unwrap().is_none());
4830
4831		// After these unpins, block 1 should also be removed
4832		backend.unpin_block(blocks[1]);
4833		assert!(bc.body(blocks[1]).unwrap().is_some());
4834		assert!(bc.justifications(blocks[1]).unwrap().is_some());
4835		backend.unpin_block(blocks[1]);
4836		assert!(bc.body(blocks[1]).unwrap().is_none());
4837		assert!(bc.justifications(blocks[1]).unwrap().is_none());
4838
4839		// Block 4 is inside the pruning window and still kept
4840		assert_eq!(
4841			Some(vec![UncheckedXt::new_transaction(4.into(), ())]),
4842			bc.body(blocks[4]).unwrap()
4843		);
4844		assert_eq!(
4845			Some(Justifications::from(build_justification(4))),
4846			bc.justifications(blocks[4]).unwrap()
4847		);
4848
4849		// Block tree:
4850		//   0 -> 1 -> 2 -> 3 -> 4 -> 5
4851		let hash = insert_block(
4852			&backend,
4853			5,
4854			prev_hash,
4855			None,
4856			Default::default(),
4857			vec![UncheckedXt::new_transaction(5.into(), ())],
4858			None,
4859		)
4860		.unwrap();
4861		blocks.push(hash);
4862
4863		backend.pin_block(blocks[4]).unwrap();
4864		// Mark block 5 as finalized.
4865		let mut op = backend.begin_operation().unwrap();
4866		backend.begin_state_operation(&mut op, blocks[5]).unwrap();
4867		op.mark_finalized(blocks[5], Some(build_justification(5))).unwrap();
4868		backend.commit_operation(op).unwrap();
4869
4870		assert!(bc.body(blocks[0]).unwrap().is_none());
4871		assert!(bc.body(blocks[1]).unwrap().is_none());
4872		assert!(bc.body(blocks[2]).unwrap().is_none());
4873		assert!(bc.body(blocks[3]).unwrap().is_none());
4874
4875		assert_eq!(
4876			Some(vec![UncheckedXt::new_transaction(4.into(), ())]),
4877			bc.body(blocks[4]).unwrap()
4878		);
4879		assert_eq!(
4880			Some(Justifications::from(build_justification(4))),
4881			bc.justifications(blocks[4]).unwrap()
4882		);
4883		assert_eq!(
4884			Some(vec![UncheckedXt::new_transaction(5.into(), ())]),
4885			bc.body(blocks[5]).unwrap()
4886		);
4887		assert!(bc.header(blocks[5]).ok().flatten().is_some());
4888
4889		backend.unpin_block(blocks[4]);
4890		assert!(bc.body(blocks[4]).unwrap().is_none());
4891		assert!(bc.justifications(blocks[4]).unwrap().is_none());
4892
4893		// Append a justification to block 5.
4894		backend.append_justification(blocks[5], ([0, 0, 0, 1], vec![42])).unwrap();
4895
4896		let hash = insert_block(
4897			&backend,
4898			6,
4899			blocks[5],
4900			None,
4901			Default::default(),
4902			vec![UncheckedXt::new_transaction(6.into(), ())],
4903			None,
4904		)
4905		.unwrap();
4906		blocks.push(hash);
4907
4908		// Pin block 5 so it gets loaded into the cache on prune
4909		backend.pin_block(blocks[5]).unwrap();
4910
4911		// Finalize block 6 so block 5 gets pruned. Since it is pinned both justifications should be
4912		// in memory.
4913		let mut op = backend.begin_operation().unwrap();
4914		backend.begin_state_operation(&mut op, blocks[6]).unwrap();
4915		op.mark_finalized(blocks[6], None).unwrap();
4916		backend.commit_operation(op).unwrap();
4917
4918		assert_eq!(
4919			Some(vec![UncheckedXt::new_transaction(5.into(), ())]),
4920			bc.body(blocks[5]).unwrap()
4921		);
4922		assert!(bc.header(blocks[5]).ok().flatten().is_some());
4923		let mut expected = Justifications::from(build_justification(5));
4924		expected.append(([0, 0, 0, 1], vec![42]));
4925		assert_eq!(Some(expected), bc.justifications(blocks[5]).unwrap());
4926	}
4927
4928	#[test]
4929	fn test_pinned_blocks_on_finalize_with_fork() {
4930		let backend = Backend::<Block>::new_test_with_tx_storage(BlocksPruning::Some(1), 10);
4931		let mut blocks = Vec::new();
4932		let mut prev_hash = Default::default();
4933
4934		// Block tree:
4935		//   0 -> 1 -> 2 -> 3 -> 4
4936		for i in 0..5 {
4937			let hash = insert_block(
4938				&backend,
4939				i,
4940				prev_hash,
4941				None,
4942				Default::default(),
4943				vec![UncheckedXt::new_transaction(i.into(), ())],
4944				None,
4945			)
4946			.unwrap();
4947			blocks.push(hash);
4948
4949			// Avoid block pruning.
4950			backend.pin_block(blocks[i as usize]).unwrap();
4951
4952			prev_hash = hash;
4953		}
4954
4955		// Insert a fork at the second block.
4956		// Block tree:
4957		//   0 -> 1 -> 2 -> 3 -> 4
4958		//        \ -> 2 -> 3
4959		let fork_hash_root = insert_block(
4960			&backend,
4961			2,
4962			blocks[1],
4963			None,
4964			H256::random(),
4965			vec![UncheckedXt::new_transaction(2.into(), ())],
4966			None,
4967		)
4968		.unwrap();
4969		let fork_hash_3 = insert_block(
4970			&backend,
4971			3,
4972			fork_hash_root,
4973			None,
4974			H256::random(),
4975			vec![
4976				UncheckedXt::new_transaction(3.into(), ()),
4977				UncheckedXt::new_transaction(11.into(), ()),
4978			],
4979			None,
4980		)
4981		.unwrap();
4982
4983		// Do not prune the fork hash.
4984		backend.pin_block(fork_hash_3).unwrap();
4985
4986		let mut op = backend.begin_operation().unwrap();
4987		backend.begin_state_operation(&mut op, blocks[4]).unwrap();
4988		op.mark_head(blocks[4]).unwrap();
4989		backend.commit_operation(op).unwrap();
4990
4991		for i in 1..5 {
4992			let mut op = backend.begin_operation().unwrap();
4993			backend.begin_state_operation(&mut op, blocks[4]).unwrap();
4994			op.mark_finalized(blocks[i], None).unwrap();
4995			backend.commit_operation(op).unwrap();
4996		}
4997
4998		let bc = backend.blockchain();
4999		assert_eq!(
5000			Some(vec![UncheckedXt::new_transaction(0.into(), ())]),
5001			bc.body(blocks[0]).unwrap()
5002		);
5003		assert_eq!(
5004			Some(vec![UncheckedXt::new_transaction(1.into(), ())]),
5005			bc.body(blocks[1]).unwrap()
5006		);
5007		assert_eq!(
5008			Some(vec![UncheckedXt::new_transaction(2.into(), ())]),
5009			bc.body(blocks[2]).unwrap()
5010		);
5011		assert_eq!(
5012			Some(vec![UncheckedXt::new_transaction(3.into(), ())]),
5013			bc.body(blocks[3]).unwrap()
5014		);
5015		assert_eq!(
5016			Some(vec![UncheckedXt::new_transaction(4.into(), ())]),
5017			bc.body(blocks[4]).unwrap()
5018		);
5019		// Check the fork hashes.
5020		assert_eq!(None, bc.body(fork_hash_root).unwrap());
5021		assert_eq!(
5022			Some(vec![
5023				UncheckedXt::new_transaction(3.into(), ()),
5024				UncheckedXt::new_transaction(11.into(), ())
5025			]),
5026			bc.body(fork_hash_3).unwrap()
5027		);
5028
5029		// Unpin all blocks, except the forked one.
5030		for block in &blocks {
5031			backend.unpin_block(*block);
5032		}
5033		assert!(bc.body(blocks[0]).unwrap().is_none());
5034		assert!(bc.body(blocks[1]).unwrap().is_none());
5035		assert!(bc.body(blocks[2]).unwrap().is_none());
5036		assert!(bc.body(blocks[3]).unwrap().is_none());
5037
5038		assert!(bc.body(fork_hash_3).unwrap().is_some());
5039		backend.unpin_block(fork_hash_3);
5040		assert!(bc.body(fork_hash_3).unwrap().is_none());
5041	}
5042}