Update "attestation" family of structs in types
Also adds/splits up some testing builders.
This commit is contained in:
		
							parent
							
								
									8050ed7a26
								
							
						
					
					
						commit
						20a439101e
					
				| @ -8,7 +8,7 @@ use test_random_derive::TestRandom; | ||||
| 
 | ||||
| /// The data upon which an attestation is based.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| #[derive(
 | ||||
|     Debug, | ||||
|     Clone, | ||||
| @ -24,14 +24,19 @@ use test_random_derive::TestRandom; | ||||
|     SignedRoot, | ||||
| )] | ||||
| pub struct AttestationData { | ||||
|     // LMD GHOST vote
 | ||||
|     pub slot: Slot, | ||||
|     pub shard: u64, | ||||
|     pub beacon_block_root: Hash256, | ||||
|     pub epoch_boundary_root: Hash256, | ||||
| 
 | ||||
|     // FFG Vote
 | ||||
|     pub source_epoch: Epoch, | ||||
|     pub source_root: Hash256, | ||||
|     pub target_root: Hash256, | ||||
| 
 | ||||
|     // Crosslink Vote
 | ||||
|     pub shard: u64, | ||||
|     pub previous_crosslink: Crosslink, | ||||
|     pub crosslink_data_root: Hash256, | ||||
|     pub latest_crosslink: Crosslink, | ||||
|     pub justified_epoch: Epoch, | ||||
|     pub justified_block_root: Hash256, | ||||
| } | ||||
| 
 | ||||
| impl Eq for AttestationData {} | ||||
|  | ||||
| @ -6,7 +6,7 @@ use ssz_derive::{Decode, Encode, TreeHash}; | ||||
| 
 | ||||
| /// Used for pairing an attestation with a proof-of-custody.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| #[derive(Debug, Clone, PartialEq, Default, Serialize, Encode, Decode, TreeHash)] | ||||
| pub struct AttestationDataAndCustodyBit { | ||||
|     pub data: AttestationData, | ||||
|  | ||||
| @ -9,7 +9,7 @@ use test_random_derive::TestRandom; | ||||
| ///
 | ||||
| /// To be included in an `AttesterSlashing`.
 | ||||
| ///
 | ||||
| /// Spec v0.4.0
 | ||||
| /// Spec v0.5.0
 | ||||
| #[derive(
 | ||||
|     Debug, | ||||
|     PartialEq, | ||||
| @ -33,17 +33,17 @@ pub struct SlashableAttestation { | ||||
| impl SlashableAttestation { | ||||
|     /// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target.
 | ||||
|     ///
 | ||||
|     /// Spec v0.4.0
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn is_double_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool { | ||||
|         self.data.slot.epoch(spec.slots_per_epoch) == other.data.slot.epoch(spec.slots_per_epoch) | ||||
|     } | ||||
| 
 | ||||
|     /// Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
 | ||||
|     ///
 | ||||
|     /// Spec v0.4.0
 | ||||
|     /// Spec v0.5.0
 | ||||
|     pub fn is_surround_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool { | ||||
|         let source_epoch_1 = self.data.justified_epoch; | ||||
|         let source_epoch_2 = other.data.justified_epoch; | ||||
|         let source_epoch_1 = self.data.source_epoch; | ||||
|         let source_epoch_2 = other.data.source_epoch; | ||||
|         let target_epoch_1 = self.data.slot.epoch(spec.slots_per_epoch); | ||||
|         let target_epoch_2 = other.data.slot.epoch(spec.slots_per_epoch); | ||||
| 
 | ||||
| @ -134,14 +134,14 @@ mod tests { | ||||
| 
 | ||||
|     fn create_slashable_attestation( | ||||
|         slot_factor: u64, | ||||
|         justified_epoch: u64, | ||||
|         source_epoch: u64, | ||||
|         spec: &ChainSpec, | ||||
|     ) -> SlashableAttestation { | ||||
|         let mut rng = XorShiftRng::from_seed([42; 16]); | ||||
|         let mut slashable_vote = SlashableAttestation::random_for_test(&mut rng); | ||||
| 
 | ||||
|         slashable_vote.data.slot = Slot::new(slot_factor * spec.slots_per_epoch); | ||||
|         slashable_vote.data.justified_epoch = Epoch::new(justified_epoch); | ||||
|         slashable_vote.data.source_epoch = Epoch::new(source_epoch); | ||||
|         slashable_vote | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -4,10 +4,12 @@ mod generate_deterministic_keypairs; | ||||
| mod keypairs_file; | ||||
| mod test_random; | ||||
| mod testing_attestation_builder; | ||||
| mod testing_attestation_data_builder; | ||||
| mod testing_attester_slashing_builder; | ||||
| mod testing_beacon_block_builder; | ||||
| mod testing_beacon_state_builder; | ||||
| mod testing_deposit_builder; | ||||
| mod testing_pending_attestation_builder; | ||||
| mod testing_proposer_slashing_builder; | ||||
| mod testing_transfer_builder; | ||||
| mod testing_voluntary_exit_builder; | ||||
| @ -17,10 +19,12 @@ pub use keypairs_file::KeypairsFile; | ||||
| pub use rand::{prng::XorShiftRng, SeedableRng}; | ||||
| pub use test_random::TestRandom; | ||||
| pub use testing_attestation_builder::TestingAttestationBuilder; | ||||
| pub use testing_attestation_data_builder::TestingAttestationDataBuilder; | ||||
| pub use testing_attester_slashing_builder::TestingAttesterSlashingBuilder; | ||||
| pub use testing_beacon_block_builder::TestingBeaconBlockBuilder; | ||||
| pub use testing_beacon_state_builder::{keypairs_path, TestingBeaconStateBuilder}; | ||||
| pub use testing_deposit_builder::TestingDepositBuilder; | ||||
| pub use testing_pending_attestation_builder::TestingPendingAttestationBuilder; | ||||
| pub use testing_proposer_slashing_builder::TestingProposerSlashingBuilder; | ||||
| pub use testing_transfer_builder::TestingTransferBuilder; | ||||
| pub use testing_voluntary_exit_builder::TestingVoluntaryExitBuilder; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| use crate::test_utils::TestingAttestationDataBuilder; | ||||
| use crate::*; | ||||
| use ssz::TreeHash; | ||||
| 
 | ||||
| @ -18,31 +19,7 @@ impl TestingAttestationBuilder { | ||||
|         shard: u64, | ||||
|         spec: &ChainSpec, | ||||
|     ) -> Self { | ||||
|         let current_epoch = state.current_epoch(spec); | ||||
|         let previous_epoch = state.previous_epoch(spec); | ||||
| 
 | ||||
|         let is_previous_epoch = | ||||
|             state.slot.epoch(spec.slots_per_epoch) != slot.epoch(spec.slots_per_epoch); | ||||
| 
 | ||||
|         let justified_epoch = if is_previous_epoch { | ||||
|             state.previous_justified_epoch | ||||
|         } else { | ||||
|             state.justified_epoch | ||||
|         }; | ||||
| 
 | ||||
|         let epoch_boundary_root = if is_previous_epoch { | ||||
|             *state | ||||
|                 .get_block_root(previous_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|                 .unwrap() | ||||
|         } else { | ||||
|             *state | ||||
|                 .get_block_root(current_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|                 .unwrap() | ||||
|         }; | ||||
| 
 | ||||
|         let justified_block_root = *state | ||||
|             .get_block_root(justified_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|             .unwrap(); | ||||
|         let data_builder = TestingAttestationDataBuilder::new(state, shard, slot, spec); | ||||
| 
 | ||||
|         let mut aggregation_bitfield = Bitfield::new(); | ||||
|         let mut custody_bitfield = Bitfield::new(); | ||||
| @ -54,16 +31,7 @@ impl TestingAttestationBuilder { | ||||
| 
 | ||||
|         let attestation = Attestation { | ||||
|             aggregation_bitfield, | ||||
|             data: AttestationData { | ||||
|                 slot, | ||||
|                 shard, | ||||
|                 beacon_block_root: *state.get_block_root(slot, spec).unwrap(), | ||||
|                 epoch_boundary_root, | ||||
|                 crosslink_data_root: Hash256::zero(), | ||||
|                 latest_crosslink: state.latest_crosslinks[shard as usize].clone(), | ||||
|                 justified_epoch, | ||||
|                 justified_block_root, | ||||
|             }, | ||||
|             data: data_builder.build(), | ||||
|             custody_bitfield, | ||||
|             aggregate_signature: AggregateSignature::new(), | ||||
|         }; | ||||
|  | ||||
| @ -0,0 +1,66 @@ | ||||
| use crate::*; | ||||
| 
 | ||||
| /// Builds an `AttestationData` to be used for testing purposes.
 | ||||
| ///
 | ||||
| /// This struct should **never be used for production purposes.**
 | ||||
| pub struct TestingAttestationDataBuilder { | ||||
|     data: AttestationData, | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|         let current_epoch = state.current_epoch(spec); | ||||
|         let previous_epoch = state.previous_epoch(spec); | ||||
| 
 | ||||
|         let is_previous_epoch = | ||||
|             state.slot.epoch(spec.slots_per_epoch) != slot.epoch(spec.slots_per_epoch); | ||||
| 
 | ||||
|         let source_epoch = if is_previous_epoch { | ||||
|             state.previous_justified_epoch | ||||
|         } else { | ||||
|             state.justified_epoch | ||||
|         }; | ||||
| 
 | ||||
|         let target_root = if is_previous_epoch { | ||||
|             *state | ||||
|                 .get_block_root(previous_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|                 .unwrap() | ||||
|         } else { | ||||
|             *state | ||||
|                 .get_block_root(current_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|                 .unwrap() | ||||
|         }; | ||||
| 
 | ||||
|         let source_root = *state | ||||
|             .get_block_root(source_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|             .unwrap(); | ||||
| 
 | ||||
|         let data = AttestationData { | ||||
|             // LMD GHOST vote
 | ||||
|             slot, | ||||
|             beacon_block_root: *state.get_block_root(slot, spec).unwrap(), | ||||
| 
 | ||||
|             // FFG Vote
 | ||||
|             source_epoch, | ||||
|             source_root, | ||||
|             target_root, | ||||
| 
 | ||||
|             // Crosslink vote
 | ||||
|             shard, | ||||
|             previous_crosslink: Crosslink { | ||||
|                 epoch: slot.epoch(spec.slots_per_epoch), | ||||
|                 crosslink_data_root: spec.zero_hash, | ||||
|             }, | ||||
|             crosslink_data_root: spec.zero_hash, | ||||
|         }; | ||||
| 
 | ||||
|         Self { data } | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the `AttestationData`, consuming the builder.
 | ||||
|     pub fn build(self) -> AttestationData { | ||||
|         self.data | ||||
|     } | ||||
| } | ||||
| @ -23,45 +23,39 @@ impl TestingAttesterSlashingBuilder { | ||||
|     { | ||||
|         let double_voted_slot = Slot::new(0); | ||||
|         let shard = 0; | ||||
|         let justified_epoch = Epoch::new(0); | ||||
|         let epoch = Epoch::new(0); | ||||
|         let hash_1 = Hash256::from_low_u64_le(1); | ||||
|         let hash_2 = Hash256::from_low_u64_le(2); | ||||
| 
 | ||||
|         let data_1 = AttestationData { | ||||
|             slot: double_voted_slot, | ||||
|             beacon_block_root: hash_1, | ||||
|             source_epoch: epoch, | ||||
|             source_root: hash_1, | ||||
|             target_root: hash_1, | ||||
|             shard, | ||||
|             previous_crosslink: Crosslink { | ||||
|                 epoch, | ||||
|                 crosslink_data_root: hash_1, | ||||
|             }, | ||||
|             crosslink_data_root: hash_1, | ||||
|         }; | ||||
| 
 | ||||
|         let data_2 = AttestationData { | ||||
|             beacon_block_root: hash_2, | ||||
|             ..data_1.clone() | ||||
|         }; | ||||
| 
 | ||||
|         let mut slashable_attestation_1 = SlashableAttestation { | ||||
|             validator_indices: validator_indices.to_vec(), | ||||
|             data: AttestationData { | ||||
|                 slot: double_voted_slot, | ||||
|                 shard, | ||||
|                 beacon_block_root: hash_1, | ||||
|                 epoch_boundary_root: hash_1, | ||||
|                 crosslink_data_root: hash_1, | ||||
|                 latest_crosslink: Crosslink { | ||||
|                     epoch, | ||||
|                     crosslink_data_root: hash_1, | ||||
|                 }, | ||||
|                 justified_epoch, | ||||
|                 justified_block_root: hash_1, | ||||
|             }, | ||||
|             data: data_1, | ||||
|             custody_bitfield: Bitfield::new(), | ||||
|             aggregate_signature: AggregateSignature::new(), | ||||
|         }; | ||||
| 
 | ||||
|         let mut slashable_attestation_2 = SlashableAttestation { | ||||
|             validator_indices: validator_indices.to_vec(), | ||||
|             data: AttestationData { | ||||
|                 slot: double_voted_slot, | ||||
|                 shard, | ||||
|                 beacon_block_root: hash_2, | ||||
|                 epoch_boundary_root: hash_2, | ||||
|                 crosslink_data_root: hash_2, | ||||
|                 latest_crosslink: Crosslink { | ||||
|                     epoch, | ||||
|                     crosslink_data_root: hash_2, | ||||
|                 }, | ||||
|                 justified_epoch, | ||||
|                 justified_block_root: hash_2, | ||||
|             }, | ||||
|             data: data_2, | ||||
|             custody_bitfield: Bitfield::new(), | ||||
|             aggregate_signature: AggregateSignature::new(), | ||||
|         }; | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| use super::{generate_deterministic_keypairs, KeypairsFile}; | ||||
| use crate::beacon_state::BeaconStateBuilder; | ||||
| use crate::test_utils::TestingPendingAttestationBuilder; | ||||
| use crate::*; | ||||
| use bls::get_withdrawal_credentials; | ||||
| use dirs; | ||||
| @ -227,76 +228,13 @@ impl TestingBeaconStateBuilder { | ||||
|                 .clone(); | ||||
| 
 | ||||
|             for (committee, shard) in committees { | ||||
|                 state | ||||
|                     .latest_attestations | ||||
|                     .push(committee_to_pending_attestation( | ||||
|                         state, &committee, shard, slot, spec, | ||||
|                     )) | ||||
|                 let mut builder = TestingPendingAttestationBuilder::new(state, shard, slot, spec); | ||||
|                 // The entire committee should have signed the pending attestation.
 | ||||
|                 let signers = vec![true; committee.len()]; | ||||
|                 builder.add_committee_participation(signers); | ||||
| 
 | ||||
|                 state.latest_attestations.push(builder.build()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Maps a committee to a `PendingAttestation`.
 | ||||
| ///
 | ||||
| /// The committee will be signed by all validators in the committee.
 | ||||
| fn committee_to_pending_attestation( | ||||
|     state: &BeaconState, | ||||
|     committee: &[usize], | ||||
|     shard: u64, | ||||
|     slot: Slot, | ||||
|     spec: &ChainSpec, | ||||
| ) -> PendingAttestation { | ||||
|     let current_epoch = state.current_epoch(spec); | ||||
|     let previous_epoch = state.previous_epoch(spec); | ||||
| 
 | ||||
|     let mut aggregation_bitfield = Bitfield::new(); | ||||
|     let mut custody_bitfield = Bitfield::new(); | ||||
| 
 | ||||
|     for (i, _) in committee.iter().enumerate() { | ||||
|         aggregation_bitfield.set(i, true); | ||||
|         custody_bitfield.set(i, true); | ||||
|     } | ||||
| 
 | ||||
|     let is_previous_epoch = | ||||
|         state.slot.epoch(spec.slots_per_epoch) != slot.epoch(spec.slots_per_epoch); | ||||
| 
 | ||||
|     let justified_epoch = if is_previous_epoch { | ||||
|         state.previous_justified_epoch | ||||
|     } else { | ||||
|         state.justified_epoch | ||||
|     }; | ||||
| 
 | ||||
|     let epoch_boundary_root = if is_previous_epoch { | ||||
|         *state | ||||
|             .get_block_root(previous_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|             .unwrap() | ||||
|     } else { | ||||
|         *state | ||||
|             .get_block_root(current_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|             .unwrap() | ||||
|     }; | ||||
| 
 | ||||
|     let justified_block_root = *state | ||||
|         .get_block_root(justified_epoch.start_slot(spec.slots_per_epoch), spec) | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     PendingAttestation { | ||||
|         aggregation_bitfield, | ||||
|         data: AttestationData { | ||||
|             slot, | ||||
|             shard, | ||||
|             beacon_block_root: *state.get_block_root(slot, spec).unwrap(), | ||||
|             epoch_boundary_root, | ||||
|             crosslink_data_root: Hash256::zero(), | ||||
|             latest_crosslink: Crosslink { | ||||
|                 epoch: slot.epoch(spec.slots_per_epoch), | ||||
|                 crosslink_data_root: Hash256::zero(), | ||||
|             }, | ||||
|             justified_epoch, | ||||
|             justified_block_root, | ||||
|         }, | ||||
|         custody_bitfield, | ||||
|         inclusion_slot: slot + spec.min_attestation_inclusion_delay, | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,55 @@ | ||||
| use crate::test_utils::TestingAttestationDataBuilder; | ||||
| use crate::*; | ||||
| 
 | ||||
| /// Builds an `AttesterSlashing` to be used for testing purposes.
 | ||||
| ///
 | ||||
| /// This struct should **never be used for production purposes.**
 | ||||
| pub struct TestingPendingAttestationBuilder { | ||||
|     pending_attestation: PendingAttestation, | ||||
| } | ||||
| 
 | ||||
| impl TestingPendingAttestationBuilder { | ||||
|     /// Create a new valid* `PendingAttestation` for the given parameters.
 | ||||
|     ///
 | ||||
|     /// The `inclusion_slot` will be set to be the earliest possible slot the `Attestation` could
 | ||||
|     /// have been included (`slot + MIN_ATTESTATION_INCLUSION_DELAY`).
 | ||||
|     ///
 | ||||
|     /// * 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 { | ||||
|         let data_builder = TestingAttestationDataBuilder::new(state, shard, slot, spec); | ||||
| 
 | ||||
|         let pending_attestation = PendingAttestation { | ||||
|             aggregation_bitfield: Bitfield::new(), | ||||
|             data: data_builder.build(), | ||||
|             custody_bitfield: Bitfield::new(), | ||||
|             inclusion_slot: slot + spec.min_attestation_inclusion_delay, | ||||
|         }; | ||||
| 
 | ||||
|         Self { | ||||
|             pending_attestation, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /// Sets the committee participation in the `PendingAttestation`.
 | ||||
|     ///
 | ||||
|     /// The `PendingAttestation` will appear to be signed by each committee member who's value in
 | ||||
|     /// `signers` is true.
 | ||||
|     pub fn add_committee_participation(&mut self, signers: Vec<bool>) { | ||||
|         let mut aggregation_bitfield = Bitfield::new(); | ||||
|         let mut custody_bitfield = Bitfield::new(); | ||||
| 
 | ||||
|         for (i, signed) in signers.iter().enumerate() { | ||||
|             aggregation_bitfield.set(i, *signed); | ||||
|             custody_bitfield.set(i, false); // Fixed to `false` for phase 0.
 | ||||
|         } | ||||
| 
 | ||||
|         self.pending_attestation.aggregation_bitfield = aggregation_bitfield; | ||||
|         self.pending_attestation.custody_bitfield = custody_bitfield; | ||||
|     } | ||||
| 
 | ||||
|     /// Returns the `PendingAttestation`, consuming the builder.
 | ||||
|     pub fn build(self) -> PendingAttestation { | ||||
|         self.pending_attestation | ||||
|     } | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user