1use sp_consensus::BlockOrigin;
22use sp_core::storage::StorageKey;
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>>>>;
141
142 fn block(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
144
145 fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result<sp_consensus::BlockStatus>;
147
148 fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Justifications>>;
150
151 fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
153
154 fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>;
159
160 fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<bool> {
162 Ok(self.indexed_transaction(hash)?.is_some())
163 }
164
165 fn requires_full_sync(&self) -> bool;
167}
168
169pub trait ProvideUncles<Block: BlockT> {
171 fn uncles(
173 &self,
174 target_hash: Block::Hash,
175 max_generation: NumberFor<Block>,
176 ) -> sp_blockchain::Result<Vec<Block::Header>>;
177}
178
179#[derive(Debug, Clone)]
181pub struct ClientInfo<Block: BlockT> {
182 pub chain: Info<Block>,
184 pub usage: Option<UsageInfo>,
186}
187
188#[derive(Default, Clone, Debug, Copy)]
190pub struct MemorySize(usize);
191
192impl MemorySize {
193 pub fn from_bytes(bytes: usize) -> Self {
195 Self(bytes)
196 }
197
198 pub fn as_bytes(self) -> usize {
200 self.0
201 }
202}
203
204impl fmt::Display for MemorySize {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 if self.0 < 1024 {
207 write!(f, "{} bytes", self.0)
208 } else if self.0 < 1024 * 1024 {
209 write!(f, "{:.2} KiB", self.0 as f64 / 1024f64)
210 } else if self.0 < 1024 * 1024 * 1024 {
211 write!(f, "{:.2} MiB", self.0 as f64 / (1024f64 * 1024f64))
212 } else {
213 write!(f, "{:.2} GiB", self.0 as f64 / (1024f64 * 1024f64 * 1024f64))
214 }
215 }
216}
217
218#[derive(Default, Clone, Debug)]
220pub struct MemoryInfo {
221 pub state_cache: MemorySize,
223 pub database_cache: MemorySize,
225}
226
227#[derive(Default, Clone, Debug)]
229pub struct IoInfo {
230 pub transactions: u64,
232 pub bytes_read: u64,
234 pub bytes_written: u64,
236 pub writes: u64,
238 pub reads: u64,
240 pub average_transaction_size: u64,
242 pub state_reads: u64,
244 pub state_reads_cache: u64,
246 pub state_writes: u64,
248 pub state_writes_cache: u64,
250 pub state_writes_nodes: u64,
252}
253
254#[derive(Default, Clone, Debug)]
260pub struct UsageInfo {
261 pub memory: MemoryInfo,
263 pub io: IoInfo,
265}
266
267impl fmt::Display for UsageInfo {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 write!(
270 f,
271 "caches: ({} state, {} db overlay), \
272 i/o: ({} tx, {} write, {} read, {} avg tx, {}/{} key cache reads/total, {} trie nodes writes)",
273 self.memory.state_cache,
274 self.memory.database_cache,
275 self.io.transactions,
276 self.io.bytes_written,
277 self.io.bytes_read,
278 self.io.average_transaction_size,
279 self.io.state_reads_cache,
280 self.io.state_reads,
281 self.io.state_writes_nodes,
282 )
283 }
284}
285
286pub struct UnpinHandleInner<Block: BlockT> {
288 hash: Block::Hash,
290 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
291}
292
293impl<Block: BlockT> Debug for UnpinHandleInner<Block> {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 f.debug_struct("UnpinHandleInner").field("pinned_block", &self.hash).finish()
296 }
297}
298
299impl<Block: BlockT> UnpinHandleInner<Block> {
300 pub fn new(
302 hash: Block::Hash,
303 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
304 ) -> Self {
305 Self { hash, unpin_worker_sender }
306 }
307}
308
309impl<Block: BlockT> Drop for UnpinHandleInner<Block> {
310 fn drop(&mut self) {
311 if let Err(err) =
312 self.unpin_worker_sender.unbounded_send(UnpinWorkerMessage::Unpin(self.hash))
313 {
314 log::debug!(target: "db", "Unable to unpin block with hash: {}, error: {:?}", self.hash, err);
315 };
316 }
317}
318
319#[derive(Debug)]
323pub enum UnpinWorkerMessage<Block: BlockT> {
324 AnnouncePin(Block::Hash),
326 Unpin(Block::Hash),
328}
329
330#[derive(Debug, Clone)]
334pub struct UnpinHandle<Block: BlockT>(Arc<UnpinHandleInner<Block>>);
335
336impl<Block: BlockT> UnpinHandle<Block> {
337 pub fn new(
339 hash: Block::Hash,
340 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
341 ) -> UnpinHandle<Block> {
342 UnpinHandle(Arc::new(UnpinHandleInner::new(hash, unpin_worker_sender)))
343 }
344
345 pub fn hash(&self) -> Block::Hash {
347 self.0.hash
348 }
349}
350
351#[derive(Clone, Debug)]
353pub struct BlockImportNotification<Block: BlockT> {
354 pub hash: Block::Hash,
356 pub origin: BlockOrigin,
358 pub header: Block::Header,
360 pub is_new_best: bool,
362 pub tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
366 unpin_handle: UnpinHandle<Block>,
368}
369
370impl<Block: BlockT> BlockImportNotification<Block> {
371 pub fn new(
373 hash: Block::Hash,
374 origin: BlockOrigin,
375 header: Block::Header,
376 is_new_best: bool,
377 tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
378 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
379 ) -> Self {
380 Self {
381 hash,
382 origin,
383 header,
384 is_new_best,
385 tree_route,
386 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
387 }
388 }
389
390 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
394 self.unpin_handle
395 }
396}
397
398#[derive(Clone, Debug)]
400pub struct FinalityNotification<Block: BlockT> {
401 pub hash: Block::Hash,
403 pub header: Block::Header,
405 pub tree_route: Arc<[Block::Hash]>,
409 pub stale_blocks: Arc<[Arc<StaleBlock<Block>>]>,
411 unpin_handle: UnpinHandle<Block>,
413}
414
415impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
416 type Error = ();
417
418 fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
419 if n.is_new_best {
420 Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
421 } else {
422 Err(())
423 }
424 }
425}
426
427impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
428 fn from(n: FinalityNotification<B>) -> Self {
429 Self::Finalized { hash: n.hash, tree_route: n.tree_route }
430 }
431}
432
433impl<Block: BlockT> FinalityNotification<Block> {
434 pub fn from_summary(
436 mut summary: FinalizeSummary<Block>,
437 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
438 ) -> FinalityNotification<Block> {
439 let hash = summary.finalized.pop().unwrap_or_default();
440 FinalityNotification {
441 hash,
442 header: summary.header,
443 tree_route: Arc::from(summary.finalized),
444 stale_blocks: Arc::from(
445 summary.stale_blocks.into_iter().map(Arc::from).collect::<Vec<_>>(),
446 ),
447 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
448 }
449 }
450
451 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
455 self.unpin_handle
456 }
457}
458
459impl<Block: BlockT> BlockImportNotification<Block> {
460 pub fn from_summary(
462 summary: ImportSummary<Block>,
463 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
464 ) -> BlockImportNotification<Block> {
465 let hash = summary.hash;
466 BlockImportNotification {
467 hash,
468 origin: summary.origin,
469 header: summary.header,
470 is_new_best: summary.is_new_best,
471 tree_route: summary.tree_route.map(Arc::new),
472 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
473 }
474 }
475}