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::{blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary};
35
36use sc_transaction_pool_api::ChainEvent;
37use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender};
38use sp_blockchain;
39
40pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
42
43pub type FinalityNotifications<Block> = TracingUnboundedReceiver<FinalityNotification<Block>>;
45
46pub type ForkBlocks<Block> = Option<Vec<(NumberFor<Block>, <Block as BlockT>::Hash)>>;
52
53pub type BadBlocks<Block> = Option<HashSet<<Block as BlockT>::Hash>>;
57
58pub trait BlockOf {
60 type Type: BlockT;
62}
63
64pub trait BlockchainEvents<Block: BlockT> {
66 fn import_notification_stream(&self) -> ImportNotifications<Block>;
79
80 fn every_import_notification_stream(&self) -> ImportNotifications<Block>;
82
83 fn finality_notification_stream(&self) -> FinalityNotifications<Block>;
86
87 fn storage_changes_notification_stream(
91 &self,
92 filter_keys: Option<&[StorageKey]>,
93 child_filter_keys: Option<&[(StorageKey, Option<Vec<StorageKey>>)]>,
94 ) -> sp_blockchain::Result<StorageEventStream<Block::Hash>>;
95}
96
97pub type AuxDataOperations = Vec<(Vec<u8>, Option<Vec<u8>>)>;
102
103pub type OnImportAction<Block> =
107 Box<dyn (Fn(&BlockImportNotification<Block>) -> AuxDataOperations) + Send>;
108
109pub type OnFinalityAction<Block> =
113 Box<dyn (Fn(&FinalityNotification<Block>) -> AuxDataOperations) + Send>;
114
115pub trait PreCommitActions<Block: BlockT> {
118 fn register_import_action(&self, op: OnImportAction<Block>);
120
121 fn register_finality_action(&self, op: OnFinalityAction<Block>);
123}
124
125pub trait BlockBackend<Block: BlockT> {
127 fn block_body(
129 &self,
130 hash: Block::Hash,
131 ) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
132
133 fn block_indexed_body(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<Vec<u8>>>>;
139
140 fn block(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
142
143 fn block_status(&self, hash: Block::Hash) -> sp_blockchain::Result<sp_consensus::BlockStatus>;
145
146 fn justifications(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Justifications>>;
148
149 fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
151
152 fn indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<Option<Vec<u8>>>;
157
158 fn has_indexed_transaction(&self, hash: Block::Hash) -> sp_blockchain::Result<bool> {
160 Ok(self.indexed_transaction(hash)?.is_some())
161 }
162
163 fn requires_full_sync(&self) -> bool;
165}
166
167pub trait ProvideUncles<Block: BlockT> {
169 fn uncles(
171 &self,
172 target_hash: Block::Hash,
173 max_generation: NumberFor<Block>,
174 ) -> sp_blockchain::Result<Vec<Block::Header>>;
175}
176
177#[derive(Debug, Clone)]
179pub struct ClientInfo<Block: BlockT> {
180 pub chain: Info<Block>,
182 pub usage: Option<UsageInfo>,
184}
185
186#[derive(Default, Clone, Debug, Copy)]
188pub struct MemorySize(usize);
189
190impl MemorySize {
191 pub fn from_bytes(bytes: usize) -> Self {
193 Self(bytes)
194 }
195
196 pub fn as_bytes(self) -> usize {
198 self.0
199 }
200}
201
202impl fmt::Display for MemorySize {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 if self.0 < 1024 {
205 write!(f, "{} bytes", self.0)
206 } else if self.0 < 1024 * 1024 {
207 write!(f, "{:.2} KiB", self.0 as f64 / 1024f64)
208 } else if self.0 < 1024 * 1024 * 1024 {
209 write!(f, "{:.2} MiB", self.0 as f64 / (1024f64 * 1024f64))
210 } else {
211 write!(f, "{:.2} GiB", self.0 as f64 / (1024f64 * 1024f64 * 1024f64))
212 }
213 }
214}
215
216#[derive(Default, Clone, Debug)]
218pub struct MemoryInfo {
219 pub state_cache: MemorySize,
221 pub database_cache: MemorySize,
223}
224
225#[derive(Default, Clone, Debug)]
227pub struct IoInfo {
228 pub transactions: u64,
230 pub bytes_read: u64,
232 pub bytes_written: u64,
234 pub writes: u64,
236 pub reads: u64,
238 pub average_transaction_size: u64,
240 pub state_reads: u64,
242 pub state_reads_cache: u64,
244 pub state_writes: u64,
246 pub state_writes_cache: u64,
248 pub state_writes_nodes: u64,
250}
251
252#[derive(Default, Clone, Debug)]
258pub struct UsageInfo {
259 pub memory: MemoryInfo,
261 pub io: IoInfo,
263}
264
265impl fmt::Display for UsageInfo {
266 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267 write!(
268 f,
269 "caches: ({} state, {} db overlay), \
270 i/o: ({} tx, {} write, {} read, {} avg tx, {}/{} key cache reads/total, {} trie nodes writes)",
271 self.memory.state_cache,
272 self.memory.database_cache,
273 self.io.transactions,
274 self.io.bytes_written,
275 self.io.bytes_read,
276 self.io.average_transaction_size,
277 self.io.state_reads_cache,
278 self.io.state_reads,
279 self.io.state_writes_nodes,
280 )
281 }
282}
283
284pub struct UnpinHandleInner<Block: BlockT> {
286 hash: Block::Hash,
288 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
289}
290
291impl<Block: BlockT> Debug for UnpinHandleInner<Block> {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 f.debug_struct("UnpinHandleInner").field("pinned_block", &self.hash).finish()
294 }
295}
296
297impl<Block: BlockT> UnpinHandleInner<Block> {
298 pub fn new(
300 hash: Block::Hash,
301 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
302 ) -> Self {
303 Self { hash, unpin_worker_sender }
304 }
305}
306
307impl<Block: BlockT> Drop for UnpinHandleInner<Block> {
308 fn drop(&mut self) {
309 if let Err(err) =
310 self.unpin_worker_sender.unbounded_send(UnpinWorkerMessage::Unpin(self.hash))
311 {
312 log::debug!(target: "db", "Unable to unpin block with hash: {}, error: {:?}", self.hash, err);
313 };
314 }
315}
316
317#[derive(Debug)]
321pub enum UnpinWorkerMessage<Block: BlockT> {
322 AnnouncePin(Block::Hash),
324 Unpin(Block::Hash),
326}
327
328#[derive(Debug, Clone)]
332pub struct UnpinHandle<Block: BlockT>(Arc<UnpinHandleInner<Block>>);
333
334impl<Block: BlockT> UnpinHandle<Block> {
335 pub fn new(
337 hash: Block::Hash,
338 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
339 ) -> UnpinHandle<Block> {
340 UnpinHandle(Arc::new(UnpinHandleInner::new(hash, unpin_worker_sender)))
341 }
342
343 pub fn hash(&self) -> Block::Hash {
345 self.0.hash
346 }
347}
348
349#[derive(Clone, Debug)]
351pub struct BlockImportNotification<Block: BlockT> {
352 pub hash: Block::Hash,
354 pub origin: BlockOrigin,
356 pub header: Block::Header,
358 pub is_new_best: bool,
360 pub tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
364 unpin_handle: UnpinHandle<Block>,
366}
367
368impl<Block: BlockT> BlockImportNotification<Block> {
369 pub fn new(
371 hash: Block::Hash,
372 origin: BlockOrigin,
373 header: Block::Header,
374 is_new_best: bool,
375 tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
376 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
377 ) -> Self {
378 Self {
379 hash,
380 origin,
381 header,
382 is_new_best,
383 tree_route,
384 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
385 }
386 }
387
388 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
392 self.unpin_handle
393 }
394}
395
396#[derive(Clone, Debug)]
398pub struct FinalityNotification<Block: BlockT> {
399 pub hash: Block::Hash,
401 pub header: Block::Header,
403 pub tree_route: Arc<[Block::Hash]>,
407 pub stale_heads: Arc<[Block::Hash]>,
409 unpin_handle: UnpinHandle<Block>,
411}
412
413impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
414 type Error = ();
415
416 fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
417 if n.is_new_best {
418 Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
419 } else {
420 Err(())
421 }
422 }
423}
424
425impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
426 fn from(n: FinalityNotification<B>) -> Self {
427 Self::Finalized { hash: n.hash, tree_route: n.tree_route }
428 }
429}
430
431impl<Block: BlockT> FinalityNotification<Block> {
432 pub fn from_summary(
434 mut summary: FinalizeSummary<Block>,
435 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
436 ) -> FinalityNotification<Block> {
437 let hash = summary.finalized.pop().unwrap_or_default();
438 FinalityNotification {
439 hash,
440 header: summary.header,
441 tree_route: Arc::from(summary.finalized),
442 stale_heads: Arc::from(summary.stale_heads),
443 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
444 }
445 }
446
447 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
451 self.unpin_handle
452 }
453}
454
455impl<Block: BlockT> BlockImportNotification<Block> {
456 pub fn from_summary(
458 summary: ImportSummary<Block>,
459 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
460 ) -> BlockImportNotification<Block> {
461 let hash = summary.hash;
462 BlockImportNotification {
463 hash,
464 origin: summary.origin,
465 header: summary.header,
466 is_new_best: summary.is_new_best,
467 tree_route: summary.tree_route.map(Arc::new),
468 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
469 }
470 }
471}