Skip to content

Commit

Permalink
Add optional borsh serialization (#84)
Browse files Browse the repository at this point in the history
* Add optional borsh serialization

* Add borsh derives to PhantomHasher
  • Loading branch information
preston-evans98 authored Mar 16, 2023
1 parent feeb96c commit 3d374ed
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ publish = true

[features]
default = ["ics23"]
borsh = ["dep:borsh"]

[dependencies]
ics23 = { git = "https://github.com/penumbra-zone/ics23", branch = "compare-prehashed-keys", optional = true }
anyhow = "1.0.38"
borsh = { version = "0.10.0", optional = true}
byteorder = "1.4.3"
itertools = { version = "0.10.0", default-features = false }
mirai-annotations = "1.10.1"
Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,18 @@ pub struct RootHash(pub [u8; 32]);
/// keys can be converted to a [`KeyHash`] using the provided `From` impl.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct KeyHash(pub [u8; 32]);

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
// This needs to be public for the fuzzing/Arbitrary feature, but we don't
// really want it to be, so #[doc(hidden)] is the next best thing.
#[doc(hidden)]
Expand Down Expand Up @@ -244,6 +252,10 @@ pub trait SimpleHasher: Sized {
/// structs to derive these traits even if the concrete hasher does not
/// implement them.
#[derive(Clone, Eq, Serialize, Deserialize)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct PhantomHasher<H: SimpleHasher>(std::marker::PhantomData<H>);

impl<H: SimpleHasher> Debug for PhantomHasher<H> {
Expand Down
28 changes: 28 additions & 0 deletions src/node_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ use crate::SimpleHasher;
/// The unique key of each node.
#[derive(Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct NodeKey {
// The version at which the node is created.
version: Version,
Expand Down Expand Up @@ -138,6 +142,10 @@ impl NodeKey {
}

#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub enum NodeType {
Leaf,
/// A internal node that haven't been finished the leaf count migration, i.e. None or not all
Expand Down Expand Up @@ -166,6 +174,10 @@ impl Arbitrary for NodeType {
/// Each child of [`InternalNode`] encapsulates a nibble forking at this node.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct Child {
/// The hash value of this child node.
pub hash: [u8; 32],
Expand Down Expand Up @@ -203,6 +215,10 @@ impl Child {
/// [`Children`] is just a collection of children belonging to a [`InternalNode`], indexed from 0 to
/// 15, inclusive.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct Children {
/// The actual children. We box this array to avoid stack overflows, since the space consumed
/// is somewhat large
Expand Down Expand Up @@ -311,6 +327,10 @@ impl Children {
/// computation logic is similar to a 4-level sparse Merkle tree except for some customizations. See
/// the `CryptoHash` trait implementation below for details.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct InternalNode {
/// Up to 16 children.
children: Children,
Expand Down Expand Up @@ -802,6 +822,10 @@ pub(crate) fn get_child_half_start(n: Nibble, height: u8) -> u8 {
///
/// Note: this does not store the key itself.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct LeafNode {
/// The hash of the key for this entry.
key_hash: KeyHash,
Expand Down Expand Up @@ -850,6 +874,10 @@ enum NodeTag {

/// The concrete node type of [`JellyfishMerkleTree`](crate::JellyfishMerkleTree).
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub enum Node {
/// Represents `null`.
Null,
Expand Down
4 changes: 4 additions & 0 deletions src/types/nibble/nibble_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ use crate::types::nibble::{Nibble, ROOT_NIBBLE_HEIGHT};

/// NibblePath defines a path in Merkle tree in the unit of nibble (4 bits).
#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct NibblePath {
/// Indicates the total number of nibbles in bytes. Either `bytes.len() * 2 - 1` or
/// `bytes.len() * 2`.
Expand Down
4 changes: 4 additions & 0 deletions src/types/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ impl SparseMerkleInternalNode {

#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct SparseMerkleLeafNode {
key_hash: KeyHash,
value_hash: ValueHash,
Expand Down
8 changes: 8 additions & 0 deletions src/types/proof/definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ use crate::{
/// A proof that can be used to authenticate an element in a Sparse Merkle Tree given trusted root
/// hash. For example, `TransactionInfoToAccountProof` can be constructed on top of this structure.
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct SparseMerkleProof<H: SimpleHasher> {
/// This proof can be used to authenticate whether a given leaf exists in the tree or not.
/// - If this is `Some(leaf_node)`
Expand Down Expand Up @@ -231,6 +235,10 @@ impl<H: SimpleHasher> SparseMerkleProof<H> {
/// if the proof wants show that `[a, b, c, d, e]` exists in the tree, it would need the siblings
/// `X` and `h` on the right.
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct SparseMerkleRangeProof {
/// The vector of siblings on the right of the path from root to last leaf. The ones near the
/// bottom are at the beginning of the vector. In the above example, it's `[X, h]`.
Expand Down
16 changes: 16 additions & 0 deletions src/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub trait TreeWriter {

/// Node batch that will be written into db atomically with other batches.
#[derive(Debug, Clone, PartialEq, Default, Eq)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct NodeBatch {
nodes: BTreeMap<NodeKey, Node>,
values: BTreeMap<(Version, KeyHash), Option<OwnedValue>>,
Expand Down Expand Up @@ -82,6 +86,10 @@ impl NodeBatch {
pub type StaleNodeIndexBatch = BTreeSet<StaleNodeIndex>;

#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct NodeStats {
pub new_nodes: usize,
pub new_leaves: usize,
Expand All @@ -92,6 +100,10 @@ pub struct NodeStats {
/// Indicates a node becomes stale since `stale_since_version`.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct StaleNodeIndex {
/// The version since when the node is overwritten and becomes stale.
pub stale_since_version: Version,
Expand All @@ -105,6 +117,10 @@ pub struct StaleNodeIndex {
/// the incremental updates of a tree and pruning indices after applying a write set,
/// which is a vector of `hashed_account_address` and `new_value` pairs.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
)]
pub struct TreeUpdateBatch {
pub node_batch: NodeBatch,
pub stale_node_index_batch: StaleNodeIndexBatch,
Expand Down

0 comments on commit 3d374ed

Please sign in to comment.