diff --git a/serialization/src/impls.rs b/serialization/src/impls.rs index 07ee169b..1948e9b2 100644 --- a/serialization/src/impls.rs +++ b/serialization/src/impls.rs @@ -247,6 +247,28 @@ impl Deserializable for Compact { } } +impl Serializable for Option { + fn serialize(&self, stream: &mut Stream) { + match *self { + None => { stream.append(&false); }, + Some(ref t) => { stream.append(&true); stream.append(t); }, + } + } +} + +impl Deserializable for Option { + fn deserialize(reader: &mut Reader) -> Result where R: io::Read { + let has_value = reader.read::()?; + Ok( + if has_value { + Some(reader.read::()?) + } else { + None + } + ) + } +} + #[cfg(test)] mod tests { use bytes::Bytes; diff --git a/serialization/src/stream.rs b/serialization/src/stream.rs index 2b0ffee5..8f52da15 100644 --- a/serialization/src/stream.rs +++ b/serialization/src/stream.rs @@ -4,7 +4,7 @@ use std::borrow::Borrow; use compact_integer::CompactInteger; use bytes::Bytes; -pub fn serialize(t: &T) -> Bytes where T: Serializable{ +pub fn serialize(t: &T) -> Bytes where T: Serializable { let mut stream = Stream::new(); stream.append(t); stream.out() diff --git a/storage/src/lib.rs b/storage/src/lib.rs index a6d7637e..e42d690f 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -24,7 +24,7 @@ mod store; mod transaction_meta; mod transaction_provider; mod nullifier; -mod commitments; +mod tree_state; pub use primitives::{hash, bytes}; diff --git a/storage/src/commitments.rs b/storage/src/tree_state.rs similarity index 60% rename from storage/src/commitments.rs rename to storage/src/tree_state.rs index 8e28fcb7..aff7a5dd 100644 --- a/storage/src/commitments.rs +++ b/storage/src/tree_state.rs @@ -72,21 +72,40 @@ lazy_static! { ].to_vec(); } -struct TreeState { - height: u32, +pub trait Dim { + fn height() -> u32; +} + +pub struct H4; + +impl Dim for H4 { + fn height() -> u32 { + 4 + } +} + +pub struct H32; + +impl Dim for H32 { + fn height() -> u32 { + 32 + } +} + +pub struct TreeState { + _phantom: ::std::marker::PhantomData, left: Option, right: Option, parents: Vec>, } -impl TreeState { - - fn new(height: u32) -> Self { +impl TreeState { + fn new() -> Self { TreeState { - height: height, + _phantom: ::std::marker::PhantomData, left: None, right: None, - parents: vec![None; height as usize], + parents: vec![None; D::height() as usize], } } @@ -102,7 +121,7 @@ impl TreeState { .expect("none variant is handled in the branch above; qed"); let mut combined = sha256_compress(&*former_left, &*former_right); - for i in 0..self.height { + for i in 0..D::height() { let parent_slot = self.parents.get_mut(i as usize) .expect("Vector is at least self.height in size"); @@ -126,7 +145,7 @@ impl TreeState { let mut root = sha256_compress(&**left, &**right); - for i in 1..self.height { + for i in 1..D::height() { match &self.parents[i as usize] { &None => { root = sha256_compress(&*root, &*EMPTY_ROOTS[i as usize]); }, &Some(ref parent) => { root = sha256_compress(&**parent, &*root); } @@ -137,15 +156,55 @@ impl TreeState { } } +pub type TestTreeState = TreeState

; +pub type RegularTreeState = TreeState; + +impl serialization::Serializable for TreeState { + fn serialize(&self, stream: &mut serialization::Stream) { + stream.append(&self.left); + stream.append(&self.right); + stream.append_list(&self.parents); + } +} + +impl serialization::Deserializable for TreeState { + fn deserialize(reader: &mut serialization::Reader) + -> Result + { + let mut tree_state = TreeState::::new(); + tree_state.left = reader.read()?; + tree_state.right = reader.read()?; + tree_state.parents = reader.read_list()?; + + Ok(tree_state) + } +} + #[cfg(test)] mod tests { use super::*; use EpochTag; + pub struct H1; + + impl Dim for H1 { + fn height() -> u32 { + 1 + } + } + + pub struct H2; + + impl Dim for H2 { + fn height() -> u32 { + 2 + } + } + #[test] fn single_root() { - let mut tree = TreeState::new(1); + let mut tree = TreeState::

::new(); tree.append(EMPTY_ROOTS[0].clone()).unwrap(); assert_eq!( @@ -156,7 +215,7 @@ mod tests { #[test] fn single_elem_in_double_tree() { - let mut tree = TreeState::new(2); + let mut tree = TreeState::

::new(); tree.append(EMPTY_ROOTS[0].clone()).unwrap(); assert_eq!( @@ -167,7 +226,7 @@ mod tests { #[test] fn commitment_1() { - let mut tree = TreeState::new(4); + let mut tree = TestTreeState::new(); tree.append(H256::from_reversed_str("bab6e8992959caf0ca94847c36b4e648a7f88a9b9c6a62ea387cf1fb9badfd62")) .unwrap(); @@ -179,7 +238,7 @@ mod tests { #[test] fn commitment_2() { - let mut tree = TreeState::new(4); + let mut tree = TestTreeState::new(); tree.append(H256::from_reversed_str("bab6e8992959caf0ca94847c36b4e648a7f88a9b9c6a62ea387cf1fb9badfd62")) .unwrap(); tree.append(H256::from_reversed_str("43c9a4b21555b832a79fc12ce27a97d4f4eca1638e7161a780db1d5ebc35eb68")) @@ -190,4 +249,71 @@ mod tests { H256::from("73f18d3f9cd11010aa01d4f444039e566f14ef282109df9649b2eb75e7a53ed1") ); } + + #[test] + fn glass() { + let mut tree = TestTreeState::new(); + tree.append(H256::from_reversed_str("bab6e8992959caf0ca94847c36b4e648a7f88a9b9c6a62ea387cf1fb9badfd62")) + .unwrap(); + tree.append(H256::from_reversed_str("43c9a4b21555b832a79fc12ce27a97d4f4eca1638e7161a780db1d5ebc35eb68")) + .unwrap(); + tree.append(H256::from_reversed_str("fb92a6142315bb3396b693222bf2d0e260b448cda74e189063cf774048456083")) + .unwrap(); + + assert_eq!( + tree.root(), + H256::from("73f18d3f9cd11010aa01d4f444039e566f14ef282109df9649b2eb75e7a53ed1") + ); + } + + #[test] + fn commitments_full() { + let commitments_list = [ + H256::from_reversed_str("bab6e8992959caf0ca94847c36b4e648a7f88a9b9c6a62ea387cf1fb9badfd62"), + H256::from_reversed_str("43c9a4b21555b832a79fc12ce27a97d4f4eca1638e7161a780db1d5ebc35eb68"), + H256::from_reversed_str("fb92a6142315bb3396b693222bf2d0e260b448cda74e189063cf774048456083"), + H256::from_reversed_str("e44a57cd544018937680d385817be3a3e35bb5b87ceeea93d536ea95828a4992"), + H256::from_reversed_str("43f48bfb9ab6f12ef91ce83e8f9190ce5dff2721784c90e08a50a67403367cff"), + H256::from_reversed_str("fce910561c3c7ebf14ed5d712e6838cdc6f1145c87eec256b7181f9df6d0c468"), + H256::from_reversed_str("b1e7016392805b227b11e58ba629f9a6684a0b4c34306e85e47548c43ecd168b"), + H256::from_reversed_str("2d9a49d9425449a449cc62d16febaf9c7f8b32349752ecc39191c36130b4c050"), + H256::from_reversed_str("53969b31a862b893dde857b8b7d4f53ce0e2c21a0f70d48ba1aef3a05fddff70"), + H256::from_reversed_str("17f8fabd440fdf9e2eafd75a3407e8bbde048d2d2232cd803d5763004af61ed8"), + H256::from_reversed_str("9b7805cb5e8ef337c13c73cab58ee719bf33a4a80ecc161bfe714269eca4928b"), + H256::from_reversed_str("a3ebada94d4329899ae136391604799d8cea39c0c331f9aaaa4a1e73ab63e904"), + H256::from_reversed_str("12091a20c9ebe67c2793bb71a6fdddb0ffe3ca781fcf1e192428161f186c3fbe"), + H256::from_reversed_str("e9c65749638df548b8909c0ea1d0f79079a6bb3235c649a8806322c87f968018"), + H256::from_reversed_str("8e8fddf0438a4263bc926fcfa6733dc201633959f294103533a2cb9328bb65c4"), + H256::from_reversed_str("206a202bd08dd31f77afc7114b17850192b83948cff5828df0d638cbe734c884") + ]; + + let root_list = [ + H256::from("95bf71d8e803b8601c14b5949d0f92690181154ef9d82eb3e24852266823317a"), + H256::from("73f18d3f9cd11010aa01d4f444039e566f14ef282109df9649b2eb75e7a53ed1"), + H256::from("dcde8a273c9672bee1a894d7f7f4abb81078f52b498e095f2a87d0aec5addf25"), + H256::from("4677d481ec6d1e97969afbc530958d1cbb4f1c047af6fdad4687cd10830e02bd"), + H256::from("74cd9d82de30c4222a06d420b75522ae1273729c1d8419446adf1184df61dc69"), + H256::from("2ff57f5468c6afdad30ec0fb6c2cb67289f12584e2c20c4e0065f66748697d77"), + H256::from("27e4ce010670801911c5765a003b15f75cde31d7378bd36540f593c8a44b3011"), + H256::from("62231ef2ec8c4da461072871ab7bc9de10253fcb40e164ddbad05b47e0b7fb69"), + H256::from("733a4ce688fdf07efb9e9f5a4b2dafff87cfe198fbe1dff71e028ef4cdee1f1b"), + H256::from("df39ed31924facdd69a93db07311d45fceac7a4987c091648044f37e6ecbb0d2"), + H256::from("87795c069bdb55281c666b9cb872d13174334ce135c12823541e9536489a9107"), + H256::from("438c80f532903b283230446514e400c329b29483db4fe9e279fdfc79e8f4347d"), + H256::from("08afb2813eda17e94aba1ab28ec191d4af99283cd4f1c5a04c0c2bc221bc3119"), + H256::from("a8b3ab3284f3288f7caa21bd2b69789a159ab4188b0908825b34723305c1228c"), + H256::from("db9b289e620de7dca2ae8fdac96808752e32e7a2c6d97ce0755dcebaa03123ab"), + H256::from("0bf622cb9f901b7532433ea2e7c1b7632f5935899b62dcf897a71551997dc8cc"), + ]; + + let mut tree = TestTreeState::new(); + + for i in 0..commitments_list.len() { + tree.append(commitments_list[i].clone()).expect(&format!("Failed to add commitment #{}", i)); + assert_eq!(&tree.root(), &root_list[i]); + } + + // should return error because tree is full + assert!(tree.append(H256::from("0bf622cb9f901b7532433ea2e7c1b7632f5935899b62dcf897a71551997dc8cc")).is_err()); + } } \ No newline at end of file