referrerpolicy=no-referrer-when-downgrade

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