use std::mem;
use base::Result;
use base::Checkable;
use base::Datable;
use base::Serializable;
use base::{Sizable, ConstantSize};
use base::Numerical;
use base::{Eval, EvalMut};
use base::Meta;
use crypto::{Hash, Prove};
use io::{Store, Storable};
use model::Transaction;
use model::BlockNode;
pub const BLOCK_CODE: u64 = 5;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Default, Hash, Serialize, Deserialize)]
pub struct Block<D, A, IP, OP, TP, P, Pr>
where D: Ord + Datable + ConstantSize,
A: Numerical,
IP: Datable,
OP: Datable,
TP: Datable,
P: Datable,
Pr: Datable
{
pub id: D,
pub meta: Meta,
pub height: u64,
pub prev_blocks_len: u64,
pub prev_blocks: Vec<BlockNode<D>>,
pub transactions_len: u64,
pub transactions: Vec<Transaction<D, A, IP, OP, TP>>,
pub payload: P,
pub proof: Pr,
}
impl<D, A, IP, OP, TP, P, Pr> Block<D, A, IP, OP, TP, P, Pr>
where D: Ord + Datable + ConstantSize,
A: Numerical,
IP: Datable,
OP: Datable,
TP: Datable,
P: Datable,
Pr: Datable,
Self: Serializable
{
pub fn new() -> Self {
let mut block = Block::default();
block.update_size();
block
}
pub fn update_size(&mut self) {
let size = self.size();
self.meta.set_size(size);
}
pub fn meta(mut self, meta: &Meta) -> Result<Self> {
meta.check()?;
self.meta = meta.clone();
self.update_size();
Ok(self)
}
pub fn prev_blocks(mut self, prev_blocks: &Vec<BlockNode<D>>) -> Result<Self> {
prev_blocks.check()?;
let mut unique_prev_blocks = prev_blocks.clone();
unique_prev_blocks.dedup_by(|a, b| { a == b });
if unique_prev_blocks.len() != prev_blocks.len() {
return Err(format!("duplicates found"));
}
let mut prev_height = 0;
for prev_block in prev_blocks.clone() {
if prev_block.block_height > prev_height {
prev_height = prev_block.block_height;
}
}
self.height = prev_height + 1;
self.prev_blocks_len = prev_blocks.len() as u64;
self.prev_blocks = prev_blocks.clone();
self.update_size();
Ok(self)
}
pub fn transactions(mut self, transactions: &Vec<Transaction<D, A, IP, OP, TP>>) -> Result<Self> {
transactions.check()?;
let mut unique_transactions = transactions.clone();
unique_transactions.dedup_by(|a, b| { a == b });
if unique_transactions.len() != transactions.len() {
return Err(format!("duplicates found"));
}
self.transactions_len = transactions.len() as u64;
self.transactions = transactions.clone();
self.update_size();
Ok(self)
}
pub fn payload(mut self, payload: &P) -> Result<Self> {
payload.check()?;
self.payload = payload.clone();
self.update_size();
Ok(self)
}
pub fn prove<Prv: Prove<Pr>>(mut self, prover: &mut Prv) -> Result<Self> {
let mut block = self.clone();
block.proof = Pr::default();
block.id = D::default();
block.update_size();
let msg = block.to_bytes()?;
self.proof = prover.prove(&msg)?;
self.update_size();
Ok(self)
}
pub fn verify_proof<Prv: Prove<Pr>>(&self, prover: &mut Prv) -> Result<bool> {
let proof = self.proof.clone();
proof.check()?;
let mut block = self.clone();
block.proof = Pr::default();
block.id = D::default();
block.update_size();
let msg = block.to_bytes()?;
prover.verify(&msg, &proof)
}
pub fn check_proof<Prv: Prove<Pr>>(&self, prover: &mut Prv) -> Result<()> {
let proof = self.proof.clone();
proof.check()?;
let mut block = self.clone();
block.proof = Pr::default();
block.id = D::default();
block.update_size();
let msg = block.to_bytes()?;
prover.check(&msg, &proof)
}
pub fn finalize<H: Hash<D>>(mut self, hasher: &mut H) -> Result<Self> {
let msg = self.to_bytes()?;
self.id = hasher.digest(&msg)?;
self.update_size();
self.check()?;
Ok(self)
}
pub fn digest<H: Hash<D>>(&self, hasher: &mut H) -> Result<D> {
let mut block = self.clone();
block.id = D::default();
block.update_size();
let msg = block.to_bytes()?;
hasher.digest(&msg)
}
pub fn verify_digest<H: Hash<D>>(&self, hasher: &mut H) -> Result<bool> {
let digest = self.id.clone();
digest.check()?;
let mut block = self.clone();
block.id = D::default();
block.update_size();
let msg = block.to_bytes()?;
hasher.verify(&msg, &digest)
}
pub fn check_digest<H: Hash<D>>(&self, hasher: &mut H) -> Result<()> {
let digest = self.id.clone();
digest.check()?;
let mut block = self.clone();
block.id = D::default();
block.update_size();
let msg = block.to_bytes()?;
hasher.check(&msg, &digest)
}
pub fn eval<Ev, EP, ER>(&self, params: &EP, evaluator: &Ev)
-> Result<ER>
where Ev: Eval<Self, EP, ER>,
EP: Datable,
ER: Datable
{
self.check()?;
params.check()?;
evaluator.eval(self, params)
}
pub fn eval_mut<EvM, EP, ER>(&mut self, params: &EP, evaluator: &mut EvM)
-> Result<ER>
where EvM: EvalMut<Self, EP, ER>,
EP: Datable,
ER: Datable
{
self.check()?;
params.check()?;
let result = evaluator.eval_mut(self, params)?;
self.update_size();
self.check()?;
Ok(result)
}
}
impl<D, A, IP, OP, TP, P, Pr> Sizable for Block<D, A, IP, OP, TP, P, Pr>
where D: Ord + Datable + ConstantSize,
A: Numerical,
IP: Datable,
OP: Datable,
TP: Datable,
P: Datable,
Pr: Datable
{
fn size(&self) -> u64 {
self.id.size() +
self.meta.size() +
self.height.size() +
self.prev_blocks_len.size() +
self.prev_blocks.size() +
self.transactions_len.size() +
self.transactions.size() +
self.payload.size() +
self.proof.size()
}
}
impl<D, A, IP, OP, TP, P, Pr> Checkable for Block<D, A, IP, OP, TP, P, Pr>
where D: Ord + Datable + ConstantSize,
A: Numerical,
IP: Datable,
OP: Datable,
TP: Datable,
P: Datable,
Pr: Datable
{
fn check(&self) -> Result<()> {
self.id.check()?;
self.id.check_size()?;
self.meta.check()?;
if self.meta.get_size() != self.size() {
return Err(String::from("invalid meta size"));
}
self.height.check()?;
self.prev_blocks_len.check()?;
self.prev_blocks.check()?;
if self.prev_blocks.len() != self.prev_blocks_len as usize {
return Err(String::from("invalid previous blocks length"));
}
let mut unique_prev_blocks = self.prev_blocks.clone();
unique_prev_blocks.dedup_by(|a, b| { a == b });
if unique_prev_blocks.len() != self.prev_blocks.len() {
return Err(format!("duplicates found"));
}
self.transactions_len.check()?;
self.transactions.check()?;
if self.transactions.len() != self.transactions_len as usize {
return Err(String::from("invalid transactions length"));
}
let mut unique_transactions = self.transactions.clone();
unique_transactions.dedup_by(|a, b| { a == b });
if unique_transactions.len() != self.transactions.len() {
return Err(format!("duplicates found"));
}
self.payload.check()?;
self.proof.check()?;
Ok(())
}
}
impl<D, A, IP, OP, TP, P, Pr> Serializable for Block<D, A, IP, OP, TP, P, Pr>
where D: Ord + Datable + ConstantSize + Serializable,
A: Numerical + Serializable,
IP: Datable + Serializable,
OP: Datable + Serializable,
TP: Datable + Serializable,
P: Datable + Serializable,
Pr: Datable + Serializable
{}
impl<D, A, IP, OP, TP, P, Pr> Datable for Block<D, A, IP, OP, TP, P, Pr>
where D: Ord + Datable + ConstantSize,
A: Numerical,
IP: Datable,
OP: Datable,
TP: Datable,
P: Datable,
Pr: Datable
{}
impl<St, S, D, A, IP, OP, TP, P, Pr>
Storable<St, S, D, Block<D, A, IP, OP, TP, P, Pr>>
for Block<D, A, IP, OP, TP, P, Pr>
where St: Store<S>,
S: Datable + Serializable,
D: Ord + Datable + ConstantSize + Serializable,
A: Numerical + Serializable,
IP: Datable + Serializable,
OP: Datable + Serializable,
TP: Datable + Serializable,
P: Datable + Serializable,
Pr: Datable + Serializable
{
fn store_prefix() -> Vec<u8> {
let mut prefix = Vec::new();
let _prefix: [u8; 8] = unsafe { mem::transmute(BLOCK_CODE) };
prefix.extend_from_slice(&_prefix[..]);
prefix
}
fn store_key(&self) -> Result<D> {
self.id.check()?;
Ok(self.id.clone())
}
fn store_value(&self) -> Result<Self> {
self.check()?;
Ok(self.clone())
}
}