updated with latest spec changes

This commit is contained in:
mjkeating 2018-12-12 13:48:54 -08:00
parent 1e4e92bf2e
commit be2c82a732
5 changed files with 34 additions and 130 deletions

View File

@ -1,5 +1,3 @@
use super::ssz::{merkle_hash, TreeHash};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct ShardAndCommittee { pub struct ShardAndCommittee {
pub shard: u16, pub shard: u16,
@ -17,22 +15,6 @@ impl ShardAndCommittee {
} }
} }
impl TreeHash for ShardAndCommittee {
fn tree_hash(&self) -> Vec<u8> {
let mut committee_ssz_items = Vec::new();
for c in &self.committee {
let mut h = (*c as u32).tree_hash();
h.resize(3, 0);
committee_ssz_items.push(h);
}
let mut result = Vec::new();
result.append(&mut self.shard.tree_hash());
result.append(&mut merkle_hash(&mut committee_ssz_items));
result.as_slice().tree_hash()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -43,15 +25,4 @@ mod tests {
assert_eq!(s.shard, 0); assert_eq!(s.shard, 0);
assert_eq!(s.committee.len(), 0); assert_eq!(s.committee.len(), 0);
} }
#[test]
fn test_shard_and_committee_tree_hash() {
let s = ShardAndCommittee {
shard: 1,
committee: vec![1, 2, 3],
};
// should test a known hash value
assert_eq!(s.tree_hash().len(), 32);
}
} }

View File

@ -1,17 +1,6 @@
use super::bls::{Keypair, PublicKey}; use super::bls::{Keypair, PublicKey};
use super::ssz::TreeHash;
use super::{Address, Hash256}; use super::{Address, Hash256};
pub const HASH_SSZ_VALIDATOR_RECORD_LENGTH: usize = {
32 + // pubkey.to_bytes(32, 'big')
2 + // withdrawal_shard.to_bytes(2, 'big')
20 + // withdrawal_address
32 + // randao_commitment
16 + // balance.to_bytes(16, 'big')
16 + // start_dynasty.to_bytes(8, 'big')
8 // end_dynasty.to_bytes(8, 'big')
};
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum ValidatorStatus { pub enum ValidatorStatus {
PendingActivation = 0, PendingActivation = 0,
@ -55,32 +44,6 @@ impl ValidatorRecord {
} }
} }
impl TreeHash for ValidatorRecord {
fn tree_hash(&self) -> Vec<u8> {
let mut ssz = Vec::with_capacity(HASH_SSZ_VALIDATOR_RECORD_LENGTH);
// From python sample: "val.pubkey.to_bytes(32, 'big')"
// TODO:
// Need to actually convert (szz) pubkey into a big-endian 32 byte
// array.
// Also, our ValidatorRecord seems to be missing the start_dynasty
// and end_dynasty fields
let pub_key_bytes = &mut self.pubkey.as_bytes();
pub_key_bytes.resize(32, 0);
ssz.append(pub_key_bytes);
ssz.append(&mut self.withdrawal_shard.tree_hash());
ssz.append(&mut self.withdrawal_address.tree_hash());
ssz.append(&mut self.randao_commitment.tree_hash());
let mut balance = self.balance.tree_hash();
balance.resize(16, 0);
ssz.append(&mut balance);
ssz.as_slice().tree_hash()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -96,13 +59,4 @@ mod tests {
assert_eq!(v.status, 0); assert_eq!(v.status, 0);
assert_eq!(v.exit_slot, 0); assert_eq!(v.exit_slot, 0);
} }
#[test]
fn test_validator_record_ree_hash() {
let (v, _kp) = ValidatorRecord::zero_with_thread_rand_keypair();
let h = v.tree_hash();
// TODO: should check a known hash result value
assert_eq!(h.len(), 32);
}
} }

View File

@ -6,4 +6,4 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
[dependencies] [dependencies]
bytes = "0.4.9" bytes = "0.4.9"
ethereum-types = "0.4.0" ethereum-types = "0.4.0"
blake2-rfc = "0.2.18" hashing = { path = "../hashing" }

View File

@ -1,6 +1,6 @@
extern crate blake2_rfc; extern crate hashing;
use self::blake2_rfc::blake2b::blake2b; use self::hashing::canonical_hash;
use super::ethereum_types::{Address, H256}; use super::ethereum_types::{Address, H256};
use super::{merkle_hash, ssz_encode, TreeHash}; use super::{merkle_hash, ssz_encode, TreeHash};
use std::cmp::Ord; use std::cmp::Ord;
@ -84,11 +84,8 @@ where
} }
} }
/// From the Spec:
/// We define hash(x) as BLAKE2b-512(x)[0:32]
fn hash(data: &[u8]) -> Vec<u8> { fn hash(data: &[u8]) -> Vec<u8> {
let result = blake2b(32, &[], &data); canonical_hash(data)
result.as_bytes().to_vec()
} }
#[cfg(test)] #[cfg(test)]
@ -113,13 +110,12 @@ mod tests {
map.insert("f", 5); map.insert("f", 5);
let result = map.tree_hash(); let result = map.tree_hash();
// TODO: resolve inconsistencies between the python sample code and // TODO: create tests that tie-out to an offical result
// the spec; and create tests that tie-out to an offical result
assert_eq!( assert_eq!(
result, result,
[ [
59, 110, 242, 24, 177, 184, 73, 109, 190, 19, 172, 39, 74, 94, 224, 198, 0, 170, 232, 63, 235, 91, 115, 69, 159, 54, 95, 239, 147, 30, 179, 96, 232, 210, 225, 31,
225, 152, 249, 59, 10, 76, 137, 124, 52, 159, 37, 42, 26, 157 12, 95, 149, 104, 134, 158, 45, 51, 20, 101, 202, 164, 200, 163
] ]
); );
} }

View File

@ -1,4 +1,4 @@
const CHUNKSIZE: usize = 128; const SSZ_CHUNK_SIZE: usize = 128;
const HASHSIZE: usize = 32; const HASHSIZE: usize = 32;
pub trait TreeHash { pub trait TreeHash {
@ -9,15 +9,15 @@ pub trait TreeHash {
/// Note that this will consume 'list'. /// Note that this will consume 'list'.
pub fn merkle_hash(list: &mut Vec<Vec<u8>>) -> Vec<u8> { pub fn merkle_hash(list: &mut Vec<Vec<u8>>) -> Vec<u8> {
// flatten list // flatten list
let data = &mut list_to_blob(list); let (chunk_size, mut data) = list_to_blob(list);
// get data_len as bytes. It will hashed will the merkle root // get data_len as bytes. It will hashed will the merkle root
let dlen = data.len() as u64; let dlen = list.len() as u64;
let data_len_bytes = &mut dlen.tree_hash(); let data_len_bytes = &mut dlen.tree_hash();
data_len_bytes.resize(32, 0); data_len_bytes.resize(32, 0);
// merklize // merklize
let mut mhash = hash_level(data, CHUNKSIZE); let mut mhash = hash_level(&mut data, chunk_size);
while mhash.len() > HASHSIZE { while mhash.len() > HASHSIZE {
mhash = hash_level(&mut mhash, HASHSIZE); mhash = hash_level(&mut mhash, HASHSIZE);
} }
@ -33,9 +33,9 @@ fn hash_level(data: &mut Vec<u8>, chunk_size: usize) -> Vec<u8> {
for two_chunks in data.chunks(chunk_size * 2) { for two_chunks in data.chunks(chunk_size * 2) {
if two_chunks.len() == chunk_size && data.len() > chunk_size { if two_chunks.len() == chunk_size && data.len() > chunk_size {
// if there is only one chunk here, hash it with a zero-byte // if there is only one chunk here, hash it with a zero-byte
// CHUNKSIZE vector // SSZ_CHUNK_SIZE vector
let mut c = two_chunks.to_vec(); let mut c = two_chunks.to_vec();
c.append(&mut vec![0; CHUNKSIZE]); c.append(&mut vec![0; SSZ_CHUNK_SIZE]);
result.append(&mut c.as_slice().tree_hash()); result.append(&mut c.as_slice().tree_hash());
} else { } else {
result.append(&mut two_chunks.tree_hash()); result.append(&mut two_chunks.tree_hash());
@ -45,46 +45,30 @@ fn hash_level(data: &mut Vec<u8>, chunk_size: usize) -> Vec<u8> {
result result
} }
fn list_to_blob(list: &mut Vec<Vec<u8>>) -> Vec<u8> { fn list_to_blob(list: &mut Vec<Vec<u8>>) -> (usize, Vec<u8>) {
if list[0].len().is_power_of_two() == false { let chunk_size = if list.is_empty() {
for x in list.iter_mut() { SSZ_CHUNK_SIZE
extend_to_power_of_2(x); } else if list[0].len() < SSZ_CHUNK_SIZE {
} let items_per_chunk = SSZ_CHUNK_SIZE / list[0].len();
} items_per_chunk * list[0].len()
let mut data_len = list[0].len() * list.len();
// do we need padding?
let extend_by = if data_len % CHUNKSIZE > 0 {
CHUNKSIZE - (data_len % CHUNKSIZE)
} else { } else {
0 list[0].len()
}; };
// allocate buffer and append each list element (flatten the vec of vecs) let mut data = Vec::new();
data_len += extend_by; if list.is_empty() {
let mut data: Vec<u8> = Vec::with_capacity(data_len); // handle and empty list
for x in list.iter_mut() { data.append(&mut vec![0; SSZ_CHUNK_SIZE]);
data.append(x); } else {
// just create a blob here; we'll divide into
// chunked slices when we merklize
data.reserve(list[0].len() * list.len());
for item in list.iter_mut() {
data.append(item);
}
} }
// add padding (chunk_size, data)
let mut i = 0;
while i < extend_by {
data.push(0);
i += 1;
}
data
}
/// Extends data length to a power of 2 by minimally right-zero-padding
fn extend_to_power_of_2(data: &mut Vec<u8>) {
let len = data.len();
let new_len = len.next_power_of_two();
if new_len > len {
data.resize(new_len, 0);
}
} }
#[cfg(test)] #[cfg(test)]
@ -103,5 +87,4 @@ mod tests {
assert_eq!(HASHSIZE, result.len()); assert_eq!(HASHSIZE, result.len());
println!("merkle_hash: {:?}", result); println!("merkle_hash: {:?}", result);
} }
} }