Skip to content

Commit

Permalink
wip: Mast zip tree
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuhvi committed Dec 14, 2023
1 parent b193cb5 commit 9596efc
Show file tree
Hide file tree
Showing 9 changed files with 356 additions and 1 deletion.
58 changes: 57 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"kytz",
"mast",
]

# See: https://github.com/rust-lang/rust/issues/90148#issuecomment-949194352
Expand Down
11 changes: 11 additions & 0 deletions mast/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "mast"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
blake3 = "1.5.0"
bytes = "1.5.0"
varu64 = "0.7.0"
18 changes: 18 additions & 0 deletions mast/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#![allow(unused)]

mod node;
mod storage;
mod tree;

use crate::node::Node;

// // TODO: maybe add nonce for encrypted trees.
// // TODO: why add header in each node? or in the Mast commit?
// // Would we need to read a node without traversing down from the Mast commit?
// pub struct Mast {
// /// The name of this Mast to be used as a prefix for all nodes
// /// in the storage, seperating different Masts.
// name: String,
// root: Option<Hash>,
// storage: MastStorage,
// }
3 changes: 3 additions & 0 deletions mast/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}
129 changes: 129 additions & 0 deletions mast/src/node.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//! Zip tree node.
use blake3::{Hash, Hasher};
use bytes::{BufMut, Bytes, BytesMut};

pub const HASH_LEN: usize = blake3::OUT_LEN;
pub const EMPTY_HASH: Hash = Hash::from_bytes([0_u8; HASH_LEN]);

#[derive(Debug)]
/// A serialized node.
pub struct Node {
key: String,
value: Hash,
left: Option<Hash>,
right: Option<Hash>,
}

impl Node {
pub fn new(key: String, value: Hash) -> Self {
Self {
key,
value,
left: None,
right: None,
}
}

// === Getters ===

// pub fn key(&self) -> &String {
// &self.key
// }

// pub fn left(&self) -> Option<Hash> {
// self.left
// }

// === Public Methods ===
//
pub fn serialize(&self) -> Bytes {
let mut bytes = BytesMut::new();

let mut header = 0_u8;
if self.left.is_some() {
header |= 0b0000_0010;
}
if self.right.is_some() {
header |= 0b0000_0001;
}
bytes.put_u8(0_u8);

// Encode the key
let mut key_len = [0_u8; 9];
let size = varu64::encode(self.key.len() as u64, &mut key_len);
bytes.extend_from_slice(&key_len[..size]);
bytes.extend_from_slice(self.key.as_bytes());

// Encode the value
bytes.extend_from_slice(self.value.as_bytes());

if let Some(left) = self.left {
bytes.extend_from_slice(left.as_bytes());
}
if let Some(right) = self.right {
bytes.extend_from_slice(right.as_bytes());
}

bytes.freeze()
}

// pub fn hash(&self) -> Hash {
// let mut hasher = Hasher::new();
// hasher.update(&self.serialize());
// hasher.finalize().into()
// }

pub fn deserialize(encoded: &Bytes) -> Result<Node, ()> {
let header = encoded.first().ok_or(())?;

let (n, rest) = varu64::decode(&encoded[1..]).map_err(|_| ())?;
let key_len = n as usize;
let key = String::from_utf8(rest[..key_len].to_vec()).map_err(|_| ())?;
let value = Hash::from_bytes(
rest[key_len..key_len + HASH_LEN]
.try_into()
.map_err(|_| ())?,
);

let mut left: Option<Hash> = None;
let mut right: Option<Hash> = None;

if *header & 0b0000_0010 != 0 {
let start = key_len + HASH_LEN;
let end = start + HASH_LEN;

left = Some(Hash::from_bytes(
rest[start..end].try_into().map_err(|_| ())?,
))
}
if *header & 0b0000_0001 != 0 {
let start = key_len + HASH_LEN + if left.is_some() { HASH_LEN } else { 0 };
let end = start + HASH_LEN;

right = Some(Hash::from_bytes(
rest[start..end].try_into().map_err(|_| ())?,
))
}

Ok(Self {
key,
value,
left,
right,
})
}
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn encode() {
let node = Node::new("key".to_string(), EMPTY_HASH);

let encoded = node.serialize();
let decoded = Node::deserialize(&encoded);
}
}
36 changes: 36 additions & 0 deletions mast/src/storage/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! In memory Mast storage.
use blake3::{Hash, Hasher};
use bytes::{Bytes, BytesMut};
use std::collections::HashMap;

// TODO: storage abstraction.
#[derive(Debug)]
pub struct Storage {
storage: HashMap<Hash, Bytes>,
}

impl Storage {
pub fn new() -> Self {
Self {
storage: HashMap::default(),
}
}

pub fn get(&self, hash: &Hash) -> Option<Bytes> {
self.storage.get(hash).cloned()
}

pub fn insert_bytes(&mut self, bytes: Bytes) -> Hash {
let hash = Hasher::new().update(&bytes).finalize();
// TODO: should I add a prefix here?
self.storage.insert(hash, bytes);
hash
}
}

impl Default for Storage {
fn default() -> Self {
Self::new()
}
}
1 change: 1 addition & 0 deletions mast/src/storage/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod memory;
Loading

0 comments on commit 9596efc

Please sign in to comment.