1use super::{
22 block_rules::{BlockRules, LookupResult as BlockLookupResult},
23 CodeProvider,
24};
25use crate::client::notification_pinning::NotificationPinningWorker;
26use log::{debug, info, trace, warn};
27use parking_lot::{Mutex, RwLock};
28use prometheus_endpoint::Registry;
29use rand::Rng;
30use sc_chain_spec::{resolve_state_version_from_wasm, BuildGenesisBlock};
31use sc_client_api::{
32 backend::{
33 self, apply_aux, BlockImportOperation, ClientImportOperation, FinalizeSummary, Finalizer,
34 ImportNotificationAction, ImportSummary, LockImportRun, NewBlockState, StorageProvider,
35 },
36 client::{
37 BadBlocks, BlockBackend, BlockImportNotification, BlockOf, BlockchainEvents, ClientInfo,
38 FinalityNotification, FinalityNotifications, ForkBlocks, ImportNotifications,
39 PreCommitActions, ProvideUncles,
40 },
41 execution_extensions::ExecutionExtensions,
42 notifications::{StorageEventStream, StorageNotifications},
43 CallExecutor, ExecutorProvider, KeysIter, OnFinalityAction, OnImportAction, PairsIter,
44 ProofProvider, StaleBlock, TrieCacheContext, UnpinWorkerMessage, UsageProvider,
45};
46use sc_consensus::{
47 BlockCheckParams, BlockImportParams, ForkChoiceStrategy, ImportResult, StateAction,
48};
49use sc_executor::RuntimeVersion;
50use sc_telemetry::{telemetry, TelemetryHandle, SUBSTRATE_INFO};
51use sp_api::{
52 ApiExt, ApiRef, CallApiAt, CallApiAtParams, ConstructRuntimeApi, Core as CoreApi,
53 ProvideRuntimeApi,
54};
55use sp_blockchain::{
56 self as blockchain, Backend as ChainBackend, CachedHeaderMetadata, Error,
57 HeaderBackend as ChainHeaderBackend, HeaderMetadata, Info as BlockchainInfo,
58};
59use sp_consensus::{BlockOrigin, BlockStatus, Error as ConsensusError};
60
61use sc_utils::mpsc::{tracing_unbounded, TracingUnboundedSender};
62use sp_core::{
63 storage::{ChildInfo, ChildType, PrefixedStorageKey, StorageChild, StorageData, StorageKey},
64 traits::{CallContext, SpawnNamed},
65};
66use sp_runtime::{
67 generic::{BlockId, SignedBlock},
68 traits::{
69 Block as BlockT, BlockIdTo, HashingFor, Header as HeaderT, NumberFor, One,
70 SaturatedConversion, Zero,
71 },
72 Justification, Justifications, StateVersion,
73};
74use sp_state_machine::{
75 prove_child_read, prove_range_read_with_child_with_size, prove_read,
76 read_range_proof_check_with_child_on_proving_backend, Backend as StateBackend,
77 ChildStorageCollection, KeyValueStates, KeyValueStorageLevel, StorageCollection,
78 MAX_NESTED_TRIE_DEPTH,
79};
80use sp_trie::{proof_size_extension::ProofSizeExt, CompactProof, MerkleValue, StorageProof};
81use std::{
82 collections::{HashMap, HashSet},
83 marker::PhantomData,
84 path::PathBuf,
85 sync::Arc,
86};
87
88use super::call_executor::LocalCallExecutor;
89use sp_core::traits::CodeExecutor;
90
91type NotificationSinks<T> = Mutex<Vec<TracingUnboundedSender<T>>>;
92
93pub struct Client<B, E, Block, RA>
95where
96 Block: BlockT,
97{
98 backend: Arc<B>,
99 executor: E,
100 storage_notifications: StorageNotifications<Block>,
101 import_notification_sinks: NotificationSinks<BlockImportNotification<Block>>,
102 every_import_notification_sinks: NotificationSinks<BlockImportNotification<Block>>,
103 finality_notification_sinks: NotificationSinks<FinalityNotification<Block>>,
104 import_actions: Mutex<Vec<OnImportAction<Block>>>,
107 finality_actions: Mutex<Vec<OnFinalityAction<Block>>>,
110 importing_block: RwLock<Option<Block::Hash>>,
112 block_rules: BlockRules<Block>,
113 config: ClientConfig<Block>,
114 telemetry: Option<TelemetryHandle>,
115 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
116 code_provider: CodeProvider<Block, B, E>,
117 _phantom: PhantomData<RA>,
118}
119
120enum PrePostHeader<H> {
123 Same(H),
125 Different(H, H),
127}
128
129impl<H> PrePostHeader<H> {
130 fn post(&self) -> &H {
133 match *self {
134 PrePostHeader::Same(ref h) => h,
135 PrePostHeader::Different(_, ref h) => h,
136 }
137 }
138
139 fn into_post(self) -> H {
142 match self {
143 PrePostHeader::Same(h) => h,
144 PrePostHeader::Different(_, h) => h,
145 }
146 }
147}
148
149enum PrepareStorageChangesResult<Block: BlockT> {
150 Discard(ImportResult),
151 Import(Option<sc_consensus::StorageChanges<Block>>),
152}
153#[derive(Debug, Clone)]
155pub struct ClientConfig<Block: BlockT> {
156 pub offchain_worker_enabled: bool,
158 pub offchain_indexing_api: bool,
160 pub wasm_runtime_overrides: Option<PathBuf>,
162 pub no_genesis: bool,
164 pub wasm_runtime_substitutes: HashMap<NumberFor<Block>, Vec<u8>>,
167 pub enable_import_proof_recording: bool,
169}
170
171impl<Block: BlockT> Default for ClientConfig<Block> {
172 fn default() -> Self {
173 Self {
174 offchain_worker_enabled: false,
175 offchain_indexing_api: false,
176 wasm_runtime_overrides: None,
177 no_genesis: false,
178 wasm_runtime_substitutes: HashMap::new(),
179 enable_import_proof_recording: false,
180 }
181 }
182}
183
184pub fn new_with_backend<B, E, Block, G, RA>(
187 backend: Arc<B>,
188 executor: E,
189 genesis_block_builder: G,
190 spawn_handle: Box<dyn SpawnNamed>,
191 prometheus_registry: Option<Registry>,
192 telemetry: Option<TelemetryHandle>,
193 config: ClientConfig<Block>,
194) -> sp_blockchain::Result<Client<B, LocalCallExecutor<Block, B, E>, Block, RA>>
195where
196 E: CodeExecutor + sc_executor::RuntimeVersionOf,
197 G: BuildGenesisBlock<
198 Block,
199 BlockImportOperation = <B as backend::Backend<Block>>::BlockImportOperation,
200 >,
201 Block: BlockT,
202 B: backend::LocalBackend<Block> + 'static,
203{
204 let extensions = ExecutionExtensions::new(None, Arc::new(executor.clone()));
205
206 let call_executor =
207 LocalCallExecutor::new(backend.clone(), executor, config.clone(), extensions)?;
208
209 Client::new(
210 backend,
211 call_executor,
212 spawn_handle,
213 genesis_block_builder,
214 Default::default(),
215 Default::default(),
216 prometheus_registry,
217 telemetry,
218 config,
219 )
220}
221
222impl<B, E, Block, RA> BlockOf for Client<B, E, Block, RA>
223where
224 B: backend::Backend<Block>,
225 E: CallExecutor<Block>,
226 Block: BlockT,
227{
228 type Type = Block;
229}
230
231impl<B, E, Block, RA> LockImportRun<Block, B> for Client<B, E, Block, RA>
232where
233 B: backend::Backend<Block>,
234 E: CallExecutor<Block>,
235 Block: BlockT,
236{
237 fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
238 where
239 F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
240 Err: From<sp_blockchain::Error>,
241 {
242 let inner = || {
243 let _import_lock = self.backend.get_import_lock().write();
244
245 let mut op = ClientImportOperation {
246 op: self.backend.begin_operation()?,
247 notify_imported: None,
248 notify_finalized: None,
249 };
250
251 let r = f(&mut op)?;
252
253 let ClientImportOperation { mut op, notify_imported, notify_finalized } = op;
254
255 let finality_notification = notify_finalized.map(|summary| {
256 FinalityNotification::from_summary(summary, self.unpin_worker_sender.clone())
257 });
258
259 let (import_notification, storage_changes, import_notification_action) =
260 match notify_imported {
261 Some(mut summary) => {
262 let import_notification_action = summary.import_notification_action;
263 let storage_changes = summary.storage_changes.take();
264 (
265 Some(BlockImportNotification::from_summary(
266 summary,
267 self.unpin_worker_sender.clone(),
268 )),
269 storage_changes,
270 import_notification_action,
271 )
272 },
273 None => (None, None, ImportNotificationAction::None),
274 };
275
276 if let Some(ref notification) = finality_notification {
277 for action in self.finality_actions.lock().iter_mut() {
278 op.insert_aux(action(notification))?;
279 }
280 }
281 if let Some(ref notification) = import_notification {
282 for action in self.import_actions.lock().iter_mut() {
283 op.insert_aux(action(notification))?;
284 }
285 }
286
287 self.backend.commit_operation(op)?;
288
289 if let Some(ref notification) = finality_notification {
293 if let Err(err) = self.backend.pin_block(notification.hash) {
294 debug!(
295 "Unable to pin block for finality notification. hash: {}, Error: {}",
296 notification.hash, err
297 );
298 } else {
299 let _ = self
300 .unpin_worker_sender
301 .unbounded_send(UnpinWorkerMessage::AnnouncePin(notification.hash))
302 .map_err(|e| {
303 log::error!(
304 "Unable to send AnnouncePin worker message for finality: {e}"
305 )
306 });
307 }
308 }
309
310 if let Some(ref notification) = import_notification {
311 if let Err(err) = self.backend.pin_block(notification.hash) {
312 debug!(
313 "Unable to pin block for import notification. hash: {}, Error: {}",
314 notification.hash, err
315 );
316 } else {
317 let _ = self
318 .unpin_worker_sender
319 .unbounded_send(UnpinWorkerMessage::AnnouncePin(notification.hash))
320 .map_err(|e| {
321 log::error!("Unable to send AnnouncePin worker message for import: {e}")
322 });
323 };
324 }
325
326 self.notify_finalized(finality_notification)?;
327 self.notify_imported(import_notification, import_notification_action, storage_changes)?;
328
329 Ok(r)
330 };
331
332 let result = inner();
333 *self.importing_block.write() = None;
334
335 result
336 }
337}
338
339impl<B, E, Block, RA> LockImportRun<Block, B> for &Client<B, E, Block, RA>
340where
341 Block: BlockT,
342 B: backend::Backend<Block>,
343 E: CallExecutor<Block>,
344{
345 fn lock_import_and_run<R, Err, F>(&self, f: F) -> Result<R, Err>
346 where
347 F: FnOnce(&mut ClientImportOperation<Block, B>) -> Result<R, Err>,
348 Err: From<sp_blockchain::Error>,
349 {
350 (**self).lock_import_and_run(f)
351 }
352}
353
354impl<B, E, Block, RA> Client<B, E, Block, RA>
355where
356 B: backend::Backend<Block>,
357 E: CallExecutor<Block>,
358 Block: BlockT,
359 Block::Header: Clone,
360{
361 pub fn new<G>(
363 backend: Arc<B>,
364 executor: E,
365 spawn_handle: Box<dyn SpawnNamed>,
366 genesis_block_builder: G,
367 fork_blocks: ForkBlocks<Block>,
368 bad_blocks: BadBlocks<Block>,
369 prometheus_registry: Option<Registry>,
370 telemetry: Option<TelemetryHandle>,
371 config: ClientConfig<Block>,
372 ) -> sp_blockchain::Result<Self>
373 where
374 G: BuildGenesisBlock<
375 Block,
376 BlockImportOperation = <B as backend::Backend<Block>>::BlockImportOperation,
377 >,
378 E: Clone,
379 B: 'static,
380 {
381 let info = backend.blockchain().info();
382 if info.finalized_state.is_none() {
383 let (genesis_block, mut op) = genesis_block_builder.build_genesis_block()?;
384 info!(
385 "🔨 Initializing Genesis block/state (state: {}, header-hash: {})",
386 genesis_block.header().state_root(),
387 genesis_block.header().hash()
388 );
389 let block_state = if info.best_hash == Default::default() {
392 NewBlockState::Final
393 } else {
394 NewBlockState::Normal
395 };
396 let (header, body) = genesis_block.deconstruct();
397 op.set_block_data(header, Some(body), None, None, block_state, true)?;
398 backend.commit_operation(op)?;
399 }
400
401 let (unpin_worker_sender, rx) = tracing_unbounded::<UnpinWorkerMessage<Block>>(
402 "notification-pinning-worker-channel",
403 10_000,
404 );
405 let unpin_worker = NotificationPinningWorker::new(rx, backend.clone());
406 spawn_handle.spawn("notification-pinning-worker", None, Box::pin(unpin_worker.run()));
407 let code_provider = CodeProvider::new(&config, executor.clone(), backend.clone())?;
408
409 Ok(Client {
410 backend,
411 executor,
412 storage_notifications: StorageNotifications::new(prometheus_registry),
413 import_notification_sinks: Default::default(),
414 every_import_notification_sinks: Default::default(),
415 finality_notification_sinks: Default::default(),
416 import_actions: Default::default(),
417 finality_actions: Default::default(),
418 importing_block: Default::default(),
419 block_rules: BlockRules::new(fork_blocks, bad_blocks),
420 config,
421 telemetry,
422 unpin_worker_sender,
423 code_provider,
424 _phantom: Default::default(),
425 })
426 }
427
428 pub fn import_notification_sinks(&self) -> &NotificationSinks<BlockImportNotification<Block>> {
431 &self.import_notification_sinks
432 }
433
434 pub fn finality_notification_sinks(&self) -> &NotificationSinks<FinalityNotification<Block>> {
437 &self.finality_notification_sinks
438 }
439
440 pub fn state_at(&self, hash: Block::Hash) -> sp_blockchain::Result<B::State> {
442 self.backend.state_at(hash, TrieCacheContext::Untrusted)
443 }
444
445 pub fn code_at(&self, hash: Block::Hash) -> sp_blockchain::Result<Vec<u8>> {
449 self.code_provider.code_at_ignoring_overrides(hash)
450 }
451
452 pub fn runtime_version_at(
454 &self,
455 hash: Block::Hash,
456 call_context: CallContext,
457 ) -> sp_blockchain::Result<RuntimeVersion> {
458 CallExecutor::runtime_version(&self.executor, hash, call_context)
459 }
460
461 fn apply_block(
463 &self,
464 operation: &mut ClientImportOperation<Block, B>,
465 import_block: BlockImportParams<Block>,
466 storage_changes: Option<sc_consensus::StorageChanges<Block>>,
467 ) -> sp_blockchain::Result<ImportResult>
468 where
469 Self: ProvideRuntimeApi<Block>,
470 <Self as ProvideRuntimeApi<Block>>::Api: CoreApi<Block> + ApiExt<Block>,
471 {
472 let BlockImportParams {
473 origin,
474 header,
475 justifications,
476 post_digests,
477 body,
478 indexed_body,
479 finalized,
480 auxiliary,
481 fork_choice,
482 intermediates,
483 import_existing,
484 create_gap,
485 ..
486 } = import_block;
487
488 if !intermediates.is_empty() {
489 return Err(Error::IncompletePipeline);
490 }
491
492 let fork_choice = fork_choice.ok_or(Error::IncompletePipeline)?;
493
494 let import_headers = if post_digests.is_empty() {
495 PrePostHeader::Same(header)
496 } else {
497 let mut post_header = header.clone();
498 for item in post_digests {
499 post_header.digest_mut().push(item);
500 }
501 PrePostHeader::Different(header, post_header)
502 };
503
504 let hash = import_headers.post().hash();
505 let height = (*import_headers.post().number()).saturated_into::<u64>();
506
507 *self.importing_block.write() = Some(hash);
508
509 operation.op.set_create_gap(create_gap);
510
511 let result = self.execute_and_import_block(
512 operation,
513 origin,
514 hash,
515 import_headers,
516 justifications,
517 body,
518 indexed_body,
519 storage_changes,
520 finalized,
521 auxiliary,
522 fork_choice,
523 import_existing,
524 );
525
526 if let Ok(ImportResult::Imported(ref aux)) = result {
527 if aux.is_new_best {
528 if origin != BlockOrigin::NetworkInitialSync || rand::thread_rng().gen_bool(0.1) {
532 telemetry!(
533 self.telemetry;
534 SUBSTRATE_INFO;
535 "block.import";
536 "height" => height,
537 "best" => ?hash,
538 "origin" => ?origin
539 );
540 }
541 }
542 }
543
544 result
545 }
546
547 fn execute_and_import_block(
548 &self,
549 operation: &mut ClientImportOperation<Block, B>,
550 origin: BlockOrigin,
551 hash: Block::Hash,
552 import_headers: PrePostHeader<Block::Header>,
553 justifications: Option<Justifications>,
554 body: Option<Vec<Block::Extrinsic>>,
555 indexed_body: Option<Vec<Vec<u8>>>,
556 storage_changes: Option<sc_consensus::StorageChanges<Block>>,
557 finalized: bool,
558 aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
559 fork_choice: ForkChoiceStrategy,
560 import_existing: bool,
561 ) -> sp_blockchain::Result<ImportResult>
562 where
563 Self: ProvideRuntimeApi<Block>,
564 <Self as ProvideRuntimeApi<Block>>::Api: CoreApi<Block> + ApiExt<Block>,
565 {
566 let parent_hash = *import_headers.post().parent_hash();
567 let status = self.backend.blockchain().status(hash)?;
568 let parent_exists =
569 self.backend.blockchain().status(parent_hash)? == blockchain::BlockStatus::InChain;
570
571 match (import_existing, status) {
572 (false, blockchain::BlockStatus::InChain) => return Ok(ImportResult::AlreadyInChain),
573 (false, blockchain::BlockStatus::Unknown) => {},
574 (true, blockchain::BlockStatus::InChain) => {},
575 (true, blockchain::BlockStatus::Unknown) => {},
576 }
577
578 let info = self.backend.blockchain().info();
579 let gap_block =
580 info.block_gap.map_or(false, |gap| *import_headers.post().number() == gap.start);
581
582 if status == blockchain::BlockStatus::Unknown &&
585 *import_headers.post().number() <= info.finalized_number &&
586 !gap_block
587 {
588 return Err(sp_blockchain::Error::NotInFinalizedChain);
589 }
590
591 let make_notifications = match origin {
595 BlockOrigin::NetworkBroadcast | BlockOrigin::Own | BlockOrigin::ConsensusBroadcast => {
596 true
597 },
598 BlockOrigin::Genesis |
599 BlockOrigin::NetworkInitialSync |
600 BlockOrigin::File |
601 BlockOrigin::WarpSync |
602 BlockOrigin::GapSync => false,
603 };
604
605 let storage_changes = match storage_changes {
606 Some(storage_changes) => {
607 let storage_changes = match storage_changes {
608 sc_consensus::StorageChanges::Changes(storage_changes) => {
609 self.backend.begin_state_operation(&mut operation.op, parent_hash)?;
610 let (main_sc, child_sc, offchain_sc, tx, _, tx_index) =
611 storage_changes.into_inner();
612
613 if self.config.offchain_indexing_api {
614 operation.op.update_offchain_storage(offchain_sc)?;
615 }
616
617 operation.op.update_db_storage(tx)?;
618 operation.op.update_storage(main_sc.clone(), child_sc.clone())?;
619 operation.op.update_transaction_index(tx_index)?;
620
621 Some((main_sc, child_sc))
622 },
623 sc_consensus::StorageChanges::Import(changes) => {
624 let mut storage = sp_storage::Storage::default();
625 for state in changes.state.0.into_iter() {
626 if state.parent_storage_keys.is_empty() && state.state_root.is_empty() {
627 for (key, value) in state.key_values.into_iter() {
628 storage.top.insert(key, value);
629 }
630 } else {
631 for parent_storage in state.parent_storage_keys {
632 let storage_key = PrefixedStorageKey::new_ref(&parent_storage);
633 let storage_key =
634 match ChildType::from_prefixed_key(storage_key) {
635 Some((ChildType::ParentKeyId, storage_key)) => {
636 storage_key
637 },
638 None => {
639 return Err(Error::Backend(
640 "Invalid child storage key.".to_string(),
641 ))
642 },
643 };
644 let entry = storage
645 .children_default
646 .entry(storage_key.to_vec())
647 .or_insert_with(|| StorageChild {
648 data: Default::default(),
649 child_info: ChildInfo::new_default(storage_key),
650 });
651 for (key, value) in state.key_values.iter() {
652 entry.data.insert(key.clone(), value.clone());
653 }
654 }
655 }
656 }
657
658 let state_version = resolve_state_version_from_wasm::<_, HashingFor<Block>>(
661 &storage,
662 &self.executor,
663 )?;
664 let state_root = operation.op.reset_storage(storage, state_version)?;
665 if state_root != *import_headers.post().state_root() {
666 warn!("Error importing state: State root mismatch.");
669 return Err(Error::InvalidStateRoot);
670 }
671 None
672 },
673 };
674
675 storage_changes
676 },
677 None => None,
678 };
679
680 if finalized && parent_exists && info.finalized_hash != parent_hash {
683 self.apply_finality_with_block_hash(
684 operation,
685 parent_hash,
686 None,
687 &info,
688 make_notifications,
689 )?;
690 }
691
692 let is_new_best = !gap_block &&
693 (finalized ||
694 match fork_choice {
695 ForkChoiceStrategy::LongestChain => {
696 import_headers.post().number() > &info.best_number
697 },
698 ForkChoiceStrategy::Custom(v) => v,
699 });
700
701 let leaf_state = if finalized {
702 NewBlockState::Final
703 } else if is_new_best {
704 NewBlockState::Best
705 } else {
706 NewBlockState::Normal
707 };
708
709 let register_as_leaf = origin != BlockOrigin::WarpSync;
712
713 let tree_route = if is_new_best && info.best_hash != parent_hash && parent_exists {
714 let route_from_best =
715 sp_blockchain::tree_route(self.backend.blockchain(), info.best_hash, parent_hash)?;
716 Some(route_from_best)
717 } else {
718 None
719 };
720
721 trace!(
722 "Imported {}, (#{}), best={}, origin={:?}",
723 hash,
724 import_headers.post().number(),
725 is_new_best,
726 origin,
727 );
728
729 operation.op.set_block_data(
730 import_headers.post().clone(),
731 body,
732 indexed_body,
733 justifications,
734 leaf_state,
735 register_as_leaf,
736 )?;
737
738 operation.op.insert_aux(aux)?;
739
740 let should_notify_every_block = !self.every_import_notification_sinks.lock().is_empty();
741
742 let should_notify_recent_block = make_notifications || tree_route.is_some();
745
746 if should_notify_every_block || should_notify_recent_block {
747 let header = import_headers.into_post();
748 if finalized && should_notify_recent_block {
749 let mut summary = match operation.notify_finalized.take() {
750 Some(mut summary) => {
751 summary.header = header.clone();
752 summary.finalized.push(hash);
753 summary
754 },
755 None => FinalizeSummary {
756 header: header.clone(),
757 finalized: vec![hash],
758 stale_blocks: Vec::new(),
759 },
760 };
761
762 if parent_exists {
763 let stale_heads = self.backend.blockchain().displaced_leaves_after_finalizing(
765 hash,
766 *header.number(),
767 parent_hash,
768 )?;
769
770 summary.stale_blocks.extend(stale_heads.displaced_blocks.into_iter().map(
771 |b| StaleBlock {
772 hash: b,
773 is_head: stale_heads.displaced_leaves.iter().any(|(_, h)| *h == b),
774 },
775 ));
776 }
777 operation.notify_finalized = Some(summary);
778 }
779
780 let import_notification_action = if should_notify_every_block {
781 if should_notify_recent_block {
782 ImportNotificationAction::Both
783 } else {
784 ImportNotificationAction::EveryBlock
785 }
786 } else {
787 ImportNotificationAction::RecentBlock
788 };
789
790 operation.notify_imported = Some(ImportSummary {
791 hash,
792 origin,
793 header,
794 is_new_best,
795 storage_changes,
796 tree_route,
797 import_notification_action,
798 })
799 }
800
801 Ok(ImportResult::imported(is_new_best))
802 }
803
804 fn prepare_block_storage_changes(
810 &self,
811 import_block: &mut BlockImportParams<Block>,
812 ) -> sp_blockchain::Result<PrepareStorageChangesResult<Block>>
813 where
814 Self: ProvideRuntimeApi<Block>,
815 <Self as ProvideRuntimeApi<Block>>::Api: CoreApi<Block> + ApiExt<Block>,
816 {
817 let parent_hash = import_block.header.parent_hash();
818 let state_action = std::mem::replace(&mut import_block.state_action, StateAction::Skip);
819 let (enact_state, storage_changes) = match (self.block_status(*parent_hash)?, state_action)
820 {
821 (BlockStatus::KnownBad, _) => {
822 return Ok(PrepareStorageChangesResult::Discard(ImportResult::KnownBad))
823 },
824 (
825 BlockStatus::InChainPruned,
826 StateAction::ApplyChanges(sc_consensus::StorageChanges::Changes(_)),
827 ) => return Ok(PrepareStorageChangesResult::Discard(ImportResult::MissingState)),
828 (_, StateAction::ApplyChanges(changes)) => (true, Some(changes)),
829 (_, StateAction::Skip) => (false, None),
830 (BlockStatus::Unknown, _) => {
831 return Ok(PrepareStorageChangesResult::Discard(ImportResult::UnknownParent))
832 },
833 (BlockStatus::InChainPruned, StateAction::Execute) => {
834 return Ok(PrepareStorageChangesResult::Discard(ImportResult::MissingState))
835 },
836 (BlockStatus::InChainPruned, StateAction::ExecuteIfPossible) => (false, None),
837 (_, StateAction::Execute) => (true, None),
838 (_, StateAction::ExecuteIfPossible) => (true, None),
839 };
840
841 let storage_changes = match (enact_state, storage_changes, &import_block.body) {
842 (true, changes @ Some(_), _) => changes,
845 (true, None, Some(ref body)) => {
848 let mut runtime_api = self.runtime_api();
849 let call_context = CallContext::Onchain;
850 runtime_api.set_call_context(call_context);
851
852 if self.config.enable_import_proof_recording {
853 runtime_api.record_proof();
854 let recorder = runtime_api
855 .proof_recorder()
856 .expect("Proof recording is enabled in the line above; qed.");
857 runtime_api.register_extension(ProofSizeExt::new(recorder));
858 }
859
860 runtime_api.execute_block(
861 *parent_hash,
862 Block::new(import_block.header.clone(), body.clone()).into(),
863 )?;
864
865 let state = self.backend.state_at(*parent_hash, call_context.into())?;
866 let gen_storage_changes = runtime_api
867 .into_storage_changes(&state, *parent_hash)
868 .map_err(sp_blockchain::Error::Storage)?;
869
870 if import_block.header.state_root() != &gen_storage_changes.transaction_storage_root
871 {
872 return Err(Error::InvalidStateRoot);
873 }
874 Some(sc_consensus::StorageChanges::Changes(gen_storage_changes))
875 },
876 (true, None, None) => None,
878 (false, _, _) => None,
880 };
881
882 Ok(PrepareStorageChangesResult::Import(storage_changes))
883 }
884
885 fn apply_finality_with_block_hash(
886 &self,
887 operation: &mut ClientImportOperation<Block, B>,
888 hash: Block::Hash,
889 justification: Option<Justification>,
890 info: &BlockchainInfo<Block>,
891 notify: bool,
892 ) -> sp_blockchain::Result<()> {
893 if hash == info.finalized_hash {
894 warn!(
895 "Possible safety violation: attempted to re-finalize last finalized block {:?} ",
896 hash,
897 );
898 return Ok(());
899 }
900
901 let route_from_finalized =
903 sp_blockchain::tree_route(self.backend.blockchain(), info.finalized_hash, hash)?;
904
905 if let Some(retracted) = route_from_finalized.retracted().get(0) {
906 warn!(
907 "Safety violation: attempted to revert finalized block {:?} which is not in the \
908 same chain as last finalized {:?}",
909 retracted, info.finalized_hash
910 );
911
912 return Err(sp_blockchain::Error::NotInFinalizedChain);
913 }
914
915 let block_number = self
920 .backend
921 .blockchain()
922 .number(hash)?
923 .ok_or(Error::MissingHeader(format!("{hash:?}")))?;
924 if self.backend.blockchain().leaves()?.len() > 1 || info.best_number < block_number {
925 let route_from_best =
926 sp_blockchain::tree_route(self.backend.blockchain(), info.best_hash, hash)?;
927
928 if route_from_best.common_block().hash != hash {
931 operation.op.mark_head(hash)?;
938 }
939 }
940
941 let enacted = route_from_finalized.enacted();
942 assert!(enacted.len() > 0);
943 for finalize_new in &enacted[..enacted.len() - 1] {
944 operation.op.mark_finalized(finalize_new.hash, None)?;
945 }
946
947 assert_eq!(enacted.last().map(|e| e.hash), Some(hash));
948 operation.op.mark_finalized(hash, justification)?;
949
950 if notify {
951 let finalized =
952 route_from_finalized.enacted().iter().map(|elem| elem.hash).collect::<Vec<_>>();
953
954 let header = self
955 .backend
956 .blockchain()
957 .header(hash)?
958 .expect("Block to finalize expected to be onchain; qed");
959 let block_number = *header.number();
960
961 let mut stale_blocks = Vec::new();
963
964 let stale_heads = self.backend.blockchain().displaced_leaves_after_finalizing(
965 hash,
966 block_number,
967 *header.parent_hash(),
968 )?;
969
970 stale_blocks.extend(stale_heads.displaced_blocks.into_iter().map(|b| StaleBlock {
971 hash: b,
972 is_head: stale_heads.displaced_leaves.iter().any(|(_, h)| *h == b),
973 }));
974
975 operation.notify_finalized = Some(FinalizeSummary { header, finalized, stale_blocks });
976 }
977
978 Ok(())
979 }
980
981 fn notify_finalized(
982 &self,
983 notification: Option<FinalityNotification<Block>>,
984 ) -> sp_blockchain::Result<()> {
985 let mut sinks = self.finality_notification_sinks.lock();
986
987 let notification = match notification {
988 Some(notify_finalized) => notify_finalized,
989 None => {
990 sinks.retain(|sink| !sink.is_closed());
994 return Ok(());
995 },
996 };
997
998 telemetry!(
999 self.telemetry;
1000 SUBSTRATE_INFO;
1001 "notify.finalized";
1002 "height" => format!("{}", notification.header.number()),
1003 "best" => ?notification.hash,
1004 );
1005
1006 sinks.retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
1007
1008 Ok(())
1009 }
1010
1011 fn notify_imported(
1012 &self,
1013 notification: Option<BlockImportNotification<Block>>,
1014 import_notification_action: ImportNotificationAction,
1015 storage_changes: Option<(StorageCollection, ChildStorageCollection)>,
1016 ) -> sp_blockchain::Result<()> {
1017 let notification = match notification {
1018 Some(notify_import) => notify_import,
1019 None => {
1020 self.import_notification_sinks.lock().retain(|sink| !sink.is_closed());
1027
1028 self.every_import_notification_sinks.lock().retain(|sink| !sink.is_closed());
1029
1030 return Ok(());
1031 },
1032 };
1033
1034 let trigger_storage_changes_notification = || {
1035 if let Some(storage_changes) = storage_changes {
1036 self.storage_notifications.trigger(
1038 ¬ification.hash,
1039 storage_changes.0.into_iter(),
1040 storage_changes.1.into_iter().map(|(sk, v)| (sk, v.into_iter())),
1041 );
1042 }
1043 };
1044
1045 match import_notification_action {
1046 ImportNotificationAction::Both => {
1047 trigger_storage_changes_notification();
1048 self.import_notification_sinks
1049 .lock()
1050 .retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
1051
1052 self.every_import_notification_sinks
1053 .lock()
1054 .retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
1055 },
1056 ImportNotificationAction::RecentBlock => {
1057 trigger_storage_changes_notification();
1058 self.import_notification_sinks
1059 .lock()
1060 .retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
1061
1062 self.every_import_notification_sinks.lock().retain(|sink| !sink.is_closed());
1063 },
1064 ImportNotificationAction::EveryBlock => {
1065 self.every_import_notification_sinks
1066 .lock()
1067 .retain(|sink| sink.unbounded_send(notification.clone()).is_ok());
1068
1069 self.import_notification_sinks.lock().retain(|sink| !sink.is_closed());
1070 },
1071 ImportNotificationAction::None => {
1072 self.import_notification_sinks.lock().retain(|sink| !sink.is_closed());
1076
1077 self.every_import_notification_sinks.lock().retain(|sink| !sink.is_closed());
1078 },
1079 }
1080
1081 Ok(())
1082 }
1083
1084 pub fn revert(&self, n: NumberFor<Block>) -> sp_blockchain::Result<NumberFor<Block>> {
1088 let (number, _) = self.backend.revert(n, false)?;
1089 Ok(number)
1090 }
1091
1092 pub fn unsafe_revert(
1102 &mut self,
1103 n: NumberFor<Block>,
1104 blacklist: bool,
1105 ) -> sp_blockchain::Result<NumberFor<Block>> {
1106 let (number, reverted) = self.backend.revert(n, true)?;
1107 if blacklist {
1108 for b in reverted {
1109 self.block_rules.mark_bad(b);
1110 }
1111 }
1112 Ok(number)
1113 }
1114
1115 pub fn chain_info(&self) -> BlockchainInfo<Block> {
1117 self.backend.blockchain().info()
1118 }
1119
1120 pub fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result<BlockStatus> {
1122 if self
1124 .importing_block
1125 .read()
1126 .as_ref()
1127 .map_or(false, |importing| &hash == importing)
1128 {
1129 return Ok(BlockStatus::Queued);
1130 }
1131
1132 let hash_and_number = self.backend.blockchain().number(hash)?.map(|n| (hash, n));
1133 match hash_and_number {
1134 Some((hash, number)) => {
1135 if self.backend.have_state_at(hash, number) {
1136 Ok(BlockStatus::InChainWithState)
1137 } else {
1138 Ok(BlockStatus::InChainPruned)
1139 }
1140 },
1141 None => Ok(BlockStatus::Unknown),
1142 }
1143 }
1144
1145 pub fn header(
1147 &self,
1148 hash: Block::Hash,
1149 ) -> sp_blockchain::Result<Option<<Block as BlockT>::Header>> {
1150 self.backend.blockchain().header(hash)
1151 }
1152
1153 pub fn body(
1155 &self,
1156 hash: Block::Hash,
1157 ) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
1158 self.backend.blockchain().body(hash)
1159 }
1160
1161 pub fn uncles(
1163 &self,
1164 target_hash: Block::Hash,
1165 max_generation: NumberFor<Block>,
1166 ) -> sp_blockchain::Result<Vec<Block::Hash>> {
1167 let load_header = |hash: Block::Hash| -> sp_blockchain::Result<Block::Header> {
1168 self.backend
1169 .blockchain()
1170 .header(hash)?
1171 .ok_or_else(|| Error::UnknownBlock(format!("{:?}", hash)))
1172 };
1173
1174 let genesis_hash = self.backend.blockchain().info().genesis_hash;
1175 if genesis_hash == target_hash {
1176 return Ok(Vec::new());
1177 }
1178
1179 let mut current_hash = target_hash;
1180 let mut current = load_header(current_hash)?;
1181 let mut ancestor_hash = *current.parent_hash();
1182 let mut ancestor = load_header(ancestor_hash)?;
1183 let mut uncles = Vec::new();
1184
1185 let mut generation: NumberFor<Block> = Zero::zero();
1186 while generation < max_generation {
1187 let children = self.backend.blockchain().children(ancestor_hash)?;
1188 uncles.extend(children.into_iter().filter(|h| h != ¤t_hash));
1189 current_hash = ancestor_hash;
1190
1191 if genesis_hash == current_hash {
1192 break;
1193 }
1194
1195 current = ancestor;
1196 ancestor_hash = *current.parent_hash();
1197 ancestor = load_header(ancestor_hash)?;
1198 generation += One::one();
1199 }
1200 trace!("Collected {} uncles", uncles.len());
1201 Ok(uncles)
1202 }
1203}
1204
1205impl<B, E, Block, RA> UsageProvider<Block> for Client<B, E, Block, RA>
1206where
1207 B: backend::Backend<Block>,
1208 E: CallExecutor<Block>,
1209 Block: BlockT,
1210{
1211 fn usage_info(&self) -> ClientInfo<Block> {
1213 ClientInfo { chain: self.chain_info(), usage: self.backend.usage_info() }
1214 }
1215}
1216
1217impl<B, E, Block, RA> ProofProvider<Block> for Client<B, E, Block, RA>
1218where
1219 B: backend::Backend<Block>,
1220 E: CallExecutor<Block>,
1221 Block: BlockT,
1222{
1223 fn read_proof(
1224 &self,
1225 hash: Block::Hash,
1226 keys: &mut dyn Iterator<Item = &[u8]>,
1227 ) -> sp_blockchain::Result<StorageProof> {
1228 self.state_at(hash)
1229 .and_then(|state| prove_read(state, keys).map_err(Into::into))
1230 }
1231
1232 fn read_child_proof(
1233 &self,
1234 hash: Block::Hash,
1235 child_info: &ChildInfo,
1236 keys: &mut dyn Iterator<Item = &[u8]>,
1237 ) -> sp_blockchain::Result<StorageProof> {
1238 self.state_at(hash)
1239 .and_then(|state| prove_child_read(state, child_info, keys).map_err(Into::into))
1240 }
1241
1242 fn execution_proof(
1243 &self,
1244 hash: Block::Hash,
1245 method: &str,
1246 call_data: &[u8],
1247 ) -> sp_blockchain::Result<(Vec<u8>, StorageProof)> {
1248 self.executor.prove_execution(hash, method, call_data)
1249 }
1250
1251 fn read_proof_collection(
1252 &self,
1253 hash: Block::Hash,
1254 start_key: &[Vec<u8>],
1255 size_limit: usize,
1256 ) -> sp_blockchain::Result<(CompactProof, u32)> {
1257 let state = self.state_at(hash)?;
1258 let root = state.storage_root(std::iter::empty(), StateVersion::V0).0;
1260
1261 let (proof, count) = prove_range_read_with_child_with_size::<_, HashingFor<Block>>(
1262 state, size_limit, start_key,
1263 )?;
1264 let proof = proof
1265 .into_compact_proof::<HashingFor<Block>>(root)
1266 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?;
1267 Ok((proof, count))
1268 }
1269
1270 fn storage_collection(
1271 &self,
1272 hash: Block::Hash,
1273 start_key: &[Vec<u8>],
1274 size_limit: usize,
1275 ) -> sp_blockchain::Result<Vec<(KeyValueStorageLevel, bool)>> {
1276 if start_key.len() > MAX_NESTED_TRIE_DEPTH {
1277 return Err(Error::Backend("Invalid start key.".to_string()));
1278 }
1279 let state = self.state_at(hash)?;
1280 let child_info = |storage_key: &Vec<u8>| -> sp_blockchain::Result<ChildInfo> {
1281 let storage_key = PrefixedStorageKey::new_ref(storage_key);
1282 match ChildType::from_prefixed_key(storage_key) {
1283 Some((ChildType::ParentKeyId, storage_key)) => {
1284 Ok(ChildInfo::new_default(storage_key))
1285 },
1286 None => Err(Error::Backend("Invalid child storage key.".to_string())),
1287 }
1288 };
1289 let mut current_child = if start_key.len() == 2 {
1290 let start_key = start_key.get(0).expect("checked len");
1291 if let Some(child_root) = state
1292 .storage(start_key)
1293 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1294 {
1295 Some((child_info(start_key)?, child_root))
1296 } else {
1297 return Err(Error::Backend("Invalid root start key.".to_string()));
1298 }
1299 } else {
1300 None
1301 };
1302 let mut current_key = start_key.last().map(Clone::clone).unwrap_or_default();
1303 let mut total_size = 0;
1304 let mut result = vec![(
1305 KeyValueStorageLevel {
1306 state_root: Vec::new(),
1307 key_values: Vec::new(),
1308 parent_storage_keys: Vec::new(),
1309 },
1310 false,
1311 )];
1312
1313 let mut child_roots = HashSet::new();
1314 loop {
1315 let mut entries = Vec::new();
1316 let mut complete = true;
1317 let mut switch_child_key = None;
1318 while let Some(next_key) = if let Some(child) = current_child.as_ref() {
1319 state
1320 .next_child_storage_key(&child.0, ¤t_key)
1321 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1322 } else {
1323 state
1324 .next_storage_key(¤t_key)
1325 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1326 } {
1327 let value = if let Some(child) = current_child.as_ref() {
1328 state
1329 .child_storage(&child.0, next_key.as_ref())
1330 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1331 .unwrap_or_default()
1332 } else {
1333 state
1334 .storage(next_key.as_ref())
1335 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1336 .unwrap_or_default()
1337 };
1338 let size = value.len() + next_key.len();
1339 if total_size + size > size_limit && !entries.is_empty() {
1340 complete = false;
1341 break;
1342 }
1343 total_size += size;
1344
1345 if current_child.is_none() &&
1346 sp_core::storage::well_known_keys::is_child_storage_key(next_key.as_slice()) &&
1347 !child_roots.contains(value.as_slice())
1348 {
1349 child_roots.insert(value.clone());
1350 switch_child_key = Some((next_key.clone(), value.clone()));
1351 entries.push((next_key.clone(), value));
1352 break;
1353 }
1354 entries.push((next_key.clone(), value));
1355 current_key = next_key;
1356 }
1357 if let Some((child, child_root)) = switch_child_key.take() {
1358 result[0].0.key_values.extend(entries.into_iter());
1359 current_child = Some((child_info(&child)?, child_root));
1360 current_key = Vec::new();
1361 } else if let Some((child, child_root)) = current_child.take() {
1362 current_key = child.into_prefixed_storage_key().into_inner();
1363 result.push((
1364 KeyValueStorageLevel {
1365 state_root: child_root,
1366 key_values: entries,
1367 parent_storage_keys: Vec::new(),
1368 },
1369 complete,
1370 ));
1371 if !complete {
1372 break;
1373 }
1374 } else {
1375 result[0].0.key_values.extend(entries.into_iter());
1376 result[0].1 = complete;
1377 break;
1378 }
1379 }
1380 Ok(result)
1381 }
1382
1383 fn verify_range_proof(
1384 &self,
1385 root: Block::Hash,
1386 proof: CompactProof,
1387 start_key: &[Vec<u8>],
1388 ) -> sp_blockchain::Result<(KeyValueStates, usize)> {
1389 let mut db = sp_state_machine::MemoryDB::<HashingFor<Block>>::new(&[]);
1390 sp_trie::decode_compact::<sp_state_machine::LayoutV0<HashingFor<Block>>, _, _>(
1392 &mut db,
1393 proof.iter_compact_encoded_nodes(),
1394 Some(&root),
1395 )
1396 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?;
1397 let proving_backend = sp_state_machine::TrieBackendBuilder::new(db, root).build();
1398 let state = read_range_proof_check_with_child_on_proving_backend::<HashingFor<Block>>(
1399 &proving_backend,
1400 start_key,
1401 )?;
1402
1403 Ok(state)
1404 }
1405}
1406
1407impl<B, E, Block, RA> ExecutorProvider<Block> for Client<B, E, Block, RA>
1408where
1409 B: backend::Backend<Block>,
1410 E: CallExecutor<Block>,
1411 Block: BlockT,
1412{
1413 type Executor = E;
1414
1415 fn executor(&self) -> &Self::Executor {
1416 &self.executor
1417 }
1418
1419 fn execution_extensions(&self) -> &ExecutionExtensions<Block> {
1420 self.executor.execution_extensions()
1421 }
1422}
1423
1424impl<B, E, Block, RA> StorageProvider<Block, B> for Client<B, E, Block, RA>
1425where
1426 B: backend::Backend<Block>,
1427 E: CallExecutor<Block>,
1428 Block: BlockT,
1429{
1430 fn storage_keys(
1431 &self,
1432 hash: <Block as BlockT>::Hash,
1433 prefix: Option<&StorageKey>,
1434 start_key: Option<&StorageKey>,
1435 ) -> sp_blockchain::Result<KeysIter<B::State, Block>> {
1436 let state = self.state_at(hash)?;
1437 KeysIter::new(state, prefix, start_key)
1438 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1439 }
1440
1441 fn child_storage_keys(
1442 &self,
1443 hash: <Block as BlockT>::Hash,
1444 child_info: ChildInfo,
1445 prefix: Option<&StorageKey>,
1446 start_key: Option<&StorageKey>,
1447 ) -> sp_blockchain::Result<KeysIter<B::State, Block>> {
1448 let state = self.state_at(hash)?;
1449 KeysIter::new_child(state, child_info, prefix, start_key)
1450 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1451 }
1452
1453 fn storage_pairs(
1454 &self,
1455 hash: <Block as BlockT>::Hash,
1456 prefix: Option<&StorageKey>,
1457 start_key: Option<&StorageKey>,
1458 ) -> sp_blockchain::Result<PairsIter<B::State, Block>> {
1459 let state = self.state_at(hash)?;
1460 PairsIter::new(state, prefix, start_key)
1461 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1462 }
1463
1464 fn storage(
1465 &self,
1466 hash: Block::Hash,
1467 key: &StorageKey,
1468 ) -> sp_blockchain::Result<Option<StorageData>> {
1469 Ok(self
1470 .state_at(hash)?
1471 .storage(&key.0)
1472 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1473 .map(StorageData))
1474 }
1475
1476 fn storage_hash(
1477 &self,
1478 hash: <Block as BlockT>::Hash,
1479 key: &StorageKey,
1480 ) -> sp_blockchain::Result<Option<Block::Hash>> {
1481 self.state_at(hash)?
1482 .storage_hash(&key.0)
1483 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1484 }
1485
1486 fn child_storage(
1487 &self,
1488 hash: <Block as BlockT>::Hash,
1489 child_info: &ChildInfo,
1490 key: &StorageKey,
1491 ) -> sp_blockchain::Result<Option<StorageData>> {
1492 Ok(self
1493 .state_at(hash)?
1494 .child_storage(child_info, &key.0)
1495 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))?
1496 .map(StorageData))
1497 }
1498
1499 fn child_storage_hash(
1500 &self,
1501 hash: <Block as BlockT>::Hash,
1502 child_info: &ChildInfo,
1503 key: &StorageKey,
1504 ) -> sp_blockchain::Result<Option<Block::Hash>> {
1505 self.state_at(hash)?
1506 .child_storage_hash(child_info, &key.0)
1507 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1508 }
1509
1510 fn closest_merkle_value(
1511 &self,
1512 hash: <Block as BlockT>::Hash,
1513 key: &StorageKey,
1514 ) -> blockchain::Result<Option<MerkleValue<<Block as BlockT>::Hash>>> {
1515 self.state_at(hash)?
1516 .closest_merkle_value(&key.0)
1517 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1518 }
1519
1520 fn child_closest_merkle_value(
1521 &self,
1522 hash: <Block as BlockT>::Hash,
1523 child_info: &ChildInfo,
1524 key: &StorageKey,
1525 ) -> blockchain::Result<Option<MerkleValue<<Block as BlockT>::Hash>>> {
1526 self.state_at(hash)?
1527 .child_closest_merkle_value(child_info, &key.0)
1528 .map_err(|e| sp_blockchain::Error::from_state(Box::new(e)))
1529 }
1530}
1531
1532impl<B, E, Block, RA> HeaderMetadata<Block> for Client<B, E, Block, RA>
1533where
1534 B: backend::Backend<Block>,
1535 E: CallExecutor<Block>,
1536 Block: BlockT,
1537{
1538 type Error = sp_blockchain::Error;
1539
1540 fn header_metadata(
1541 &self,
1542 hash: Block::Hash,
1543 ) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
1544 self.backend.blockchain().header_metadata(hash)
1545 }
1546
1547 fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata<Block>) {
1548 self.backend.blockchain().insert_header_metadata(hash, metadata)
1549 }
1550
1551 fn remove_header_metadata(&self, hash: Block::Hash) {
1552 self.backend.blockchain().remove_header_metadata(hash)
1553 }
1554}
1555
1556impl<B, E, Block, RA> ProvideUncles<Block> for Client<B, E, Block, RA>
1557where
1558 B: backend::Backend<Block>,
1559 E: CallExecutor<Block>,
1560 Block: BlockT,
1561{
1562 fn uncles(
1563 &self,
1564 target_hash: Block::Hash,
1565 max_generation: NumberFor<Block>,
1566 ) -> sp_blockchain::Result<Vec<Block::Header>> {
1567 Ok(Client::uncles(self, target_hash, max_generation)?
1568 .into_iter()
1569 .filter_map(|hash| Client::header(self, hash).unwrap_or(None))
1570 .collect())
1571 }
1572}
1573
1574impl<B, E, Block, RA> ChainHeaderBackend<Block> for Client<B, E, Block, RA>
1575where
1576 B: backend::Backend<Block>,
1577 E: CallExecutor<Block> + Send + Sync,
1578 Block: BlockT,
1579 RA: Send + Sync,
1580{
1581 fn header(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Block::Header>> {
1582 self.backend.blockchain().header(hash)
1583 }
1584
1585 fn info(&self) -> blockchain::Info<Block> {
1586 self.backend.blockchain().info()
1587 }
1588
1589 fn status(&self, hash: Block::Hash) -> sp_blockchain::Result<blockchain::BlockStatus> {
1590 self.backend.blockchain().status(hash)
1591 }
1592
1593 fn number(
1594 &self,
1595 hash: Block::Hash,
1596 ) -> sp_blockchain::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
1597 self.backend.blockchain().number(hash)
1598 }
1599
1600 fn hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>> {
1601 self.backend.blockchain().hash(number)
1602 }
1603}
1604
1605impl<B, E, Block, RA> BlockIdTo<Block> for Client<B, E, Block, RA>
1606where
1607 B: backend::Backend<Block>,
1608 E: CallExecutor<Block> + Send + Sync,
1609 Block: BlockT,
1610 RA: Send + Sync,
1611{
1612 type Error = Error;
1613
1614 fn to_hash(&self, block_id: &BlockId<Block>) -> sp_blockchain::Result<Option<Block::Hash>> {
1615 self.block_hash_from_id(block_id)
1616 }
1617
1618 fn to_number(
1619 &self,
1620 block_id: &BlockId<Block>,
1621 ) -> sp_blockchain::Result<Option<NumberFor<Block>>> {
1622 self.block_number_from_id(block_id)
1623 }
1624}
1625
1626impl<B, E, Block, RA> ChainHeaderBackend<Block> for &Client<B, E, Block, RA>
1627where
1628 B: backend::Backend<Block>,
1629 E: CallExecutor<Block> + Send + Sync,
1630 Block: BlockT,
1631 RA: Send + Sync,
1632{
1633 fn header(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Block::Header>> {
1634 self.backend.blockchain().header(hash)
1635 }
1636
1637 fn info(&self) -> blockchain::Info<Block> {
1638 self.backend.blockchain().info()
1639 }
1640
1641 fn status(&self, hash: Block::Hash) -> sp_blockchain::Result<blockchain::BlockStatus> {
1642 (**self).status(hash)
1643 }
1644
1645 fn number(
1646 &self,
1647 hash: Block::Hash,
1648 ) -> sp_blockchain::Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>> {
1649 (**self).number(hash)
1650 }
1651
1652 fn hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>> {
1653 (**self).hash(number)
1654 }
1655}
1656
1657impl<B, E, Block, RA> ProvideRuntimeApi<Block> for Client<B, E, Block, RA>
1658where
1659 B: backend::Backend<Block>,
1660 E: CallExecutor<Block, Backend = B> + Send + Sync,
1661 Block: BlockT,
1662 RA: ConstructRuntimeApi<Block, Self> + Send + Sync,
1663{
1664 type Api = <RA as ConstructRuntimeApi<Block, Self>>::RuntimeApi;
1665
1666 fn runtime_api(&self) -> ApiRef<'_, Self::Api> {
1667 RA::construct_runtime_api(self)
1668 }
1669}
1670
1671impl<B, E, Block, RA> CallApiAt<Block> for Client<B, E, Block, RA>
1672where
1673 B: backend::Backend<Block>,
1674 E: CallExecutor<Block, Backend = B> + Send + Sync,
1675 Block: BlockT,
1676 RA: Send + Sync,
1677{
1678 type StateBackend = B::State;
1679
1680 fn call_api_at(&self, params: CallApiAtParams<Block>) -> Result<Vec<u8>, sp_api::ApiError> {
1681 self.executor
1682 .contextual_call(
1683 params.at,
1684 params.function,
1685 ¶ms.arguments,
1686 params.overlayed_changes,
1687 params.recorder,
1688 params.call_context,
1689 params.extensions,
1690 )
1691 .map_err(Into::into)
1692 }
1693
1694 fn runtime_version_at(
1695 &self,
1696 hash: Block::Hash,
1697 call_context: CallContext,
1698 ) -> Result<RuntimeVersion, sp_api::ApiError> {
1699 CallExecutor::runtime_version(&self.executor, hash, call_context).map_err(Into::into)
1700 }
1701
1702 fn state_at(&self, at: Block::Hash) -> Result<Self::StateBackend, sp_api::ApiError> {
1703 self.state_at(at).map_err(Into::into)
1704 }
1705
1706 fn initialize_extensions(
1707 &self,
1708 at: Block::Hash,
1709 extensions: &mut sp_externalities::Extensions,
1710 ) -> Result<(), sp_api::ApiError> {
1711 let block_number = self.expect_block_number_from_id(&BlockId::Hash(at))?;
1712
1713 extensions.merge(self.executor.execution_extensions().extensions(at, block_number));
1714
1715 Ok(())
1716 }
1717}
1718
1719#[async_trait::async_trait]
1723impl<B, E, Block, RA> sc_consensus::BlockImport<Block> for &Client<B, E, Block, RA>
1724where
1725 B: backend::Backend<Block>,
1726 E: CallExecutor<Block> + Send + Sync,
1727 Block: BlockT,
1728 Client<B, E, Block, RA>: ProvideRuntimeApi<Block>,
1729 <Client<B, E, Block, RA> as ProvideRuntimeApi<Block>>::Api: CoreApi<Block> + ApiExt<Block>,
1730 RA: Sync + Send,
1731{
1732 type Error = ConsensusError;
1733
1734 async fn import_block(
1743 &self,
1744 mut import_block: BlockImportParams<Block>,
1745 ) -> Result<ImportResult, Self::Error> {
1746 let span = tracing::span!(tracing::Level::DEBUG, "import_block");
1747 let _enter = span.enter();
1748
1749 let storage_changes =
1750 match self.prepare_block_storage_changes(&mut import_block).map_err(|e| {
1751 warn!("Block prepare storage changes error: {}", e);
1752 ConsensusError::ClientImport(e.to_string())
1753 })? {
1754 PrepareStorageChangesResult::Discard(res) => return Ok(res),
1755 PrepareStorageChangesResult::Import(storage_changes) => storage_changes,
1756 };
1757
1758 self.lock_import_and_run(|operation| {
1759 self.apply_block(operation, import_block, storage_changes)
1760 })
1761 .map_err(|e| {
1762 warn!("Block import error: {}", e);
1763 ConsensusError::ClientImport(e.to_string())
1764 })
1765 }
1766
1767 async fn check_block(
1769 &self,
1770 block: BlockCheckParams<Block>,
1771 ) -> Result<ImportResult, Self::Error> {
1772 let BlockCheckParams {
1773 hash,
1774 number,
1775 parent_hash,
1776 allow_missing_state,
1777 import_existing,
1778 allow_missing_parent,
1779 } = block;
1780
1781 match self.block_rules.lookup(number, &hash) {
1784 BlockLookupResult::KnownBad => {
1785 trace!("Rejecting known bad block: #{} {:?}", number, hash);
1786 return Ok(ImportResult::KnownBad);
1787 },
1788 BlockLookupResult::Expected(expected_hash) => {
1789 trace!(
1790 "Rejecting block from known invalid fork. Got {:?}, expected: {:?} at height {}",
1791 hash,
1792 expected_hash,
1793 number
1794 );
1795 return Ok(ImportResult::KnownBad);
1796 },
1797 BlockLookupResult::NotSpecial => {},
1798 }
1799
1800 match self
1803 .block_status(hash)
1804 .map_err(|e| ConsensusError::ClientImport(e.to_string()))?
1805 {
1806 BlockStatus::InChainWithState | BlockStatus::Queued => {
1807 return Ok(ImportResult::AlreadyInChain)
1808 },
1809 BlockStatus::InChainPruned if !import_existing => {
1810 return Ok(ImportResult::AlreadyInChain)
1811 },
1812 BlockStatus::InChainPruned => {},
1813 BlockStatus::Unknown => {},
1814 BlockStatus::KnownBad => return Ok(ImportResult::KnownBad),
1815 }
1816
1817 match self
1818 .block_status(parent_hash)
1819 .map_err(|e| ConsensusError::ClientImport(e.to_string()))?
1820 {
1821 BlockStatus::InChainWithState | BlockStatus::Queued => {},
1822 BlockStatus::Unknown if allow_missing_parent => {},
1823 BlockStatus::Unknown => return Ok(ImportResult::UnknownParent),
1824 BlockStatus::InChainPruned if allow_missing_state => {},
1825 BlockStatus::InChainPruned => return Ok(ImportResult::MissingState),
1826 BlockStatus::KnownBad => return Ok(ImportResult::KnownBad),
1827 }
1828
1829 Ok(ImportResult::imported(false))
1830 }
1831}
1832
1833#[async_trait::async_trait]
1834impl<B, E, Block, RA> sc_consensus::BlockImport<Block> for Client<B, E, Block, RA>
1835where
1836 B: backend::Backend<Block>,
1837 E: CallExecutor<Block> + Send + Sync,
1838 Block: BlockT,
1839 Self: ProvideRuntimeApi<Block>,
1840 <Self as ProvideRuntimeApi<Block>>::Api: CoreApi<Block> + ApiExt<Block>,
1841 RA: Sync + Send,
1842{
1843 type Error = ConsensusError;
1844
1845 async fn check_block(
1846 &self,
1847 block: BlockCheckParams<Block>,
1848 ) -> Result<ImportResult, Self::Error> {
1849 (&self).check_block(block).await
1850 }
1851
1852 async fn import_block(
1853 &self,
1854 import_block: BlockImportParams<Block>,
1855 ) -> Result<ImportResult, Self::Error> {
1856 (&self).import_block(import_block).await
1857 }
1858}
1859
1860impl<B, E, Block, RA> Finalizer<Block, B> for Client<B, E, Block, RA>
1861where
1862 B: backend::Backend<Block>,
1863 E: CallExecutor<Block>,
1864 Block: BlockT,
1865{
1866 fn apply_finality(
1867 &self,
1868 operation: &mut ClientImportOperation<Block, B>,
1869 hash: Block::Hash,
1870 justification: Option<Justification>,
1871 notify: bool,
1872 ) -> sp_blockchain::Result<()> {
1873 let info = self.backend.blockchain().info();
1874 self.apply_finality_with_block_hash(operation, hash, justification, &info, notify)
1875 }
1876
1877 fn finalize_block(
1878 &self,
1879 hash: Block::Hash,
1880 justification: Option<Justification>,
1881 notify: bool,
1882 ) -> sp_blockchain::Result<()> {
1883 self.lock_import_and_run(|operation| {
1884 self.apply_finality(operation, hash, justification, notify)
1885 })
1886 }
1887}
1888
1889impl<B, E, Block, RA> Finalizer<Block, B> for &Client<B, E, Block, RA>
1890where
1891 B: backend::Backend<Block>,
1892 E: CallExecutor<Block>,
1893 Block: BlockT,
1894{
1895 fn apply_finality(
1896 &self,
1897 operation: &mut ClientImportOperation<Block, B>,
1898 hash: Block::Hash,
1899 justification: Option<Justification>,
1900 notify: bool,
1901 ) -> sp_blockchain::Result<()> {
1902 (**self).apply_finality(operation, hash, justification, notify)
1903 }
1904
1905 fn finalize_block(
1906 &self,
1907 hash: Block::Hash,
1908 justification: Option<Justification>,
1909 notify: bool,
1910 ) -> sp_blockchain::Result<()> {
1911 (**self).finalize_block(hash, justification, notify)
1912 }
1913}
1914
1915impl<B, E, Block, RA> PreCommitActions<Block> for Client<B, E, Block, RA>
1916where
1917 Block: BlockT,
1918{
1919 fn register_import_action(&self, action: OnImportAction<Block>) {
1920 self.import_actions.lock().push(action);
1921 }
1922
1923 fn register_finality_action(&self, action: OnFinalityAction<Block>) {
1924 self.finality_actions.lock().push(action);
1925 }
1926}
1927
1928impl<B, E, Block, RA> BlockchainEvents<Block> for Client<B, E, Block, RA>
1929where
1930 E: CallExecutor<Block>,
1931 Block: BlockT,
1932{
1933 fn import_notification_stream(&self) -> ImportNotifications<Block> {
1935 let (sink, stream) = tracing_unbounded("mpsc_import_notification_stream", 100_000);
1936 self.import_notification_sinks.lock().push(sink);
1937 stream
1938 }
1939
1940 fn every_import_notification_stream(&self) -> ImportNotifications<Block> {
1941 let (sink, stream) = tracing_unbounded("mpsc_every_import_notification_stream", 100_000);
1942 self.every_import_notification_sinks.lock().push(sink);
1943 stream
1944 }
1945
1946 fn finality_notification_stream(&self) -> FinalityNotifications<Block> {
1947 let (sink, stream) = tracing_unbounded("mpsc_finality_notification_stream", 100_000);
1948 self.finality_notification_sinks.lock().push(sink);
1949 stream
1950 }
1951
1952 fn storage_changes_notification_stream(
1954 &self,
1955 filter_keys: Option<&[StorageKey]>,
1956 child_filter_keys: Option<&[(StorageKey, Option<Vec<StorageKey>>)]>,
1957 ) -> sp_blockchain::Result<StorageEventStream<Block::Hash>> {
1958 Ok(self.storage_notifications.listen(filter_keys, child_filter_keys))
1959 }
1960}
1961
1962impl<B, E, Block, RA> BlockBackend<Block> for Client<B, E, Block, RA>
1963where
1964 B: backend::Backend<Block>,
1965 E: CallExecutor<Block>,
1966 Block: BlockT,
1967{
1968 fn block_body(
1969 &self,
1970 hash: Block::Hash,
1971 ) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>> {
1972 self.body(hash)
1973 }
1974
1975 fn block(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<SignedBlock<Block>>> {
1976 Ok(match (self.header(hash)?, self.body(hash)?, self.justifications(hash)?) {
1977 (Some(header), Some(extrinsics), justifications) => {
1978 Some(SignedBlock { block: Block::new(header, extrinsics), justifications })
1979 },
1980 _ => None,
1981 })
1982 }
1983
1984 fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result<BlockStatus> {
1985 Client::block_status(self, hash)
1986 }
1987
1988 fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Justifications>> {
1989 self.backend.blockchain().justifications(hash)
1990 }
1991
1992 fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>> {
1993 self.backend.blockchain().hash(number)
1994 }
1995
1996 fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>> {
1997 self.backend.blockchain().indexed_transaction(hash)
1998 }
1999
2000 fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<bool> {
2001 self.backend.blockchain().has_indexed_transaction(hash)
2002 }
2003
2004 fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>> {
2005 self.backend.blockchain().block_indexed_body(hash)
2006 }
2007
2008 fn requires_full_sync(&self) -> bool {
2009 self.backend.requires_full_sync()
2010 }
2011}
2012
2013impl<B, E, Block, RA> backend::AuxStore for Client<B, E, Block, RA>
2014where
2015 B: backend::Backend<Block>,
2016 E: CallExecutor<Block>,
2017 Block: BlockT,
2018 Self: ProvideRuntimeApi<Block>,
2019 <Self as ProvideRuntimeApi<Block>>::Api: CoreApi<Block>,
2020{
2021 fn insert_aux<
2023 'a,
2024 'b: 'a,
2025 'c: 'a,
2026 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
2027 D: IntoIterator<Item = &'a &'b [u8]>,
2028 >(
2029 &self,
2030 insert: I,
2031 delete: D,
2032 ) -> sp_blockchain::Result<()> {
2033 self.lock_import_and_run(|operation| apply_aux(operation, insert, delete))
2038 }
2039 fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
2041 backend::AuxStore::get_aux(&*self.backend, key)
2042 }
2043}
2044
2045impl<B, E, Block, RA> backend::AuxStore for &Client<B, E, Block, RA>
2046where
2047 B: backend::Backend<Block>,
2048 E: CallExecutor<Block>,
2049 Block: BlockT,
2050 Client<B, E, Block, RA>: ProvideRuntimeApi<Block>,
2051 <Client<B, E, Block, RA> as ProvideRuntimeApi<Block>>::Api: CoreApi<Block>,
2052{
2053 fn insert_aux<
2054 'a,
2055 'b: 'a,
2056 'c: 'a,
2057 I: IntoIterator<Item = &'a (&'c [u8], &'c [u8])>,
2058 D: IntoIterator<Item = &'a &'b [u8]>,
2059 >(
2060 &self,
2061 insert: I,
2062 delete: D,
2063 ) -> sp_blockchain::Result<()> {
2064 (**self).insert_aux(insert, delete)
2065 }
2066
2067 fn get_aux(&self, key: &[u8]) -> sp_blockchain::Result<Option<Vec<u8>>> {
2068 (**self).get_aux(key)
2069 }
2070}
2071
2072impl<BE, E, B, RA> sp_consensus::block_validation::Chain<B> for Client<BE, E, B, RA>
2073where
2074 BE: backend::Backend<B>,
2075 E: CallExecutor<B>,
2076 B: BlockT,
2077{
2078 fn block_status(
2079 &self,
2080 hash: B::Hash,
2081 ) -> Result<BlockStatus, Box<dyn std::error::Error + Send>> {
2082 Client::block_status(self, hash).map_err(|e| Box::new(e) as Box<_>)
2083 }
2084}
2085
2086impl<BE, E, B, RA> sp_transaction_storage_proof::IndexedBody<B> for Client<BE, E, B, RA>
2087where
2088 BE: backend::Backend<B>,
2089 E: CallExecutor<B>,
2090 B: BlockT,
2091{
2092 fn block_indexed_body(
2093 &self,
2094 number: NumberFor<B>,
2095 ) -> Result<Option<Vec<Vec<u8>>>, sp_transaction_storage_proof::Error> {
2096 let hash = match self
2097 .backend
2098 .blockchain()
2099 .block_hash_from_id(&BlockId::Number(number))
2100 .map_err(|e| sp_transaction_storage_proof::Error::Application(Box::new(e)))?
2101 {
2102 Some(hash) => hash,
2103 None => return Ok(None),
2104 };
2105
2106 self.backend
2107 .blockchain()
2108 .block_indexed_body(hash)
2109 .map_err(|e| sp_transaction_storage_proof::Error::Application(Box::new(e)))
2110 }
2111
2112 fn number(
2113 &self,
2114 hash: B::Hash,
2115 ) -> Result<Option<NumberFor<B>>, sp_transaction_storage_proof::Error> {
2116 self.backend
2117 .blockchain()
2118 .number(hash)
2119 .map_err(|e| sp_transaction_storage_proof::Error::Application(Box::new(e)))
2120 }
2121}