Update "attestation" family of structs in types

Also adds/splits up some testing builders.
This commit is contained in:
Paul Hauner 2019-03-15 15:19:17 +11:00
parent 8050ed7a26
commit 20a439101e
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
9 changed files with 175 additions and 145 deletions

View File

@ -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 {}

View File

@ -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,

View File

@ -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
}
}

View File

@ -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;

View File

@ -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(),
};

View File

@ -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
}
}

View File

@ -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 mut slashable_attestation_1 = SlashableAttestation {
validator_indices: validator_indices.to_vec(),
data: AttestationData {
let data_1 = AttestationData {
slot: double_voted_slot,
shard,
beacon_block_root: hash_1,
epoch_boundary_root: hash_1,
crosslink_data_root: hash_1,
latest_crosslink: Crosslink {
source_epoch: epoch,
source_root: hash_1,
target_root: hash_1,
shard,
previous_crosslink: Crosslink {
epoch,
crosslink_data_root: hash_1,
},
justified_epoch,
justified_block_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: 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(),
};

View File

@ -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,
}
}

View File

@ -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
}
}