Merge branch 'fixed-vec' into sos

This commit is contained in:
Paul Hauner
2019-05-10 15:27:21 +10:00
164 changed files with 1498 additions and 4513 deletions

View File

@@ -220,7 +220,7 @@ impl Decodable for BooleanBitfield {
// as the BitVec library and the hex-parser use opposing bit orders.
fn reverse_bit_order(mut bytes: Vec<u8>) -> Vec<u8> {
bytes.reverse();
bytes.into_iter().map(|b| b.swap_bits()).collect()
bytes.into_iter().map(LookupReverse::swap_bits).collect()
}
impl Serialize for BooleanBitfield {

View File

@@ -0,0 +1,13 @@
[package]
name = "fixed_len_vec"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
cached_tree_hash = { path = "../cached_tree_hash" }
tree_hash = { path = "../tree_hash" }
serde = "1.0"
serde_derive = "1.0"
ssz = { path = "../ssz" }
typenum = "1.10"

View File

@@ -0,0 +1,70 @@
use super::*;
// use cached_tree_hash::CachedTreeHash;
// use ssz::{Decodable, Encodable};
// use tree_hash::TreeHash;
impl<T, N: Unsigned> tree_hash::TreeHash for FixedLenVec<T, N>
where
T: tree_hash::TreeHash,
{
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::Vector
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
unreachable!("Vector should never be packed.")
}
fn tree_hash_packing_factor() -> usize {
unreachable!("Vector should never be packed.")
}
fn tree_hash_root(&self) -> Vec<u8> {
tree_hash::impls::vec_tree_hash_root(&self.vec)
}
}
impl<T, N: Unsigned> cached_tree_hash::CachedTreeHash for FixedLenVec<T, N>
where
T: cached_tree_hash::CachedTreeHash + tree_hash::TreeHash,
{
fn new_tree_hash_cache(
&self,
depth: usize,
) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
let (cache, _overlay) = cached_tree_hash::vec::new_tree_hash_cache(&self.vec, depth)?;
Ok(cache)
}
fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema {
cached_tree_hash::vec::produce_schema(&self.vec, depth)
}
fn update_tree_hash_cache(
&self,
cache: &mut cached_tree_hash::TreeHashCache,
) -> Result<(), cached_tree_hash::Error> {
cached_tree_hash::vec::update_tree_hash_cache(&self.vec, cache)?;
Ok(())
}
}
impl<T, N: Unsigned> ssz::Encodable for FixedLenVec<T, N>
where
T: ssz::Encodable,
{
fn ssz_append(&self, s: &mut ssz::SszStream) {
s.append_vec(&self.vec)
}
}
impl<T, N: Unsigned> ssz::Decodable for FixedLenVec<T, N>
where
T: ssz::Decodable + Default,
{
fn ssz_decode(bytes: &[u8], index: usize) -> Result<(Self, usize), ssz::DecodeError> {
ssz::decode_ssz_list(bytes, index).and_then(|(vec, i)| Ok((vec.into(), i)))
}
}

View File

@@ -0,0 +1,118 @@
use serde_derive::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::ops::{Index, IndexMut};
use std::slice::SliceIndex;
use typenum::Unsigned;
pub use typenum;
mod impls;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct FixedLenVec<T, N>
where
N: Unsigned,
{
vec: Vec<T>,
_phantom: PhantomData<N>,
}
impl<T, N: Unsigned> FixedLenVec<T, N> {
pub fn len(&self) -> usize {
self.vec.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn capacity() -> usize {
N::to_usize()
}
}
impl<T: Default, N: Unsigned> From<Vec<T>> for FixedLenVec<T, N> {
fn from(mut vec: Vec<T>) -> Self {
vec.resize_with(Self::capacity(), Default::default);
Self {
vec,
_phantom: PhantomData,
}
}
}
impl<T, N: Unsigned> Into<Vec<T>> for FixedLenVec<T, N> {
fn into(self) -> Vec<T> {
self.vec
}
}
impl<T, N: Unsigned> Default for FixedLenVec<T, N> {
fn default() -> Self {
Self {
vec: Vec::default(),
_phantom: PhantomData,
}
}
}
impl<T, N: Unsigned, I: SliceIndex<[T]>> Index<I> for FixedLenVec<T, N> {
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
Index::index(&self.vec, index)
}
}
impl<T, N: Unsigned, I: SliceIndex<[T]>> IndexMut<I> for FixedLenVec<T, N> {
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
IndexMut::index_mut(&mut self.vec, index)
}
}
#[cfg(test)]
mod test {
use super::*;
use typenum::*;
#[test]
fn indexing() {
let vec = vec![1, 2];
let mut fixed: FixedLenVec<u64, U8192> = vec.clone().into();
assert_eq!(fixed[0], 1);
assert_eq!(&fixed[0..1], &vec[0..1]);
assert_eq!((&fixed[..]).len(), 8192);
fixed[1] = 3;
assert_eq!(fixed[1], 3);
}
#[test]
fn length() {
let vec = vec![42; 5];
let fixed: FixedLenVec<u64, U4> = FixedLenVec::from(vec.clone());
assert_eq!(&fixed[..], &vec[0..4]);
let vec = vec![42; 3];
let fixed: FixedLenVec<u64, U4> = FixedLenVec::from(vec.clone());
assert_eq!(&fixed[0..3], &vec[..]);
assert_eq!(&fixed[..], &vec![42, 42, 42, 0][..]);
let vec = vec![];
let fixed: FixedLenVec<u64, U4> = FixedLenVec::from(vec.clone());
assert_eq!(&fixed[..], &vec![0, 0, 0, 0][..]);
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

View File

@@ -8,6 +8,36 @@ pub fn hash(input: &[u8]) -> Vec<u8> {
result
}
/// Get merkle root of some hashed values - the input leaf nodes is expected to already be hashed
/// Outputs a `Vec<u8>` byte array of the merkle root given a set of leaf node values.
pub fn merkle_root(values: &[Vec<u8>]) -> Option<Vec<u8>> {
let values_len = values.len();
// check size of vector > 0 and ^ 2
if values.is_empty() || !values_len.is_power_of_two() {
return None;
}
// vector to store hashes
// filled with 0 as placeholders
let mut o: Vec<Vec<u8>> = vec![vec![0]; values_len];
// append values to the end
o.append(&mut values.to_vec());
// traverse backwards as values are at the end
// then fill placeholders with a hash of two leaf nodes
for i in (0..values_len).rev() {
let mut current_value: Vec<u8> = o[i * 2].clone();
current_value.append(&mut o[i * 2 + 1].clone());
o[i] = hash(&current_value[..]);
}
// the root hash will be at index 1
Some(o[1].clone())
}
#[cfg(test)]
mod tests {
use super::*;
@@ -25,4 +55,51 @@ mod tests {
];
assert_eq!(expected, output.as_slice());
}
#[test]
fn test_merkle_root() {
// hash the leaf nodes
let mut input = vec![
hash("a".as_bytes()),
hash("b".as_bytes()),
hash("c".as_bytes()),
hash("d".as_bytes()),
];
// generate a merkle tree and return the root
let output = merkle_root(&input[..]);
// create merkle root manually
let mut leaf_1_2: Vec<u8> = input[0].clone(); // a
leaf_1_2.append(&mut input[1].clone()); // b
let mut leaf_3_4: Vec<u8> = input[2].clone(); // c
leaf_3_4.append(&mut input[3].clone()); // d
let node_1 = hash(&leaf_1_2[..]);
let node_2 = hash(&leaf_3_4[..]);
let mut root: Vec<u8> = node_1.clone(); // ab
root.append(&mut node_2.clone()); // cd
let expected = hash(&root[..]);
assert_eq!(&expected[..], output.unwrap().as_slice());
}
#[test]
fn test_empty_input_merkle_root() {
let input = vec![];
let output = merkle_root(&input[..]);
assert_eq!(None, output);
}
#[test]
fn test_odd_leaf_merkle_root() {
let input = vec![
hash("a".as_bytes()),
hash("b".as_bytes()),
hash("a".as_bytes()),
];
let output = merkle_root(&input[..]);
assert_eq!(None, output);
}
}

View File

@@ -72,6 +72,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
let item = parse_macro_input!(input as DeriveInput);
let name = &item.ident;
let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl();
let struct_data = match &item.data {
syn::Data::Struct(s) => s,
@@ -84,7 +85,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream {
let field_types_c = field_types_a.clone();
let output = quote! {
impl ssz::Encodable for #name {
impl #impl_generics ssz::Encodable for #name #ty_generics #where_clause {
fn is_ssz_fixed_len() -> bool {
#(
<#field_types_a as ssz::Encodable>::is_ssz_fixed_len() &&
@@ -142,6 +143,7 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
let item = parse_macro_input!(input as DeriveInput);
let name = &item.ident;
let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl();
let struct_data = match &item.data {
syn::Data::Struct(s) => s,
@@ -188,7 +190,7 @@ pub fn ssz_decode_derive(input: TokenStream) -> TokenStream {
}
let output = quote! {
impl ssz::Decodable for #name {
impl #impl_generics ssz::Decodable for #name #ty_generics #where_clause {
fn is_ssz_fixed_len() -> bool {
#(
#is_fixed_lens &&

View File

@@ -21,6 +21,7 @@ fn should_use_default(field: &syn::Field) -> bool {
pub fn test_random_derive(input: TokenStream) -> TokenStream {
let derived_input = parse_macro_input!(input as DeriveInput);
let name = &derived_input.ident;
let (impl_generics, ty_generics, where_clause) = &derived_input.generics.split_for_impl();
let struct_data = match &derived_input.data {
syn::Data::Struct(s) => s,
@@ -48,8 +49,8 @@ pub fn test_random_derive(input: TokenStream) -> TokenStream {
}
let output = quote! {
impl<T: RngCore> TestRandom<T> for #name {
fn random_for_test(rng: &mut T) -> Self {
impl #impl_generics TestRandom for #name #ty_generics #where_clause {
fn random_for_test(rng: &mut impl rand::RngCore) -> Self {
Self {
#(
#quotes

View File

@@ -43,6 +43,7 @@ fn should_skip_hashing(field: &syn::Field) -> bool {
#[proc_macro_derive(CachedTreeHash, attributes(tree_hash))]
pub fn subtree_derive(input: TokenStream) -> TokenStream {
let item = parse_macro_input!(input as DeriveInput);
let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl();
let name = &item.ident;
@@ -56,7 +57,7 @@ pub fn subtree_derive(input: TokenStream) -> TokenStream {
let idents_c = idents_a.clone();
let output = quote! {
impl cached_tree_hash::CachedTreeHash for #name {
impl #impl_generics cached_tree_hash::CachedTreeHash for #name #ty_generics #where_clause {
fn new_tree_hash_cache(&self, depth: usize) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
let tree = cached_tree_hash::TreeHashCache::from_subtrees(
self,
@@ -119,6 +120,7 @@ pub fn tree_hash_derive(input: TokenStream) -> TokenStream {
let item = parse_macro_input!(input as DeriveInput);
let name = &item.ident;
let (impl_generics, ty_generics, where_clause) = &item.generics.split_for_impl();
let struct_data = match &item.data {
syn::Data::Struct(s) => s,
@@ -128,7 +130,7 @@ pub fn tree_hash_derive(input: TokenStream) -> TokenStream {
let idents = get_hashable_named_field_idents(&struct_data);
let output = quote! {
impl tree_hash::TreeHash for #name {
impl #impl_generics tree_hash::TreeHash for #name #ty_generics #where_clause {
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::Container
}