pezsc_client_db/
lib.rs

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