use std::sync::Arc;
use tp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
use tp_runtime::generic::BlockId;
use tp_runtime::Justification;
use log::warn;
use parking_lot::RwLock;
use crate::header_metadata::HeaderMetadata;
use crate::error::{Error, Result};
pub trait HeaderBackend<Block: BlockT>: Send + Sync {
fn header(&self, id: BlockId<Block>) -> Result<Option<Block::Header>>;
fn info(&self) -> Info<Block>;
fn status(&self, id: BlockId<Block>) -> Result<BlockStatus>;
fn number(&self, hash: Block::Hash) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Number>>;
fn hash(&self, number: NumberFor<Block>) -> Result<Option<Block::Hash>>;
fn block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Option<Block::Hash>> {
match *id {
BlockId::Hash(h) => Ok(Some(h)),
BlockId::Number(n) => self.hash(n),
}
}
fn block_number_from_id(&self, id: &BlockId<Block>) -> Result<Option<NumberFor<Block>>> {
match *id {
BlockId::Hash(h) => self.number(h),
BlockId::Number(n) => Ok(Some(n)),
}
}
fn expect_header(&self, id: BlockId<Block>) -> Result<Block::Header> {
self.header(id)?.ok_or_else(|| Error::UnknownBlock(format!("Expect header: {}", id)))
}
fn expect_block_number_from_id(&self, id: &BlockId<Block>) -> Result<NumberFor<Block>> {
self.block_number_from_id(id)
.and_then(|n| n.ok_or_else(||
Error::UnknownBlock(format!("Expect block number from id: {}", id))
))
}
fn expect_block_hash_from_id(&self, id: &BlockId<Block>) -> Result<Block::Hash> {
self.block_hash_from_id(id)
.and_then(|n| n.ok_or_else(||
Error::UnknownBlock(format!("Expect block hash from id: {}", id))
))
}
}
pub trait Backend<Block: BlockT>: HeaderBackend<Block> + HeaderMetadata<Block, Error=Error> {
fn body(&self, id: BlockId<Block>) -> Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
fn justification(&self, id: BlockId<Block>) -> Result<Option<Justification>>;
fn last_finalized(&self) -> Result<Block::Hash>;
fn cache(&self) -> Option<Arc<dyn Cache<Block>>>;
fn leaves(&self) -> Result<Vec<Block::Hash>>;
fn children(&self, parent_hash: Block::Hash) -> Result<Vec<Block::Hash>>;
fn best_containing(
&self,
target_hash: Block::Hash,
maybe_max_number: Option<NumberFor<Block>>,
import_lock: &RwLock<()>,
) -> Result<Option<Block::Hash>> {
let target_header = {
match self.header(BlockId::Hash(target_hash))? {
Some(x) => x,
None => { return Ok(None); },
}
};
if let Some(max_number) = maybe_max_number {
if target_header.number() > &max_number {
return Ok(None);
}
}
let leaves = {
let _import_guard = import_lock.read();
let info = self.info();
let maybe_canon_hash = self.hash(*target_header.number())?;
if maybe_canon_hash.as_ref() == Some(&target_hash) {
if let Some(max_number) = maybe_max_number {
if let Some(header) = self.hash(max_number)? {
return Ok(Some(header));
}
}
} else if info.finalized_number >= *target_header.number() {
return Ok(None);
}
self.leaves()?
};
for leaf_hash in leaves {
let mut current_hash = leaf_hash;
let mut best_hash = leaf_hash;
if let Some(max_number) = maybe_max_number {
loop {
let current_header = self.header(BlockId::Hash(current_hash.clone()))?
.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
if current_header.number() <= &max_number {
best_hash = current_header.hash();
break;
}
current_hash = *current_header.parent_hash();
}
}
loop {
if current_hash == target_hash {
return Ok(Some(best_hash));
}
let current_header = self.header(BlockId::Hash(current_hash.clone()))?
.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
if current_header.number() < target_header.number() {
break;
}
current_hash = *current_header.parent_hash();
}
}
warn!(
"Block {:?} exists in chain but not found when following all \
leaves backwards. Number limit = {:?}",
target_hash,
maybe_max_number,
);
Ok(None)
}
}
pub trait ProvideCache<Block: BlockT> {
fn cache(&self) -> Option<Arc<dyn Cache<Block>>>;
}
pub trait Cache<Block: BlockT>: Send + Sync {
fn initialize(&self, key: &well_known_cache_keys::Id, value_at_genesis: Vec<u8>) -> Result<()>;
fn get_at(
&self,
key: &well_known_cache_keys::Id,
block: &BlockId<Block>,
) -> Result<Option<((NumberFor<Block>, Block::Hash), Option<(NumberFor<Block>, Block::Hash)>, Vec<u8>)>>;
}
#[derive(Debug, Eq, PartialEq)]
pub struct Info<Block: BlockT> {
pub best_hash: Block::Hash,
pub best_number: <<Block as BlockT>::Header as HeaderT>::Number,
pub genesis_hash: Block::Hash,
pub finalized_hash: Block::Hash,
pub finalized_number: <<Block as BlockT>::Header as HeaderT>::Number,
pub number_leaves: usize
}
#[derive(Debug, PartialEq, Eq)]
pub enum BlockStatus {
InChain,
Unknown,
}
pub mod well_known_cache_keys {
pub type Id = tp_consensus::import_queue::CacheKeyId;
pub const AUTHORITIES: Id = *b"auth";
pub const EPOCH: Id = *b"epch";
pub const CHANGES_TRIE_CONFIG: Id = *b"chtr";
}