zcash_history: Implement V2 tree format

This commit is contained in:
Jack Grigg 2021-06-11 01:57:28 +01:00
parent 63f554b308
commit e84bb874af
4 changed files with 92 additions and 4 deletions

View File

@ -10,6 +10,7 @@ and this library adheres to Rust's notion of
- Support for multiple history tree versions:
- `zcash_history::Version` trait.
- `zcash_history::V1`, marking the original history tree version.
- `zcash_history::V2`, marking the history tree version from NU5.
- `zcash_history::Entry::new_leaf`
### Changed

View File

@ -14,7 +14,7 @@ mod version;
pub use entry::{Entry, MAX_ENTRY_SIZE};
pub use node_data::{NodeData, MAX_NODE_DATA_SIZE};
pub use tree::Tree;
pub use version::{Version, V1};
pub use version::{Version, V1, V2};
/// Crate-level error type
#[derive(Debug)]

View File

@ -14,8 +14,11 @@ pub const MAX_NODE_DATA_SIZE: usize = 32 + // subtree commitment
32 + // subtree total work
9 + // start height (compact uint)
9 + // end height (compact uint)
9; // Sapling tx count (compact uint)
// = total of 171
9 + // Sapling tx count (compact uint)
32 + // start Orchard tree root
32 + // end Orchard tree root
9; // Orchard tx count (compact uint)
// = total of 244
/// V1 node metadata.
#[repr(C)]
@ -166,6 +169,53 @@ impl NodeData {
}
}
/// V2 node metadata.
#[derive(Debug, Clone, Default)]
#[cfg_attr(test, derive(PartialEq))]
pub struct V2 {
/// The V1 node data retained in V2.
pub v1: NodeData,
/// Start Orchard tree root.
pub start_orchard_root: [u8; 32],
/// End Orchard tree root.
pub end_orchard_root: [u8; 32],
/// Number of Orchard transactions.
pub orchard_tx: u64,
}
impl V2 {
pub(crate) fn combine_inner(subtree_commitment: [u8; 32], left: &V2, right: &V2) -> V2 {
V2 {
v1: NodeData::combine_inner(subtree_commitment, &left.v1, &right.v1),
start_orchard_root: left.start_orchard_root,
end_orchard_root: right.end_orchard_root,
orchard_tx: left.orchard_tx + right.orchard_tx,
}
}
/// Write to the byte representation.
pub fn write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
self.v1.write(w)?;
w.write_all(&self.start_orchard_root)?;
w.write_all(&self.end_orchard_root)?;
NodeData::write_compact(w, self.orchard_tx)?;
Ok(())
}
/// Read from the byte representation.
pub fn read<R: std::io::Read>(consensus_branch_id: u32, r: &mut R) -> std::io::Result<Self> {
let mut data = V2 {
v1: NodeData::read(consensus_branch_id, r)?,
..Default::default()
};
r.read_exact(&mut data.start_orchard_root)?;
r.read_exact(&mut data.end_orchard_root)?;
data.orchard_tx = NodeData::read_compact(r)?;
Ok(data)
}
}
#[cfg(test)]
impl quickcheck::Arbitrary for NodeData {
fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {

View File

@ -4,7 +4,7 @@ use std::io;
use blake2::Params as Blake2Params;
use byteorder::{ByteOrder, LittleEndian};
use crate::{NodeData, MAX_NODE_DATA_SIZE};
use crate::{node_data, NodeData, MAX_NODE_DATA_SIZE};
fn blake2b_personal(personalization: &[u8], input: &[u8]) -> [u8; 32] {
let hash_result = Blake2Params::new()
@ -141,3 +141,40 @@ impl Version for V1 {
data.write(w)
}
}
/// Version 2 of the Zcash chain history tree.
///
/// This version is used from the NU5 epoch.
pub enum V2 {}
impl Version for V2 {
type NodeData = node_data::V2;
fn consensus_branch_id(data: &Self::NodeData) -> u32 {
data.v1.consensus_branch_id
}
fn start_height(data: &Self::NodeData) -> u64 {
data.v1.start_height
}
fn end_height(data: &Self::NodeData) -> u64 {
data.v1.end_height
}
fn combine_inner(
subtree_commitment: [u8; 32],
left: &Self::NodeData,
right: &Self::NodeData,
) -> Self::NodeData {
node_data::V2::combine_inner(subtree_commitment, left, right)
}
fn read<R: io::Read>(consensus_branch_id: u32, r: &mut R) -> io::Result<Self::NodeData> {
node_data::V2::read(consensus_branch_id, r)
}
fn write<W: io::Write>(data: &Self::NodeData, w: &mut W) -> io::Result<()> {
data.write(w)
}
}