This commit is contained in:
NikVolf 2019-09-24 12:45:23 +02:00
parent ce2416623f
commit 7879b63321
4 changed files with 48 additions and 0 deletions

View File

@ -2,8 +2,10 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use crate::{EntryKind, NodeData, Error, EntryLink, MAX_NODE_DATA_SIZE};
/// Max serialized length of entry data.
pub const MAX_ENTRY_SIZE: usize = MAX_NODE_DATA_SIZE + 9;
/// MMR Entry.
#[derive(Debug)]
pub struct Entry {
pub(crate) kind: EntryKind,
@ -11,23 +13,28 @@ pub struct Entry {
}
impl Entry {
/// Update siblings of the entry (to promote it from leaf to node)
pub fn update_siblings(&mut self, left: EntryLink, right: EntryLink) {
self.kind = EntryKind::Node(left, right);
}
/// Returns if is this node complete (has total of 2^N leaves)
pub fn complete(&self) -> bool {
let leaves = self.leaf_count();
leaves & (leaves - 1) == 0
}
/// Number of leaves under this node.
pub fn leaf_count(&self) -> u64 {
self.data.end_height - self.data.start_height + 1
}
/// Is this node a leaf.
pub fn is_leaf(&self) -> bool {
if let EntryKind::Leaf = self.kind { true } else { false }
}
/// Left child
pub fn left(&self) -> Result<EntryLink, Error> {
match self.kind {
EntryKind::Leaf => { Err(Error::ExpectedNode) }
@ -35,6 +42,7 @@ impl Entry {
}
}
/// Right child.
pub fn right(&self) -> Result<EntryLink, Error> {
match self.kind {
EntryKind::Leaf => { Err(Error::ExpectedNode) }
@ -42,6 +50,7 @@ impl Entry {
}
}
/// Read from byte representation.
pub fn read<R: std::io::Read>(consensus_branch_id: u32, r: &mut R) -> std::io::Result<Self> {
let kind = {
match r.read_u8()? {
@ -67,6 +76,7 @@ impl Entry {
})
}
/// Write to byte representation.
pub fn write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
match self.kind {
EntryKind::Node(EntryLink::Stored(left), EntryLink::Stored(right)) => {
@ -85,6 +95,7 @@ impl Entry {
Ok(())
}
/// Convert from byte representation.
pub fn from_bytes<T: AsRef<[u8]>>(consensus_branch_id: u32, buf: T) -> std::io::Result<Self> {
let mut cursor = std::io::Cursor::new(buf);
Self::read(consensus_branch_id, &mut cursor)

View File

@ -1,19 +1,25 @@
//! MMR library for Zcash
//!
//! To be used in zebra and via FFI bindings in zcashd
#![warn(missing_docs)]
mod tree;
mod node_data;
mod entry;
pub use tree::Tree;
pub use node_data::{NodeData, MAX_NODE_DATA_SIZE};
pub use entry::{Entry, MAX_ENTRY_SIZE};
/// Crate-level error type
#[derive(Debug)]
pub enum Error {
/// Entry expected to be presented in the tree view while it was not.
ExpectedInMemory(EntryLink),
/// Entry expected to be a node.
ExpectedNode,
/// Entry expected to be a node (specifying for which link this is not true).
ExpectedNodeForLink(EntryLink),
}
@ -50,7 +56,9 @@ impl std::fmt::Display for EntryLink {
#[repr(C)]
#[derive(Debug)]
pub enum EntryKind {
/// Leaf entry.
Leaf,
/// Node entry with children links.
Node(EntryLink, EntryLink),
}

View File

@ -2,23 +2,36 @@ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt, ByteOrder};
use bigint::U256;
use blake2::Params as Blake2Params;
/// Maximum serialized size of the node metadata.
pub const MAX_NODE_DATA_SIZE: usize = 32 + 4 + 4 + 4 + 4 + 32 + 32 + 32 + 9 + 9 + 9; // 171
/// Node metadata.
#[repr(C)]
#[derive(Debug, Clone, Default)]
pub struct NodeData {
/// Consensus branch id, should be provided by deserializing node.
pub consensus_branch_id: u32,
/// Subtree commitment - either block hash for leaves or hashsum of children for nodes.
pub subtree_commitment: [u8; 32],
/// Start time.
pub start_time: u32,
/// End time.
pub end_time: u32,
/// Start target.
pub start_target: u32,
/// End target.
pub end_target: u32,
/// Start sapling tree root.
pub start_sapling_root: [u8; 32],
/// End sapling tree root.
pub end_sapling_root: [u8; 32],
/// Part of tree total work.
pub subtree_total_work: U256,
/// Start height.
pub start_height: u64,
/// End height
pub end_height: u64,
/// Number of shielded transactions.
pub shielded_tx: u64,
}
@ -42,6 +55,7 @@ fn personalization(branch_id: u32) -> [u8; 16] {
}
impl NodeData {
/// Combine two nodes metadata.
pub fn combine(left: &NodeData, right: &NodeData) -> NodeData {
assert_eq!(left.consensus_branch_id, right.consensus_branch_id);
@ -106,6 +120,7 @@ impl NodeData {
Ok(result)
}
/// Write to the byte representation.
pub fn write<W: std::io::Write>(&self, w: &mut W) -> std::io::Result<()> {
w.write_all(&self.subtree_commitment)?;
w.write_u32::<LittleEndian>(self.start_time)?;
@ -125,6 +140,7 @@ impl NodeData {
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 = Self::default();
data.consensus_branch_id = consensus_branch_id;
@ -147,6 +163,7 @@ impl NodeData {
Ok(data)
}
/// Convert to byte representation.
pub fn to_bytes(&self) -> Vec<u8> {
let mut buf = [0u8; MAX_NODE_DATA_SIZE];
let pos = {
@ -158,6 +175,7 @@ impl NodeData {
buf[0..pos].to_vec()
}
/// Convert from byte representation.
pub fn from_bytes<T: AsRef<[u8]>>(consensus_branch_id: u32, buf: T) -> std::io::Result<Self> {
let mut cursor = std::io::Cursor::new(buf);
Self::read(consensus_branch_id, &mut cursor)

View File

@ -24,6 +24,7 @@ pub struct Tree {
}
impl Tree {
/// Resolve link originated from this tree
pub fn resolve_link(&self, link: EntryLink) -> Result<IndexedNode, Error> {
match link {
EntryLink::Generated(index) => {
@ -80,6 +81,12 @@ impl Tree {
}
}
/// New view into the the tree array representation
///
/// `length` is total length of the array representation
/// `peaks` is peaks of the mmr tree
/// `extra` is some extra nodes that calculated to be required during next one or more
/// operations on the tree.
pub fn new(
length: u32,
peaks: Vec<(u32, Entry)>,
@ -267,6 +274,7 @@ impl Tree {
}
}
/// Reference to the node with link attached.
#[derive(Debug)]
pub struct IndexedNode<'a> {
node: &'a Entry,
@ -283,14 +291,17 @@ impl<'a> IndexedNode<'a> {
self.node.right().map_err(|e| e.augment(self.link))
}
/// Reference to the entry struct.
pub fn node(&self) -> &Entry {
self.node
}
/// Reference to the entry metadata.
pub fn data(&self) -> &NodeData {
&self.node.data
}
/// Actual link by what this node was resolved.
pub fn link(&self) -> EntryLink {
self.link
}