use ckb_hash::{blake2b_256, new_blake2b};
use crate::{packed, prelude::*, vec::Vec};
pub(crate) trait CalcHash {
fn calc_hash(&self) -> packed::Byte32;
}
impl<'r, R> CalcHash for R
where
R: Reader<'r>,
{
fn calc_hash(&self) -> packed::Byte32 {
blake2b_256(self.as_slice()).into()
}
}
macro_rules! impl_calc_special_hash_for_entity {
($entity:ident, $func_name:ident, $return:ty, $comment:expr) => {
impl packed::$entity {
#[doc = $comment]
pub fn $func_name(&self) -> $return {
self.as_reader().$func_name()
}
}
};
($entity:ident, $func_name:ident, $return:ty) => {
impl_calc_special_hash_for_entity!(
$entity,
$func_name,
$return,
concat!(
"Calls [`",
stringify!($entity),
"Reader.",
stringify!($func_name),
"()`](struct.",
stringify!($entity),
"Reader.html#method.",
stringify!($func_name),
") for [`self.as_reader()`](#method.as_reader)."
)
);
};
($entity:ident, $func_name:ident) => {
impl_calc_special_hash_for_entity!($entity, $func_name, packed::Byte32);
};
}
impl packed::CellOutput {
pub fn calc_data_hash(data: &[u8]) -> packed::Byte32 {
if data.is_empty() {
packed::Byte32::zero()
} else {
blake2b_256(data).into()
}
}
}
impl<'r> packed::BytesReader<'r> {
pub fn calc_raw_data_hash(&self) -> packed::Byte32 {
blake2b_256(self.raw_data()).into()
}
}
impl_calc_special_hash_for_entity!(Bytes, calc_raw_data_hash);
impl<'r> packed::ScriptReader<'r> {
pub fn calc_script_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(Script, calc_script_hash);
impl<'r> packed::CellOutputReader<'r> {
pub fn calc_lock_hash(&self) -> packed::Byte32 {
self.lock().calc_script_hash()
}
}
impl_calc_special_hash_for_entity!(CellOutput, calc_lock_hash);
impl<'r> packed::ProposalShortIdVecReader<'r> {
pub fn calc_proposals_hash(&self) -> packed::Byte32 {
if self.is_empty() {
packed::Byte32::zero()
} else {
let mut ret = [0u8; 32];
let mut blake2b = new_blake2b();
for id in self.iter() {
blake2b.update(id.as_slice());
}
blake2b.finalize(&mut ret);
ret.into()
}
}
}
impl_calc_special_hash_for_entity!(ProposalShortIdVec, calc_proposals_hash);
impl<'r> packed::RawTransactionReader<'r> {
pub fn calc_tx_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(RawTransaction, calc_tx_hash);
impl<'r> packed::TransactionReader<'r> {
pub fn calc_tx_hash(&self) -> packed::Byte32 {
self.raw().calc_tx_hash()
}
pub fn calc_witness_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(Transaction, calc_tx_hash);
impl_calc_special_hash_for_entity!(Transaction, calc_witness_hash);
impl<'r> packed::RawHeaderReader<'r> {
pub fn calc_pow_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(RawHeader, calc_pow_hash);
impl<'r> packed::HeaderReader<'r> {
pub fn calc_pow_hash(&self) -> packed::Byte32 {
self.raw().calc_pow_hash()
}
pub fn calc_header_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(Header, calc_pow_hash);
impl_calc_special_hash_for_entity!(Header, calc_header_hash);
impl<'r> packed::UncleBlockReader<'r> {
pub fn calc_header_hash(&self) -> packed::Byte32 {
self.header().calc_header_hash()
}
pub fn calc_proposals_hash(&self) -> packed::Byte32 {
self.proposals().calc_proposals_hash()
}
}
impl_calc_special_hash_for_entity!(UncleBlock, calc_header_hash);
impl_calc_special_hash_for_entity!(UncleBlock, calc_proposals_hash);
impl<'r> packed::UncleBlockVecReader<'r> {
pub fn calc_uncles_hash(&self) -> packed::Byte32 {
if self.is_empty() {
packed::Byte32::zero()
} else {
let mut ret = [0u8; 32];
let mut blake2b = new_blake2b();
for uncle in self.iter() {
blake2b.update(uncle.calc_header_hash().as_slice());
}
blake2b.finalize(&mut ret);
ret.into()
}
}
}
impl_calc_special_hash_for_entity!(UncleBlockVec, calc_uncles_hash);
impl<'r> packed::BlockReader<'r> {
pub fn calc_header_hash(&self) -> packed::Byte32 {
self.header().calc_header_hash()
}
pub fn calc_proposals_hash(&self) -> packed::Byte32 {
self.proposals().calc_proposals_hash()
}
pub fn calc_uncles_hash(&self) -> packed::Byte32 {
self.uncles().calc_uncles_hash()
}
pub fn calc_extension_hash(&self) -> Option<packed::Byte32> {
self.extension()
.map(|extension| extension.calc_raw_data_hash())
}
pub fn calc_tx_hashes(&self) -> Vec<packed::Byte32> {
self.transactions()
.iter()
.map(|tx| tx.calc_tx_hash())
.collect::<Vec<_>>()
}
pub fn calc_tx_witness_hashes(&self) -> Vec<packed::Byte32> {
self.transactions()
.iter()
.map(|tx| tx.calc_witness_hash())
.collect::<Vec<_>>()
}
}
impl_calc_special_hash_for_entity!(Block, calc_header_hash);
impl_calc_special_hash_for_entity!(Block, calc_proposals_hash);
impl_calc_special_hash_for_entity!(Block, calc_uncles_hash);
impl_calc_special_hash_for_entity!(Block, calc_extension_hash, Option<packed::Byte32>);
impl_calc_special_hash_for_entity!(Block, calc_tx_hashes, Vec<packed::Byte32>);
impl_calc_special_hash_for_entity!(Block, calc_tx_witness_hashes, Vec<packed::Byte32>);
impl<'r> packed::CompactBlockReader<'r> {
pub fn calc_header_hash(&self) -> packed::Byte32 {
self.header().calc_header_hash()
}
}
impl_calc_special_hash_for_entity!(CompactBlock, calc_header_hash);
impl<'r> packed::RawAlertReader<'r> {
pub fn calc_alert_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(RawAlert, calc_alert_hash);
impl<'r> packed::AlertReader<'r> {
pub fn calc_alert_hash(&self) -> packed::Byte32 {
self.raw().calc_alert_hash()
}
}
impl_calc_special_hash_for_entity!(Alert, calc_alert_hash);
impl<'r> packed::HeaderDigestReader<'r> {
pub fn calc_mmr_hash(&self) -> packed::Byte32 {
self.calc_hash()
}
}
impl_calc_special_hash_for_entity!(HeaderDigest, calc_mmr_hash);