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