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