use std::{fmt, collections::HashSet, sync::Arc, convert::TryFrom};
use sp_core::storage::StorageKey;
use sp_runtime::{
traits::{Block as BlockT, NumberFor},
generic::{BlockId, SignedBlock},
Justification,
};
use sp_consensus::BlockOrigin;
use crate::blockchain::Info;
use crate::notifications::StorageEventStream;
use sp_utils::mpsc::TracingUnboundedReceiver;
use sp_blockchain;
pub type ImportNotifications<Block> = TracingUnboundedReceiver<BlockImportNotification<Block>>;
pub type FinalityNotifications<Block> = TracingUnboundedReceiver<FinalityNotification<Block>>;
pub type ForkBlocks<Block> = Option<Vec<(NumberFor<Block>, <Block as BlockT>::Hash)>>;
pub type BadBlocks<Block> = Option<HashSet<<Block as BlockT>::Hash>>;
pub trait BlockOf {
type Type: BlockT;
}
pub trait BlockchainEvents<Block: BlockT> {
fn import_notification_stream(&self) -> ImportNotifications<Block>;
fn finality_notification_stream(&self) -> FinalityNotifications<Block>;
fn storage_changes_notification_stream(
&self,
filter_keys: Option<&[StorageKey]>,
child_filter_keys: Option<&[(StorageKey, Option<Vec<StorageKey>>)]>,
) -> sp_blockchain::Result<StorageEventStream<Block::Hash>>;
}
pub trait BlockBackend<Block: BlockT> {
fn block_body(
&self,
id: &BlockId<Block>
) -> sp_blockchain::Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
fn block(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<SignedBlock<Block>>>;
fn block_status(&self, id: &BlockId<Block>) -> sp_blockchain::Result<sp_consensus::BlockStatus>;
fn justification(&self, id: &BlockId<Block>) -> sp_blockchain::Result<Option<Justification>>;
fn block_hash(&self, number: NumberFor<Block>) -> sp_blockchain::Result<Option<Block::Hash>>;
}
pub trait ProvideUncles<Block: BlockT> {
fn uncles(&self, target_hash: Block::Hash, max_generation: NumberFor<Block>)
-> sp_blockchain::Result<Vec<Block::Header>>;
}
#[derive(Debug)]
pub struct ClientInfo<Block: BlockT> {
pub chain: Info<Block>,
pub usage: Option<UsageInfo>,
}
#[derive(Default, Clone, Debug, Copy)]
pub struct MemorySize(usize);
impl MemorySize {
pub fn from_bytes(bytes: usize) -> Self {
Self(bytes)
}
pub fn as_bytes(self) -> usize {
self.0
}
}
impl fmt::Display for MemorySize {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.0 < 1024 {
write!(f, "{} bytes", self.0)
} else if self.0 < 1024 * 1024 {
write!(f, "{:.2} KiB", self.0 as f64 / 1024f64)
} else if self.0 < 1024 * 1024 * 1024 {
write!(f, "{:.2} MiB", self.0 as f64 / (1024f64 * 1024f64))
} else {
write!(f, "{:.2} GiB", self.0 as f64 / (1024f64 * 1024f64 * 1024f64))
}
}
}
#[derive(Default, Clone, Debug)]
pub struct StateDbMemoryInfo {
pub non_canonical: MemorySize,
pub pruning: Option<MemorySize>,
pub pinned: MemorySize,
}
#[derive(Default, Clone, Debug)]
pub struct MemoryInfo {
pub state_cache: MemorySize,
pub database_cache: MemorySize,
pub state_db: StateDbMemoryInfo,
}
#[derive(Default, Clone, Debug)]
pub struct IoInfo {
pub transactions: u64,
pub bytes_read: u64,
pub bytes_written: u64,
pub writes: u64,
pub reads: u64,
pub average_transaction_size: u64,
pub state_reads: u64,
pub state_reads_cache: u64,
pub state_writes: u64,
pub state_writes_cache: u64,
pub state_writes_nodes: u64,
}
#[derive(Default, Clone, Debug)]
pub struct UsageInfo {
pub memory: MemoryInfo,
pub io: IoInfo,
}
impl fmt::Display for UsageInfo {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"caches: ({} state, {} db overlay), \
state db: ({} non-canonical, {} pruning, {} pinned), \
i/o: ({} tx, {} write, {} read, {} avg tx, {}/{} key cache reads/total, {} trie nodes writes)",
self.memory.state_cache,
self.memory.database_cache,
self.memory.state_db.non_canonical,
self.memory.state_db.pruning.unwrap_or_default(),
self.memory.state_db.pinned,
self.io.transactions,
self.io.bytes_written,
self.io.bytes_read,
self.io.average_transaction_size,
self.io.state_reads_cache,
self.io.state_reads,
self.io.state_writes_nodes,
)
}
}
#[derive(Clone, Debug)]
pub struct BlockImportNotification<Block: BlockT> {
pub hash: Block::Hash,
pub origin: BlockOrigin,
pub header: Block::Header,
pub is_new_best: bool,
pub tree_route: Option<Arc<sp_blockchain::TreeRoute<Block>>>,
}
#[derive(Clone, Debug)]
pub struct FinalityNotification<Block: BlockT> {
pub hash: Block::Hash,
pub header: Block::Header,
}
impl<B: BlockT> TryFrom<BlockImportNotification<B>> for sp_transaction_pool::ChainEvent<B> {
type Error = ();
fn try_from(n: BlockImportNotification<B>) -> Result<Self, ()> {
if n.is_new_best {
Ok(Self::NewBestBlock {
hash: n.hash,
tree_route: n.tree_route,
})
} else {
Err(())
}
}
}
impl<B: BlockT> From<FinalityNotification<B>> for sp_transaction_pool::ChainEvent<B> {
fn from(n: FinalityNotification<B>) -> Self {
Self::Finalized {
hash: n.hash,
}
}
}