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