diff --git a/Cargo.toml b/Cargo.toml index c05e22286..37ec4ad0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "eth2/utils/bls", "eth2/utils/boolean-bitfield", "eth2/utils/cached_tree_hash", + "eth2/utils/fixed_len_vec", "eth2/utils/hashing", "eth2/utils/honey-badger-split", "eth2/utils/merkle_proof", diff --git a/eth2/types/Cargo.toml b/eth2/types/Cargo.toml index a2bd08d61..160697edd 100644 --- a/eth2/types/Cargo.toml +++ b/eth2/types/Cargo.toml @@ -11,6 +11,7 @@ cached_tree_hash = { path = "../utils/cached_tree_hash" } dirs = "1.0" derivative = "1.0" ethereum-types = "0.5" +fixed_len_vec = { path = "../utils/fixed_len_vec" } hashing = { path = "../utils/hashing" } hex = "0.3" honey-badger-split = { path = "../utils/honey-badger-split" } @@ -29,7 +30,6 @@ swap_or_not_shuffle = { path = "../utils/swap_or_not_shuffle" } test_random_derive = { path = "../utils/test_random_derive" } tree_hash = { path = "../utils/tree_hash" } tree_hash_derive = { path = "../utils/tree_hash_derive" } -typenum = "1.10" libp2p = { git = "https://github.com/SigP/rust-libp2p", rev = "b3c32d9a821ae6cc89079499cc6e8a6bab0bffc3" } [dev-dependencies] diff --git a/eth2/types/src/attestation.rs b/eth2/types/src/attestation.rs index d1511763d..d6d5d3a22 100644 --- a/eth2/types/src/attestation.rs +++ b/eth2/types/src/attestation.rs @@ -1,6 +1,6 @@ use super::{AggregateSignature, AttestationData, Bitfield}; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/attestation_data.rs b/eth2/types/src/attestation_data.rs index c963d6001..60e539ab8 100644 --- a/eth2/types/src/attestation_data.rs +++ b/eth2/types/src/attestation_data.rs @@ -1,6 +1,6 @@ use crate::test_utils::TestRandom; use crate::{Crosslink, Epoch, Hash256, Slot}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/attestation_data_and_custody_bit.rs b/eth2/types/src/attestation_data_and_custody_bit.rs index 85a5875ab..f1437cb54 100644 --- a/eth2/types/src/attestation_data_and_custody_bit.rs +++ b/eth2/types/src/attestation_data_and_custody_bit.rs @@ -1,5 +1,6 @@ use super::AttestationData; use crate::test_utils::TestRandom; + use rand::RngCore; use serde_derive::Serialize; use ssz_derive::{Decode, Encode}; @@ -14,8 +15,8 @@ pub struct AttestationDataAndCustodyBit { pub custody_bit: bool, } -impl TestRandom for AttestationDataAndCustodyBit { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for AttestationDataAndCustodyBit { + fn random_for_test(rng: &mut impl RngCore) -> Self { Self { data: <_>::random_for_test(rng), custody_bit: <_>::random_for_test(rng), diff --git a/eth2/types/src/attester_slashing.rs b/eth2/types/src/attester_slashing.rs index d4848b01c..d7b5d5942 100644 --- a/eth2/types/src/attester_slashing.rs +++ b/eth2/types/src/attester_slashing.rs @@ -1,5 +1,5 @@ use crate::{test_utils::TestRandom, SlashableAttestation}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/beacon_block.rs b/eth2/types/src/beacon_block.rs index d198d16fc..33d73db16 100644 --- a/eth2/types/src/beacon_block.rs +++ b/eth2/types/src/beacon_block.rs @@ -1,7 +1,7 @@ use crate::test_utils::TestRandom; use crate::*; use bls::Signature; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/beacon_block_body.rs b/eth2/types/src/beacon_block_body.rs index 15ba00d6b..867db78c4 100644 --- a/eth2/types/src/beacon_block_body.rs +++ b/eth2/types/src/beacon_block_body.rs @@ -1,6 +1,6 @@ use crate::test_utils::TestRandom; use crate::*; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/beacon_block_header.rs b/eth2/types/src/beacon_block_header.rs index 5b35da1b6..601346db5 100644 --- a/eth2/types/src/beacon_block_header.rs +++ b/eth2/types/src/beacon_block_header.rs @@ -1,7 +1,7 @@ use crate::test_utils::TestRandom; use crate::*; use bls::Signature; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/beacon_state.rs b/eth2/types/src/beacon_state.rs index 29c9d9b31..46c4ae87d 100644 --- a/eth2/types/src/beacon_state.rs +++ b/eth2/types/src/beacon_state.rs @@ -4,7 +4,8 @@ use crate::*; use cached_tree_hash::{Error as TreeHashCacheError, TreeHashCache}; use int_to_bytes::int_to_bytes32; use pubkey_cache::PubkeyCache; -use rand::RngCore; + +use fixed_len_vec::FixedLenVec; use serde_derive::{Deserialize, Serialize}; use ssz::{hash, ssz_encode}; use ssz_derive::{Decode, Encode}; @@ -12,8 +13,10 @@ use test_random_derive::TestRandom; use tree_hash::TreeHash; use tree_hash_derive::{CachedTreeHash, TreeHash}; +pub use beacon_state_types::{BeaconStateTypes, FoundationBeaconState}; + +mod beacon_state_types; mod epoch_cache; -mod fixed_params; mod pubkey_cache; mod tests; @@ -62,7 +65,10 @@ pub enum Error { TreeHash, CachedTreeHash, )] -pub struct BeaconState { +pub struct BeaconState +where + T: BeaconStateTypes, +{ // Misc pub slot: Slot, pub genesis_time: u64, @@ -74,7 +80,7 @@ pub struct BeaconState { pub validator_registry_update_epoch: Epoch, // Randomness and committees - pub latest_randao_mixes: TreeHashVector, + pub latest_randao_mixes: FixedLenVec, pub previous_shuffling_start_shard: u64, pub current_shuffling_start_shard: u64, pub previous_shuffling_epoch: Epoch, @@ -134,14 +140,18 @@ pub struct BeaconState { pub tree_hash_cache: TreeHashCache, } -impl BeaconState { +impl BeaconState { /// Produce the first state of the Beacon Chain. /// /// This does not fully build a genesis beacon state, it omits processing of initial validator /// deposits. To obtain a full genesis beacon state, use the `BeaconStateBuilder`. /// /// Spec v0.5.1 - pub fn genesis(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> BeaconState { + pub fn genesis( + genesis_time: u64, + latest_eth1_data: Eth1Data, + spec: &ChainSpec, + ) -> BeaconState { let initial_crosslink = Crosslink { epoch: spec.genesis_epoch, crosslink_data_root: spec.zero_hash, @@ -425,7 +435,8 @@ impl BeaconState { & (epoch <= current_epoch) { let i = epoch.as_usize() % spec.latest_randao_mixes_length; - if i < self.latest_randao_mixes.len() { + + if i < (&self.latest_randao_mixes[..]).len() { Ok(i) } else { Err(Error::InsufficientRandaoMixes) diff --git a/eth2/types/src/beacon_state/beacon_state_types.rs b/eth2/types/src/beacon_state/beacon_state_types.rs new file mode 100644 index 000000000..63c038575 --- /dev/null +++ b/eth2/types/src/beacon_state/beacon_state_types.rs @@ -0,0 +1,15 @@ +use crate::*; +use fixed_len_vec::typenum::{Unsigned, U8192}; + +pub trait BeaconStateTypes { + type NumLatestRandaoMixes: Unsigned + Clone + Sync + Send; +} + +#[derive(Clone, PartialEq, Debug)] +pub struct FoundationStateParams; + +impl BeaconStateTypes for FoundationStateParams { + type NumLatestRandaoMixes = U8192; +} + +pub type FoundationBeaconState = BeaconState; diff --git a/eth2/types/src/beacon_state/epoch_cache.rs b/eth2/types/src/beacon_state/epoch_cache.rs index 1a63e9eb9..31becc5d3 100644 --- a/eth2/types/src/beacon_state/epoch_cache.rs +++ b/eth2/types/src/beacon_state/epoch_cache.rs @@ -28,8 +28,8 @@ pub struct EpochCache { impl EpochCache { /// Return a new, fully initialized cache. - pub fn initialized( - state: &BeaconState, + pub fn initialized( + state: &BeaconState, relative_epoch: RelativeEpoch, spec: &ChainSpec, ) -> Result { @@ -200,8 +200,8 @@ pub struct EpochCrosslinkCommitteesBuilder { impl EpochCrosslinkCommitteesBuilder { /// Instantiates a builder that will build for the `state`'s previous epoch. - pub fn for_previous_epoch( - state: &BeaconState, + pub fn for_previous_epoch( + state: &BeaconState, active_validator_indices: Vec, spec: &ChainSpec, ) -> Self { @@ -215,8 +215,8 @@ impl EpochCrosslinkCommitteesBuilder { } /// Instantiates a builder that will build for the `state`'s next epoch. - pub fn for_current_epoch( - state: &BeaconState, + pub fn for_current_epoch( + state: &BeaconState, active_validator_indices: Vec, spec: &ChainSpec, ) -> Self { @@ -233,8 +233,8 @@ impl EpochCrosslinkCommitteesBuilder { /// /// Note: there are two possible epoch builds for the next epoch, one where there is a registry /// change and one where there is not. - pub fn for_next_epoch( - state: &BeaconState, + pub fn for_next_epoch( + state: &BeaconState, active_validator_indices: Vec, registry_change: bool, spec: &ChainSpec, diff --git a/eth2/types/src/beacon_state/epoch_cache/tests.rs b/eth2/types/src/beacon_state/epoch_cache/tests.rs index 5b1e53338..e196560a3 100644 --- a/eth2/types/src/beacon_state/epoch_cache/tests.rs +++ b/eth2/types/src/beacon_state/epoch_cache/tests.rs @@ -4,8 +4,8 @@ use super::*; use crate::test_utils::*; use swap_or_not_shuffle::shuffle_list; -fn do_sane_cache_test( - state: BeaconState, +fn do_sane_cache_test( + state: BeaconState, epoch: Epoch, relative_epoch: RelativeEpoch, validator_count: usize, @@ -64,7 +64,10 @@ fn do_sane_cache_test( } } -fn setup_sane_cache_test(validator_count: usize, spec: &ChainSpec) -> BeaconState { +fn setup_sane_cache_test( + validator_count: usize, + spec: &ChainSpec, +) -> BeaconState { let mut builder = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(validator_count, spec); @@ -101,7 +104,7 @@ fn builds_sane_current_epoch_cache() { let mut spec = ChainSpec::few_validators(); spec.shard_count = 4; let validator_count = (spec.shard_count * spec.target_committee_size) + 1; - let state = setup_sane_cache_test(validator_count as usize, &spec); + let state: FoundationBeaconState = setup_sane_cache_test(validator_count as usize, &spec); do_sane_cache_test( state.clone(), state.current_epoch(&spec), @@ -118,7 +121,7 @@ fn builds_sane_previous_epoch_cache() { let mut spec = ChainSpec::few_validators(); spec.shard_count = 2; let validator_count = (spec.shard_count * spec.target_committee_size) + 1; - let state = setup_sane_cache_test(validator_count as usize, &spec); + let state: FoundationBeaconState = setup_sane_cache_test(validator_count as usize, &spec); do_sane_cache_test( state.clone(), state.previous_epoch(&spec), @@ -135,7 +138,7 @@ fn builds_sane_next_without_update_epoch_cache() { let mut spec = ChainSpec::few_validators(); spec.shard_count = 2; let validator_count = (spec.shard_count * spec.target_committee_size) + 1; - let mut state = setup_sane_cache_test(validator_count as usize, &spec); + let mut state: FoundationBeaconState = setup_sane_cache_test(validator_count as usize, &spec); state.validator_registry_update_epoch = state.slot.epoch(spec.slots_per_epoch); do_sane_cache_test( state.clone(), diff --git a/eth2/types/src/beacon_state/tests.rs b/eth2/types/src/beacon_state/tests.rs index d5862559a..759061498 100644 --- a/eth2/types/src/beacon_state/tests.rs +++ b/eth2/types/src/beacon_state/tests.rs @@ -2,16 +2,16 @@ use super::*; use crate::test_utils::*; -ssz_tests!(BeaconState); -cached_tree_hash_tests!(BeaconState); +ssz_tests!(FoundationBeaconState); +cached_tree_hash_tests!(FoundationBeaconState); /// Test that /// /// 1. Using the cache before it's built fails. /// 2. Using the cache after it's build passes. /// 3. Using the cache after it's dropped fails. -fn test_cache_initialization<'a>( - state: &'a mut BeaconState, +fn test_cache_initialization<'a, T: BeaconStateTypes>( + state: &'a mut BeaconState, relative_epoch: RelativeEpoch, spec: &ChainSpec, ) { @@ -46,7 +46,7 @@ fn test_cache_initialization<'a>( #[test] fn cache_initialization() { let spec = ChainSpec::few_validators(); - let (mut state, _keypairs) = + let (mut state, _keypairs): (FoundationBeaconState, Vec) = TestingBeaconStateBuilder::from_default_keypairs_file_if_exists(16, &spec).build(); state.slot = (spec.genesis_epoch + 1).start_slot(spec.slots_per_epoch); @@ -64,7 +64,7 @@ fn tree_hash_cache() { let mut rng = XorShiftRng::from_seed([42; 16]); - let mut state = BeaconState::random_for_test(&mut rng); + let mut state: FoundationBeaconState = BeaconState::random_for_test(&mut rng); let root = state.update_tree_hash_cache().unwrap(); diff --git a/eth2/types/src/crosslink.rs b/eth2/types/src/crosslink.rs index 448f5ea30..cb3ce5615 100644 --- a/eth2/types/src/crosslink.rs +++ b/eth2/types/src/crosslink.rs @@ -1,6 +1,6 @@ use crate::test_utils::TestRandom; use crate::{Epoch, Hash256}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/deposit.rs b/eth2/types/src/deposit.rs index e8d2f5a4b..1f5d90fab 100644 --- a/eth2/types/src/deposit.rs +++ b/eth2/types/src/deposit.rs @@ -1,6 +1,6 @@ use super::{DepositData, Hash256, TreeHashVector}; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/deposit_data.rs b/eth2/types/src/deposit_data.rs index 38c44d1a7..bee1d503e 100644 --- a/eth2/types/src/deposit_data.rs +++ b/eth2/types/src/deposit_data.rs @@ -1,6 +1,6 @@ use super::DepositInput; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/deposit_input.rs b/eth2/types/src/deposit_input.rs index af1049a20..f44c75f5a 100644 --- a/eth2/types/src/deposit_input.rs +++ b/eth2/types/src/deposit_input.rs @@ -1,7 +1,7 @@ use crate::test_utils::TestRandom; use crate::*; use bls::{PublicKey, Signature}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/eth1_data.rs b/eth2/types/src/eth1_data.rs index 3c0c3af02..aaf5bca54 100644 --- a/eth2/types/src/eth1_data.rs +++ b/eth2/types/src/eth1_data.rs @@ -1,6 +1,6 @@ use super::Hash256; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/eth1_data_vote.rs b/eth2/types/src/eth1_data_vote.rs index 00818ebf4..27cb0be78 100644 --- a/eth2/types/src/eth1_data_vote.rs +++ b/eth2/types/src/eth1_data_vote.rs @@ -1,6 +1,6 @@ use super::Eth1Data; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/fork.rs b/eth2/types/src/fork.rs index 83d4f5dc6..3e7254dd3 100644 --- a/eth2/types/src/fork.rs +++ b/eth2/types/src/fork.rs @@ -3,7 +3,7 @@ use crate::{ ChainSpec, Epoch, }; use int_to_bytes::int_to_bytes4; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/historical_batch.rs b/eth2/types/src/historical_batch.rs index 13e57131a..3f8baabbc 100644 --- a/eth2/types/src/historical_batch.rs +++ b/eth2/types/src/historical_batch.rs @@ -1,6 +1,6 @@ use crate::test_utils::TestRandom; use crate::{Hash256, TreeHashVector}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/lib.rs b/eth2/types/src/lib.rs index 070ed6745..efe7f2327 100644 --- a/eth2/types/src/lib.rs +++ b/eth2/types/src/lib.rs @@ -36,6 +36,7 @@ pub mod slot_epoch; pub mod slot_height; pub mod validator; +use beacon_state::FoundationBeaconState; use ethereum_types::{H160, H256, U256}; use std::collections::HashMap; @@ -47,7 +48,7 @@ pub use crate::attester_slashing::AttesterSlashing; pub use crate::beacon_block::BeaconBlock; pub use crate::beacon_block_body::BeaconBlockBody; pub use crate::beacon_block_header::BeaconBlockHeader; -pub use crate::beacon_state::{BeaconState, Error as BeaconStateError}; +pub use crate::beacon_state::{BeaconState, BeaconStateTypes, Error as BeaconStateError}; pub use crate::chain_spec::{ChainSpec, Domain}; pub use crate::crosslink::Crosslink; pub use crate::crosslink_committee::CrosslinkCommittee; @@ -87,6 +88,7 @@ pub type AttesterMap = HashMap<(u64, u64), Vec>; pub type ProposerMap = HashMap; pub use bls::{AggregatePublicKey, AggregateSignature, Keypair, PublicKey, SecretKey, Signature}; +pub use fixed_len_vec::FixedLenVec; pub use libp2p::floodsub::{Topic, TopicBuilder, TopicHash}; pub use libp2p::multiaddr; pub use libp2p::Multiaddr; diff --git a/eth2/types/src/pending_attestation.rs b/eth2/types/src/pending_attestation.rs index b71351f9a..b158f1274 100644 --- a/eth2/types/src/pending_attestation.rs +++ b/eth2/types/src/pending_attestation.rs @@ -1,6 +1,6 @@ use crate::test_utils::TestRandom; use crate::{Attestation, AttestationData, Bitfield, Slot}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/proposer_slashing.rs b/eth2/types/src/proposer_slashing.rs index bf26ae508..0c419dd56 100644 --- a/eth2/types/src/proposer_slashing.rs +++ b/eth2/types/src/proposer_slashing.rs @@ -1,6 +1,6 @@ use super::BeaconBlockHeader; use crate::test_utils::TestRandom; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/slashable_attestation.rs b/eth2/types/src/slashable_attestation.rs index fb838e0c4..19d9a87b6 100644 --- a/eth2/types/src/slashable_attestation.rs +++ b/eth2/types/src/slashable_attestation.rs @@ -1,5 +1,5 @@ use crate::{test_utils::TestRandom, AggregateSignature, AttestationData, Bitfield, ChainSpec}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/slot_epoch.rs b/eth2/types/src/slot_epoch.rs index 6c6a92ecb..7f1f704ca 100644 --- a/eth2/types/src/slot_epoch.rs +++ b/eth2/types/src/slot_epoch.rs @@ -1,15 +1,16 @@ +//! The `Slot` and `Epoch` types are defined as newtypes over u64 to enforce type-safety between +//! the two types. +//! +//! `Slot` and `Epoch` have implementations which permit conversion, comparison and math operations +//! between each and `u64`, however specifically not between each other. +//! +//! All math operations on `Slot` and `Epoch` are saturating, they never wrap. +//! +//! It would be easy to define `PartialOrd` and other traits generically across all types which +//! implement `Into`, however this would allow operations between `Slots` and `Epochs` which +//! may lead to programming errors which are not detected by the compiler. + use crate::slot_height::SlotHeight; -/// The `Slot` and `Epoch` types are defined as newtypes over u64 to enforce type-safety between -/// the two types. -/// -/// `Slot` and `Epoch` have implementations which permit conversion, comparison and math operations -/// between each and `u64`, however specifically not between each other. -/// -/// All math operations on `Slot` and `Epoch` are saturating, they never wrap. -/// -/// It would be easy to define `PartialOrd` and other traits generically across all types which -/// implement `Into`, however this would allow operations between `Slots` and `Epochs` which -/// may lead to programming errors which are not detected by the compiler. use crate::test_utils::TestRandom; use rand::RngCore; use serde_derive::{Deserialize, Serialize}; diff --git a/eth2/types/src/slot_epoch_macros.rs b/eth2/types/src/slot_epoch_macros.rs index 4a48bba9f..076efbb77 100644 --- a/eth2/types/src/slot_epoch_macros.rs +++ b/eth2/types/src/slot_epoch_macros.rs @@ -244,8 +244,8 @@ macro_rules! impl_ssz { } } - impl TestRandom for $type { - fn random_for_test(rng: &mut T) -> Self { + impl TestRandom for $type { + fn random_for_test(rng: &mut impl RngCore) -> Self { $type::from(u64::random_for_test(rng)) } } diff --git a/eth2/types/src/slot_height.rs b/eth2/types/src/slot_height.rs index f7a34cbba..b0d5d65d9 100644 --- a/eth2/types/src/slot_height.rs +++ b/eth2/types/src/slot_height.rs @@ -1,5 +1,6 @@ use crate::slot_epoch::{Epoch, Slot}; use crate::test_utils::TestRandom; + use rand::RngCore; use serde_derive::Serialize; use ssz::{ssz_encode, Decodable, DecodeError, Encodable, SszStream}; diff --git a/eth2/types/src/test_utils/test_random.rs b/eth2/types/src/test_utils/test_random.rs index 2d4269b08..ceb785424 100644 --- a/eth2/types/src/test_utils/test_random.rs +++ b/eth2/types/src/test_utils/test_random.rs @@ -1,3 +1,5 @@ +use crate::*; +use fixed_len_vec::typenum::Unsigned; use rand::RngCore; mod address; @@ -8,42 +10,39 @@ mod public_key; mod secret_key; mod signature; -pub trait TestRandom -where - T: RngCore, -{ - fn random_for_test(rng: &mut T) -> Self; +pub trait TestRandom { + fn random_for_test(rng: &mut impl RngCore) -> Self; } -impl TestRandom for bool { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for bool { + fn random_for_test(rng: &mut impl RngCore) -> Self { (rng.next_u32() % 2) == 1 } } -impl TestRandom for u64 { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for u64 { + fn random_for_test(rng: &mut impl RngCore) -> Self { rng.next_u64() } } -impl TestRandom for u32 { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for u32 { + fn random_for_test(rng: &mut impl RngCore) -> Self { rng.next_u32() } } -impl TestRandom for usize { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for usize { + fn random_for_test(rng: &mut impl RngCore) -> Self { rng.next_u32() as usize } } -impl TestRandom for Vec +impl TestRandom for Vec where - U: TestRandom, + U: TestRandom, { - fn random_for_test(rng: &mut T) -> Self { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut output = vec![]; for _ in 0..(usize::random_for_test(rng) % 4) { @@ -54,10 +53,25 @@ where } } +impl TestRandom for FixedLenVec +where + T: TestRandom + Default, +{ + fn random_for_test(rng: &mut impl RngCore) -> Self { + let mut output = vec![]; + + for _ in 0..(usize::random_for_test(rng) % std::cmp::min(4, N::to_usize())) { + output.push(::random_for_test(rng)); + } + + output.into() + } +} + macro_rules! impl_test_random_for_u8_array { ($len: expr) => { - impl TestRandom for [u8; $len] { - fn random_for_test(rng: &mut T) -> Self { + impl TestRandom for [u8; $len] { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut bytes = [0; $len]; rng.fill_bytes(&mut bytes); bytes diff --git a/eth2/types/src/test_utils/test_random/address.rs b/eth2/types/src/test_utils/test_random/address.rs index 13de2dec9..3aaad307e 100644 --- a/eth2/types/src/test_utils/test_random/address.rs +++ b/eth2/types/src/test_utils/test_random/address.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use crate::Address; -use rand::RngCore; -impl TestRandom for Address { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Address { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut key_bytes = vec![0; 20]; rng.fill_bytes(&mut key_bytes); Address::from_slice(&key_bytes[..]) diff --git a/eth2/types/src/test_utils/test_random/aggregate_signature.rs b/eth2/types/src/test_utils/test_random/aggregate_signature.rs index 6a15f7366..a346d2d88 100644 --- a/eth2/types/src/test_utils/test_random/aggregate_signature.rs +++ b/eth2/types/src/test_utils/test_random/aggregate_signature.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::{AggregateSignature, Signature}; -use rand::RngCore; -impl TestRandom for AggregateSignature { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for AggregateSignature { + fn random_for_test(rng: &mut impl RngCore) -> Self { let signature = Signature::random_for_test(rng); let mut aggregate_signature = AggregateSignature::new(); aggregate_signature.add(&signature); diff --git a/eth2/types/src/test_utils/test_random/bitfield.rs b/eth2/types/src/test_utils/test_random/bitfield.rs index 9748458f1..9a4d21840 100644 --- a/eth2/types/src/test_utils/test_random/bitfield.rs +++ b/eth2/types/src/test_utils/test_random/bitfield.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use crate::Bitfield; -use rand::RngCore; -impl TestRandom for Bitfield { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Bitfield { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut raw_bytes = vec![0; 32]; rng.fill_bytes(&mut raw_bytes); Bitfield::from_bytes(&raw_bytes) diff --git a/eth2/types/src/test_utils/test_random/hash256.rs b/eth2/types/src/test_utils/test_random/hash256.rs index a227679da..8733f7de2 100644 --- a/eth2/types/src/test_utils/test_random/hash256.rs +++ b/eth2/types/src/test_utils/test_random/hash256.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use crate::Hash256; -use rand::RngCore; -impl TestRandom for Hash256 { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Hash256 { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut key_bytes = vec![0; 32]; rng.fill_bytes(&mut key_bytes); Hash256::from_slice(&key_bytes[..]) diff --git a/eth2/types/src/test_utils/test_random/public_key.rs b/eth2/types/src/test_utils/test_random/public_key.rs index bfccd3e53..d643eaf0b 100644 --- a/eth2/types/src/test_utils/test_random/public_key.rs +++ b/eth2/types/src/test_utils/test_random/public_key.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::{PublicKey, SecretKey}; -use rand::RngCore; -impl TestRandom for PublicKey { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for PublicKey { + fn random_for_test(rng: &mut impl RngCore) -> Self { let secret_key = SecretKey::random_for_test(rng); PublicKey::from_secret_key(&secret_key) } diff --git a/eth2/types/src/test_utils/test_random/secret_key.rs b/eth2/types/src/test_utils/test_random/secret_key.rs index 17481c3de..a833a4488 100644 --- a/eth2/types/src/test_utils/test_random/secret_key.rs +++ b/eth2/types/src/test_utils/test_random/secret_key.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::SecretKey; -use rand::RngCore; -impl TestRandom for SecretKey { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for SecretKey { + fn random_for_test(rng: &mut impl RngCore) -> Self { let mut key_bytes = vec![0; 48]; rng.fill_bytes(&mut key_bytes); /* diff --git a/eth2/types/src/test_utils/test_random/signature.rs b/eth2/types/src/test_utils/test_random/signature.rs index d9995835a..ef5d9a17f 100644 --- a/eth2/types/src/test_utils/test_random/signature.rs +++ b/eth2/types/src/test_utils/test_random/signature.rs @@ -1,9 +1,8 @@ -use super::TestRandom; +use super::*; use bls::{SecretKey, Signature}; -use rand::RngCore; -impl TestRandom for Signature { - fn random_for_test(rng: &mut T) -> Self { +impl TestRandom for Signature { + fn random_for_test(rng: &mut impl RngCore) -> Self { let secret_key = SecretKey::random_for_test(rng); let mut message = vec![0; 32]; rng.fill_bytes(&mut message); diff --git a/eth2/types/src/test_utils/testing_attestation_builder.rs b/eth2/types/src/test_utils/testing_attestation_builder.rs index 162facc8e..2d9b5ac6f 100644 --- a/eth2/types/src/test_utils/testing_attestation_builder.rs +++ b/eth2/types/src/test_utils/testing_attestation_builder.rs @@ -12,8 +12,8 @@ pub struct TestingAttestationBuilder { impl TestingAttestationBuilder { /// Create a new attestation builder. - pub fn new( - state: &BeaconState, + pub fn new( + state: &BeaconState, committee: &[usize], slot: Slot, shard: u64, diff --git a/eth2/types/src/test_utils/testing_attestation_data_builder.rs b/eth2/types/src/test_utils/testing_attestation_data_builder.rs index a270e3859..4cb83a6b8 100644 --- a/eth2/types/src/test_utils/testing_attestation_data_builder.rs +++ b/eth2/types/src/test_utils/testing_attestation_data_builder.rs @@ -10,7 +10,12 @@ pub struct TestingAttestationDataBuilder { impl TestingAttestationDataBuilder { /// Configures a new `AttestationData` which attests to all of the same parameters as the /// state. - pub fn new(state: &BeaconState, shard: u64, slot: Slot, spec: &ChainSpec) -> Self { + pub fn new( + state: &BeaconState, + shard: u64, + slot: Slot, + spec: &ChainSpec, + ) -> Self { let current_epoch = state.current_epoch(spec); let previous_epoch = state.previous_epoch(spec); diff --git a/eth2/types/src/test_utils/testing_beacon_block_builder.rs b/eth2/types/src/test_utils/testing_beacon_block_builder.rs index 549c00ac0..a2ea65949 100644 --- a/eth2/types/src/test_utils/testing_beacon_block_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_block_builder.rs @@ -82,9 +82,9 @@ impl TestingBeaconBlockBuilder { /// /// Note: the signed messages of the split committees will be identical -- it would be possible /// to aggregate these split attestations. - pub fn insert_attestations( + pub fn insert_attestations( &mut self, - state: &BeaconState, + state: &BeaconState, secret_keys: &[&SecretKey], num_attestations: usize, spec: &ChainSpec, @@ -171,11 +171,11 @@ impl TestingBeaconBlockBuilder { } /// Insert a `Valid` deposit into the state. - pub fn insert_deposit( + pub fn insert_deposit( &mut self, amount: u64, index: u64, - state: &BeaconState, + state: &BeaconState, spec: &ChainSpec, ) { let keypair = Keypair::random(); @@ -193,9 +193,9 @@ impl TestingBeaconBlockBuilder { } /// Insert a `Valid` exit into the state. - pub fn insert_exit( + pub fn insert_exit( &mut self, - state: &BeaconState, + state: &BeaconState, validator_index: u64, secret_key: &SecretKey, spec: &ChainSpec, @@ -214,9 +214,9 @@ impl TestingBeaconBlockBuilder { /// /// Note: this will set the validator to be withdrawable by directly modifying the state /// validator registry. This _may_ cause problems historic hashes, etc. - pub fn insert_transfer( + pub fn insert_transfer( &mut self, - state: &BeaconState, + state: &BeaconState, from: u64, to: u64, amount: u64, diff --git a/eth2/types/src/test_utils/testing_beacon_state_builder.rs b/eth2/types/src/test_utils/testing_beacon_state_builder.rs index 9bdd9e149..67f23a44c 100644 --- a/eth2/types/src/test_utils/testing_beacon_state_builder.rs +++ b/eth2/types/src/test_utils/testing_beacon_state_builder.rs @@ -25,12 +25,12 @@ pub fn keypairs_path() -> PathBuf { /// /// This struct should **never be used for production purposes.** #[derive(Clone)] -pub struct TestingBeaconStateBuilder { - state: BeaconState, +pub struct TestingBeaconStateBuilder { + state: BeaconState, keypairs: Vec, } -impl TestingBeaconStateBuilder { +impl TestingBeaconStateBuilder { /// Attempts to load validators from a file in `$HOME/.lighthouse/keypairs.raw_keypairs`. If /// the file is unavailable, it generates the keys at runtime. /// @@ -154,7 +154,7 @@ impl TestingBeaconStateBuilder { } /// Consume the builder and return the `BeaconState` and the keypairs for each validator. - pub fn build(self) -> (BeaconState, Vec) { + pub fn build(self) -> (BeaconState, Vec) { (self.state, self.keypairs) } diff --git a/eth2/types/src/test_utils/testing_pending_attestation_builder.rs b/eth2/types/src/test_utils/testing_pending_attestation_builder.rs index 655b3d1e8..330203448 100644 --- a/eth2/types/src/test_utils/testing_pending_attestation_builder.rs +++ b/eth2/types/src/test_utils/testing_pending_attestation_builder.rs @@ -16,7 +16,12 @@ impl TestingPendingAttestationBuilder { /// /// * The aggregation and custody bitfields will all be empty, they need to be set with /// `Self::add_committee_participation`. - pub fn new(state: &BeaconState, shard: u64, slot: Slot, spec: &ChainSpec) -> Self { + pub fn new( + state: &BeaconState, + shard: u64, + slot: Slot, + spec: &ChainSpec, + ) -> Self { let data_builder = TestingAttestationDataBuilder::new(state, shard, slot, spec); let pending_attestation = PendingAttestation { diff --git a/eth2/types/src/transfer.rs b/eth2/types/src/transfer.rs index aea13fdd7..176a9d75d 100644 --- a/eth2/types/src/transfer.rs +++ b/eth2/types/src/transfer.rs @@ -2,7 +2,7 @@ use super::Slot; use crate::test_utils::TestRandom; use bls::{PublicKey, Signature}; use derivative::Derivative; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/tree_hash_vector.rs b/eth2/types/src/tree_hash_vector.rs index 42a730f25..2600ff62f 100644 --- a/eth2/types/src/tree_hash_vector.rs +++ b/eth2/types/src/tree_hash_vector.rs @@ -100,11 +100,11 @@ where } } -impl TestRandom for TreeHashVector +impl TestRandom for TreeHashVector where - U: TestRandom, + U: TestRandom, { - fn random_for_test(rng: &mut T) -> Self { + fn random_for_test(rng: &mut impl RngCore) -> Self { TreeHashVector::from(vec![ U::random_for_test(rng), U::random_for_test(rng), diff --git a/eth2/types/src/validator.rs b/eth2/types/src/validator.rs index a20eb6426..ff4cabf35 100644 --- a/eth2/types/src/validator.rs +++ b/eth2/types/src/validator.rs @@ -1,5 +1,5 @@ use crate::{test_utils::TestRandom, Epoch, Hash256, PublicKey}; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/types/src/voluntary_exit.rs b/eth2/types/src/voluntary_exit.rs index 8a780db75..a138fb480 100644 --- a/eth2/types/src/voluntary_exit.rs +++ b/eth2/types/src/voluntary_exit.rs @@ -1,6 +1,6 @@ use crate::{test_utils::TestRandom, Epoch}; use bls::Signature; -use rand::RngCore; + use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; diff --git a/eth2/utils/fixed_len_vec/Cargo.toml b/eth2/utils/fixed_len_vec/Cargo.toml new file mode 100644 index 000000000..ddfc33103 --- /dev/null +++ b/eth2/utils/fixed_len_vec/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "fixed_len_vec" +version = "0.1.0" +authors = ["Paul Hauner "] +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" diff --git a/eth2/utils/fixed_len_vec/src/impls.rs b/eth2/utils/fixed_len_vec/src/impls.rs new file mode 100644 index 000000000..98c70e3eb --- /dev/null +++ b/eth2/utils/fixed_len_vec/src/impls.rs @@ -0,0 +1,70 @@ +use super::*; +// use cached_tree_hash::CachedTreeHash; +// use ssz::{Decodable, Encodable}; +// use tree_hash::TreeHash; + +impl tree_hash::TreeHash for FixedLenVec +where + T: tree_hash::TreeHash, +{ + fn tree_hash_type() -> tree_hash::TreeHashType { + tree_hash::TreeHashType::Vector + } + + fn tree_hash_packed_encoding(&self) -> Vec { + unreachable!("Vector should never be packed.") + } + + fn tree_hash_packing_factor() -> usize { + unreachable!("Vector should never be packed.") + } + + fn tree_hash_root(&self) -> Vec { + tree_hash::impls::vec_tree_hash_root(&self.vec) + } +} + +impl cached_tree_hash::CachedTreeHash for FixedLenVec +where + T: cached_tree_hash::CachedTreeHash + tree_hash::TreeHash, +{ + fn new_tree_hash_cache( + &self, + depth: usize, + ) -> Result { + 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 ssz::Encodable for FixedLenVec +where + T: ssz::Encodable, +{ + fn ssz_append(&self, s: &mut ssz::SszStream) { + s.append_vec(&self.vec) + } +} + +impl ssz::Decodable for FixedLenVec +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))) + } +} diff --git a/eth2/types/src/beacon_state/fixed_params.rs b/eth2/utils/fixed_len_vec/src/lib.rs similarity index 51% rename from eth2/types/src/beacon_state/fixed_params.rs rename to eth2/utils/fixed_len_vec/src/lib.rs index 08aa675cf..a2e73a338 100644 --- a/eth2/types/src/beacon_state/fixed_params.rs +++ b/eth2/utils/fixed_len_vec/src/lib.rs @@ -1,9 +1,14 @@ -use std::borrow::{Borrow, BorrowMut}; +use serde_derive::{Deserialize, Serialize}; use std::marker::PhantomData; -use std::ops::{Deref, Index, IndexMut}; +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 where N: Unsigned, @@ -14,6 +19,7 @@ where impl From> for FixedLenVec { fn from(mut vec: Vec) -> Self { + dbg!(Self::capacity()); vec.resize_with(Self::capacity(), Default::default); Self { @@ -23,6 +29,21 @@ impl From> for FixedLenVec { } } +impl Into> for FixedLenVec { + fn into(self) -> Vec { + self.vec + } +} + +impl Default for FixedLenVec { + fn default() -> Self { + Self { + vec: Vec::default(), + _phantom: PhantomData, + } + } +} + impl FixedLenVec { pub fn capacity() -> usize { N::to_usize() @@ -48,25 +69,43 @@ impl> IndexMut for FixedLenVec { #[cfg(test)] mod test { use super::*; - use typenum::U8192; + use typenum::*; #[test] - fn slice_ops() { + fn indexing() { let vec = vec![1, 2]; let mut fixed: FixedLenVec = vec.clone().into(); assert_eq!(fixed[0], 1); assert_eq!(&fixed[0..1], &vec[0..1]); - assert_eq!(&fixed[..], &vec[..]); + assert_eq!((&fixed[..]).len(), 8192); fixed[1] = 3; assert_eq!(fixed[1], 3); } + + #[test] + fn length() { + let vec = vec![42; 5]; + let fixed: FixedLenVec = FixedLenVec::from(vec.clone()); + assert_eq!(&fixed[..], &vec[0..4]); + + let vec = vec![42; 3]; + let fixed: FixedLenVec = FixedLenVec::from(vec.clone()); + assert_eq!(&fixed[0..3], &vec[..]); + assert_eq!(&fixed[..], &vec![42, 42, 42, 0][..]); + + let vec = vec![]; + let fixed: FixedLenVec = FixedLenVec::from(vec.clone()); + assert_eq!(&fixed[..], &vec![0, 0, 0, 0][..]); + } } -/* -pub trait FixedParams { - type LatestCrosslinks: +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } } -*/ diff --git a/eth2/utils/ssz_derive/src/lib.rs b/eth2/utils/ssz_derive/src/lib.rs index c5b53e934..ebe04b322 100644 --- a/eth2/utils/ssz_derive/src/lib.rs +++ b/eth2/utils/ssz_derive/src/lib.rs @@ -100,6 +100,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, @@ -109,7 +110,7 @@ pub fn ssz_encode_derive(input: TokenStream) -> TokenStream { let field_idents = get_serializable_named_field_idents(&struct_data); let output = quote! { - impl ssz::Encodable for #name { + impl #impl_generics ssz::Encodable for #name #ty_generics #where_clause { fn ssz_append(&self, s: &mut ssz::SszStream) { #( s.append(&self.#field_idents); @@ -140,6 +141,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, @@ -169,7 +171,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 ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), ssz::DecodeError> { #( #quotes diff --git a/eth2/utils/test_random_derive/src/lib.rs b/eth2/utils/test_random_derive/src/lib.rs index 7920ea695..a268161dd 100644 --- a/eth2/utils/test_random_derive/src/lib.rs +++ b/eth2/utils/test_random_derive/src/lib.rs @@ -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 TestRandom 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 diff --git a/eth2/utils/tree_hash_derive/src/lib.rs b/eth2/utils/tree_hash_derive/src/lib.rs index 50727a89f..fe94af181 100644 --- a/eth2/utils/tree_hash_derive/src/lib.rs +++ b/eth2/utils/tree_hash_derive/src/lib.rs @@ -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 { 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 }