From 6abf87eec355275bd943eb6965c57666d9faeaf0 Mon Sep 17 00:00:00 2001 From: Santiago Carmuega Date: Thu, 10 Feb 2022 09:57:06 -0300 Subject: [PATCH] feat: Add Byron header hashing (#45) --- pallas-primitives/src/byron/crypto.rs | 47 +++++ pallas-primitives/src/byron/mod.rs | 2 +- pallas-primitives/src/byron/model.rs | 164 ++++++++++-------- .../src/byron/test_data/test1.header | 1 + 4 files changed, 141 insertions(+), 73 deletions(-) create mode 100644 pallas-primitives/src/byron/crypto.rs create mode 100644 pallas-primitives/src/byron/test_data/test1.header diff --git a/pallas-primitives/src/byron/crypto.rs b/pallas-primitives/src/byron/crypto.rs new file mode 100644 index 0000000..a9bc608 --- /dev/null +++ b/pallas-primitives/src/byron/crypto.rs @@ -0,0 +1,47 @@ +use super::{Block, BlockHead, EbbHead}; +use pallas_crypto::hash::{Hash, Hasher}; + +pub fn hash_boundary_block_header(header: &EbbHead) -> Hash<32> { + // hash expects to have a prefix for the type of block + Hasher::<256>::hash_cbor(&(0, header)) +} + +pub fn hash_main_block_header(header: &BlockHead) -> Hash<32> { + // hash expects to have a prefix for the type of block + Hasher::<256>::hash_cbor(&(1, header)) +} + +pub fn hash_block_header(block: &Block) -> Hash<32> { + match block { + Block::EbBlock(x) => hash_boundary_block_header(&x.header), + Block::MainBlock(x) => hash_main_block_header(&x.header), + } +} + +//pub fn hash_transaction(data: &TransactionBody) -> Hash<32> { +// Hasher::<256>::hash_cbor(data) +//} + +#[cfg(test)] +mod tests { + use crate::byron::Block; + use crate::Fragment; + + const KNOWN_HASH: &'static str = + "5c196e7394ace0449ba5a51c919369699b13896e97432894b4f0354dce8670b6"; + + #[test] + fn transaction_hash_works() { + // TODO: expand this test to include more test blocks + let block_idx = 1; + let block_str = include_str!("test_data/test1.block"); + + let block_bytes = hex::decode(block_str).expect(&format!("bad block file {}", block_idx)); + let block_model = Block::decode_fragment(&block_bytes[..]) + .expect(&format!("error decoding cbor for file {}", block_idx)); + + let computed_hash = super::hash_block_header(&block_model); + + assert_eq!(hex::encode(computed_hash), KNOWN_HASH) + } +} diff --git a/pallas-primitives/src/byron/mod.rs b/pallas-primitives/src/byron/mod.rs index 316d97d..394d238 100644 --- a/pallas-primitives/src/byron/mod.rs +++ b/pallas-primitives/src/byron/mod.rs @@ -4,4 +4,4 @@ mod model; pub use model::*; -// pub mod crypto; +pub mod crypto; diff --git a/pallas-primitives/src/byron/model.rs b/pallas-primitives/src/byron/model.rs index 88c73a3..fac4b18 100644 --- a/pallas-primitives/src/byron/model.rs +++ b/pallas-primitives/src/byron/model.rs @@ -29,10 +29,10 @@ pub type EpochId = u64; #[derive(Encode, Decode, Debug)] pub struct SlotId { #[n(0)] - epoch: EpochId, + pub epoch: EpochId, #[n(1)] - slot: u64, + pub slot: u64, } pub type PubKey = ByteVec; @@ -489,16 +489,16 @@ impl minicbor::Encode for SscProof { #[derive(Debug, Encode, Decode)] pub struct Dlg { #[n(0)] - epoch: EpochId, + pub epoch: EpochId, #[n(1)] - issuer: PubKey, + pub issuer: PubKey, #[n(2)] - delegate: PubKey, + pub delegate: PubKey, #[n(3)] - certificate: Signature, + pub certificate: Signature, } pub type DlgSig = (Dlg, Signature); @@ -506,16 +506,16 @@ pub type DlgSig = (Dlg, Signature); #[derive(Debug, Encode, Decode)] pub struct Lwdlg { #[n(0)] - epoch_range: (EpochId, EpochId), + pub epoch_range: (EpochId, EpochId), #[n(1)] - issuer: PubKey, + pub issuer: PubKey, #[n(2)] - delegate: PubKey, + pub delegate: PubKey, #[n(3)] - certificate: Signature, + pub certificate: Signature, } pub type LwdlgSig = (Lwdlg, Signature); @@ -573,46 +573,46 @@ impl minicbor::Encode for TxFeePol { #[derive(Debug, Encode, Decode)] pub struct BVerMod { #[n(0)] - script_version: (Option,), + pub script_version: (Option,), #[n(1)] - slot_duration: (Option,), + pub slot_duration: (Option,), #[n(2)] - max_block_size: (Option,), + pub max_block_size: (Option,), #[n(3)] - max_header_size: (Option,), + pub max_header_size: (Option,), #[n(4)] - max_tx_size: (Option,), + pub max_tx_size: (Option,), #[n(5)] - max_proposal_size: (Option,), + pub max_proposal_size: (Option,), #[n(6)] - mpc_thd: (Option,), + pub mpc_thd: (Option,), #[n(7)] - heavy_del_thd: (Option,), + pub heavy_del_thd: (Option,), #[n(8)] - update_vote_thd: (Option,), + pub update_vote_thd: (Option,), #[n(9)] - update_proposal_thd: (Option,), + pub update_proposal_thd: (Option,), #[n(10)] - update_implicit: (Option,), + pub update_implicit: (Option,), #[n(11)] - soft_fork_rule: (Option<(u64, u64, u64)>,), + pub soft_fork_rule: (Option<(u64, u64, u64)>,), #[n(12)] - tx_fee_policy: (Option,), + pub tx_fee_policy: (Option,), #[n(13)] - unlock_stake_epoch: (Option,), + pub unlock_stake_epoch: (Option,), } pub type UpData = (ByronHash, ByronHash, ByronHash, ByronHash); @@ -620,49 +620,49 @@ pub type UpData = (ByronHash, ByronHash, ByronHash, ByronHash); #[derive(Debug, Encode, Decode)] pub struct UpProp { #[n(0)] - block_version: Option, + pub block_version: Option, #[n(1)] - block_version_mod: Option, + pub block_version_mod: Option, #[n(2)] - software_version: Option<(String, u32)>, + pub software_version: Option<(String, u32)>, #[n(3)] - data: Option>, + pub data: Option>, #[n(4)] - attributes: Option, + pub attributes: Option, #[n(5)] - from: Option, + pub from: Option, #[n(6)] - signature: Option, + pub signature: Option, } #[derive(Debug, Encode, Decode)] pub struct UpVote { #[n(0)] - voter: PubKey, + pub voter: PubKey, #[n(1)] - proposal_id: UpdId, + pub proposal_id: UpdId, #[n(2)] - vote: bool, + pub vote: bool, #[n(3)] - signature: Signature, + pub signature: Signature, } #[derive(Debug, Encode, Decode)] pub struct Up { #[n(0)] - proposal: Option, + pub proposal: Option, #[n(1)] - votes: MaybeIndefArray, + pub votes: MaybeIndefArray, } // Blocks @@ -726,58 +726,58 @@ impl minicbor::Encode for BlockSig { #[derive(Encode, Decode, Debug)] pub struct BlockCons( - #[n(0)] SlotId, - #[n(1)] PubKey, - #[n(2)] Difficulty, - #[n(3)] BlockSig, + #[n(0)] pub SlotId, + #[n(1)] pub PubKey, + #[n(2)] pub Difficulty, + #[n(3)] pub BlockSig, ); #[derive(Encode, Decode, Debug)] pub struct BlockHeadEx { #[n(0)] - block_version: BVer, + pub block_version: BVer, #[n(1)] - software_version: (String, u32), + pub software_version: (String, u32), #[n(2)] - attributes: Option, + pub attributes: Option, #[n(3)] - extra_proof: ByronHash, + pub extra_proof: ByronHash, } #[derive(Encode, Decode, Debug)] pub struct BlockProof { #[n(0)] - tx_proof: TxProof, + pub tx_proof: TxProof, #[n(1)] - ssc_proof: SscProof, + pub ssc_proof: SscProof, #[n(2)] - dlg_proof: ByronHash, + pub dlg_proof: ByronHash, #[n(3)] - upd_proof: ByronHash, + pub upd_proof: ByronHash, } #[derive(Encode, Decode, Debug)] pub struct BlockHead { #[n(0)] - protocol_magic: u32, + pub protocol_magic: u32, #[n(1)] - prev_block: BlockId, + pub prev_block: BlockId, #[n(2)] - body_proof: BlockProof, + pub body_proof: BlockProof, #[n(3)] - consensus_data: BlockCons, + pub consensus_data: BlockCons, #[n(4)] - extra_data: BlockHeadEx, + pub extra_data: BlockHeadEx, } // [tx, [* twit]] @@ -786,16 +786,16 @@ pub type TxPayload = (Tx, Vec); #[derive(Encode, Decode, Debug)] pub struct BlockBody { #[n(0)] - tx_payload: MaybeIndefArray, + pub tx_payload: MaybeIndefArray, #[n(1)] - ssc_payload: Ssc, + pub ssc_payload: Ssc, #[n(2)] - dlg_payload: MaybeIndefArray, + pub dlg_payload: MaybeIndefArray, #[n(3)] - upd_payload: Up, + pub upd_payload: Up, } // Epoch Boundary Blocks @@ -803,52 +803,52 @@ pub struct BlockBody { #[derive(Encode, Decode, Debug)] pub struct EbbCons { #[n(0)] - epoch_id: EpochId, + pub epoch_id: EpochId, #[n(1)] - difficulty: Difficulty, + pub difficulty: Difficulty, } #[derive(Encode, Decode, Debug)] pub struct EbbHead { #[n(0)] - protocol_magic: u32, + pub protocol_magic: u32, #[n(1)] - prev_block: BlockId, + pub prev_block: BlockId, #[n(2)] - body_proof: ByronHash, + pub body_proof: ByronHash, #[n(3)] - consensus_data: EbbCons, + pub consensus_data: EbbCons, #[n(4)] - extra_data: (Attributes,), + pub extra_data: (Attributes,), } #[derive(Encode, Decode, Debug)] pub struct MainBlock { #[n(0)] - header: BlockHead, + pub header: BlockHead, #[n(1)] - body: BlockBody, + pub body: BlockBody, #[n(2)] - extra: MaybeIndefArray, + pub extra: MaybeIndefArray, } #[derive(Encode, Decode, Debug)] pub struct EbBlock { #[n(0)] - header: EbbHead, + pub header: EbbHead, #[n(1)] - body: MaybeIndefArray, + pub body: MaybeIndefArray, #[n(2)] - extra: Option, + pub extra: Option, } #[allow(clippy::large_enum_variant)] @@ -900,7 +900,7 @@ impl minicbor::Encode for Block { #[cfg(test)] mod tests { - use crate::byron::Block; + use crate::byron::{Block, BlockHead}; use crate::Fragment; use minicbor::{self, to_vec}; @@ -928,4 +928,24 @@ mod tests { // assert_eq!(bytes, bytes2); } } + + #[test] + fn header_isomorphic_decoding_encoding() { + let subjects = vec![include_str!("test_data/test1.header")]; + + for (idx, str) in subjects.iter().enumerate() { + println!("decoding test header {}", idx + 1); + let bytes = hex::decode(str).expect(&format!("bad header file {}", idx)); + + let block = BlockHead::decode_fragment(&bytes[..]) + .expect(&format!("error decoding cbor for file {}", idx)); + + println!("{:?}", block); + + let bytes2 = + to_vec(block).expect(&format!("error encoding header cbor for file {}", idx)); + + assert_eq!(bytes, bytes2); + } + } } diff --git a/pallas-primitives/src/byron/test_data/test1.header b/pallas-primitives/src/byron/test_data/test1.header new file mode 100644 index 0000000..076c08d --- /dev/null +++ b/pallas-primitives/src/byron/test_data/test1.header @@ -0,0 +1 @@ +851A2D964A0958205C196E7394ACE0449BA5A51C919369699B13896E97432894B4F0354DCE8670B68483015820D09F2306C1CD4756C1A7FF3ADB5DC8D7CADEDF882DBCC06E098C381078449A495820080A7075FDD79C20F6DA7AEEAA8A9765A0F83175851F3BB1AF583BD99F84358B82035820D36A2619A672494604E11BB447CBCF5231E9F2BA25C2169177EDC941BD50AD6C5820AFC0DA64183BF2664F3D4EEC7238D524BA607FAEEAB24FC100EB861DBA69971B58204E66280CD94D591072349BEC0A3090A53AA945562EFB6D08D56E53654B0E4098848218CF19545B58401BC97A2FE02C297880CE8ECFD997FE4C1EC09EE10FEEEE9F686760166B05281D6283468FFD93BECB0C956CCDDD642DF9B1244C915911185FA49355F6F22BFAB9811A0044850A820282840058401BC97A2FE02C297880CE8ECFD997FE4C1EC09EE10FEEEE9F686760166B05281D6283468FFD93BECB0C956CCDDD642DF9B1244C915911185FA49355F6F22BFAB9584061261A95B7613EE6BF2067DAD77B70349729B0C50D57BC1CF30DE0DB4A1E73A885D0054AF7C23FC6C37919DBA41C602A57E2D0F9329A7954B867338D6FB2C9455840E03E62F083DF5576360E60A32E22BBB07B3C8DF4FCAB8079F1D6F61AF3954D242BA8A06516C395939F24096F3DF14E103A7D9C2B80A68A9363CF1F27C7A4E30758409F9CBAA9AE2751FC9D97E7DAE0CEF3E2C6D740627818B735E39EADF92F83A04DC36D42C42D258450F13C0BA3E1470EDE42A1F0D239A99EA284BCAA031A514A098483020000826A63617264616E6F2D736C01A058204BA92AA320C60ACC9AD7B9A64F2EDA55C4D2EC28E604FAF186708B4F0C4E8EDF \ No newline at end of file