Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Implement EIP-7495: StableContainer #15

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ members = [
"tree_hash_derive",
]
resolver = "2"

[patch."https://github.com/macladson/tree_hash"]
tree_hash = { path = "./tree_hash" }
tree_hash_derive = { path = "./tree_hash_derive" }
6 changes: 4 additions & 2 deletions tree_hash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ smallvec = "1.6.1"
[dev-dependencies]
rand = "0.8.5"
tree_hash_derive = { path = "../tree_hash_derive", version = "0.6.0" }
ethereum_ssz = "0.5"
ethereum_ssz_derive = "0.5"
ethereum_ssz = { git = "https://github.com/macladson/ethereum_ssz", branch = "stable-container" }
ethereum_ssz_derive = { git = "https://github.com/macladson/ethereum_ssz", branch = "stable-container" }
ssz_types = { git = "https://github.com/macladson/ssz_types", branch = "stable-container" }
typenum = "1.12.0"

[features]
arbitrary = ["ethereum-types/arbitrary"]
24 changes: 24 additions & 0 deletions tree_hash/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,30 @@ impl<T: TreeHash> TreeHash for Arc<T> {
}
}

impl<T: TreeHash> TreeHash for Option<T> {
fn tree_hash_type() -> TreeHashType {
T::tree_hash_type()
}

fn tree_hash_packed_encoding(&self) -> PackedEncoding {
match self {
Some(inner) => inner.tree_hash_packed_encoding(),
None => unreachable!(),
}
}

fn tree_hash_packing_factor() -> usize {
T::tree_hash_packing_factor()
}

fn tree_hash_root(&self) -> Hash256 {
match self {
Some(inner) => inner.tree_hash_root(),
None => unreachable!(),
}
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
8 changes: 8 additions & 0 deletions tree_hash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ pub fn mix_in_selector(root: &Hash256, selector: u8) -> Option<Hash256> {
Some(Hash256::from_slice(&root))
}

pub fn mix_in_aux(root: &Hash256, aux: &Hash256) -> Hash256 {
Hash256::from_slice(&ethereum_hashing::hash32_concat(
root.as_bytes(),
aux.as_bytes(),
))
}

/// Returns a cached padding node for a given height.
fn get_zero_hash(height: usize) -> &'static [u8] {
if height <= ZERO_HASHES_MAX_INDEX {
Expand All @@ -107,6 +114,7 @@ pub enum TreeHashType {
Vector,
List,
Container,
StableContainer,
}

pub trait TreeHash {
Expand Down
89 changes: 88 additions & 1 deletion tree_hash/tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use ssz_derive::Encode;
use tree_hash::{Hash256, MerkleHasher, PackedEncoding, TreeHash, BYTES_PER_CHUNK};
use ssz_types::BitVector;
use tree_hash::{self, Hash256, MerkleHasher, PackedEncoding, TreeHash, BYTES_PER_CHUNK};
use tree_hash_derive::TreeHash;
use typenum::Unsigned;

#[derive(Encode)]
struct HashVec {
Expand Down Expand Up @@ -126,3 +128,88 @@ fn variable_union() {
mix_in_selector(u8_hash_concat(2, 1), 1)
);
}

#[derive(TreeHash)]
#[tree_hash(struct_behaviour = "stable_container")]
#[tree_hash(max_fields = "typenum::U8")]
struct Shape {
side: Option<u16>,
color: Option<u8>,
radius: Option<u16>,
}

#[derive(TreeHash, Clone)]
#[tree_hash(struct_behaviour = "profile")]
#[tree_hash(max_fields = "typenum::U8")]
struct Square {
// We always start with a stable_index of 0.
side: u16,
color: u8,
}

#[derive(TreeHash, Clone)]
#[tree_hash(struct_behaviour = "profile")]
#[tree_hash(max_fields = "typenum::U8")]
struct Circle {
#[tree_hash(stable_index = 1)]
color: u8,
#[tree_hash(skip_hashing)]
phantom: u8,
// Note that we do not need to specify `stable_index = 2` here since
// we always increment by 1 from the previous index.
radius: u16,
}

#[derive(TreeHash)]
#[tree_hash(enum_behaviour = "transparent_stable")]
enum ShapeEnum {
SquareVariant(Square),
CircleVariant(Circle),
}

#[test]
fn shape_1() {
let shape_1 = Shape {
side: Some(16),
color: Some(2),
radius: None,
};

let square = Square { side: 16, color: 2 };

assert_eq!(shape_1.tree_hash_root(), square.tree_hash_root());
}

#[test]
fn shape_2() {
let shape_2 = Shape {
side: None,
color: Some(1),
radius: Some(42),
};

let circle = Circle {
color: 1,
phantom: 6,
radius: 42,
};

assert_eq!(shape_2.tree_hash_root(), circle.tree_hash_root());
}

#[test]
fn shape_enum() {
let square = Square { side: 16, color: 2 };

let circle = Circle {
color: 1,
phantom: 6,
radius: 14,
};

let enum_square = ShapeEnum::SquareVariant(square.clone());
let enum_circle = ShapeEnum::CircleVariant(circle.clone());

assert_eq!(square.tree_hash_root(), enum_square.tree_hash_root());
assert_eq!(circle.tree_hash_root(), enum_circle.tree_hash_root());
}
2 changes: 2 additions & 0 deletions tree_hash_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ proc-macro = true
syn = "1.0.42"
quote = "1.0.7"
darling = "0.13.0"
proc-macro2 = "1.0.23"
ssz_types = { git = "https://github.com/macladson/ssz_types", branch = "stable-container" }
Loading