mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-23 14:54:45 +00:00
Merge branch 'fixed-vec' into sos
This commit is contained in:
@@ -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 {
|
||||
|
||||
13
eth2/utils/fixed_len_vec/Cargo.toml
Normal file
13
eth2/utils/fixed_len_vec/Cargo.toml
Normal 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"
|
||||
70
eth2/utils/fixed_len_vec/src/impls.rs
Normal file
70
eth2/utils/fixed_len_vec/src/impls.rs
Normal 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)))
|
||||
}
|
||||
}
|
||||
118
eth2/utils/fixed_len_vec/src/lib.rs
Normal file
118
eth2/utils/fixed_len_vec/src/lib.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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(¤t_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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user