diff --git a/zebra-chain/src/block.rs b/zebra-chain/src/block.rs index 1c26afdfe..d0c45dcd9 100644 --- a/zebra-chain/src/block.rs +++ b/zebra-chain/src/block.rs @@ -1,26 +1,62 @@ //! Definitions of block datastructures. -use crate::transaction::Transaction; use chrono::{DateTime, Utc}; +use std::io; + +use crate::merkle_tree::MerkleTree; +use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; +use crate::sha256d_writer::Sha256dWriter; +use crate::transaction::Transaction; + +/// A SHA-256d hash of a BlockHeader. +/// +/// This is useful when one block header is pointing to its parent +/// block header in the block chain. ⛓️ +pub struct BlockHash([u8; 32]); + +impl From for BlockHash { + fn from(block_header: BlockHeader) -> Self { + let mut hash_writer = Sha256dWriter::default(); + block_header + .zcash_serialize(&mut hash_writer) + .expect("Block headers must serialize."); + Self(hash_writer.finish()) + } +} + +/// A SHA-256d hash of the root node of a merkle tree of SHA256-d +/// hashed transactions in a block. +pub struct MerkleRootHash([u8; 32]); + +impl From> for MerkleRootHash { + fn from(merkle_tree: MerkleTree) -> Self { + let mut hash_writer = Sha256dWriter::default(); + merkle_tree + .zcash_serialize(&mut hash_writer) + .expect("The merkle tree of transactions must serialize."); + Self(hash_writer.finish()) + } +} /// Block header pub struct BlockHeader { /// A SHA-256d hash in internal byte order of the previous block’s /// header. This ensures no previous block can be changed without /// also changing this block’s header . - previous_block_hash: [u8; 32], + previous_block_hash: BlockHash, /// A SHA-256d hash in internal byte order. The merkle root is - /// derived from the hashes of all transactions included in this - /// block, ensuring that none of those transactions can be modied - /// without modifying the header. + /// derived from the SHA256d hashes of all transactions included + /// in this block as assembled in a binary tree, ensuring that + /// none of those transactions can be modied without modifying the + /// header. merkle_root_hash: [u8; 32], /// [Sapling onward] The root LEBS2OSP256(rt) of the Sapling note /// commitment tree corresponding to the nal Sapling treestate of /// this block. // TODO: replace type with custom SaplingRoot or similar type - // hash_final_sapling_root: [u8; 32], + // hash_final_sapling_root: SaplingRootHash, /// The block timestamp is a Unix epoch time (UTC) when the miner /// started hashing the header (according to the miner). @@ -55,12 +91,24 @@ impl BlockHeader { } } +impl ZcashSerialize for BlockHeader { + fn zcash_serialize(&self, writer: W) -> Result<(), SerializationError> { + unimplemented!(); + } +} + +impl ZcashDeserialize for BlockHeader { + fn zcash_deserialize(reader: R) -> Result { + unimplemented!(); + } +} + /// A block in your blockchain. pub struct Block { /// First 80 bytes of the block as defined by the encoding used by - /// "block" messages + /// "block" messages. pub header: BlockHeader, - /// + /// Block transactions. pub transactions: Vec, } diff --git a/zebra-chain/src/lib.rs b/zebra-chain/src/lib.rs index c945b00e1..710d09934 100644 --- a/zebra-chain/src/lib.rs +++ b/zebra-chain/src/lib.rs @@ -4,6 +4,9 @@ #[macro_use] extern crate failure; +mod merkle_tree; +mod sha256d_writer; + pub mod block; pub mod serialization; pub mod transaction; diff --git a/zebra-chain/src/merkle_tree.rs b/zebra-chain/src/merkle_tree.rs new file mode 100644 index 000000000..bc828f517 --- /dev/null +++ b/zebra-chain/src/merkle_tree.rs @@ -0,0 +1,34 @@ +//! A binary hash tree of SHA256d (two rounds of SHA256) hashes for +//! node values. + +use std::io; +use std::io::prelude::*; + +use sha2::{Digest, Sha256}; + +use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; + +/// A binary hash tree of SHA256d (two rounds of SHA256) hashes for +/// node values. +#[derive(Default)] +pub struct MerkleTree { + leaves: Vec, +} + +impl MerkleTree { + pub fn get_root(&self) -> Sha256 { + unimplemented!(); + } +} + +impl ZcashSerialize for MerkleTree { + fn zcash_serialize(&self, writer: W) -> Result<(), SerializationError> { + unimplemented!(); + } +} + +impl ZcashDeserialize for MerkleTree { + fn zcash_deserialize(reader: R) -> Result { + unimplemented!(); + } +} diff --git a/zebra-chain/src/sha256d_writer.rs b/zebra-chain/src/sha256d_writer.rs new file mode 100644 index 000000000..5e835cdfc --- /dev/null +++ b/zebra-chain/src/sha256d_writer.rs @@ -0,0 +1,33 @@ +//! A Writer for Sha256d-related (two rounds of SHA256) types. + +use std::io::prelude::*; + +use sha2::{Digest, Sha256}; + +/// A type that lets you write out SHA256d (double-SHA256, as in two rounds). +#[derive(Default)] +pub struct Sha256dWriter { + hash: Sha256, +} + +impl Sha256dWriter { + /// Consume the Writer and produce the hash result. + pub fn finish(self) -> [u8; 32] { + let result1 = self.hash.result(); + let result2 = Sha256::digest(&result1); + let mut buffer = [0u8; 32]; + buffer[0..32].copy_from_slice(&result2[0..32]); + buffer + } +} + +impl Write for Sha256dWriter { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.hash.input(buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + Ok(()) + } +} diff --git a/zebra-chain/src/types.rs b/zebra-chain/src/types.rs index a9a7e8203..43be396c6 100644 --- a/zebra-chain/src/types.rs +++ b/zebra-chain/src/types.rs @@ -1,6 +1,6 @@ //! Newtype wrappers for primitive data types with semantic meaning. -/// A 4-byte checksum using truncated double SHA256. +/// A 4-byte checksum using truncated double-SHA256 (two rounds of SHA256). #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct Sha256dChecksum(pub [u8; 4]);