1use sp_consensus::BlockOrigin;
22use sp_core::{storage::StorageKey, H256};
23use sp_runtime::{
24 generic::SignedBlock,
25 traits::{Block as BlockT, NumberFor},
26 Justifications,
27};
28use std::{
29 collections::HashSet,
30 fmt::{self, Debug},
31 sync::Arc,
32};
33
34use crate::{
35 blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary, StaleBlock,
36};
37
38use sc_transaction_pool_api::ChainEvent;
39use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender};
40use sp_blockchain;
41
42pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
44
45pub type FinalityNotifications<Block> = TracingUnboundedReceiver<FinalityNotification<Block>>;
47
48pub type ForkBlocks<Block> = Option<Vec<(NumberFor<Block>, <Block as BlockT>::Hash)>>;
54
55pub type BadBlocks<Block> = Option<HashSet<<Block as BlockT>::Hash>>;
59
60pub trait BlockOf {
62 type Type: BlockT;
64}
65
66pub trait BlockchainEvents<Block: BlockT> {
68 fn import_notification_stream(&self) -> ImportNotifications<Block>;
81
82 fn every_import_notification_stream(&self) -> ImportNotifications<Block>;
84
85 fn finality_notification_stream(&self) -> FinalityNotifications<Block>;
88
89 fn storage_changes_notification_stream(
93 &self,
94 filter_keys: Option<&[StorageKey]>,
95 child_filter_keys: Option<&[(StorageKey, Option<Vec<StorageKey>>)]>,
96 ) -> sp_blockchain::Result<StorageEventStream<Block::Hash>>;
97}
98
99pub type AuxDataOperations = Vec<(Vec<u8>, Option<Vec<u8>>)>;
104
105pub type OnImportAction<Block> =
109 Box<dyn (Fn(&BlockImportNotification<Block>) -> AuxDataOperations) + Send>;
110
111pub type OnFinalityAction<Block> =
115 Box<dyn (Fn(&FinalityNotification<Block>) -> AuxDataOperations) + Send>;
116
117pub trait PreCommitActions<Block: BlockT> {
120 fn register_import_action(&self, op: OnImportAction<Block>);
122
123 fn register_finality_action(&self, op: OnFinalityAction<Block>);
125}
126
127pub trait BlockBackend<Block: BlockT> {
129 fn block_body(
131 &self,
132 hash: Block::Hash,
133 ) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
134
135 fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>>;
140
141 fn block_indexed_hashes(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<H256>>>;
147
148 fn block(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
150
151 fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result<sp_consensus::BlockStatus>;
153
154 fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Justifications>>;
156
157 fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
159
160 fn indexed_transaction(&self, hash: H256) -> sp_blockchain::Result<Option<Vec<u8>>>;
165
166 fn has_indexed_transaction(&self, hash: H256) -> sp_blockchain::Result<bool> {
168 Ok(self.indexed_transaction(hash)?.is_some())
169 }
170
171 fn requires_full_sync(&self) -> bool;
173}
174
175pub trait ProvideUncles<Block: BlockT> {
177 fn uncles(
179 &self,
180 target_hash: Block::Hash,
181 max_generation: NumberFor<Block>,
182 ) -> sp_blockchain::Result<Vec<Block::Header>>;
183}
184
185#[derive(Debug, Clone)]
187pub struct ClientInfo<Block: BlockT> {
188 pub chain: Info<Block>,
190 pub usage: Option<UsageInfo>,
192}
193
194#[derive(Default, Clone, Debug, Copy)]
196pub struct MemorySize(usize);
197
198impl MemorySize {
199 pub fn from_bytes(bytes: usize) -> Self {
201 Self(bytes)
202 }
203
204 pub fn as_bytes(self) -> usize {
206 self.0
207 }
208}
209
210impl fmt::Display for MemorySize {
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 if self.0 < 1024 {
213 write!(f, "{} bytes", self.0)
214 } else if self.0 < 1024 * 1024 {
215 write!(f, "{:.2} KiB", self.0 as f64 / 1024f64)
216 } else if self.0 < 1024 * 1024 * 1024 {
217 write!(f, "{:.2} MiB", self.0 as f64 / (1024f64 * 1024f64))
218 } else {
219 write!(f, "{:.2} GiB", self.0 as f64 / (1024f64 * 1024f64 * 1024f64))
220 }
221 }
222}
223
224#[derive(Default, Clone, Debug)]
226pub struct MemoryInfo {
227 pub state_cache: MemorySize,
229 pub database_cache: MemorySize,
231}
232
233#[derive(Default, Clone, Debug)]
235pub struct IoInfo {
236 pub transactions: u64,
238 pub bytes_read: u64,
240 pub bytes_written: u64,
242 pub writes: u64,
244 pub reads: u64,
246 pub average_transaction_size: u64,
248 pub state_reads: u64,
250 pub state_reads_cache: u64,
252 pub state_writes: u64,
254 pub state_writes_cache: u64,
256 pub state_writes_nodes: u64,
258}
259
260#[derive(Default, Clone, Debug)]
266pub struct UsageInfo {
267 pub memory: MemoryInfo,
269 pub io: IoInfo,
271}
272
273impl fmt::Display for UsageInfo {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 write!(
276 f,
277 "caches: ({} state, {} db overlay), \
278 i/o: ({} tx, {} write, {} read, {} avg tx, {}/{} key cache reads/total, {} trie nodes writes)",
279 self.memory.state_cache,
280 self.memory.database_cache,
281 self.io.transactions,
282 self.io.bytes_written,
283 self.io.bytes_read,
284 self.io.average_transaction_size,
285 self.io.state_reads_cache,
286 self.io.state_reads,
287 self.io.state_writes_nodes,
288 )
289 }
290}
291
292pub struct UnpinHandleInner<Block: BlockT> {
294 hash: Block::Hash,
296 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
297}
298
299impl<Block: BlockT> Debug for UnpinHandleInner<Block> {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 f.debug_struct("UnpinHandleInner").field("pinned_block", &self.hash).finish()
302 }
303}
304
305impl<Block: BlockT> UnpinHandleInner<Block> {
306 pub fn new(
308 hash: Block::Hash,
309 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
310 ) -> Self {
311 Self { hash, unpin_worker_sender }
312 }
313}
314
315impl<Block: BlockT> Drop for UnpinHandleInner<Block> {
316 fn drop(&mut self) {
317 if let Err(err) =
318 self.unpin_worker_sender.unbounded_send(UnpinWorkerMessage::Unpin(self.hash))
319 {
320 log::debug!(target: "db", "Unable to unpin block with hash: {}, error: {:?}", self.hash, err);
321 };
322 }
323}
324
325#[derive(Debug)]
329pub enum UnpinWorkerMessage<Block: BlockT> {
330 AnnouncePin(Block::Hash),
332 Unpin(Block::Hash),
334}
335
336#[derive(Debug, Clone)]
340pub struct UnpinHandle<Block: BlockT>(Arc<UnpinHandleInner<Block>>);
341
342impl<Block: BlockT> UnpinHandle<Block> {
343 pub fn new(
345 hash: Block::Hash,
346 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
347 ) -> UnpinHandle<Block> {
348 UnpinHandle(Arc::new(UnpinHandleInner::new(hash, unpin_worker_sender)))
349 }
350
351 pub fn hash(&self) -> Block::Hash {
353 self.0.hash
354 }
355}
356
357#[derive(Clone, Debug)]
359pub struct BlockImportNotification<Block: BlockT> {
360 pub hash: Block::Hash,
362 pub origin: BlockOrigin,
364 pub header: Block::Header,
366 pub is_new_best: bool,
368 pub tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
372 unpin_handle: UnpinHandle<Block>,
374}
375
376impl<Block: BlockT> BlockImportNotification<Block> {
377 pub fn new(
379 hash: Block::Hash,
380 origin: BlockOrigin,
381 header: Block::Header,
382 is_new_best: bool,
383 tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
384 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
385 ) -> Self {
386 Self {
387 hash,
388 origin,
389 header,
390 is_new_best,
391 tree_route,
392 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
393 }
394 }
395
396 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
400 self.unpin_handle
401 }
402}
403
404#[derive(Clone, Debug)]
406pub struct FinalityNotification<Block: BlockT> {
407 pub hash: Block::Hash,
409 pub header: Block::Header,
411 pub tree_route: Arc<[Block::Hash]>,
415 pub stale_blocks: Arc<[Arc<StaleBlock<Block>>]>,
417 unpin_handle: UnpinHandle<Block>,
419}
420
421impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
422 type Error = ();
423
424 fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
425 if n.is_new_best {
426 Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
427 } else {
428 Err(())
429 }
430 }
431}
432
433impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
434 fn from(n: FinalityNotification<B>) -> Self {
435 Self::Finalized { hash: n.hash, tree_route: n.tree_route }
436 }
437}
438
439impl<Block: BlockT> FinalityNotification<Block> {
440 pub fn from_summary(
442 mut summary: FinalizeSummary<Block>,
443 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
444 ) -> FinalityNotification<Block> {
445 let hash = summary.finalized.pop().unwrap_or_default();
446 FinalityNotification {
447 hash,
448 header: summary.header,
449 tree_route: Arc::from(summary.finalized),
450 stale_blocks: Arc::from(
451 summary.stale_blocks.into_iter().map(Arc::from).collect::<Vec<_>>(),
452 ),
453 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
454 }
455 }
456
457 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
461 self.unpin_handle
462 }
463}
464
465impl<Block: BlockT> BlockImportNotification<Block> {
466 pub fn from_summary(
468 summary: ImportSummary<Block>,
469 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
470 ) -> BlockImportNotification<Block> {
471 let hash = summary.hash;
472 BlockImportNotification {
473 hash,
474 origin: summary.origin,
475 header: summary.header,
476 is_new_best: summary.is_new_best,
477 tree_route: summary.tree_route.map(Arc::new),
478 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
479 }
480 }
481}