spec v0.6.0: update types
This commit is contained in:
parent
7dda85e87e
commit
1ad0024045
@ -9,7 +9,7 @@ use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||
|
||||
/// Details an attestation that can be slashable.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@ -28,7 +28,7 @@ pub struct Attestation {
|
||||
pub data: AttestationData,
|
||||
pub custody_bitfield: Bitfield,
|
||||
#[signed_root(skip_hashing)]
|
||||
pub aggregate_signature: AggregateSignature,
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
|
||||
impl Attestation {
|
||||
@ -49,8 +49,7 @@ impl Attestation {
|
||||
self.aggregation_bitfield
|
||||
.union_inplace(&other.aggregation_bitfield);
|
||||
self.custody_bitfield.union_inplace(&other.custody_bitfield);
|
||||
self.aggregate_signature
|
||||
.add_aggregate(&other.aggregate_signature);
|
||||
self.signature.add_aggregate(&other.signature);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||
|
||||
/// The data upon which an attestation is based.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@ -37,7 +37,7 @@ pub struct AttestationData {
|
||||
|
||||
// Crosslink Vote
|
||||
pub shard: u64,
|
||||
pub previous_crosslink: Crosslink,
|
||||
pub previous_crosslink_root: Crosslink,
|
||||
pub crosslink_data_root: Hash256,
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::{test_utils::TestRandom, SlashableAttestation};
|
||||
use crate::{test_utils::TestRandom, IndexedAttestation};
|
||||
use rand::RngCore;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@ -7,7 +7,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
|
||||
/// Two conflicting attestations.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@ -21,8 +21,8 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct AttesterSlashing {
|
||||
pub slashable_attestation_1: SlashableAttestation,
|
||||
pub slashable_attestation_2: SlashableAttestation,
|
||||
pub attestation_1: IndexedAttestation,
|
||||
pub attestation_2: IndexedAttestation,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -47,6 +47,7 @@ impl BeaconBlock {
|
||||
eth1_data: Eth1Data {
|
||||
deposit_root: spec.zero_hash,
|
||||
block_hash: spec.zero_hash,
|
||||
deposit_count: 0,
|
||||
},
|
||||
proposer_slashings: vec![],
|
||||
attester_slashings: vec![],
|
||||
|
@ -69,17 +69,11 @@ pub struct BeaconState {
|
||||
|
||||
// Validator registry
|
||||
pub validator_registry: Vec<Validator>,
|
||||
pub validator_balances: Vec<u64>,
|
||||
pub validator_registry_update_epoch: Epoch,
|
||||
pub balances: Vec<u64>,
|
||||
|
||||
// Randomness and committees
|
||||
pub latest_randao_mixes: TreeHashVector<Hash256>,
|
||||
pub previous_shuffling_start_shard: u64,
|
||||
pub current_shuffling_start_shard: u64,
|
||||
pub previous_shuffling_epoch: Epoch,
|
||||
pub current_shuffling_epoch: Epoch,
|
||||
pub previous_shuffling_seed: Hash256,
|
||||
pub current_shuffling_seed: Hash256,
|
||||
pub latest_start_shard: u64,
|
||||
|
||||
// Finality
|
||||
pub previous_epoch_attestations: Vec<PendingAttestation>,
|
||||
@ -93,7 +87,8 @@ pub struct BeaconState {
|
||||
pub finalized_root: Hash256,
|
||||
|
||||
// Recent state
|
||||
pub latest_crosslinks: TreeHashVector<Crosslink>,
|
||||
pub current_crosslinks: TreeHashVector<Crosslink>,
|
||||
pub previous_crosslinks: TreeHashVector<Crosslink>,
|
||||
pub latest_block_roots: TreeHashVector<Hash256>,
|
||||
latest_state_roots: TreeHashVector<Hash256>,
|
||||
latest_active_index_roots: TreeHashVector<Hash256>,
|
||||
@ -103,7 +98,7 @@ pub struct BeaconState {
|
||||
|
||||
// Ethereum 1.0 chain data
|
||||
pub latest_eth1_data: Eth1Data,
|
||||
pub eth1_data_votes: Vec<Eth1DataVote>,
|
||||
pub eth1_data_votes: Vec<Eth1Data>,
|
||||
pub deposit_index: u64,
|
||||
|
||||
// Caching (not in the spec)
|
||||
@ -143,6 +138,7 @@ impl BeaconState {
|
||||
pub fn genesis(genesis_time: u64, latest_eth1_data: Eth1Data, spec: &ChainSpec) -> BeaconState {
|
||||
let initial_crosslink = Crosslink {
|
||||
epoch: spec.genesis_epoch,
|
||||
previous_crosslink_root: spec.zero_hash,
|
||||
crosslink_data_root: spec.zero_hash,
|
||||
};
|
||||
|
||||
@ -154,18 +150,12 @@ impl BeaconState {
|
||||
|
||||
// Validator registry
|
||||
validator_registry: vec![], // Set later in the function.
|
||||
validator_balances: vec![], // Set later in the function.
|
||||
validator_registry_update_epoch: spec.genesis_epoch,
|
||||
balances: vec![], // Set later in the function.
|
||||
|
||||
// Randomness and committees
|
||||
latest_randao_mixes: vec![spec.zero_hash; spec.latest_randao_mixes_length as usize]
|
||||
.into(),
|
||||
previous_shuffling_start_shard: spec.genesis_start_shard,
|
||||
current_shuffling_start_shard: spec.genesis_start_shard,
|
||||
previous_shuffling_epoch: spec.genesis_epoch,
|
||||
current_shuffling_epoch: spec.genesis_epoch,
|
||||
previous_shuffling_seed: spec.zero_hash,
|
||||
current_shuffling_seed: spec.zero_hash,
|
||||
latest_start_shard: 0, // FIXME(sproul)
|
||||
|
||||
// Finality
|
||||
previous_epoch_attestations: vec![],
|
||||
@ -179,7 +169,8 @@ impl BeaconState {
|
||||
finalized_root: spec.zero_hash,
|
||||
|
||||
// Recent state
|
||||
latest_crosslinks: vec![initial_crosslink; spec.shard_count as usize].into(),
|
||||
current_crosslinks: vec![initial_crosslink.clone(); spec.shard_count as usize].into(),
|
||||
previous_crosslinks: vec![initial_crosslink; spec.shard_count as usize].into(),
|
||||
latest_block_roots: vec![spec.zero_hash; spec.slots_per_historical_root].into(),
|
||||
latest_state_roots: vec![spec.zero_hash; spec.slots_per_historical_root].into(),
|
||||
latest_active_index_roots: vec![spec.zero_hash; spec.latest_active_index_roots_length]
|
||||
@ -630,7 +621,7 @@ impl BeaconState {
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, Error> {
|
||||
let balance = self
|
||||
.validator_balances
|
||||
.balances
|
||||
.get(validator_index)
|
||||
.ok_or_else(|| Error::UnknownValidator)?;
|
||||
Ok(std::cmp::min(*balance, spec.max_deposit_amount))
|
||||
@ -647,7 +638,8 @@ impl BeaconState {
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
pub fn initiate_validator_exit(&mut self, validator_index: usize) {
|
||||
self.validator_registry[validator_index].initiated_exit = true;
|
||||
// FIXME(sproul)
|
||||
// self.validator_registry[validator_index].initiated_exit = true;
|
||||
}
|
||||
|
||||
/// Returns the `slot`, `shard` and `committee_index` for which a validator must produce an
|
||||
|
@ -207,8 +207,9 @@ impl EpochCrosslinkCommitteesBuilder {
|
||||
) -> Self {
|
||||
Self {
|
||||
epoch: state.previous_epoch(spec),
|
||||
shuffling_start_shard: state.previous_shuffling_start_shard,
|
||||
shuffling_seed: state.previous_shuffling_seed,
|
||||
// FIXME(sproul)
|
||||
shuffling_start_shard: 0,
|
||||
shuffling_seed: spec.zero_hash,
|
||||
committees_per_epoch: spec.get_epoch_committee_count(active_validator_indices.len()),
|
||||
active_validator_indices,
|
||||
}
|
||||
@ -222,8 +223,9 @@ impl EpochCrosslinkCommitteesBuilder {
|
||||
) -> Self {
|
||||
Self {
|
||||
epoch: state.current_epoch(spec),
|
||||
shuffling_start_shard: state.current_shuffling_start_shard,
|
||||
shuffling_seed: state.current_shuffling_seed,
|
||||
// FIXME(sproul)
|
||||
shuffling_start_shard: 0,
|
||||
shuffling_seed: spec.zero_hash,
|
||||
committees_per_epoch: spec.get_epoch_committee_count(active_validator_indices.len()),
|
||||
active_validator_indices,
|
||||
}
|
||||
@ -243,8 +245,9 @@ impl EpochCrosslinkCommitteesBuilder {
|
||||
let next_epoch = state.next_epoch(spec);
|
||||
let committees_per_epoch = spec.get_epoch_committee_count(active_validator_indices.len());
|
||||
|
||||
let epochs_since_last_registry_update =
|
||||
current_epoch - state.validator_registry_update_epoch;
|
||||
// FIXME(sproul)
|
||||
// current_epoch - state.validator_registry_update_epoch;
|
||||
let epochs_since_last_registry_update = 0u64;
|
||||
|
||||
let (seed, shuffling_start_shard) = if registry_change {
|
||||
let next_seed = state
|
||||
@ -252,7 +255,9 @@ impl EpochCrosslinkCommitteesBuilder {
|
||||
.map_err(|_| Error::UnableToGenerateSeed)?;
|
||||
(
|
||||
next_seed,
|
||||
(state.current_shuffling_start_shard + committees_per_epoch) % spec.shard_count,
|
||||
0,
|
||||
// FIXME(sproul)
|
||||
// (state.current_shuffling_start_shard + committees_per_epoch) % spec.shard_count,
|
||||
)
|
||||
} else if (epochs_since_last_registry_update > 1)
|
||||
& epochs_since_last_registry_update.is_power_of_two()
|
||||
@ -260,11 +265,13 @@ impl EpochCrosslinkCommitteesBuilder {
|
||||
let next_seed = state
|
||||
.generate_seed(next_epoch, spec)
|
||||
.map_err(|_| Error::UnableToGenerateSeed)?;
|
||||
(next_seed, state.current_shuffling_start_shard)
|
||||
(
|
||||
next_seed, 0, /* FIXME(sproul) state.current_shuffling_start_shard*/
|
||||
)
|
||||
} else {
|
||||
(
|
||||
state.current_shuffling_seed,
|
||||
state.current_shuffling_start_shard,
|
||||
spec.zero_hash, // state.current_shuffling_seed,
|
||||
0 // state.current_shuffling_start_shard,
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -8,7 +8,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
|
||||
/// Specifies the block hash for a shard at an epoch.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@ -25,6 +25,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
)]
|
||||
pub struct Crosslink {
|
||||
pub epoch: Epoch,
|
||||
pub previous_crosslink_root: Hash256,
|
||||
pub crosslink_data_root: Hash256,
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
|
||||
/// A deposit to potentially become a beacon chain validator.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@ -24,7 +24,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
pub struct Deposit {
|
||||
pub proof: TreeHashVector<Hash256>,
|
||||
pub index: u64,
|
||||
pub deposit_data: DepositData,
|
||||
pub data: DepositData,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,14 +1,16 @@
|
||||
use super::DepositInput;
|
||||
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;
|
||||
use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
use tree_hash::{SignedRoot, TreeHash};
|
||||
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||
|
||||
/// Data generated by the deposit contract.
|
||||
/// The data supplied by the user to the deposit contract.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@ -17,14 +19,45 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
SignedRoot,
|
||||
TreeHash,
|
||||
CachedTreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct DepositData {
|
||||
pub pubkey: PublicKey,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
pub amount: u64,
|
||||
pub timestamp: u64,
|
||||
pub deposit_input: DepositInput,
|
||||
#[signed_root(skip_hashing)]
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
impl DepositData {
|
||||
/// Generate the signature for a given DepositData details.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
pub fn create_signature(
|
||||
&self,
|
||||
secret_key: &SecretKey,
|
||||
epoch: Epoch,
|
||||
fork: &Fork,
|
||||
spec: &ChainSpec,
|
||||
) -> Signature {
|
||||
let msg = self.signed_root();
|
||||
let domain = spec.get_domain(epoch, Domain::Deposit, fork);
|
||||
|
||||
Signature::new(msg.as_slice(), domain, secret_key)
|
||||
}
|
||||
|
||||
/// Verify that proof-of-possession is valid.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
pub fn validate_signature(&self, epoch: Epoch, fork: &Fork, spec: &ChainSpec) -> bool {
|
||||
let msg = self.signed_root();
|
||||
let domain = spec.get_domain(epoch, Domain::Deposit, fork);
|
||||
|
||||
self.signature.verify(&msg, domain, &self.pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -33,4 +66,22 @@ mod tests {
|
||||
|
||||
ssz_tests!(DepositData);
|
||||
cached_tree_hash_tests!(DepositData);
|
||||
|
||||
#[test]
|
||||
fn can_create_and_validate() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let fork = Fork::genesis(&spec);
|
||||
let keypair = Keypair::random();
|
||||
let epoch = Epoch::new(0);
|
||||
|
||||
let mut deposit_input = DepositData {
|
||||
pubkey: keypair.pk.clone(),
|
||||
withdrawal_credentials: Hash256::zero(),
|
||||
signature: Signature::empty_signature(),
|
||||
};
|
||||
|
||||
deposit_input.signature = deposit_input.create_signature(&keypair.sk, epoch, &fork, &spec);
|
||||
|
||||
assert!(deposit_input.validate_signature(epoch, &fork, &spec));
|
||||
}
|
||||
}
|
||||
|
@ -1,92 +0,0 @@
|
||||
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;
|
||||
use tree_hash::{SignedRoot, TreeHash};
|
||||
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||
|
||||
/// The data supplied by the user to the deposit contract.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
SignedRoot,
|
||||
TreeHash,
|
||||
CachedTreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct DepositInput {
|
||||
pub pubkey: PublicKey,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
#[signed_root(skip_hashing)]
|
||||
pub proof_of_possession: Signature,
|
||||
}
|
||||
|
||||
impl DepositInput {
|
||||
/// Generate the 'proof_of_posession' signature for a given DepositInput details.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
pub fn create_proof_of_possession(
|
||||
&self,
|
||||
secret_key: &SecretKey,
|
||||
epoch: Epoch,
|
||||
fork: &Fork,
|
||||
spec: &ChainSpec,
|
||||
) -> Signature {
|
||||
let msg = self.signed_root();
|
||||
let domain = spec.get_domain(epoch, Domain::Deposit, fork);
|
||||
|
||||
Signature::new(msg.as_slice(), domain, secret_key)
|
||||
}
|
||||
|
||||
/// Verify that proof-of-possession is valid.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
pub fn validate_proof_of_possession(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
fork: &Fork,
|
||||
spec: &ChainSpec,
|
||||
) -> bool {
|
||||
let msg = self.signed_root();
|
||||
let domain = spec.get_domain(epoch, Domain::Deposit, fork);
|
||||
|
||||
self.proof_of_possession.verify(&msg, domain, &self.pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_tests!(DepositInput);
|
||||
cached_tree_hash_tests!(DepositInput);
|
||||
|
||||
#[test]
|
||||
fn can_create_and_validate() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let fork = Fork::genesis(&spec);
|
||||
let keypair = Keypair::random();
|
||||
let epoch = Epoch::new(0);
|
||||
|
||||
let mut deposit_input = DepositInput {
|
||||
pubkey: keypair.pk.clone(),
|
||||
withdrawal_credentials: Hash256::zero(),
|
||||
proof_of_possession: Signature::empty_signature(),
|
||||
};
|
||||
|
||||
deposit_input.proof_of_possession =
|
||||
deposit_input.create_proof_of_possession(&keypair.sk, epoch, &fork, &spec);
|
||||
|
||||
assert!(deposit_input.validate_proof_of_possession(epoch, &fork, &spec));
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
|
||||
/// Contains data obtained from the Eth1 chain.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@ -24,6 +24,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
)]
|
||||
pub struct Eth1Data {
|
||||
pub deposit_root: Hash256,
|
||||
pub deposit_count: u64,
|
||||
pub block_hash: Hash256,
|
||||
}
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
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;
|
||||
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,
|
||||
CachedTreeHash,
|
||||
TestRandom,
|
||||
)]
|
||||
pub struct Eth1DataVote {
|
||||
pub eth1_data: Eth1Data,
|
||||
pub vote_count: u64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
ssz_tests!(Eth1DataVote);
|
||||
cached_tree_hash_tests!(Eth1DataVote);
|
||||
}
|
@ -10,7 +10,7 @@ use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||
///
|
||||
/// To be included in an `AttesterSlashing`.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialEq,
|
||||
@ -24,27 +24,28 @@ use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||
TestRandom,
|
||||
SignedRoot,
|
||||
)]
|
||||
pub struct SlashableAttestation {
|
||||
pub struct IndexedAttestation {
|
||||
/// Lists validator registry indices, not committee indices.
|
||||
pub validator_indices: Vec<u64>,
|
||||
pub custody_bit_0_indices: Vec<u64>,
|
||||
pub custody_bit_1_indices: Vec<u64>,
|
||||
pub data: AttestationData,
|
||||
pub custody_bitfield: Bitfield,
|
||||
#[signed_root(skip_hashing)]
|
||||
pub aggregate_signature: AggregateSignature,
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
|
||||
impl SlashableAttestation {
|
||||
impl IndexedAttestation {
|
||||
/// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
pub fn is_double_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool {
|
||||
pub fn is_double_vote(&self, other: &IndexedAttestation, 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.5.1
|
||||
pub fn is_surround_vote(&self, other: &SlashableAttestation, spec: &ChainSpec) -> bool {
|
||||
pub fn is_surround_vote(&self, other: &IndexedAttestation, spec: &ChainSpec) -> bool {
|
||||
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);
|
||||
@ -64,11 +65,11 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_is_double_vote_true() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let slashable_vote_first = create_slashable_attestation(1, 1, &spec);
|
||||
let slashable_vote_second = create_slashable_attestation(1, 1, &spec);
|
||||
let indexed_vote_first = create_indexed_attestation(1, 1, &spec);
|
||||
let indexed_vote_second = create_indexed_attestation(1, 1, &spec);
|
||||
|
||||
assert_eq!(
|
||||
slashable_vote_first.is_double_vote(&slashable_vote_second, &spec),
|
||||
indexed_vote_first.is_double_vote(&indexed_vote_second, &spec),
|
||||
true
|
||||
)
|
||||
}
|
||||
@ -76,11 +77,11 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_is_double_vote_false() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let slashable_vote_first = create_slashable_attestation(1, 1, &spec);
|
||||
let slashable_vote_second = create_slashable_attestation(2, 1, &spec);
|
||||
let indexed_vote_first = create_indexed_attestation(1, 1, &spec);
|
||||
let indexed_vote_second = create_indexed_attestation(2, 1, &spec);
|
||||
|
||||
assert_eq!(
|
||||
slashable_vote_first.is_double_vote(&slashable_vote_second, &spec),
|
||||
indexed_vote_first.is_double_vote(&indexed_vote_second, &spec),
|
||||
false
|
||||
);
|
||||
}
|
||||
@ -88,11 +89,11 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_is_surround_vote_true() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let slashable_vote_first = create_slashable_attestation(2, 1, &spec);
|
||||
let slashable_vote_second = create_slashable_attestation(1, 2, &spec);
|
||||
let indexed_vote_first = create_indexed_attestation(2, 1, &spec);
|
||||
let indexed_vote_second = create_indexed_attestation(1, 2, &spec);
|
||||
|
||||
assert_eq!(
|
||||
slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
|
||||
indexed_vote_first.is_surround_vote(&indexed_vote_second, &spec),
|
||||
true
|
||||
);
|
||||
}
|
||||
@ -100,11 +101,11 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_is_surround_vote_true_realistic() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let slashable_vote_first = create_slashable_attestation(4, 1, &spec);
|
||||
let slashable_vote_second = create_slashable_attestation(3, 2, &spec);
|
||||
let indexed_vote_first = create_indexed_attestation(4, 1, &spec);
|
||||
let indexed_vote_second = create_indexed_attestation(3, 2, &spec);
|
||||
|
||||
assert_eq!(
|
||||
slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
|
||||
indexed_vote_first.is_surround_vote(&indexed_vote_second, &spec),
|
||||
true
|
||||
);
|
||||
}
|
||||
@ -112,11 +113,11 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_is_surround_vote_false_source_epoch_fails() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let slashable_vote_first = create_slashable_attestation(2, 2, &spec);
|
||||
let slashable_vote_second = create_slashable_attestation(1, 1, &spec);
|
||||
let indexed_vote_first = create_indexed_attestation(2, 2, &spec);
|
||||
let indexed_vote_second = create_indexed_attestation(1, 1, &spec);
|
||||
|
||||
assert_eq!(
|
||||
slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
|
||||
indexed_vote_first.is_surround_vote(&indexed_vote_second, &spec),
|
||||
false
|
||||
);
|
||||
}
|
||||
@ -124,28 +125,28 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_is_surround_vote_false_target_epoch_fails() {
|
||||
let spec = ChainSpec::foundation();
|
||||
let slashable_vote_first = create_slashable_attestation(1, 1, &spec);
|
||||
let slashable_vote_second = create_slashable_attestation(2, 2, &spec);
|
||||
let indexed_vote_first = create_indexed_attestation(1, 1, &spec);
|
||||
let indexed_vote_second = create_indexed_attestation(2, 2, &spec);
|
||||
|
||||
assert_eq!(
|
||||
slashable_vote_first.is_surround_vote(&slashable_vote_second, &spec),
|
||||
indexed_vote_first.is_surround_vote(&indexed_vote_second, &spec),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
ssz_tests!(SlashableAttestation);
|
||||
cached_tree_hash_tests!(SlashableAttestation);
|
||||
ssz_tests!(IndexedAttestation);
|
||||
cached_tree_hash_tests!(IndexedAttestation);
|
||||
|
||||
fn create_slashable_attestation(
|
||||
fn create_indexed_attestation(
|
||||
slot_factor: u64,
|
||||
source_epoch: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> SlashableAttestation {
|
||||
) -> IndexedAttestation {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let mut slashable_vote = SlashableAttestation::random_for_test(&mut rng);
|
||||
let mut indexed_vote = IndexedAttestation::random_for_test(&mut rng);
|
||||
|
||||
slashable_vote.data.slot = Slot::new(slot_factor * spec.slots_per_epoch);
|
||||
slashable_vote.data.source_epoch = Epoch::new(source_epoch);
|
||||
slashable_vote
|
||||
indexed_vote.data.slot = Slot::new(slot_factor * spec.slots_per_epoch);
|
||||
indexed_vote.data.source_epoch = Epoch::new(source_epoch);
|
||||
indexed_vote
|
||||
}
|
||||
}
|
@ -17,15 +17,13 @@ pub mod crosslink;
|
||||
pub mod crosslink_committee;
|
||||
pub mod deposit;
|
||||
pub mod deposit_data;
|
||||
pub mod deposit_input;
|
||||
pub mod eth1_data;
|
||||
pub mod eth1_data_vote;
|
||||
pub mod fork;
|
||||
pub mod free_attestation;
|
||||
pub mod historical_batch;
|
||||
pub mod indexed_attestation;
|
||||
pub mod pending_attestation;
|
||||
pub mod proposer_slashing;
|
||||
pub mod slashable_attestation;
|
||||
pub mod transfer;
|
||||
pub mod tree_hash_vector;
|
||||
pub mod voluntary_exit;
|
||||
@ -53,16 +51,14 @@ pub use crate::crosslink::Crosslink;
|
||||
pub use crate::crosslink_committee::CrosslinkCommittee;
|
||||
pub use crate::deposit::Deposit;
|
||||
pub use crate::deposit_data::DepositData;
|
||||
pub use crate::deposit_input::DepositInput;
|
||||
pub use crate::eth1_data::Eth1Data;
|
||||
pub use crate::eth1_data_vote::Eth1DataVote;
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::free_attestation::FreeAttestation;
|
||||
pub use crate::historical_batch::HistoricalBatch;
|
||||
pub use crate::indexed_attestation::IndexedAttestation;
|
||||
pub use crate::pending_attestation::PendingAttestation;
|
||||
pub use crate::proposer_slashing::ProposerSlashing;
|
||||
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||
pub use crate::slashable_attestation::SlashableAttestation;
|
||||
pub use crate::slot_epoch::{Epoch, Slot};
|
||||
pub use crate::slot_height::SlotHeight;
|
||||
pub use crate::transfer::Transfer;
|
||||
|
@ -8,7 +8,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
|
||||
/// An attestation that has been included in the state but not yet fully processed.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@ -24,18 +24,22 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
pub struct PendingAttestation {
|
||||
pub aggregation_bitfield: Bitfield,
|
||||
pub data: AttestationData,
|
||||
pub custody_bitfield: Bitfield,
|
||||
pub inclusion_slot: Slot,
|
||||
pub proposer_index: u64,
|
||||
}
|
||||
|
||||
impl PendingAttestation {
|
||||
/// Create a `PendingAttestation` from an `Attestation`, at the given `inclusion_slot`.
|
||||
pub fn from_attestation(attestation: &Attestation, inclusion_slot: Slot) -> Self {
|
||||
/// Create a `PendingAttestation` from an `Attestation`.
|
||||
pub fn from_attestation(
|
||||
attestation: &Attestation,
|
||||
inclusion_slot: Slot,
|
||||
proposer_index: u64,
|
||||
) -> Self {
|
||||
PendingAttestation {
|
||||
data: attestation.data.clone(),
|
||||
aggregation_bitfield: attestation.aggregation_bitfield.clone(),
|
||||
custody_bitfield: attestation.custody_bitfield.clone(),
|
||||
inclusion_slot,
|
||||
proposer_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ impl TestingAttestationBuilder {
|
||||
aggregation_bitfield,
|
||||
data: data_builder.build(),
|
||||
custody_bitfield,
|
||||
aggregate_signature: AggregateSignature::new(),
|
||||
signature: AggregateSignature::new(),
|
||||
};
|
||||
|
||||
Self {
|
||||
@ -83,7 +83,7 @@ impl TestingAttestationBuilder {
|
||||
);
|
||||
|
||||
let signature = Signature::new(&message, domain, secret_keys[key_index]);
|
||||
self.attestation.aggregate_signature.add(&signature)
|
||||
self.attestation.signature.add(&signature)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,9 @@ impl TestingAttestationDataBuilder {
|
||||
|
||||
// Crosslink vote
|
||||
shard,
|
||||
previous_crosslink: Crosslink {
|
||||
previous_crosslink_root: Crosslink {
|
||||
epoch: slot.epoch(spec.slots_per_epoch),
|
||||
previous_crosslink_root: spec.zero_hash,
|
||||
crosslink_data_root: spec.zero_hash,
|
||||
},
|
||||
crosslink_data_root: spec.zero_hash,
|
||||
|
@ -34,8 +34,9 @@ impl TestingAttesterSlashingBuilder {
|
||||
source_root: hash_1,
|
||||
target_root: hash_1,
|
||||
shard,
|
||||
previous_crosslink: Crosslink {
|
||||
previous_crosslink_root: Crosslink {
|
||||
epoch,
|
||||
previous_crosslink_root: hash_1,
|
||||
crosslink_data_root: hash_1,
|
||||
},
|
||||
crosslink_data_root: hash_1,
|
||||
@ -46,21 +47,23 @@ impl TestingAttesterSlashingBuilder {
|
||||
..data_1.clone()
|
||||
};
|
||||
|
||||
let mut slashable_attestation_1 = SlashableAttestation {
|
||||
validator_indices: validator_indices.to_vec(),
|
||||
let mut attestation_1 = IndexedAttestation {
|
||||
custody_bit_0_indices: validator_indices.to_vec(),
|
||||
custody_bit_1_indices: vec![],
|
||||
data: data_1,
|
||||
custody_bitfield: Bitfield::new(),
|
||||
aggregate_signature: AggregateSignature::new(),
|
||||
signature: AggregateSignature::new(),
|
||||
};
|
||||
|
||||
let mut slashable_attestation_2 = SlashableAttestation {
|
||||
validator_indices: validator_indices.to_vec(),
|
||||
let mut attestation_2 = IndexedAttestation {
|
||||
custody_bit_0_indices: validator_indices.to_vec(),
|
||||
custody_bit_1_indices: vec![],
|
||||
data: data_2,
|
||||
custody_bitfield: Bitfield::new(),
|
||||
aggregate_signature: AggregateSignature::new(),
|
||||
signature: AggregateSignature::new(),
|
||||
};
|
||||
|
||||
let add_signatures = |attestation: &mut SlashableAttestation| {
|
||||
let add_signatures = |attestation: &mut IndexedAttestation| {
|
||||
// All validators sign with a `false` custody bit.
|
||||
let attestation_data_and_custody_bit = AttestationDataAndCustodyBit {
|
||||
data: attestation.data.clone(),
|
||||
@ -71,16 +74,16 @@ impl TestingAttesterSlashingBuilder {
|
||||
for (i, validator_index) in validator_indices.iter().enumerate() {
|
||||
attestation.custody_bitfield.set(i, false);
|
||||
let signature = signer(*validator_index, &message[..], epoch, Domain::Attestation);
|
||||
attestation.aggregate_signature.add(&signature);
|
||||
attestation.signature.add(&signature);
|
||||
}
|
||||
};
|
||||
|
||||
add_signatures(&mut slashable_attestation_1);
|
||||
add_signatures(&mut slashable_attestation_2);
|
||||
add_signatures(&mut attestation_1);
|
||||
add_signatures(&mut attestation_2);
|
||||
|
||||
AttesterSlashing {
|
||||
slashable_attestation_1,
|
||||
slashable_attestation_2,
|
||||
attestation_1,
|
||||
attestation_2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,6 +95,7 @@ impl TestingBeaconStateBuilder {
|
||||
/// Creates the builder from an existing set of keypairs.
|
||||
pub fn from_keypairs(keypairs: Vec<Keypair>, spec: &ChainSpec) -> Self {
|
||||
let validator_count = keypairs.len();
|
||||
let starting_balance = 32_000_000_000;
|
||||
|
||||
debug!(
|
||||
"Building {} Validator objects from keypairs...",
|
||||
@ -112,11 +113,12 @@ impl TestingBeaconStateBuilder {
|
||||
pubkey: keypair.pk.clone(),
|
||||
withdrawal_credentials,
|
||||
// All validators start active.
|
||||
activation_eligibility_epoch: spec.genesis_epoch,
|
||||
activation_epoch: spec.genesis_epoch,
|
||||
exit_epoch: spec.far_future_epoch,
|
||||
withdrawable_epoch: spec.far_future_epoch,
|
||||
initiated_exit: false,
|
||||
slashed: false,
|
||||
effective_balance: starting_balance,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -137,16 +139,17 @@ impl TestingBeaconStateBuilder {
|
||||
genesis_time,
|
||||
Eth1Data {
|
||||
deposit_root: Hash256::zero(),
|
||||
deposit_count: 0,
|
||||
block_hash: Hash256::zero(),
|
||||
},
|
||||
spec,
|
||||
);
|
||||
|
||||
let balances = vec![32_000_000_000; validator_count];
|
||||
let balances = vec![starting_balance; validator_count];
|
||||
|
||||
debug!("Importing {} existing validators...", validator_count);
|
||||
state.validator_registry = validators;
|
||||
state.validator_balances = balances;
|
||||
state.balances = balances;
|
||||
|
||||
debug!("BeaconState initialized.");
|
||||
|
||||
@ -192,18 +195,13 @@ impl TestingBeaconStateBuilder {
|
||||
|
||||
state.slot = slot;
|
||||
|
||||
state.previous_shuffling_epoch = epoch - 1;
|
||||
state.current_shuffling_epoch = epoch;
|
||||
|
||||
state.previous_shuffling_seed = Hash256::from_low_u64_le(0);
|
||||
state.current_shuffling_seed = Hash256::from_low_u64_le(1);
|
||||
// FIXME(sproul): update latest_start_shard?
|
||||
|
||||
state.previous_justified_epoch = epoch - 3;
|
||||
state.current_justified_epoch = epoch - 2;
|
||||
state.justification_bitfield = u64::max_value();
|
||||
|
||||
state.finalized_epoch = epoch - 3;
|
||||
state.validator_registry_update_epoch = epoch - 3;
|
||||
}
|
||||
|
||||
/// Creates a full set of attestations for the `BeaconState`. Each attestation has full
|
||||
|
@ -14,14 +14,11 @@ impl TestingDepositBuilder {
|
||||
let deposit = Deposit {
|
||||
proof: vec![].into(),
|
||||
index: 0,
|
||||
deposit_data: DepositData {
|
||||
data: DepositData {
|
||||
pubkey,
|
||||
withdrawal_credentials: Hash256::zero(),
|
||||
amount,
|
||||
timestamp: 1,
|
||||
deposit_input: DepositInput {
|
||||
pubkey,
|
||||
withdrawal_credentials: Hash256::zero(),
|
||||
proof_of_possession: Signature::empty_signature(),
|
||||
},
|
||||
signature: Signature::empty_signature(),
|
||||
},
|
||||
};
|
||||
|
||||
@ -43,17 +40,13 @@ impl TestingDepositBuilder {
|
||||
&get_withdrawal_credentials(&keypair.pk, spec.bls_withdrawal_prefix_byte)[..],
|
||||
);
|
||||
|
||||
self.deposit.deposit_data.deposit_input.pubkey = keypair.pk.clone();
|
||||
self.deposit
|
||||
.deposit_data
|
||||
.deposit_input
|
||||
.withdrawal_credentials = withdrawal_credentials;
|
||||
self.deposit.data.pubkey = keypair.pk.clone();
|
||||
self.deposit.data.withdrawal_credentials = withdrawal_credentials;
|
||||
|
||||
self.deposit.deposit_data.deposit_input.proof_of_possession = self
|
||||
.deposit
|
||||
.deposit_data
|
||||
.deposit_input
|
||||
.create_proof_of_possession(&keypair.sk, epoch, fork, spec);
|
||||
self.deposit.data.signature =
|
||||
self.deposit
|
||||
.data
|
||||
.create_signature(&keypair.sk, epoch, fork, spec);
|
||||
}
|
||||
|
||||
/// Builds the deposit, consuming the builder.
|
||||
|
@ -22,8 +22,9 @@ impl TestingPendingAttestationBuilder {
|
||||
let pending_attestation = PendingAttestation {
|
||||
aggregation_bitfield: Bitfield::new(),
|
||||
data: data_builder.build(),
|
||||
custody_bitfield: Bitfield::new(),
|
||||
inclusion_slot: slot + spec.min_attestation_inclusion_delay,
|
||||
// FIXME(sproul)
|
||||
proposer_index: 0,
|
||||
};
|
||||
|
||||
Self {
|
||||
@ -37,15 +38,12 @@ impl TestingPendingAttestationBuilder {
|
||||
/// `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.
|
||||
|
@ -7,7 +7,7 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
|
||||
/// Information about a `BeaconChain` validator.
|
||||
///
|
||||
/// Spec v0.5.1
|
||||
/// Spec v0.6.0
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@ -23,11 +23,12 @@ use tree_hash_derive::{CachedTreeHash, TreeHash};
|
||||
pub struct Validator {
|
||||
pub pubkey: PublicKey,
|
||||
pub withdrawal_credentials: Hash256,
|
||||
pub activation_eligibility_epoch: Epoch,
|
||||
pub activation_epoch: Epoch,
|
||||
pub exit_epoch: Epoch,
|
||||
pub withdrawable_epoch: Epoch,
|
||||
pub initiated_exit: bool,
|
||||
pub slashed: bool,
|
||||
pub effective_balance: u64,
|
||||
}
|
||||
|
||||
impl Validator {
|
||||
@ -53,11 +54,12 @@ impl Default for Validator {
|
||||
Self {
|
||||
pubkey: PublicKey::default(),
|
||||
withdrawal_credentials: Hash256::default(),
|
||||
activation_eligibility_epoch: Epoch::from(std::u64::MAX),
|
||||
activation_epoch: Epoch::from(std::u64::MAX),
|
||||
exit_epoch: Epoch::from(std::u64::MAX),
|
||||
withdrawable_epoch: Epoch::from(std::u64::MAX),
|
||||
initiated_exit: false,
|
||||
slashed: false,
|
||||
effective_balance: std::u64::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user