use enjen::Engine;
use tetsy_util_mem::MallocSizeOf;
use vapory_types::{H256, U256};
use common_types::errors::VapcoreError as Error;
pub use self::blocks::Blocks;
pub use self::headers::Headers;
pub trait BlockLike {
fn hash(&self) -> H256;
fn raw_hash(&self) -> H256;
fn parent_hash(&self) -> H256;
fn difficulty(&self) -> U256;
}
pub trait Kind: 'static + Sized + Send + Sync {
type Input: Sized + Send + BlockLike + MallocSizeOf;
type Unverified: Sized + Send + BlockLike + MallocSizeOf;
type Verified: Sized + Send + BlockLike + MallocSizeOf;
fn create(
input: Self::Input,
engine: &dyn Engine,
check_seal: bool
) -> Result<Self::Unverified, (Error, Option<Self::Input>)>;
fn verify(unverified: Self::Unverified, engine: &dyn Engine, check_seal: bool) -> Result<Self::Verified, Error>;
}
pub mod blocks {
use super::{Kind, BlockLike};
use enjen::Engine;
use common_types::{
block::PreverifiedBlock,
errors::{VapcoreError as Error, BlockError},
verification::Unverified,
};
use log::{debug, warn};
use crate::verification::{verify_block_basic, verify_block_unordered};
use vapory_types::{H256, U256};
pub struct Blocks;
impl Kind for Blocks {
type Input = Unverified;
type Unverified = Unverified;
type Verified = PreverifiedBlock;
fn create(
input: Self::Input,
engine: &dyn Engine,
check_seal: bool
) -> Result<Self::Unverified, (Error, Option<Self::Input>)> {
match verify_block_basic(&input, engine, check_seal) {
Ok(()) => Ok(input),
Err(Error::Block(BlockError::TemporarilyInvalid(oob))) => {
debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob);
Err((BlockError::TemporarilyInvalid(oob).into(), Some(input)))
},
Err(e) => {
warn!(target: "client", "Stage 1 block verification failed for {}: {:?}", input.hash(), e);
Err((e, Some(input)))
}
}
}
fn verify(un: Self::Unverified, engine: &dyn Engine, check_seal: bool) -> Result<Self::Verified, Error> {
let hash = un.hash();
match verify_block_unordered(un, engine, check_seal) {
Ok(verified) => Ok(verified),
Err(e) => {
warn!(target: "client", "Stage 2 block verification failed for {}: {:?}", hash, e);
Err(e)
}
}
}
}
impl BlockLike for Unverified {
fn hash(&self) -> H256 {
self.header.hash()
}
fn raw_hash(&self) -> H256 {
tetsy_keccak_hash::keccak(&self.bytes)
}
fn parent_hash(&self) -> H256 {
*self.header.parent_hash()
}
fn difficulty(&self) -> U256 {
*self.header.difficulty()
}
}
impl BlockLike for PreverifiedBlock {
fn hash(&self) -> H256 {
self.header.hash()
}
fn raw_hash(&self) -> H256 {
tetsy_keccak_hash::keccak(&self.bytes)
}
fn parent_hash(&self) -> H256 {
*self.header.parent_hash()
}
fn difficulty(&self) -> U256 {
*self.header.difficulty()
}
}
}
pub mod headers {
use super::{Kind, BlockLike};
use enjen::Engine;
use common_types::{
header::Header,
errors::VapcoreError as Error,
};
use crate::verification::{verify_header_params, verify_header_time};
use vapory_types::{H256, U256};
impl BlockLike for Header {
fn hash(&self) -> H256 { self.hash() }
fn raw_hash(&self) -> H256 { self.hash() }
fn parent_hash(&self) -> H256 { *self.parent_hash() }
fn difficulty(&self) -> U256 { *self.difficulty() }
}
pub struct Headers;
impl Kind for Headers {
type Input = Header;
type Unverified = Header;
type Verified = Header;
fn create(
input: Self::Input,
engine: &dyn Engine,
check_seal: bool
) -> Result<Self::Unverified, (Error, Option<Self::Input>)> {
let res = verify_header_params(&input, engine, check_seal)
.and_then(|_| verify_header_time(&input));
match res {
Ok(_) => Ok(input),
Err(e) => Err((e, Some(input))),
}
}
fn verify(unverified: Self::Unverified, engine: &dyn Engine, check_seal: bool) -> Result<Self::Verified, Error> {
match check_seal {
true => engine.verify_block_unordered(&unverified).map(|_| unverified),
false => Ok(unverified),
}
}
}
}