1use pezsp_consensus::BlockOrigin;
22use pezsp_core::storage::StorageKey;
23use pezsp_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 pezsc_transaction_pool_api::ChainEvent;
39use pezsc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender};
40use pezsp_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 ) -> pezsp_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 ) -> pezsp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
134
135 fn block_indexed_body(
141 &self,
142 hash: Block::Hash,
143 ) -> pezsp_blockchain::Result<Option<Vec<Vec<u8>>>>;
144
145 fn block(&self, hash: Block::Hash) -> pezsp_blockchain::Result<Option<SignedBlock<Block>>>;
147
148 fn block_status(
150 &self,
151 hash: Block::Hash,
152 ) -> pezsp_blockchain::Result<pezsp_consensus::BlockStatus>;
153
154 fn justifications(&self, hash: Block::Hash)
156 -> pezsp_blockchain::Result<Option<Justifications>>;
157
158 fn block_hash(&self, number: NumberFor<Block>)
160 -> pezsp_blockchain::Result<Option<Block::Hash>>;
161
162 fn indexed_transaction(&self, hash: Block::Hash) -> pezsp_blockchain::Result<Option<Vec<u8>>>;
167
168 fn has_indexed_transaction(&self, hash: Block::Hash) -> pezsp_blockchain::Result<bool> {
170 Ok(self.indexed_transaction(hash)?.is_some())
171 }
172
173 fn requires_full_sync(&self) -> bool;
175}
176
177pub trait ProvideUncles<Block: BlockT> {
179 fn uncles(
181 &self,
182 target_hash: Block::Hash,
183 max_generation: NumberFor<Block>,
184 ) -> pezsp_blockchain::Result<Vec<Block::Header>>;
185}
186
187#[derive(Debug, Clone)]
189pub struct ClientInfo<Block: BlockT> {
190 pub chain: Info<Block>,
192 pub usage: Option<UsageInfo>,
194}
195
196#[derive(Default, Clone, Debug, Copy)]
198pub struct MemorySize(usize);
199
200impl MemorySize {
201 pub fn from_bytes(bytes: usize) -> Self {
203 Self(bytes)
204 }
205
206 pub fn as_bytes(self) -> usize {
208 self.0
209 }
210}
211
212impl fmt::Display for MemorySize {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 if self.0 < 1024 {
215 write!(f, "{} bytes", self.0)
216 } else if self.0 < 1024 * 1024 {
217 write!(f, "{:.2} KiB", self.0 as f64 / 1024f64)
218 } else if self.0 < 1024 * 1024 * 1024 {
219 write!(f, "{:.2} MiB", self.0 as f64 / (1024f64 * 1024f64))
220 } else {
221 write!(f, "{:.2} GiB", self.0 as f64 / (1024f64 * 1024f64 * 1024f64))
222 }
223 }
224}
225
226#[derive(Default, Clone, Debug)]
228pub struct MemoryInfo {
229 pub state_cache: MemorySize,
231 pub database_cache: MemorySize,
233}
234
235#[derive(Default, Clone, Debug)]
237pub struct IoInfo {
238 pub transactions: u64,
240 pub bytes_read: u64,
242 pub bytes_written: u64,
244 pub writes: u64,
246 pub reads: u64,
248 pub average_transaction_size: u64,
250 pub state_reads: u64,
252 pub state_reads_cache: u64,
254 pub state_writes: u64,
256 pub state_writes_cache: u64,
258 pub state_writes_nodes: u64,
260}
261
262#[derive(Default, Clone, Debug)]
268pub struct UsageInfo {
269 pub memory: MemoryInfo,
271 pub io: IoInfo,
273}
274
275impl fmt::Display for UsageInfo {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 write!(
278 f,
279 "caches: ({} state, {} db overlay), \
280 i/o: ({} tx, {} write, {} read, {} avg tx, {}/{} key cache reads/total, {} trie nodes writes)",
281 self.memory.state_cache,
282 self.memory.database_cache,
283 self.io.transactions,
284 self.io.bytes_written,
285 self.io.bytes_read,
286 self.io.average_transaction_size,
287 self.io.state_reads_cache,
288 self.io.state_reads,
289 self.io.state_writes_nodes,
290 )
291 }
292}
293
294pub struct UnpinHandleInner<Block: BlockT> {
296 hash: Block::Hash,
298 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
299}
300
301impl<Block: BlockT> Debug for UnpinHandleInner<Block> {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 f.debug_struct("UnpinHandleInner").field("pinned_block", &self.hash).finish()
304 }
305}
306
307impl<Block: BlockT> UnpinHandleInner<Block> {
308 pub fn new(
310 hash: Block::Hash,
311 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
312 ) -> Self {
313 Self { hash, unpin_worker_sender }
314 }
315}
316
317impl<Block: BlockT> Drop for UnpinHandleInner<Block> {
318 fn drop(&mut self) {
319 if let Err(err) =
320 self.unpin_worker_sender.unbounded_send(UnpinWorkerMessage::Unpin(self.hash))
321 {
322 log::debug!(target: "db", "Unable to unpin block with hash: {}, error: {:?}", self.hash, err);
323 };
324 }
325}
326
327#[derive(Debug)]
331pub enum UnpinWorkerMessage<Block: BlockT> {
332 AnnouncePin(Block::Hash),
334 Unpin(Block::Hash),
336}
337
338#[derive(Debug, Clone)]
342pub struct UnpinHandle<Block: BlockT>(Arc<UnpinHandleInner<Block>>);
343
344impl<Block: BlockT> UnpinHandle<Block> {
345 pub fn new(
347 hash: Block::Hash,
348 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
349 ) -> UnpinHandle<Block> {
350 UnpinHandle(Arc::new(UnpinHandleInner::new(hash, unpin_worker_sender)))
351 }
352
353 pub fn hash(&self) -> Block::Hash {
355 self.0.hash
356 }
357}
358
359#[derive(Clone, Debug)]
361pub struct BlockImportNotification<Block: BlockT> {
362 pub hash: Block::Hash,
364 pub origin: BlockOrigin,
366 pub header: Block::Header,
368 pub is_new_best: bool,
370 pub tree_route: Option<Arc<pezsp_blockchain::TreeRoute<Block>>>,
374 unpin_handle: UnpinHandle<Block>,
376}
377
378impl<Block: BlockT> BlockImportNotification<Block> {
379 pub fn new(
381 hash: Block::Hash,
382 origin: BlockOrigin,
383 header: Block::Header,
384 is_new_best: bool,
385 tree_route: Option<Arc<pezsp_blockchain::TreeRoute<Block>>>,
386 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
387 ) -> Self {
388 Self {
389 hash,
390 origin,
391 header,
392 is_new_best,
393 tree_route,
394 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
395 }
396 }
397
398 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
402 self.unpin_handle
403 }
404}
405
406#[derive(Clone, Debug)]
408pub struct FinalityNotification<Block: BlockT> {
409 pub hash: Block::Hash,
411 pub header: Block::Header,
413 pub tree_route: Arc<[Block::Hash]>,
417 pub stale_blocks: Arc<[Arc<StaleBlock<Block>>]>,
419 unpin_handle: UnpinHandle<Block>,
421}
422
423impl<B: BlockT> TryFrom<BlockImportNotification<B>> for ChainEvent<B> {
424 type Error = ();
425
426 fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
427 if n.is_new_best {
428 Ok(Self::NewBestBlock { hash: n.hash, tree_route: n.tree_route })
429 } else {
430 Err(())
431 }
432 }
433}
434
435impl<B: BlockT> From<FinalityNotification<B>> for ChainEvent<B> {
436 fn from(n: FinalityNotification<B>) -> Self {
437 Self::Finalized { hash: n.hash, tree_route: n.tree_route }
438 }
439}
440
441impl<Block: BlockT> FinalityNotification<Block> {
442 pub fn from_summary(
444 mut summary: FinalizeSummary<Block>,
445 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
446 ) -> FinalityNotification<Block> {
447 let hash = summary.finalized.pop().unwrap_or_default();
448 FinalityNotification {
449 hash,
450 header: summary.header,
451 tree_route: Arc::from(summary.finalized),
452 stale_blocks: Arc::from(
453 summary.stale_blocks.into_iter().map(Arc::from).collect::<Vec<_>>(),
454 ),
455 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
456 }
457 }
458
459 pub fn into_unpin_handle(self) -> UnpinHandle<Block> {
463 self.unpin_handle
464 }
465}
466
467impl<Block: BlockT> BlockImportNotification<Block> {
468 pub fn from_summary(
470 summary: ImportSummary<Block>,
471 unpin_worker_sender: TracingUnboundedSender<UnpinWorkerMessage<Block>>,
472 ) -> BlockImportNotification<Block> {
473 let hash = summary.hash;
474 BlockImportNotification {
475 hash,
476 origin: summary.origin,
477 header: summary.header,
478 is_new_best: summary.is_new_best,
479 tree_route: summary.tree_route.map(Arc::new),
480 unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
481 }
482 }
483}