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