1use std::collections::HashSet;
22
23use parking_lot::RwLock;
24
25use sp_api::CallContext;
26use sp_consensus::BlockOrigin;
27use sp_core::offchain::OffchainStorage;
28use sp_runtime::{
29 traits::{Block as BlockT, HashingFor, NumberFor},
30 Justification, Justifications, StateVersion, Storage,
31};
32use sp_state_machine::{
33 backend::AsTrieBackend, ChildStorageCollection, IndexOperation, IterArgs,
34 OffchainChangesCollection, StorageCollection, StorageIterator,
35};
36use sp_storage::{ChildInfo, StorageData, StorageKey};
37pub use sp_trie::MerkleValue;
38
39use crate::{blockchain::Backend as BlockchainBackend, UsageInfo};
40
41pub use sp_state_machine::{Backend as StateBackend, BackendTransaction, KeyValueStates};
42
43pub type StateBackendFor<B, Block> = <B as Backend<Block>>::State;
45
46#[derive(Debug, Clone, Copy)]
48pub enum ImportNotificationAction {
49 RecentBlock,
51 EveryBlock,
53 Both,
55 None,
57}
58
59pub struct ImportSummary<Block: BlockT> {
64 pub hash: Block::Hash,
66 pub origin: BlockOrigin,
68 pub header: Block::Header,
70 pub is_new_best: bool,
72 pub storage_changes: Option<(StorageCollection, ChildStorageCollection)>,
74 pub tree_route: Option<sp_blockchain::TreeRoute<Block>>,
78 pub import_notification_action: ImportNotificationAction,
80}
81
82pub struct FinalizeSummary<Block: BlockT> {
87 pub header: Block::Header,
89 pub finalized: Vec<Block::Hash>,
92 pub stale_heads: Vec<Block::Hash>,
94}
95
96pub struct ClientImportOperation<Block: BlockT, B: Backend<Block>> {
98 pub op: B::BlockImportOperation,
100 pub notify_imported: Option<ImportSummary<Block>>,
102 pub notify_finalized: Option<FinalizeSummary<Block>>,
104}
105
106pub fn apply_aux<'a, 'b: 'a, 'c: 'a, B, Block, D, I>(
108 operation: &mut ClientImportOperation<Block, B>,
109 insert: I,
110 delete: D,
111) -> sp_blockchain::Result<()>
112where
113 Block: BlockT,
114 B: Backend<Block>,
115 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
116 D: IntoIterator<Item = &'a &'b [u8]>,
117{
118 operation.op.insert_aux(
119 insert
120 .into_iter()
121 .map(|(k, v)| (k.to_vec(), Some(v.to_vec())))
122 .chain(delete.into_iter().map(|k| (k.to_vec(), None))),
123 )
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128pub enum NewBlockState {
129 Normal,
131 Best,
133 Final,
135}
136
137impl NewBlockState {
138 pub fn is_best(self) -> bool {
140 match self {
141 NewBlockState::Best | NewBlockState::Final => true,
142 NewBlockState::Normal => false,
143 }
144 }
145
146 pub fn is_final(self) -> bool {
148 match self {
149 NewBlockState::Final => true,
150 NewBlockState::Best | NewBlockState::Normal => false,
151 }
152 }
153}
154
155pub trait BlockImportOperation<Block: BlockT> {
159 type State: StateBackend<HashingFor<Block>>;
161
162 fn state(&self) -> sp_blockchain::Result<Option<&Self::State>>;
166
167 fn set_block_data(
169 &mut self,
170 header: Block::Header,
171 body: Option<Vec<Block::Extrinsic>>,
172 indexed_body: Option<Vec<Vec<u8>>>,
173 justifications: Option<Justifications>,
174 state: NewBlockState,
175 ) -> sp_blockchain::Result<()>;
176
177 fn update_db_storage(
179 &mut self,
180 update: BackendTransaction<HashingFor<Block>>,
181 ) -> sp_blockchain::Result<()>;
182
183 fn set_genesis_state(
186 &mut self,
187 storage: Storage,
188 commit: bool,
189 state_version: StateVersion,
190 ) -> sp_blockchain::Result<Block::Hash>;
191
192 fn reset_storage(
194 &mut self,
195 storage: Storage,
196 state_version: StateVersion,
197 ) -> sp_blockchain::Result<Block::Hash>;
198
199 fn update_storage(
201 &mut self,
202 update: StorageCollection,
203 child_update: ChildStorageCollection,
204 ) -> sp_blockchain::Result<()>;
205
206 fn update_offchain_storage(
208 &mut self,
209 _offchain_update: OffchainChangesCollection,
210 ) -> sp_blockchain::Result<()> {
211 Ok(())
212 }
213
214 fn insert_aux<I>(&mut self, ops: I) -> sp_blockchain::Result<()>
218 where
219 I: IntoIterator<Item = (Vec<u8>, Option<Vec<u8>>)>;
220
221 fn mark_finalized(
224 &mut self,
225 hash: Block::Hash,
226 justification: Option<Justification>,
227 ) -> sp_blockchain::Result<()>;
228
229 fn mark_head(&mut self, hash: Block::Hash) -> sp_blockchain::Result<()>;
232
233 fn update_transaction_index(&mut self, index: Vec<IndexOperation>)
235 -> sp_blockchain::Result<()>;
236
237 fn set_create_gap(&mut self, create_gap: bool);
239}
240
241pub trait LockImportRun<Block: BlockT, B: Backend<Block>> {
243 fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
245 where
246 F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
247 Err: From<sp_blockchain::Error>;
248}
249
250pub trait Finalizer<Block: BlockT, B: Backend<Block>> {
252 fn apply_finality(
262 &self,
263 operation: &mut ClientImportOperation<Block, B>,
264 block: Block::Hash,
265 justification: Option<Justification>,
266 notify: bool,
267 ) -> sp_blockchain::Result<()>;
268
269 fn finalize_block(
283 &self,
284 block: Block::Hash,
285 justification: Option<Justification>,
286 notify: bool,
287 ) -> sp_blockchain::Result<()>;
288}
289
290pub trait AuxStore {
296 fn insert_aux<
300 'a,
301 'b: 'a,
302 'c: 'a,
303 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
304 D: IntoIterator<Item = &'a &'b [u8]>,
305 >(
306 &self,
307 insert: I,
308 delete: D,
309 ) -> sp_blockchain::Result<()>;
310
311 fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>>;
313}
314
315pub struct KeysIter<State, Block>
317where
318 State: StateBackend<HashingFor<Block>>,
319 Block: BlockT,
320{
321 inner: <State as StateBackend<HashingFor<Block>>>::RawIter,
322 state: State,
323}
324
325impl<State, Block> KeysIter<State, Block>
326where
327 State: StateBackend<HashingFor<Block>>,
328 Block: BlockT,
329{
330 pub fn new(
332 state: State,
333 prefix: Option<&StorageKey>,
334 start_at: Option<&StorageKey>,
335 ) -> Result<Self, State::Error> {
336 let mut args = IterArgs::default();
337 args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice());
338 args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice());
339 args.start_at_exclusive = true;
340
341 Ok(Self { inner: state.raw_iter(args)?, state })
342 }
343
344 pub fn new_child(
346 state: State,
347 child_info: ChildInfo,
348 prefix: Option<&StorageKey>,
349 start_at: Option<&StorageKey>,
350 ) -> Result<Self, State::Error> {
351 let mut args = IterArgs::default();
352 args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice());
353 args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice());
354 args.child_info = Some(child_info);
355 args.start_at_exclusive = true;
356
357 Ok(Self { inner: state.raw_iter(args)?, state })
358 }
359}
360
361impl<State, Block> Iterator for KeysIter<State, Block>
362where
363 Block: BlockT,
364 State: StateBackend<HashingFor<Block>>,
365{
366 type Item = StorageKey;
367
368 fn next(&mut self) -> Option<Self::Item> {
369 self.inner.next_key(&self.state)?.ok().map(StorageKey)
370 }
371}
372
373pub struct PairsIter<State, Block>
375where
376 State: StateBackend<HashingFor<Block>>,
377 Block: BlockT,
378{
379 inner: <State as StateBackend<HashingFor<Block>>>::RawIter,
380 state: State,
381}
382
383impl<State, Block> Iterator for PairsIter<State, Block>
384where
385 Block: BlockT,
386 State: StateBackend<HashingFor<Block>>,
387{
388 type Item = (StorageKey, StorageData);
389
390 fn next(&mut self) -> Option<Self::Item> {
391 self.inner
392 .next_pair(&self.state)?
393 .ok()
394 .map(|(key, value)| (StorageKey(key), StorageData(value)))
395 }
396}
397
398impl<State, Block> PairsIter<State, Block>
399where
400 State: StateBackend<HashingFor<Block>>,
401 Block: BlockT,
402{
403 pub fn new(
405 state: State,
406 prefix: Option<&StorageKey>,
407 start_at: Option<&StorageKey>,
408 ) -> Result<Self, State::Error> {
409 let mut args = IterArgs::default();
410 args.prefix = prefix.as_ref().map(|prefix| prefix.0.as_slice());
411 args.start_at = start_at.as_ref().map(|start_at| start_at.0.as_slice());
412 args.start_at_exclusive = true;
413
414 Ok(Self { inner: state.raw_iter(args)?, state })
415 }
416}
417
418pub trait StorageProvider<Block: BlockT, B: Backend<Block>> {
420 fn storage(
422 &self,
423 hash: Block::Hash,
424 key: &StorageKey,
425 ) -> sp_blockchain::Result<Option<StorageData>>;
426
427 fn storage_hash(
429 &self,
430 hash: Block::Hash,
431 key: &StorageKey,
432 ) -> sp_blockchain::Result<Option<Block::Hash>>;
433
434 fn storage_keys(
437 &self,
438 hash: Block::Hash,
439 prefix: Option<&StorageKey>,
440 start_key: Option<&StorageKey>,
441 ) -> sp_blockchain::Result<KeysIter<B::State, Block>>;
442
443 fn storage_pairs(
446 &self,
447 hash: <Block as BlockT>::Hash,
448 prefix: Option<&StorageKey>,
449 start_key: Option<&StorageKey>,
450 ) -> sp_blockchain::Result<PairsIter<B::State, Block>>;
451
452 fn child_storage(
455 &self,
456 hash: Block::Hash,
457 child_info: &ChildInfo,
458 key: &StorageKey,
459 ) -> sp_blockchain::Result<Option<StorageData>>;
460
461 fn child_storage_keys(
464 &self,
465 hash: Block::Hash,
466 child_info: ChildInfo,
467 prefix: Option<&StorageKey>,
468 start_key: Option<&StorageKey>,
469 ) -> sp_blockchain::Result<KeysIter<B::State, Block>>;
470
471 fn child_storage_hash(
474 &self,
475 hash: Block::Hash,
476 child_info: &ChildInfo,
477 key: &StorageKey,
478 ) -> sp_blockchain::Result<Option<Block::Hash>>;
479
480 fn closest_merkle_value(
482 &self,
483 hash: Block::Hash,
484 key: &StorageKey,
485 ) -> sp_blockchain::Result<Option<MerkleValue<Block::Hash>>>;
486
487 fn child_closest_merkle_value(
489 &self,
490 hash: Block::Hash,
491 child_info: &ChildInfo,
492 key: &StorageKey,
493 ) -> sp_blockchain::Result<Option<MerkleValue<Block::Hash>>>;
494}
495
496#[derive(Debug, Clone, Copy)]
500pub enum TrieCacheContext {
501 Trusted,
509 Untrusted,
513}
514
515impl From<CallContext> for TrieCacheContext {
516 fn from(call_context: CallContext) -> Self {
517 match call_context {
518 CallContext::Onchain => TrieCacheContext::Trusted,
519 CallContext::Offchain => TrieCacheContext::Untrusted,
520 }
521 }
522}
523
524pub trait Backend<Block: BlockT>: AuxStore + Send + Sync {
547 type BlockImportOperation: BlockImportOperation<Block, State = Self::State>;
549 type Blockchain: BlockchainBackend<Block>;
551 type State: StateBackend<HashingFor<Block>>
553 + Send
554 + AsTrieBackend<
555 HashingFor<Block>,
556 TrieBackendStorage = <Self::State as StateBackend<HashingFor<Block>>>::TrieBackendStorage,
557 >;
558 type OffchainStorage: OffchainStorage;
560
561 fn begin_operation(&self) -> sp_blockchain::Result<Self::BlockImportOperation>;
565
566 fn begin_state_operation(
568 &self,
569 operation: &mut Self::BlockImportOperation,
570 block: Block::Hash,
571 ) -> sp_blockchain::Result<()>;
572
573 fn commit_operation(
575 &self,
576 transaction: Self::BlockImportOperation,
577 ) -> sp_blockchain::Result<()>;
578
579 fn finalize_block(
583 &self,
584 hash: Block::Hash,
585 justification: Option<Justification>,
586 ) -> sp_blockchain::Result<()>;
587
588 fn append_justification(
592 &self,
593 hash: Block::Hash,
594 justification: Justification,
595 ) -> sp_blockchain::Result<()>;
596
597 fn blockchain(&self) -> &Self::Blockchain;
599
600 fn usage_info(&self) -> Option<UsageInfo>;
602
603 fn offchain_storage(&self) -> Option<Self::OffchainStorage>;
605
606 fn pin_block(&self, hash: Block::Hash) -> sp_blockchain::Result<()>;
610
611 fn unpin_block(&self, hash: Block::Hash);
613
614 fn have_state_at(&self, hash: Block::Hash, _number: NumberFor<Block>) -> bool {
616 self.state_at(hash, TrieCacheContext::Untrusted).is_ok()
617 }
618
619 fn state_at(
621 &self,
622 hash: Block::Hash,
623 trie_cache_context: TrieCacheContext,
624 ) -> sp_blockchain::Result<Self::State>;
625
626 fn revert(
634 &self,
635 n: NumberFor<Block>,
636 revert_finalized: bool,
637 ) -> sp_blockchain::Result<(NumberFor<Block>, HashSet<Block::Hash>)>;
638
639 fn remove_leaf_block(&self, hash: Block::Hash) -> sp_blockchain::Result<()>;
641
642 fn insert_aux<
644 'a,
645 'b: 'a,
646 'c: 'a,
647 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
648 D: IntoIterator<Item = &'a &'b [u8]>,
649 >(
650 &self,
651 insert: I,
652 delete: D,
653 ) -> sp_blockchain::Result<()> {
654 AuxStore::insert_aux(self, insert, delete)
655 }
656 fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
658 AuxStore::get_aux(self, key)
659 }
660
661 fn get_import_lock(&self) -> &RwLock<()>;
668
669 fn requires_full_sync(&self) -> bool;
671}
672
673pub trait LocalBackend<Block: BlockT>: Backend<Block> {}