sc_client_db/
lib.rs

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