From c4eb136426c112465c37320768386ae0b3347e6e Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 7 Aug 2020 19:24:00 +1000 Subject: [PATCH] feature: Add a LightClientRootHash type --- zebra-chain/src/block.rs | 1 + zebra-chain/src/block/header.rs | 13 ++--- zebra-chain/src/block/light_client.rs | 77 +++++++++++++++++++++++++++ zebra-chain/src/block/tests.rs | 18 ++++++- 4 files changed, 99 insertions(+), 10 deletions(-) create mode 100644 zebra-chain/src/block/light_client.rs diff --git a/zebra-chain/src/block.rs b/zebra-chain/src/block.rs index 81196f93..da3d1ccd 100644 --- a/zebra-chain/src/block.rs +++ b/zebra-chain/src/block.rs @@ -4,6 +4,7 @@ mod difficulty; mod hash; mod header; +mod light_client; mod serialize; #[cfg(test)] diff --git a/zebra-chain/src/block/header.rs b/zebra-chain/src/block/header.rs index 473982b5..80c2ac96 100644 --- a/zebra-chain/src/block/header.rs +++ b/zebra-chain/src/block/header.rs @@ -34,15 +34,10 @@ pub struct BlockHeader { /// header. pub merkle_root_hash: MerkleTreeRootHash, - /// [Pre-Sapling] Reserved. All zeroes. - /// [Sapling and Blossom] The root LEBS2OSP256(rt) of the Sapling note - /// commitment tree corresponding to the final Sapling treestate of - /// this block. - /// [Heartwood activation block] All zeroes. See ZIP-221 for details. - /// [After Heartwood activation block] The root of a Merkle Mountain - /// Range tree, which commits to various features of the chain's - /// history, including the Sapling commitment tree. This commitment - /// supports the FlyClient protocol. See ZIP-221 for details. + /// The light client root hash. + /// + /// This field is interpreted differently, based on the current + /// block height. See LightClientRootHash for details. pub light_client_root_hash: [u8; 32], /// The block timestamp is a Unix epoch time (UTC) when the miner diff --git a/zebra-chain/src/block/light_client.rs b/zebra-chain/src/block/light_client.rs new file mode 100644 index 00000000..862963af --- /dev/null +++ b/zebra-chain/src/block/light_client.rs @@ -0,0 +1,77 @@ +//! The LightClientRootHash enum, used for the corresponding block header field. + +use crate::note_commitment_tree::SaplingNoteTreeRootHash; +use crate::types::BlockHeight; +use crate::Network; + +/// Light client root hashes. +/// +/// The `BlockHeader.light_client_root_hash` field is interpreted differently, +/// based on the current block height. The interpretation changes at or after +/// network upgrades. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub enum LightClientRootHash { + /// [Pre-Sapling] Reserved field. + /// + /// All zeroes. + PreSaplingReserved([u8; 32]), + + /// [Sapling and Blossom] The final Sapling treestate of this block. + /// + /// The root LEBS2OSP256(rt) of the Sapling note commitment tree + /// corresponding to the final Sapling treestate of this block. + FinalSaplingRoot(SaplingNoteTreeRootHash), + + /// [Heartwood activation block] Reserved field. + /// + /// All zeroes. This MUST NOT be interpreted as a root hash. + /// See ZIP-221 for details. + ChainHistoryActivationReserved([u8; 32]), + + /// [After Heartwood activation block] The root of a Merkle Mountain + /// Range chain history tree. + /// + /// This root hash commits to various features of the chain's history, + /// including the Sapling commitment tree. This commitment supports the + /// FlyClient protocol. See ZIP-221 for details. + /// + /// The commitment in each block covers the chain history from the most + /// recent network upgrade, through to the previous block. In particular, + /// an activation block commits to the entire previous network upgrade, and + /// the block after activation commits only to the activation block. + ChainHistoryRoot(ChainHistoryMmrRootHash), +} + +impl LightClientRootHash { + /// Returns `bytes` as the LightClientRootHash variant for `network` and + /// `height`. + pub fn from_bytes( + bytes: [u8; 32], + network: Network, + height: BlockHeight, + ) -> LightClientRootHash { + // TODO(teor): use the correct network upgrade here, after moving the + // network upgrades from zebra-consensus to zebra-chain. + LightClientRootHash::PreSaplingReserved(bytes) + } + + /// Returns the serialized bytes for this LightClientRootHash. + pub fn to_bytes(self) -> [u8; 32] { + use LightClientRootHash::*; + + match self { + PreSaplingReserved(b) => b, + FinalSaplingRoot(v) => v.0, + ChainHistoryActivationReserved(b) => b, + ChainHistoryRoot(v) => v.0, + } + } +} + +/// The root hash of a Merkle Mountain Range chain history tree. +// TODO: +// - add methods for maintaining the MMR peaks, and calculating the root +// hash from the current set of peaks. +// - move to a separate file. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct ChainHistoryMmrRootHash([u8; 32]); diff --git a/zebra-chain/src/block/tests.rs b/zebra-chain/src/block/tests.rs index 589eedfa..98eb3308 100644 --- a/zebra-chain/src/block/tests.rs +++ b/zebra-chain/src/block/tests.rs @@ -1,12 +1,14 @@ use super::*; -use crate::block::difficulty::CompactDifficulty; +use crate::block::{difficulty::CompactDifficulty, light_client::LightClientRootHash}; use crate::equihash_solution::EquihashSolution; use crate::merkle_tree::MerkleTreeRootHash; use crate::serialization::{ SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize, }; +use crate::types::BlockHeight; use crate::types::LockTime; +use crate::Network; use crate::{sha256d_writer::Sha256dWriter, test::generate}; use chrono::{DateTime, Duration, LocalResult, TimeZone, Utc}; @@ -18,6 +20,20 @@ use proptest::{ use std::env; use std::io::{Cursor, ErrorKind, Write}; +impl Arbitrary for LightClientRootHash { + type Parameters = (); + + fn arbitrary_with(_args: ()) -> Self::Strategy { + (any::<[u8; 32]>(), any::(), any::()) + .prop_map(|(light_client_root_hash, network, block_height)| { + LightClientRootHash::from_bytes(light_client_root_hash, network, block_height) + }) + .boxed() + } + + type Strategy = BoxedStrategy; +} + impl Arbitrary for BlockHeader { type Parameters = ();