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