Begin implementing cached hashing in types

This commit is contained in:
Paul Hauner 2019-04-26 15:24:18 +10:00
parent ecff8f0007
commit f65e981f6f
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
41 changed files with 590 additions and 47 deletions

View File

@ -5,7 +5,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// Details an attestation that can be slashable.
///
@ -19,6 +19,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
)]
@ -58,4 +59,5 @@ mod tests {
use super::*;
ssz_tests!(Attestation);
cached_tree_hash_tests!(Attestation);
}

View File

@ -5,7 +5,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// The data upon which an attestation is based.
///
@ -21,6 +21,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
)]
@ -47,4 +48,5 @@ mod tests {
use super::*;
ssz_tests!(AttestationData);
cached_tree_hash_tests!(AttestationData);
}

View File

@ -3,12 +3,12 @@ use crate::test_utils::TestRandom;
use rand::RngCore;
use serde_derive::Serialize;
use ssz_derive::{Decode, Encode};
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Used for pairing an attestation with a proof-of-custody.
///
/// Spec v0.5.1
#[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash)]
#[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash, CachedTreeHash)]
pub struct AttestationDataAndCustodyBit {
pub data: AttestationData,
pub custody_bit: bool,
@ -28,4 +28,5 @@ mod test {
use super::*;
ssz_tests!(AttestationDataAndCustodyBit);
cached_tree_hash_tests!(AttestationDataAndCustodyBit);
}

View File

@ -3,12 +3,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Two conflicting attestations.
///
/// Spec v0.5.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct AttesterSlashing {
pub slashable_attestation_1: SlashableAttestation,
pub slashable_attestation_2: SlashableAttestation,
@ -19,4 +30,5 @@ mod tests {
use super::*;
ssz_tests!(AttesterSlashing);
cached_tree_hash_tests!(AttesterSlashing);
}

View File

@ -6,7 +6,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// A block of the `BeaconChain`.
///
@ -20,6 +20,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
)]
@ -100,4 +101,5 @@ mod tests {
use super::*;
ssz_tests!(BeaconBlock);
cached_tree_hash_tests!(BeaconBlock);
}

View File

@ -4,12 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// The body of a `BeaconChain` block, containing operations.
///
/// Spec v0.5.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct BeaconBlockBody {
pub randao_reveal: Signature,
pub eth1_data: Eth1Data,
@ -26,4 +37,5 @@ mod tests {
use super::*;
ssz_tests!(BeaconBlockBody);
cached_tree_hash_tests!(BeaconBlockBody);
}

View File

@ -6,7 +6,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// A header of a `BeaconBlock`.
///
@ -20,6 +20,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
)]
@ -59,4 +60,5 @@ mod tests {
use super::*;
ssz_tests!(BeaconBlockHeader);
cached_tree_hash_tests!(BeaconBlockHeader);
}

View File

@ -9,7 +9,7 @@ use ssz::{hash, ssz_encode};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
mod epoch_cache;
mod pubkey_cache;
@ -47,7 +47,18 @@ pub enum Error {
/// The state of the `BeaconChain` at some slot.
///
/// Spec v0.5.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, TestRandom, Encode, Decode, TreeHash)]
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
TestRandom,
Encode,
Decode,
TreeHash,
CachedTreeHash,
)]
pub struct BeaconState {
// Misc
pub slot: Slot,

View File

@ -3,6 +3,7 @@ use super::*;
use crate::test_utils::*;
ssz_tests!(BeaconState);
cached_tree_hash_tests!(BeaconState);
/// Test that
///

View File

@ -4,7 +4,7 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Specifies the block hash for a shard at an epoch.
///
@ -20,6 +20,7 @@ use tree_hash_derive::TreeHash;
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct Crosslink {
@ -32,4 +33,5 @@ mod tests {
use super::*;
ssz_tests!(Crosslink);
cached_tree_hash_tests!(Crosslink);
}

View File

@ -1,9 +1,20 @@
use crate::*;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize, Decode, Encode, TreeHash)]
#[derive(
Default,
Clone,
Debug,
PartialEq,
Serialize,
Deserialize,
Decode,
Encode,
TreeHash,
CachedTreeHash,
)]
pub struct CrosslinkCommittee {
pub slot: Slot,
pub shard: Shard,

View File

@ -4,12 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// A deposit to potentially become a beacon chain validator.
///
/// Spec v0.5.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct Deposit {
pub proof: TreeHashVector<Hash256>,
pub index: u64,
@ -21,4 +32,5 @@ mod tests {
use super::*;
ssz_tests!(Deposit);
cached_tree_hash_tests!(Deposit);
}

View File

@ -4,12 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Data generated by the deposit contract.
///
/// Spec v0.5.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct DepositData {
pub amount: u64,
pub timestamp: u64,
@ -21,4 +32,5 @@ mod tests {
use super::*;
ssz_tests!(DepositData);
cached_tree_hash_tests!(DepositData);
}

View File

@ -6,7 +6,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::{SignedRoot, TreeHash};
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// The data supplied by the user to the deposit contract.
///
@ -21,6 +21,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Decode,
SignedRoot,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct DepositInput {
@ -68,6 +69,7 @@ mod tests {
use super::*;
ssz_tests!(DepositInput);
cached_tree_hash_tests!(DepositInput);
#[test]
fn can_create_and_validate() {

View File

@ -4,13 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Contains data obtained from the Eth1 chain.
///
/// Spec v0.5.1
#[derive(
Debug, PartialEq, Clone, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
Debug,
PartialEq,
Clone,
Default,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct Eth1Data {
pub deposit_root: Hash256,
@ -22,4 +32,5 @@ mod tests {
use super::*;
ssz_tests!(Eth1Data);
cached_tree_hash_tests!(Eth1Data);
}

View File

@ -4,13 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// A summation of votes for some `Eth1Data`.
///
/// Spec v0.5.1
#[derive(
Debug, PartialEq, Clone, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
Debug,
PartialEq,
Clone,
Default,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct Eth1DataVote {
pub eth1_data: Eth1Data,
@ -22,4 +32,5 @@ mod tests {
use super::*;
ssz_tests!(Eth1DataVote);
cached_tree_hash_tests!(Eth1DataVote);
}

View File

@ -7,13 +7,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
///
/// Spec v0.5.1
#[derive(
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
Debug,
Clone,
PartialEq,
Default,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct Fork {
#[serde(deserialize_with = "fork_from_hex_str")]
@ -54,6 +64,7 @@ mod tests {
use super::*;
ssz_tests!(Fork);
cached_tree_hash_tests!(Fork);
fn test_genesis(version: u32, epoch: Epoch) {
let mut spec = ChainSpec::foundation();

View File

@ -4,12 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Historical block and state roots.
///
/// Spec v0.5.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
Clone,
PartialEq,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct HistoricalBatch {
pub block_roots: TreeHashVector<Hash256>,
pub state_roots: TreeHashVector<Hash256>,
@ -20,4 +31,5 @@ mod tests {
use super::*;
ssz_tests!(HistoricalBatch);
cached_tree_hash_tests!(HistoricalBatch);
}

View File

@ -4,12 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// An attestation that has been included in the state but not yet fully processed.
///
/// Spec v0.5.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
Clone,
PartialEq,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct PendingAttestation {
pub aggregation_bitfield: Bitfield,
pub data: AttestationData,
@ -34,4 +45,5 @@ mod tests {
use super::*;
ssz_tests!(PendingAttestation);
cached_tree_hash_tests!(PendingAttestation);
}

View File

@ -4,12 +4,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Two conflicting proposals from the same proposer (validator).
///
/// Spec v0.5.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[derive(
Debug,
PartialEq,
Clone,
Serialize,
Deserialize,
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
)]
pub struct ProposerSlashing {
pub proposer_index: u64,
pub header_1: BeaconBlockHeader,
@ -21,4 +32,5 @@ mod tests {
use super::*;
ssz_tests!(ProposerSlashing);
cached_tree_hash_tests!(ProposerSlashing);
}

View File

@ -4,7 +4,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// Details an attestation that can be slashable.
///
@ -20,6 +20,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
)]
@ -133,6 +134,7 @@ mod tests {
}
ssz_tests!(SlashableAttestation);
cached_tree_hash_tests!(SlashableAttestation);
fn create_slashable_attestation(
slot_factor: u64,

View File

@ -224,6 +224,26 @@ macro_rules! impl_ssz {
}
}
impl cached_tree_hash::CachedTreeHash<$type> for $type {
fn new_tree_hash_cache(
&self,
depth: usize,
) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
self.0.new_tree_hash_cache(depth)
}
fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema {
self.0.tree_hash_cache_schema(depth)
}
fn update_tree_hash_cache(
&self,
cache: &mut cached_tree_hash::TreeHashCache,
) -> Result<(), cached_tree_hash::Error> {
self.0.update_tree_hash_cache(cache)
}
}
impl<T: RngCore> TestRandom<T> for $type {
fn random_for_test(rng: &mut T) -> Self {
$type::from(u64::random_for_test(rng))
@ -545,6 +565,7 @@ macro_rules! all_tests {
math_between_tests!($type, $type);
math_tests!($type);
ssz_tests!($type);
cached_tree_hash_tests!($type);
mod u64_tests {
use super::*;

View File

@ -32,3 +32,29 @@ macro_rules! ssz_tests {
}
};
}
#[cfg(test)]
#[macro_export]
macro_rules! cached_tree_hash_tests {
($type: ident) => {
#[test]
pub fn test_cached_tree_hash() {
use crate::test_utils::{SeedableRng, TestRandom, XorShiftRng};
use tree_hash::TreeHash;
let mut rng = XorShiftRng::from_seed([42; 16]);
let original = $type::random_for_test(&mut rng);
let mut hasher = cached_tree_hash::CachedTreeHasher::new(&original).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), original.tree_hash_root());
let modified = $type::random_for_test(&mut rng);
hasher.update(&modified).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), modified.tree_hash_root());
}
};
}

View File

@ -7,7 +7,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// The data submitted to the deposit contract.
///
@ -20,6 +20,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
Derivative,
@ -42,4 +43,5 @@ mod tests {
use super::*;
ssz_tests!(Transfer);
cached_tree_hash_tests!(Transfer);
}

View File

@ -108,3 +108,25 @@ where
Vec::random_for_test(rng).into()
}
}
#[cfg(test)]
mod test {
use super::*;
use tree_hash::TreeHash;
#[test]
pub fn test_cached_tree_hash() {
let original = TreeHashVector::from(vec![1_u64, 2, 3, 4]);
let mut hasher = cached_tree_hash::CachedTreeHasher::new(&original).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), original.tree_hash_root());
let modified = TreeHashVector::from(vec![1_u64, 1, 1, 1]);
hasher.update(&modified).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), modified.tree_hash_root());
}
}

View File

@ -3,12 +3,23 @@ use rand::RngCore;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use tree_hash_derive::{CachedTreeHash, TreeHash};
/// Information about a `BeaconChain` validator.
///
/// Spec v0.5.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
#[derive(
Debug,
Clone,
PartialEq,
Serialize,
Deserialize,
Encode,
Decode,
TestRandom,
TreeHash,
CachedTreeHash,
)]
pub struct Validator {
pub pubkey: PublicKey,
pub withdrawal_credentials: Hash256,
@ -111,4 +122,5 @@ mod tests {
}
ssz_tests!(Validator);
cached_tree_hash_tests!(Validator);
}

View File

@ -5,7 +5,7 @@ use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
use tree_hash_derive::{SignedRoot, TreeHash};
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
/// An exit voluntarily submitted a validator who wishes to withdraw.
///
@ -19,6 +19,7 @@ use tree_hash_derive::{SignedRoot, TreeHash};
Encode,
Decode,
TreeHash,
CachedTreeHash,
TestRandom,
SignedRoot,
)]
@ -34,4 +35,5 @@ mod tests {
use super::*;
ssz_tests!(VoluntaryExit);
cached_tree_hash_tests!(VoluntaryExit);
}

View File

@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
bls-aggregates = { git = "https://github.com/sigp/signature-schemes", tag = "0.6.1" }
cached_tree_hash = { path = "../cached_tree_hash" }
hashing = { path = "../hashing" }
hex = "0.3"
serde = "1.0"

View File

@ -2,6 +2,7 @@ use super::{AggregatePublicKey, Signature, BLS_AGG_SIG_BYTE_SIZE};
use bls_aggregates::{
AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature,
};
use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode as hex_encode, HexVisitor};
@ -167,6 +168,7 @@ impl<'de> Deserialize<'de> for AggregateSignature {
}
tree_hash_ssz_encoding_as_vector!(AggregateSignature);
cached_tree_hash_ssz_encoding_as_vector!(AggregateSignature, 96);
#[cfg(test)]
mod tests {

View File

@ -1,4 +1,5 @@
use super::{fake_signature::FakeSignature, AggregatePublicKey, BLS_AGG_SIG_BYTE_SIZE};
use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode as hex_encode, PrefixedHexVisitor};
@ -100,6 +101,7 @@ impl<'de> Deserialize<'de> for FakeAggregateSignature {
}
tree_hash_ssz_encoding_as_vector!(FakeAggregateSignature);
cached_tree_hash_ssz_encoding_as_vector!(FakeAggregateSignature, 96);
#[cfg(test)]
mod tests {

View File

@ -1,4 +1,5 @@
use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE};
use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector;
use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
@ -75,6 +76,7 @@ impl Decodable for FakeSignature {
}
tree_hash_ssz_encoding_as_vector!(FakeSignature);
cached_tree_hash_ssz_encoding_as_vector!(FakeSignature, 96);
impl Serialize for FakeSignature {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@ -1,5 +1,6 @@
use super::{SecretKey, BLS_PUBLIC_KEY_BYTE_SIZE};
use bls_aggregates::PublicKey as RawPublicKey;
use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode as hex_encode, HexVisitor};
@ -106,6 +107,7 @@ impl<'de> Deserialize<'de> for PublicKey {
}
tree_hash_ssz_encoding_as_vector!(PublicKey);
cached_tree_hash_ssz_encoding_as_vector!(PublicKey, 48);
impl PartialEq for PublicKey {
fn eq(&self, other: &PublicKey) -> bool {
@ -129,6 +131,7 @@ impl Hash for PublicKey {
mod tests {
use super::*;
use ssz::ssz_encode;
use tree_hash::TreeHash;
#[test]
pub fn test_ssz_round_trip() {
@ -140,4 +143,21 @@ mod tests {
assert_eq!(original, decoded);
}
#[test]
pub fn test_cached_tree_hash() {
let sk = SecretKey::random();
let original = PublicKey::from_secret_key(&sk);
let mut hasher = cached_tree_hash::CachedTreeHasher::new(&original).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), original.tree_hash_root());
let sk = SecretKey::random();
let modified = PublicKey::from_secret_key(&sk);
hasher.update(&modified).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), modified.tree_hash_root());
}
}

View File

@ -1,5 +1,6 @@
use super::{PublicKey, SecretKey, BLS_SIG_BYTE_SIZE};
use bls_aggregates::Signature as RawSignature;
use cached_tree_hash::cached_tree_hash_ssz_encoding_as_vector;
use hex::encode as hex_encode;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
@ -116,6 +117,7 @@ impl Decodable for Signature {
}
tree_hash_ssz_encoding_as_vector!(Signature);
cached_tree_hash_ssz_encoding_as_vector!(Signature, 96);
impl Serialize for Signature {
/// Serde serialization is compliant the Ethereum YAML test format.
@ -145,6 +147,7 @@ mod tests {
use super::super::Keypair;
use super::*;
use ssz::ssz_encode;
use tree_hash::TreeHash;
#[test]
pub fn test_ssz_round_trip() {
@ -158,6 +161,22 @@ mod tests {
assert_eq!(original, decoded);
}
#[test]
pub fn test_cached_tree_hash() {
let keypair = Keypair::random();
let original = Signature::new(&[42, 42], 0, &keypair.sk);
let mut hasher = cached_tree_hash::CachedTreeHasher::new(&original).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), original.tree_hash_root());
let modified = Signature::new(&[99, 99], 0, &keypair.sk);
hasher.update(&modified).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), modified.tree_hash_root());
}
#[test]
pub fn test_empty_signature() {
let sig = Signature::empty_signature();

View File

@ -5,6 +5,7 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
cached_tree_hash = { path = "../cached_tree_hash" }
serde_hex = { path = "../serde_hex" }
ssz = { path = "../ssz" }
bit-vec = "0.5.0"

View File

@ -3,6 +3,7 @@ extern crate ssz;
use bit_reverse::LookupReverse;
use bit_vec::BitVec;
use cached_tree_hash::cached_tree_hash_bytes_as_list;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use serde_hex::{encode, PrefixedHexVisitor};
@ -270,11 +271,31 @@ impl tree_hash::TreeHash for BooleanBitfield {
}
}
cached_tree_hash_bytes_as_list!(BooleanBitfield);
#[cfg(test)]
mod tests {
use super::*;
use serde_yaml;
use ssz::{decode, ssz_encode, SszStream};
use tree_hash::TreeHash;
#[test]
pub fn test_cached_tree_hash() {
let original = BooleanBitfield::from_bytes(&vec![18; 12][..]);
let mut hasher = cached_tree_hash::CachedTreeHasher::new(&original).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), original.tree_hash_root());
/*
let modified = BooleanBitfield::from_bytes(&vec![2; 1][..]);
hasher.update(&modified).unwrap();
assert_eq!(hasher.tree_hash_root().unwrap(), modified.tree_hash_root());
*/
}
#[test]
fn test_new_bitfield() {

View File

@ -1,12 +1,46 @@
use super::*;
use crate::merkleize::merkleize;
use ethereum_types::H256;
pub mod vec;
impl CachedTreeHash<u64> for u64 {
macro_rules! impl_for_single_leaf_int {
($type: ident) => {
impl CachedTreeHash<$type> for $type {
fn new_tree_hash_cache(&self, _depth: usize) -> Result<TreeHashCache, Error> {
Ok(TreeHashCache::from_bytes(
merkleize(self.to_le_bytes().to_vec()),
false,
None,
)?)
}
fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema {
BTreeSchema::from_lengths(depth, vec![1])
}
fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> {
let leaf = merkleize(self.to_le_bytes().to_vec());
cache.maybe_update_chunk(cache.chunk_index, &leaf)?;
cache.chunk_index += 1;
Ok(())
}
}
};
}
impl_for_single_leaf_int!(u8);
impl_for_single_leaf_int!(u16);
impl_for_single_leaf_int!(u32);
impl_for_single_leaf_int!(u64);
impl_for_single_leaf_int!(usize);
impl CachedTreeHash<bool> for bool {
fn new_tree_hash_cache(&self, _depth: usize) -> Result<TreeHashCache, Error> {
Ok(TreeHashCache::from_bytes(
merkleize(self.to_le_bytes().to_vec()),
merkleize((*self as u8).to_le_bytes().to_vec()),
false,
None,
)?)
@ -17,20 +51,19 @@ impl CachedTreeHash<u64> for u64 {
}
fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> {
let leaf = merkleize(self.to_le_bytes().to_vec());
let leaf = merkleize((*self as u8).to_le_bytes().to_vec());
cache.maybe_update_chunk(cache.chunk_index, &leaf)?;
cache.chunk_index += 1;
// cache.overlay_index += 1;
Ok(())
}
}
impl CachedTreeHash<usize> for usize {
impl CachedTreeHash<[u8; 4]> for [u8; 4] {
fn new_tree_hash_cache(&self, _depth: usize) -> Result<TreeHashCache, Error> {
Ok(TreeHashCache::from_bytes(
merkleize(self.to_le_bytes().to_vec()),
merkleize(self.to_vec()),
false,
None,
)?)
@ -41,11 +74,33 @@ impl CachedTreeHash<usize> for usize {
}
fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> {
let leaf = merkleize(self.to_le_bytes().to_vec());
let leaf = merkleize(self.to_vec());
cache.maybe_update_chunk(cache.chunk_index, &leaf)?;
cache.chunk_index += 1;
Ok(())
}
}
impl CachedTreeHash<H256> for H256 {
fn new_tree_hash_cache(&self, _depth: usize) -> Result<TreeHashCache, Error> {
Ok(TreeHashCache::from_bytes(
merkleize(self.as_bytes().to_vec()),
false,
None,
)?)
}
fn tree_hash_cache_schema(&self, depth: usize) -> BTreeSchema {
BTreeSchema::from_lengths(depth, vec![1])
}
fn update_tree_hash_cache(&self, cache: &mut TreeHashCache) -> Result<(), Error> {
let leaf = merkleize(self.as_bytes().to_vec());
cache.maybe_update_chunk(cache.chunk_index, &leaf)?;
cache.chunk_index += 1;
// cache.overlay_index += 1;
Ok(())
}

View File

@ -95,6 +95,11 @@ pub fn update_tree_hash_cache<T: CachedTreeHash<T>>(
let old_overlay = cache.get_overlay(cache.schema_index, cache.chunk_index)?;
let new_overlay = BTreeOverlay::new(vec, cache.chunk_index, old_overlay.depth);
dbg!(cache.schema_index);
dbg!(cache.schemas.len());
dbg!(&old_overlay);
dbg!(&new_overlay);
cache.replace_overlay(cache.schema_index, cache.chunk_index, new_overlay.clone())?;
cache.schema_index += 1;

View File

@ -1,4 +1,5 @@
use hashing::hash;
use merkleize::num_unsanitized_leaves;
use std::ops::Range;
use tree_hash::{TreeHash, TreeHashType, BYTES_PER_CHUNK, HASHSIZE};
@ -62,3 +63,92 @@ impl CachedTreeHasher {
Ok(self.cache.root()?.to_vec())
}
}
#[macro_export]
macro_rules! cached_tree_hash_ssz_encoding_as_vector {
($type: ident, $num_bytes: expr) => {
impl cached_tree_hash::CachedTreeHash<$type> for $type {
fn new_tree_hash_cache(
&self,
depth: usize,
) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
let (cache, _schema) = cached_tree_hash::impls::vec::new_tree_hash_cache(
&ssz::ssz_encode(self),
depth,
)?;
Ok(cache)
}
fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema {
let lengths =
vec![1; cached_tree_hash::merkleize::num_unsanitized_leaves($num_bytes)];
cached_tree_hash::BTreeSchema::from_lengths(depth, lengths)
}
fn update_tree_hash_cache(
&self,
cache: &mut cached_tree_hash::TreeHashCache,
) -> Result<(), cached_tree_hash::Error> {
cached_tree_hash::impls::vec::update_tree_hash_cache(
&ssz::ssz_encode(self),
cache,
)?;
Ok(())
}
}
};
}
#[macro_export]
macro_rules! cached_tree_hash_bytes_as_list {
($type: ident) => {
impl cached_tree_hash::CachedTreeHash<$type> for $type {
fn new_tree_hash_cache(
&self,
depth: usize,
) -> Result<cached_tree_hash::TreeHashCache, cached_tree_hash::Error> {
let bytes = self.to_bytes();
let (mut cache, schema) =
cached_tree_hash::impls::vec::new_tree_hash_cache(&bytes, depth)?;
cache.add_length_nodes(schema.into_overlay(0).chunk_range(), bytes.len())?;
Ok(cache)
}
fn num_tree_hash_cache_chunks(&self) -> usize {
// Add two extra nodes to cater for the node before and after to allow mixing-in length.
cached_tree_hash::BTreeOverlay::new(self, 0, 0).num_chunks() + 2
}
fn tree_hash_cache_schema(&self, depth: usize) -> cached_tree_hash::BTreeSchema {
cached_tree_hash::impls::vec::produce_schema(&ssz::ssz_encode(self), depth)
}
fn update_tree_hash_cache(
&self,
cache: &mut cached_tree_hash::TreeHashCache,
) -> Result<(), cached_tree_hash::Error> {
let bytes = self.to_bytes();
// Skip the length-mixed-in root node.
cache.chunk_index += 1;
// Update the cache, returning the new overlay.
let new_overlay =
cached_tree_hash::impls::vec::update_tree_hash_cache(&bytes, cache)?;
// Mix in length
cache.mix_in_length(new_overlay.chunk_range(), bytes.len())?;
// Skip an extra node to clear the length node.
cache.chunk_index = new_overlay.next_node() + 1;
Ok(())
}
}
};
}

View File

@ -60,7 +60,7 @@ fn last_leaf_needs_padding(num_bytes: usize) -> bool {
}
/// Rounds up
fn num_unsanitized_leaves(num_bytes: usize) -> usize {
pub fn num_unsanitized_leaves(num_bytes: usize) -> usize {
(num_bytes + HASHSIZE - 1) / HASHSIZE
}

View File

@ -231,6 +231,41 @@ pub struct StructWithVecOfStructs {
pub c: Vec<Inner>,
}
fn get_inners() -> Vec<Inner> {
vec![
Inner {
a: 12,
b: 13,
c: 14,
d: 15,
},
Inner {
a: 99,
b: 100,
c: 101,
d: 102,
},
Inner {
a: 255,
b: 256,
c: 257,
d: 0,
},
Inner {
a: 1000,
b: 2000,
c: 3000,
d: 0,
},
Inner {
a: 0,
b: 0,
c: 0,
d: 0,
},
]
}
fn get_struct_with_vec_of_structs() -> Vec<StructWithVecOfStructs> {
let inner_a = Inner {
a: 12,
@ -342,6 +377,56 @@ fn test_struct_with_vec_of_struct_with_vec_of_structs() {
}
}
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
pub struct StructWithTwoVecs {
pub a: Vec<Inner>,
pub b: Vec<Inner>,
}
#[test]
fn test_struct_with_two_vecs() {
let inners = get_inners();
let variants = vec![
StructWithTwoVecs {
a: inners[..].to_vec(),
b: inners[..].to_vec(),
},
StructWithTwoVecs {
a: inners[0..1].to_vec(),
b: inners[..].to_vec(),
},
StructWithTwoVecs {
a: inners[0..1].to_vec(),
b: inners[0..2].to_vec(),
},
StructWithTwoVecs {
a: inners[0..4].to_vec(),
b: inners[0..2].to_vec(),
},
StructWithTwoVecs {
a: vec![],
b: inners[..].to_vec(),
},
StructWithTwoVecs {
a: inners[..].to_vec(),
b: vec![],
},
StructWithTwoVecs {
a: inners[0..3].to_vec(),
b: inners[0..1].to_vec(),
},
];
test_routine(variants[0].clone(), variants[6..7].to_vec());
/*
for v in &variants {
test_routine(v.clone(), variants.clone());
}
*/
}
#[derive(Clone, Debug, TreeHash, CachedTreeHash)]
pub struct Inner {
pub a: u64,

View File

@ -52,7 +52,7 @@ impl TreeHash for bool {
impl TreeHash for [u8; 4] {
fn tree_hash_type() -> TreeHashType {
TreeHashType::List
TreeHashType::Vector
}
fn tree_hash_packed_encoding(&self) -> Vec<u8> {