Update to spec v0.11 (#959)

* Update process_final_updates() hysteresis computation

* Update core to v0.11.1

* Bump tags to v0.11.1

* Update docs and deposit contract

* Add compute_fork_digest

* Address review comments

Co-authored-by: Herman Alonso Junge <alonso.junge@gmail.com>
This commit is contained in:
Michael Sproul 2020-04-01 22:03:03 +11:00 committed by GitHub
parent e04fc8ddb4
commit 26bdc2927b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 1060 additions and 496 deletions

View File

@ -39,7 +39,7 @@ Like all Ethereum 2.0 clients, Lighthouse is a work-in-progress.
Current development overview: Current development overview:
- Specification `v0.10.1` implemented, optimized and passing test vectors. - Specification `v0.11.1` implemented, optimized and passing test vectors.
- Rust-native libp2p with Gossipsub and Discv5. - Rust-native libp2p with Gossipsub and Discv5.
- RESTful JSON API via HTTP server. - RESTful JSON API via HTTP server.
- Events via WebSocket. - Events via WebSocket.

View File

@ -153,6 +153,8 @@ pub struct HeadInfo {
pub current_justified_checkpoint: types::Checkpoint, pub current_justified_checkpoint: types::Checkpoint,
pub finalized_checkpoint: types::Checkpoint, pub finalized_checkpoint: types::Checkpoint,
pub fork: Fork, pub fork: Fork,
pub genesis_time: u64,
pub genesis_validators_root: Hash256,
} }
pub trait BeaconChainTypes: Send + Sync + 'static { pub trait BeaconChainTypes: Send + Sync + 'static {
@ -492,6 +494,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
current_justified_checkpoint: head.beacon_state.current_justified_checkpoint.clone(), current_justified_checkpoint: head.beacon_state.current_justified_checkpoint.clone(),
finalized_checkpoint: head.beacon_state.finalized_checkpoint.clone(), finalized_checkpoint: head.beacon_state.finalized_checkpoint.clone(),
fork: head.beacon_state.fork.clone(), fork: head.beacon_state.fork.clone(),
genesis_time: head.beacon_state.genesis_time,
genesis_validators_root: head.beacon_state.genesis_validators_root,
}) })
} }
@ -1031,17 +1035,23 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
}) })
.collect::<Result<Vec<&PublicKey>, Error>>()?; .collect::<Result<Vec<&PublicKey>, Error>>()?;
let fork = self let (fork, genesis_validators_root) = self
.canonical_head .canonical_head
.try_read_for(HEAD_LOCK_TIMEOUT) .try_read_for(HEAD_LOCK_TIMEOUT)
.ok_or_else(|| Error::CanonicalHeadLockTimeout) .ok_or_else(|| Error::CanonicalHeadLockTimeout)
.map(|head| head.beacon_state.fork.clone())?; .map(|head| {
(
head.beacon_state.fork.clone(),
head.beacon_state.genesis_validators_root,
)
})?;
let signature_set = indexed_attestation_signature_set_from_pubkeys( let signature_set = indexed_attestation_signature_set_from_pubkeys(
pubkeys, pubkeys,
&attestation.signature, &attestation.signature,
&indexed_attestation, &indexed_attestation,
&fork, &fork,
genesis_validators_root,
&self.spec, &self.spec,
) )
.map_err(Error::SignatureSetError)?; .map_err(Error::SignatureSetError)?;
@ -1074,8 +1084,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Provide the valid attestation to op pool, which may choose to retain the // Provide the valid attestation to op pool, which may choose to retain the
// attestation for inclusion in a future block. // attestation for inclusion in a future block.
if self.eth1_chain.is_some() { if self.eth1_chain.is_some() {
self.op_pool self.op_pool.insert_attestation(
.insert_attestation(attestation, &fork, &self.spec)?; attestation,
&fork,
genesis_validators_root,
&self.spec,
)?;
}; };
Ok(AttestationProcessingOutcome::Processed) Ok(AttestationProcessingOutcome::Processed)
@ -1547,6 +1561,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut block = SignedBeaconBlock { let mut block = SignedBeaconBlock {
message: BeaconBlock { message: BeaconBlock {
slot: state.slot, slot: state.slot,
proposer_index: state.get_beacon_proposer_index(state.slot, &self.spec)? as u64,
parent_root, parent_root,
state_root: Hash256::zero(), state_root: Hash256::zero(),
body: BeaconBlockBody { body: BeaconBlockBody {

View File

@ -313,7 +313,9 @@ where
let randao_reveal = { let randao_reveal = {
let epoch = slot.epoch(E::slots_per_epoch()); let epoch = slot.epoch(E::slots_per_epoch());
let domain = self.spec.get_domain(epoch, Domain::Randao, fork); let domain =
self.spec
.get_domain(epoch, Domain::Randao, fork, state.genesis_validators_root);
let message = epoch.signing_root(domain); let message = epoch.signing_root(domain);
Signature::new(message.as_bytes(), sk) Signature::new(message.as_bytes(), sk)
}; };
@ -323,7 +325,7 @@ where
.produce_block_on_state(state, slot, randao_reveal) .produce_block_on_state(state, slot, randao_reveal)
.expect("should produce block"); .expect("should produce block");
let signed_block = block.sign(sk, &state.fork, &self.spec); let signed_block = block.sign(sk, &state.fork, state.genesis_validators_root, &self.spec);
(signed_block, state) (signed_block, state)
} }
@ -408,6 +410,7 @@ where
attestation.data.target.epoch, attestation.data.target.epoch,
Domain::BeaconAttester, Domain::BeaconAttester,
fork, fork,
state.genesis_validators_root,
); );
let message = attestation.data.signing_root(domain); let message = attestation.data.signing_root(domain);

View File

@ -494,7 +494,15 @@ pub fn get_genesis_time<T: BeaconChainTypes>(
req: Request<Body>, req: Request<Body>,
beacon_chain: Arc<BeaconChain<T>>, beacon_chain: Arc<BeaconChain<T>>,
) -> ApiResult { ) -> ApiResult {
ResponseBuilder::new(&req)?.body(&beacon_chain.head()?.beacon_state.genesis_time) ResponseBuilder::new(&req)?.body(&beacon_chain.head_info()?.genesis_time)
}
/// Read the `genesis_validators_root` from the current beacon chain state.
pub fn get_genesis_validators_root<T: BeaconChainTypes>(
req: Request<Body>,
beacon_chain: Arc<BeaconChain<T>>,
) -> ApiResult {
ResponseBuilder::new(&req)?.body(&beacon_chain.head_info()?.genesis_validators_root)
} }
pub fn proposer_slashing<T: BeaconChainTypes>( pub fn proposer_slashing<T: BeaconChainTypes>(

View File

@ -37,13 +37,13 @@ pub struct VoteCount {
impl Into<VoteCount> for TotalBalances { impl Into<VoteCount> for TotalBalances {
fn into(self) -> VoteCount { fn into(self) -> VoteCount {
VoteCount { VoteCount {
current_epoch_active_gwei: self.current_epoch, current_epoch_active_gwei: self.current_epoch(),
previous_epoch_active_gwei: self.previous_epoch, previous_epoch_active_gwei: self.previous_epoch(),
current_epoch_attesting_gwei: self.current_epoch_attesters, current_epoch_attesting_gwei: self.current_epoch_attesters(),
current_epoch_target_attesting_gwei: self.current_epoch_target_attesters, current_epoch_target_attesting_gwei: self.current_epoch_target_attesters(),
previous_epoch_attesting_gwei: self.previous_epoch_attesters, previous_epoch_attesting_gwei: self.previous_epoch_attesters(),
previous_epoch_target_attesting_gwei: self.previous_epoch_target_attesters, previous_epoch_target_attesting_gwei: self.previous_epoch_target_attesters(),
previous_epoch_head_attesting_gwei: self.previous_epoch_head_attesters, previous_epoch_head_attesting_gwei: self.previous_epoch_head_attesters(),
} }
} }
} }

View File

@ -82,6 +82,9 @@ pub fn route<T: BeaconChainTypes>(
(&Method::GET, "/beacon/genesis_time") => { (&Method::GET, "/beacon/genesis_time") => {
into_boxfut(beacon::get_genesis_time::<T>(req, beacon_chain)) into_boxfut(beacon::get_genesis_time::<T>(req, beacon_chain))
} }
(&Method::GET, "/beacon/genesis_validators_root") => {
into_boxfut(beacon::get_genesis_validators_root::<T>(req, beacon_chain))
}
(&Method::GET, "/beacon/validators") => { (&Method::GET, "/beacon/validators") => {
into_boxfut(beacon::get_validators::<T>(req, beacon_chain)) into_boxfut(beacon::get_validators::<T>(req, beacon_chain))
} }

View File

@ -47,17 +47,15 @@ fn get_randao_reveal<T: BeaconChainTypes>(
slot: Slot, slot: Slot,
spec: &ChainSpec, spec: &ChainSpec,
) -> Signature { ) -> Signature {
let fork = beacon_chain let head = beacon_chain.head().expect("should get head");
.head() let fork = head.beacon_state.fork;
.expect("should get head") let genesis_validators_root = head.beacon_state.genesis_validators_root;
.beacon_state
.fork;
let proposer_index = beacon_chain let proposer_index = beacon_chain
.block_proposer(slot) .block_proposer(slot)
.expect("should get proposer index"); .expect("should get proposer index");
let keypair = generate_deterministic_keypair(proposer_index); let keypair = generate_deterministic_keypair(proposer_index);
let epoch = slot.epoch(E::slots_per_epoch()); let epoch = slot.epoch(E::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::Randao, &fork); let domain = spec.get_domain(epoch, Domain::Randao, &fork, genesis_validators_root);
let message = epoch.signing_root(domain); let message = epoch.signing_root(domain);
Signature::new(message.as_bytes(), &keypair.sk) Signature::new(message.as_bytes(), &keypair.sk)
} }
@ -68,16 +66,14 @@ fn sign_block<T: BeaconChainTypes>(
block: BeaconBlock<T::EthSpec>, block: BeaconBlock<T::EthSpec>,
spec: &ChainSpec, spec: &ChainSpec,
) -> SignedBeaconBlock<T::EthSpec> { ) -> SignedBeaconBlock<T::EthSpec> {
let fork = beacon_chain let head = beacon_chain.head().expect("should get head");
.head() let fork = head.beacon_state.fork;
.expect("should get head") let genesis_validators_root = head.beacon_state.genesis_validators_root;
.beacon_state
.fork;
let proposer_index = beacon_chain let proposer_index = beacon_chain
.block_proposer(block.slot) .block_proposer(block.slot)
.expect("should get proposer index"); .expect("should get proposer index");
let keypair = generate_deterministic_keypair(proposer_index); let keypair = generate_deterministic_keypair(proposer_index);
block.sign(&keypair.sk, &fork, spec) block.sign(&keypair.sk, &fork, genesis_validators_root, spec)
} }
#[test] #[test]
@ -156,6 +152,7 @@ fn validator_produce_attestation() {
.attestation_committee_position .attestation_committee_position
.expect("should have committee position"), .expect("should have committee position"),
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
) )
.expect("should sign attestation"); .expect("should sign attestation");
@ -564,6 +561,31 @@ fn genesis_time() {
); );
} }
#[test]
fn genesis_validators_root() {
let mut env = build_env();
let node = build_node(&mut env, testing_client_config());
let remote_node = node.remote_node().expect("should produce remote node");
let genesis_validators_root = env
.runtime()
.block_on(remote_node.http.beacon().get_genesis_validators_root())
.expect("should fetch genesis time from http api");
assert_eq!(
node.client
.beacon_chain()
.expect("should have beacon chain")
.head()
.expect("should get head")
.beacon_state
.genesis_validators_root,
genesis_validators_root,
"should match genesis time from head state"
);
}
#[test] #[test]
fn fork() { fn fork() {
let mut env = build_env(); let mut env = build_env();
@ -903,6 +925,7 @@ fn proposer_slashing() {
proposer_index as u64, proposer_index as u64,
&key, &key,
fork, fork,
state.genesis_validators_root,
spec, spec,
); );
@ -927,6 +950,7 @@ fn proposer_slashing() {
proposer_index as u64, proposer_index as u64,
&key, &key,
fork, fork,
state.genesis_validators_root,
spec, spec,
); );
invalid_proposer_slashing.signed_header_2 = invalid_proposer_slashing.signed_header_1.clone(); invalid_proposer_slashing.signed_header_2 = invalid_proposer_slashing.signed_header_1.clone();
@ -981,6 +1005,7 @@ fn attester_slashing() {
&validator_indices[..], &validator_indices[..],
&secret_keys[..], &secret_keys[..],
fork, fork,
state.genesis_validators_root,
spec, spec,
); );
@ -1006,6 +1031,7 @@ fn attester_slashing() {
&validator_indices[..], &validator_indices[..],
&secret_keys[..], &secret_keys[..],
fork, fork,
state.genesis_validators_root,
spec, spec,
); );
invalid_attester_slashing.attestation_2 = invalid_attester_slashing.attestation_1.clone(); invalid_attester_slashing.attestation_2 = invalid_attester_slashing.attestation_1.clone();

View File

@ -11,7 +11,7 @@ use types::*;
/// ///
/// Utilises lazy-loading from separate storage for its vector fields. /// Utilises lazy-loading from separate storage for its vector fields.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Encode, Decode)] #[derive(Debug, PartialEq, Clone, Encode, Decode)]
pub struct PartialBeaconState<T> pub struct PartialBeaconState<T>
where where
@ -19,6 +19,7 @@ where
{ {
// Versioning // Versioning
pub genesis_time: u64, pub genesis_time: u64,
pub genesis_validators_root: Hash256,
pub slot: Slot, pub slot: Slot,
pub fork: Fork, pub fork: Fork,
@ -72,6 +73,7 @@ impl<T: EthSpec> PartialBeaconState<T> {
// TODO: could use references/Cow for fields to avoid cloning // TODO: could use references/Cow for fields to avoid cloning
PartialBeaconState { PartialBeaconState {
genesis_time: s.genesis_time, genesis_time: s.genesis_time,
genesis_validators_root: s.genesis_validators_root,
slot: s.slot, slot: s.slot,
fork: s.fork.clone(), fork: s.fork.clone(),
@ -181,6 +183,7 @@ impl<E: EthSpec> TryInto<BeaconState<E>> for PartialBeaconState<E> {
Ok(BeaconState { Ok(BeaconState {
genesis_time: self.genesis_time, genesis_time: self.genesis_time,
genesis_validators_root: self.genesis_validators_root,
slot: self.slot, slot: self.slot,
fork: self.fork, fork: self.fork,

View File

@ -166,6 +166,7 @@ Returns an object containing a single [`SignedBeaconBlock`](https://github.com/e
"beacon_block": { "beacon_block": {
"message": { "message": {
"slot": 0, "slot": 0,
"proposer_index": 14,
"parent_root": "0x0000000000000000000000000000000000000000000000000000000000000000", "parent_root": "0x0000000000000000000000000000000000000000000000000000000000000000",
"state_root": "0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f", "state_root": "0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f",
"body": { "body": {
@ -444,7 +445,7 @@ canonical chain.
### Returns ### Returns
Returns an object containing a single Returns an object containing a single
[`BeaconState`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#beaconstate) [`BeaconState`](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconstate)
and its tree hash root. and its tree hash root.
### Example Response ### Example Response
@ -454,6 +455,7 @@ and its tree hash root.
"root": "0x528e54ca5d4c957729a73f40fc513ae312e054c7295775c4a2b21f423416a72b", "root": "0x528e54ca5d4c957729a73f40fc513ae312e054c7295775c4a2b21f423416a72b",
"beacon_state": { "beacon_state": {
"genesis_time": 1575652800, "genesis_time": 1575652800,
"genesis_validators_root": "0xa8a9226edee1b2627fb4117d7dea4996e64dec2998f37f6e824f74f2ce39a538",
"slot": 18478 "slot": 18478
} }
} }
@ -505,7 +507,7 @@ Typical Responses | 200
### Returns ### Returns
Returns an object containing the genesis Returns an object containing the genesis
[`BeaconState`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#beaconstate). [`BeaconState`](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#beaconstate).
### Example Response ### Example Response
@ -565,7 +567,7 @@ Typical Responses | 200
### Returns ### Returns
Returns an object containing the [`Fork`](https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#fork) of the current head. Returns an object containing the [`Fork`](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#fork) of the current head.
### Example Response ### Example Response

View File

@ -1,8 +1,7 @@
use int_to_bytes::int_to_bytes8;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz::ssz_encode; use ssz::ssz_encode;
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
use types::{AttestationData, ChainSpec, Domain, Epoch, Fork}; use types::{AttestationData, ChainSpec, Domain, Epoch, Fork, Hash256};
/// Serialized `AttestationData` augmented with a domain to encode the fork info. /// Serialized `AttestationData` augmented with a domain to encode the fork info.
#[derive( #[derive(
@ -13,21 +12,34 @@ pub struct AttestationId {
} }
/// Number of domain bytes that the end of an attestation ID is padded with. /// Number of domain bytes that the end of an attestation ID is padded with.
const DOMAIN_BYTES_LEN: usize = 8; const DOMAIN_BYTES_LEN: usize = std::mem::size_of::<Hash256>();
impl AttestationId { impl AttestationId {
pub fn from_data(attestation: &AttestationData, fork: &Fork, spec: &ChainSpec) -> Self { pub fn from_data(
attestation: &AttestationData,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> Self {
let mut bytes = ssz_encode(attestation); let mut bytes = ssz_encode(attestation);
let epoch = attestation.target.epoch; let epoch = attestation.target.epoch;
bytes.extend_from_slice(&AttestationId::compute_domain_bytes(epoch, fork, spec)); bytes.extend_from_slice(
AttestationId::compute_domain_bytes(epoch, fork, genesis_validators_root, spec)
.as_bytes(),
);
AttestationId { v: bytes } AttestationId { v: bytes }
} }
pub fn compute_domain_bytes(epoch: Epoch, fork: &Fork, spec: &ChainSpec) -> Vec<u8> { pub fn compute_domain_bytes(
int_to_bytes8(spec.get_domain(epoch, Domain::BeaconAttester, fork)) epoch: Epoch,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> Hash256 {
spec.get_domain(epoch, Domain::BeaconAttester, fork, genesis_validators_root)
} }
pub fn domain_bytes_match(&self, domain_bytes: &[u8]) -> bool { pub fn domain_bytes_match(&self, domain_bytes: &Hash256) -> bool {
&self.v[self.v.len() - DOMAIN_BYTES_LEN..] == domain_bytes &self.v[self.v.len() - DOMAIN_BYTES_LEN..] == domain_bytes.as_bytes()
} }
} }

View File

@ -22,7 +22,7 @@ use std::collections::{hash_map, HashMap, HashSet};
use std::marker::PhantomData; use std::marker::PhantomData;
use types::{ use types::{
typenum::Unsigned, Attestation, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec, typenum::Unsigned, Attestation, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec,
EthSpec, Fork, ProposerSlashing, RelativeEpoch, SignedVoluntaryExit, Validator, EthSpec, Fork, Hash256, ProposerSlashing, RelativeEpoch, SignedVoluntaryExit, Validator,
}; };
#[derive(Default, Debug)] #[derive(Default, Debug)]
@ -58,9 +58,10 @@ impl<T: EthSpec> OperationPool<T> {
&self, &self,
attestation: Attestation<T>, attestation: Attestation<T>,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), AttestationValidationError> { ) -> Result<(), AttestationValidationError> {
let id = AttestationId::from_data(&attestation.data, fork, spec); let id = AttestationId::from_data(&attestation.data, fork, genesis_validators_root, spec);
// Take a write lock on the attestations map. // Take a write lock on the attestations map.
let mut attestations = self.attestations.write(); let mut attestations = self.attestations.write();
@ -106,9 +107,18 @@ impl<T: EthSpec> OperationPool<T> {
// Attestations for the current fork, which may be from the current or previous epoch. // Attestations for the current fork, which may be from the current or previous epoch.
let prev_epoch = state.previous_epoch(); let prev_epoch = state.previous_epoch();
let current_epoch = state.current_epoch(); let current_epoch = state.current_epoch();
let prev_domain_bytes = AttestationId::compute_domain_bytes(prev_epoch, &state.fork, spec); let prev_domain_bytes = AttestationId::compute_domain_bytes(
let curr_domain_bytes = prev_epoch,
AttestationId::compute_domain_bytes(current_epoch, &state.fork, spec); &state.fork,
state.genesis_validators_root,
spec,
);
let curr_domain_bytes = AttestationId::compute_domain_bytes(
current_epoch,
&state.fork,
state.genesis_validators_root,
spec,
);
let reader = self.attestations.read(); let reader = self.attestations.read();
let active_indices = state let active_indices = state
.get_cached_active_validator_indices(RelativeEpoch::Current) .get_cached_active_validator_indices(RelativeEpoch::Current)
@ -168,7 +178,7 @@ impl<T: EthSpec> OperationPool<T> {
verify_proposer_slashing(&slashing, state, VerifySignatures::True, spec)?; verify_proposer_slashing(&slashing, state, VerifySignatures::True, spec)?;
self.proposer_slashings self.proposer_slashings
.write() .write()
.insert(slashing.proposer_index, slashing); .insert(slashing.signed_header_1.message.proposer_index, slashing);
Ok(()) Ok(())
} }
@ -181,8 +191,18 @@ impl<T: EthSpec> OperationPool<T> {
spec: &ChainSpec, spec: &ChainSpec,
) -> (AttestationId, AttestationId) { ) -> (AttestationId, AttestationId) {
( (
AttestationId::from_data(&slashing.attestation_1.data, &state.fork, spec), AttestationId::from_data(
AttestationId::from_data(&slashing.attestation_2.data, &state.fork, spec), &slashing.attestation_1.data,
&state.fork,
state.genesis_validators_root,
spec,
),
AttestationId::from_data(
&slashing.attestation_2.data,
&state.fork,
state.genesis_validators_root,
spec,
),
) )
} }
@ -214,7 +234,7 @@ impl<T: EthSpec> OperationPool<T> {
|slashing| { |slashing| {
state state
.validators .validators
.get(slashing.proposer_index as usize) .get(slashing.signed_header_1.message.proposer_index as usize)
.map_or(false, |validator| !validator.slashed) .map_or(false, |validator| !validator.slashed)
}, },
T::MaxProposerSlashings::to_usize(), T::MaxProposerSlashings::to_usize(),
@ -224,7 +244,7 @@ impl<T: EthSpec> OperationPool<T> {
// slashings. // slashings.
let mut to_be_slashed = proposer_slashings let mut to_be_slashed = proposer_slashings
.iter() .iter()
.map(|s| s.proposer_index) .map(|s| s.signed_header_1.message.proposer_index)
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
let epoch = state.current_epoch(); let epoch = state.current_epoch();
@ -427,6 +447,7 @@ mod release_tests {
signers, signers,
&committee_keys, &committee_keys,
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
); );
extra_signer.map(|c_idx| { extra_signer.map(|c_idx| {
@ -436,6 +457,7 @@ mod release_tests {
&[validator_index], &[validator_index],
&[&keypairs[validator_index].sk], &[&keypairs[validator_index].sk],
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
) )
}); });
@ -548,7 +570,9 @@ mod release_tests {
spec, spec,
None, None,
); );
op_pool.insert_attestation(att, &state.fork, spec).unwrap(); op_pool
.insert_attestation(att, &state.fork, state.genesis_validators_root, spec)
.unwrap();
} }
} }
@ -617,9 +641,16 @@ mod release_tests {
None, None,
); );
op_pool op_pool
.insert_attestation(att.clone(), &state.fork, spec) .insert_attestation(
att.clone(),
&state.fork,
state.genesis_validators_root,
spec,
)
.unwrap();
op_pool
.insert_attestation(att, &state.fork, state.genesis_validators_root, spec)
.unwrap(); .unwrap();
op_pool.insert_attestation(att, &state.fork, spec).unwrap();
} }
assert_eq!(op_pool.num_attestations(), committees.len()); assert_eq!(op_pool.num_attestations(), committees.len());
@ -656,7 +687,9 @@ mod release_tests {
spec, spec,
None, None,
); );
op_pool.insert_attestation(att, &state.fork, spec).unwrap(); op_pool
.insert_attestation(att, &state.fork, state.genesis_validators_root, spec)
.unwrap();
} }
} }
@ -704,7 +737,9 @@ mod release_tests {
spec, spec,
if i == 0 { None } else { Some(0) }, if i == 0 { None } else { Some(0) },
); );
op_pool.insert_attestation(att, &state.fork, spec).unwrap(); op_pool
.insert_attestation(att, &state.fork, state.genesis_validators_root, spec)
.unwrap();
} }
}; };
@ -777,7 +812,9 @@ mod release_tests {
spec, spec,
if i == 0 { None } else { Some(0) }, if i == 0 { None } else { Some(0) },
); );
op_pool.insert_attestation(att, &state.fork, spec).unwrap(); op_pool
.insert_attestation(att, &state.fork, state.genesis_validators_root, spec)
.unwrap();
} }
}; };

View File

@ -82,7 +82,7 @@ impl<T: EthSpec> PersistedOperationPool<T> {
let proposer_slashings = RwLock::new( let proposer_slashings = RwLock::new(
self.proposer_slashings self.proposer_slashings
.into_iter() .into_iter()
.map(|slashing| (slashing.proposer_index, slashing)) .map(|slashing| (slashing.signed_header_1.message.proposer_index, slashing))
.collect(), .collect(),
); );
let voluntary_exits = RwLock::new( let voluntary_exits = RwLock::new(

View File

@ -3,7 +3,7 @@ use types::*;
/// Returns validator indices which participated in the attestation, sorted by increasing index. /// Returns validator indices which participated in the attestation, sorted by increasing index.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_attesting_indices<T: EthSpec>( pub fn get_attesting_indices<T: EthSpec>(
committee: &[usize], committee: &[usize],
bitlist: &BitList<T::MaxValidatorsPerCommittee>, bitlist: &BitList<T::MaxValidatorsPerCommittee>,

View File

@ -3,7 +3,7 @@ use types::*;
/// Returns the base reward for some validator. /// Returns the base reward for some validator.
/// ///
/// Spec v0.9.1 /// Spec v0.11.1
pub fn get_base_reward<T: EthSpec>( pub fn get_base_reward<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
index: usize, index: usize,

View File

@ -6,7 +6,7 @@ type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
/// Convert `attestation` to (almost) indexed-verifiable form. /// Convert `attestation` to (almost) indexed-verifiable form.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_indexed_attestation<T: EthSpec>( pub fn get_indexed_attestation<T: EthSpec>(
committee: &[usize], committee: &[usize],
attestation: &Attestation<T>, attestation: &Attestation<T>,

View File

@ -3,7 +3,7 @@ use types::{BeaconStateError as Error, *};
/// Initiate the exit of the validator of the given `index`. /// Initiate the exit of the validator of the given `index`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn initiate_validator_exit<T: EthSpec>( pub fn initiate_validator_exit<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
index: usize, index: usize,

View File

@ -4,7 +4,7 @@ use types::{BeaconStateError as Error, *};
/// Slash the validator with index ``index``. /// Slash the validator with index ``index``.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn slash_validator<T: EthSpec>( pub fn slash_validator<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
slashed_index: usize, slashed_index: usize,

View File

@ -6,7 +6,7 @@ use types::*;
/// Initialize a `BeaconState` from genesis data. /// Initialize a `BeaconState` from genesis data.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
// TODO: this is quite inefficient and we probably want to rethink how we do this // TODO: this is quite inefficient and we probably want to rethink how we do this
pub fn initialize_beacon_state_from_eth1<T: EthSpec>( pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
eth1_block_hash: Hash256, eth1_block_hash: Hash256,
@ -42,12 +42,15 @@ pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
// Now that we have our validators, initialize the caches (including the committees) // Now that we have our validators, initialize the caches (including the committees)
state.build_all_caches(spec)?; state.build_all_caches(spec)?;
// Set genesis validators root for domain separation and chain versioning
state.genesis_validators_root = state.update_validators_tree_hash_cache()?;
Ok(state) Ok(state)
} }
/// Determine whether a candidate genesis state is suitable for starting the chain. /// Determine whether a candidate genesis state is suitable for starting the chain.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn is_valid_genesis_state<T: EthSpec>(state: &BeaconState<T>, spec: &ChainSpec) -> bool { pub fn is_valid_genesis_state<T: EthSpec>(state: &BeaconState<T>, spec: &ChainSpec) -> bool {
state.genesis_time >= spec.min_genesis_time state.genesis_time >= spec.min_genesis_time
&& state.get_active_validator_indices(T::genesis_epoch()).len() as u64 && state.get_active_validator_indices(T::genesis_epoch()).len() as u64
@ -56,7 +59,7 @@ pub fn is_valid_genesis_state<T: EthSpec>(state: &BeaconState<T>, spec: &ChainSp
/// Activate genesis validators, if their balance is acceptable. /// Activate genesis validators, if their balance is acceptable.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_activations<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) { pub fn process_activations<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) {
for (index, validator) in state.validators.iter_mut().enumerate() { for (index, validator) in state.validators.iter_mut().enumerate() {
let balance = state.balances[index]; let balance = state.balances[index];

View File

@ -70,7 +70,7 @@ impl VerifySignatures {
/// tree hash root of the block, NOT the signing root of the block. This function takes /// tree hash root of the block, NOT the signing root of the block. This function takes
/// care of mixing in the domain. /// care of mixing in the domain.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn per_block_processing<T: EthSpec>( pub fn per_block_processing<T: EthSpec>(
mut state: &mut BeaconState<T>, mut state: &mut BeaconState<T>,
signed_block: &SignedBeaconBlock<T>, signed_block: &SignedBeaconBlock<T>,
@ -136,14 +136,26 @@ pub fn per_block_processing<T: EthSpec>(
/// Processes the block header. /// Processes the block header.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_block_header<T: EthSpec>( pub fn process_block_header<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
block: &BeaconBlock<T>, block: &BeaconBlock<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), BlockOperationError<HeaderInvalid>> { ) -> Result<(), BlockOperationError<HeaderInvalid>> {
// Verify that the slots match
verify!(block.slot == state.slot, HeaderInvalid::StateSlotMismatch); verify!(block.slot == state.slot, HeaderInvalid::StateSlotMismatch);
// Verify that proposer index is the correct index
let proposer_index = block.proposer_index as usize;
let state_proposer_index = state.get_beacon_proposer_index(block.slot, spec)?;
verify!(
proposer_index == state_proposer_index,
HeaderInvalid::ProposerIndexMismatch {
block_proposer_index: proposer_index,
state_proposer_index,
}
);
let expected_previous_block_root = state.latest_block_header.tree_hash_root(); let expected_previous_block_root = state.latest_block_header.tree_hash_root();
verify!( verify!(
block.parent_root == expected_previous_block_root, block.parent_root == expected_previous_block_root,
@ -156,11 +168,10 @@ pub fn process_block_header<T: EthSpec>(
state.latest_block_header = block.temporary_block_header(); state.latest_block_header = block.temporary_block_header();
// Verify proposer is not slashed // Verify proposer is not slashed
let proposer_idx = state.get_beacon_proposer_index(block.slot, spec)?; let proposer = &state.validators[proposer_index];
let proposer = &state.validators[proposer_idx];
verify!( verify!(
!proposer.slashed, !proposer.slashed,
HeaderInvalid::ProposerSlashed(proposer_idx) HeaderInvalid::ProposerSlashed(proposer_index)
); );
Ok(()) Ok(())
@ -168,7 +179,7 @@ pub fn process_block_header<T: EthSpec>(
/// Verifies the signature of a block. /// Verifies the signature of a block.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_block_signature<T: EthSpec>( pub fn verify_block_signature<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
block: &SignedBeaconBlock<T>, block: &SignedBeaconBlock<T>,
@ -186,7 +197,7 @@ pub fn verify_block_signature<T: EthSpec>(
/// Verifies the `randao_reveal` against the block's proposer pubkey and updates /// Verifies the `randao_reveal` against the block's proposer pubkey and updates
/// `state.latest_randao_mixes`. /// `state.latest_randao_mixes`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_randao<T: EthSpec>( pub fn process_randao<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
block: &BeaconBlock<T>, block: &BeaconBlock<T>,
@ -209,7 +220,7 @@ pub fn process_randao<T: EthSpec>(
/// Update the `state.eth1_data_votes` based upon the `eth1_data` provided. /// Update the `state.eth1_data_votes` based upon the `eth1_data` provided.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_eth1_data<T: EthSpec>( pub fn process_eth1_data<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
eth1_data: &Eth1Data, eth1_data: &Eth1Data,
@ -226,7 +237,7 @@ pub fn process_eth1_data<T: EthSpec>(
/// Returns `Some(eth1_data)` if adding the given `eth1_data` to `state.eth1_data_votes` would /// Returns `Some(eth1_data)` if adding the given `eth1_data` to `state.eth1_data_votes` would
/// result in a change to `state.eth1_data`. /// result in a change to `state.eth1_data`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_new_eth1_data<T: EthSpec>( pub fn get_new_eth1_data<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
eth1_data: &Eth1Data, eth1_data: &Eth1Data,
@ -250,7 +261,7 @@ pub fn get_new_eth1_data<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure. /// an `Err` describing the invalid object or cause of failure.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_proposer_slashings<T: EthSpec>( pub fn process_proposer_slashings<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
proposer_slashings: &[ProposerSlashing], proposer_slashings: &[ProposerSlashing],
@ -268,7 +279,12 @@ pub fn process_proposer_slashings<T: EthSpec>(
// Update the state. // Update the state.
for proposer_slashing in proposer_slashings { for proposer_slashing in proposer_slashings {
slash_validator(state, proposer_slashing.proposer_index as usize, None, spec)?; slash_validator(
state,
proposer_slashing.signed_header_1.message.proposer_index as usize,
None,
spec,
)?;
} }
Ok(()) Ok(())
@ -279,7 +295,7 @@ pub fn process_proposer_slashings<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure. /// an `Err` describing the invalid object or cause of failure.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_attester_slashings<T: EthSpec>( pub fn process_attester_slashings<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
attester_slashings: &[AttesterSlashing<T>], attester_slashings: &[AttesterSlashing<T>],
@ -333,7 +349,7 @@ pub fn process_attester_slashings<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure. /// an `Err` describing the invalid object or cause of failure.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_attestations<T: EthSpec>( pub fn process_attestations<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
attestations: &[Attestation<T>], attestations: &[Attestation<T>],
@ -379,7 +395,7 @@ pub fn process_attestations<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure. /// an `Err` describing the invalid object or cause of failure.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_deposits<T: EthSpec>( pub fn process_deposits<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
deposits: &[Deposit], deposits: &[Deposit],
@ -416,7 +432,7 @@ pub fn process_deposits<T: EthSpec>(
/// Process a single deposit, optionally verifying its merkle proof. /// Process a single deposit, optionally verifying its merkle proof.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_deposit<T: EthSpec>( pub fn process_deposit<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
deposit: &Deposit, deposit: &Deposit,
@ -482,7 +498,7 @@ pub fn process_deposit<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns /// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure. /// an `Err` describing the invalid object or cause of failure.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_exits<T: EthSpec>( pub fn process_exits<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
voluntary_exits: &[SignedVoluntaryExit], voluntary_exits: &[SignedVoluntaryExit],

View File

@ -56,9 +56,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index]; let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk { match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec), Some(sk) => {
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec), builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
}
None => builder.set_randao_reveal(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
),
} }
self.block_builder.insert_deposits( self.block_builder.insert_deposits(
@ -70,7 +79,12 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
spec, spec,
); );
let block = self.block_builder.build(&keypair.sk, &state.fork, spec); let block = self.block_builder.build(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }
@ -96,9 +110,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index]; let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk { match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec), Some(sk) => {
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec), builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
}
None => builder.set_randao_reveal(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
),
} }
match test_task { match test_task {
ExitTestTask::AlreadyInitiated => { ExitTestTask::AlreadyInitiated => {
@ -125,7 +148,12 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
} }
} }
let block = self.block_builder.build(&keypair.sk, &state.fork, spec); let block = self.block_builder.build(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }
@ -151,9 +179,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index]; let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk { match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec), Some(sk) => {
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec), builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
}
None => builder.set_randao_reveal(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
),
} }
let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect(); let all_secret_keys: Vec<&SecretKey> = keypairs.iter().map(|keypair| &keypair.sk).collect();
@ -166,7 +203,12 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
spec, spec,
) )
.unwrap(); .unwrap();
let block = self.block_builder.build(&keypair.sk, &state.fork, spec); let block = self.block_builder.build(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }
@ -192,9 +234,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index]; let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk { match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec), Some(sk) => {
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec), builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
}
None => builder.set_randao_reveal(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
),
} }
let mut validator_indices = vec![]; let mut validator_indices = vec![];
@ -210,10 +261,16 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
&validator_indices, &validator_indices,
&secret_keys, &secret_keys,
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
); );
} }
let block = self.block_builder.build(&keypair.sk, &state.fork, spec); let block = self.block_builder.build(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }
@ -239,9 +296,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index]; let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk { match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec), Some(sk) => {
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec), builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
}
None => builder.set_randao_reveal(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
),
} }
for i in 0..num_proposer_slashings { for i in 0..num_proposer_slashings {
@ -252,10 +318,16 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
validator_indices, validator_indices,
&secret_keys, &secret_keys,
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
); );
} }
let block = self.block_builder.build(&keypair.sk, &state.fork, spec); let block = self.block_builder.build(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }
@ -279,12 +351,26 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap(); let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index]; let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk { match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec), Some(sk) => {
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec), builder.set_randao_reveal(&sk, &state.fork, state.genesis_validators_root, spec)
}
None => builder.set_randao_reveal(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
),
} }
let block = self.block_builder.build(&keypair.sk, &state.fork, spec); let block = self.block_builder.build(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }

View File

@ -159,7 +159,14 @@ impl<T> From<ssz_types::Error> for BlockOperationError<T> {
pub enum HeaderInvalid { pub enum HeaderInvalid {
ProposalSignatureInvalid, ProposalSignatureInvalid,
StateSlotMismatch, StateSlotMismatch,
ParentBlockRootMismatch { state: Hash256, block: Hash256 }, ProposerIndexMismatch {
block_proposer_index: usize,
state_proposer_index: usize,
},
ParentBlockRootMismatch {
state: Hash256,
block: Hash256,
},
ProposerSlashed(usize), ProposerSlashed(usize),
} }
@ -171,6 +178,10 @@ pub enum ProposerSlashingInvalid {
/// ///
/// (proposal_1_slot, proposal_2_slot) /// (proposal_1_slot, proposal_2_slot)
ProposalSlotMismatch(Slot, Slot), ProposalSlotMismatch(Slot, Slot),
/// The two proposals have different proposer indices.
///
/// (proposer_index_1, proposer_index_2)
ProposerIndexMismatch(u64, u64),
/// The proposals are identical and therefore not slashable. /// The proposals are identical and therefore not slashable.
ProposalsIdentical, ProposalsIdentical,
/// The specified proposer cannot be slashed because they are already slashed, or not active. /// The specified proposer cannot be slashed because they are already slashed, or not active.

View File

@ -11,7 +11,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
/// Verify an `IndexedAttestation`. /// Verify an `IndexedAttestation`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn is_valid_indexed_attestation<T: EthSpec>( pub fn is_valid_indexed_attestation<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
indexed_attestation: &IndexedAttestation<T>, indexed_attestation: &IndexedAttestation<T>,

View File

@ -53,6 +53,7 @@ pub fn block_proposal_signature_set<'a, T: EthSpec>(
block.slot.epoch(T::slots_per_epoch()), block.slot.epoch(T::slots_per_epoch()),
Domain::BeaconProposer, Domain::BeaconProposer,
&state.fork, &state.fork,
state.genesis_validators_root,
); );
let message = if let Some(root) = block_root { let message = if let Some(root) = block_root {
@ -84,6 +85,7 @@ pub fn randao_signature_set<'a, T: EthSpec>(
block.slot.epoch(T::slots_per_epoch()), block.slot.epoch(T::slots_per_epoch()),
Domain::Randao, Domain::Randao,
&state.fork, &state.fork,
state.genesis_validators_root,
); );
let message = state.current_epoch().signing_root(domain); let message = state.current_epoch().signing_root(domain);
@ -101,7 +103,7 @@ pub fn proposer_slashing_signature_set<'a, T: EthSpec>(
proposer_slashing: &'a ProposerSlashing, proposer_slashing: &'a ProposerSlashing,
spec: &'a ChainSpec, spec: &'a ChainSpec,
) -> Result<(SignatureSet<'a>, SignatureSet<'a>)> { ) -> Result<(SignatureSet<'a>, SignatureSet<'a>)> {
let proposer_index = proposer_slashing.proposer_index as usize; let proposer_index = proposer_slashing.signed_header_1.message.proposer_index as usize;
Ok(( Ok((
block_header_signature_set( block_header_signature_set(
@ -130,6 +132,7 @@ fn block_header_signature_set<'a, T: EthSpec>(
signed_header.message.slot.epoch(T::slots_per_epoch()), signed_header.message.slot.epoch(T::slots_per_epoch()),
Domain::BeaconProposer, Domain::BeaconProposer,
&state.fork, &state.fork,
state.genesis_validators_root,
); );
let message = signed_header let message = signed_header
@ -162,6 +165,7 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>(
indexed_attestation.data.target.epoch, indexed_attestation.data.target.epoch,
Domain::BeaconAttester, Domain::BeaconAttester,
&state.fork, &state.fork,
state.genesis_validators_root,
); );
let message = indexed_attestation.data.signing_root(domain); let message = indexed_attestation.data.signing_root(domain);
@ -177,6 +181,7 @@ pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T: EthSpec>(
signature: &'a AggregateSignature, signature: &'a AggregateSignature,
indexed_attestation: &'b IndexedAttestation<T>, indexed_attestation: &'b IndexedAttestation<T>,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &'a ChainSpec, spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> { ) -> Result<SignatureSet<'a>> {
let pubkeys = pubkeys let pubkeys = pubkeys
@ -188,6 +193,7 @@ pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T: EthSpec>(
indexed_attestation.data.target.epoch, indexed_attestation.data.target.epoch,
Domain::BeaconAttester, Domain::BeaconAttester,
&fork, &fork,
genesis_validators_root,
); );
let message = indexed_attestation.data.signing_root(domain); let message = indexed_attestation.data.signing_root(domain);
@ -258,7 +264,12 @@ pub fn exit_signature_set<'a, T: EthSpec>(
let exit = &signed_exit.message; let exit = &signed_exit.message;
let proposer_index = exit.validator_index as usize; let proposer_index = exit.validator_index as usize;
let domain = spec.get_domain(exit.epoch, Domain::VoluntaryExit, &state.fork); let domain = spec.get_domain(
exit.epoch,
Domain::VoluntaryExit,
&state.fork,
state.genesis_validators_root,
);
let message = exit.signing_root(domain).as_bytes().to_vec(); let message = exit.signing_root(domain).as_bytes().to_vec();

View File

@ -10,7 +10,7 @@ use types::test_utils::{
use types::*; use types::*;
pub const NUM_DEPOSITS: u64 = 1; pub const NUM_DEPOSITS: u64 = 1;
pub const VALIDATOR_COUNT: usize = 10; pub const VALIDATOR_COUNT: usize = 64;
pub const SLOT_OFFSET: u64 = 4; pub const SLOT_OFFSET: u64 = 4;
pub const EXIT_SLOT_OFFSET: u64 = 2048; pub const EXIT_SLOT_OFFSET: u64 = 2048;
pub const NUM_ATTESTATIONS: u64 = 1; pub const NUM_ATTESTATIONS: u64 = 1;
@ -93,7 +93,12 @@ fn invalid_block_signature() {
// sign the block with a keypair that is not the expected proposer // sign the block with a keypair that is not the expected proposer
let keypair = Keypair::random(); let keypair = Keypair::random();
let block = block.message.sign(&keypair.sk, &state.fork, &spec); let block = block.message.sign(
&keypair.sk,
&state.fork,
state.genesis_validators_root,
&spec,
);
// process block with invalid block signature // process block with invalid block signature
let result = per_block_processing( let result = per_block_processing(
@ -630,7 +635,7 @@ fn invalid_attestation_wrong_justified_checkpoint() {
#[test] #[test]
fn invalid_attestation_bad_indexed_attestation_bad_signature() { fn invalid_attestation_bad_indexed_attestation_bad_signature() {
let spec = MainnetEthSpec::default_spec(); let spec = MainnetEthSpec::default_spec();
let builder = get_builder(&spec, SLOT_OFFSET, 33); // minmium number of validators required for this test let builder = get_builder(&spec, SLOT_OFFSET, VALIDATOR_COUNT);
let test_task = AttestationTestTask::BadIndexedAttestationBadSignature; let test_task = AttestationTestTask::BadIndexedAttestationBadSignature;
let (block, mut state) = let (block, mut state) =
builder.build_with_n_attestations(test_task, NUM_ATTESTATIONS, None, None, &spec); builder.build_with_n_attestations(test_task, NUM_ATTESTATIONS, None, None, &spec);

View File

@ -15,7 +15,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
/// ///
/// Optionally verifies the aggregate signature, depending on `verify_signatures`. /// Optionally verifies the aggregate signature, depending on `verify_signatures`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_attestation_for_block_inclusion<T: EthSpec>( pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attestation: &Attestation<T>, attestation: &Attestation<T>,
@ -49,7 +49,7 @@ pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
/// Returns a descriptive `Err` if the attestation is malformed or does not accurately reflect the /// Returns a descriptive `Err` if the attestation is malformed or does not accurately reflect the
/// prior blocks in `state`. /// prior blocks in `state`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_attestation_for_state<T: EthSpec>( pub fn verify_attestation_for_state<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attestation: &Attestation<T>, attestation: &Attestation<T>,
@ -58,6 +58,13 @@ pub fn verify_attestation_for_state<T: EthSpec>(
) -> Result<()> { ) -> Result<()> {
let data = &attestation.data; let data = &attestation.data;
// This emptiness check is required *in addition* to the length check in `get_attesting_indices`
// because we can parse a bitfield and know its length, even if it has no bits set.
verify!(
!attestation.aggregation_bits.is_zero(),
Invalid::AggregationBitfieldIsEmpty
);
verify!( verify!(
data.index < state.get_committee_count_at_slot(data.slot)?, data.index < state.get_committee_count_at_slot(data.slot)?,
Invalid::BadCommitteeIndex Invalid::BadCommitteeIndex
@ -76,7 +83,7 @@ pub fn verify_attestation_for_state<T: EthSpec>(
/// Check target epoch and source checkpoint. /// Check target epoch and source checkpoint.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn verify_casper_ffg_vote<T: EthSpec>( fn verify_casper_ffg_vote<T: EthSpec>(
attestation: &Attestation<T>, attestation: &Attestation<T>,
state: &BeaconState<T>, state: &BeaconState<T>,

View File

@ -15,7 +15,7 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
/// ///
/// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity. /// Returns `Ok(())` if the `AttesterSlashing` is valid, otherwise indicates the reason for invalidity.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_attester_slashing<T: EthSpec>( pub fn verify_attester_slashing<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attester_slashing: &AttesterSlashing<T>, attester_slashing: &AttesterSlashing<T>,
@ -47,7 +47,7 @@ pub fn verify_attester_slashing<T: EthSpec>(
/// ///
/// Returns Ok(indices) if `indices.len() > 0`. /// Returns Ok(indices) if `indices.len() > 0`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_slashable_indices<T: EthSpec>( pub fn get_slashable_indices<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
attester_slashing: &AttesterSlashing<T>, attester_slashing: &AttesterSlashing<T>,

View File

@ -14,7 +14,7 @@ fn error(reason: DepositInvalid) -> BlockOperationError<DepositInvalid> {
/// Verify `Deposit.pubkey` signed `Deposit.signature`. /// Verify `Deposit.pubkey` signed `Deposit.signature`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_deposit_signature(deposit_data: &DepositData, spec: &ChainSpec) -> Result<()> { pub fn verify_deposit_signature(deposit_data: &DepositData, spec: &ChainSpec) -> Result<()> {
let deposit_signature_message = deposit_pubkey_signature_message(&deposit_data, spec) let deposit_signature_message = deposit_pubkey_signature_message(&deposit_data, spec)
.ok_or_else(|| error(DepositInvalid::BadBlsBytes))?; .ok_or_else(|| error(DepositInvalid::BadBlsBytes))?;
@ -46,7 +46,7 @@ pub fn get_existing_validator_index<T: EthSpec>(
/// The deposit index is provided as a parameter so we can check proofs /// The deposit index is provided as a parameter so we can check proofs
/// before they're due to be processed, and in parallel. /// before they're due to be processed, and in parallel.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_deposit_merkle_proof<T: EthSpec>( pub fn verify_deposit_merkle_proof<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
deposit: &Deposit, deposit: &Deposit,

View File

@ -13,7 +13,7 @@ fn error(reason: ExitInvalid) -> BlockOperationError<ExitInvalid> {
/// ///
/// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity. /// Returns `Ok(())` if the `Exit` is valid, otherwise indicates the reason for invalidity.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_exit<T: EthSpec>( pub fn verify_exit<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
exit: &SignedVoluntaryExit, exit: &SignedVoluntaryExit,
@ -25,7 +25,7 @@ pub fn verify_exit<T: EthSpec>(
/// Like `verify_exit` but doesn't run checks which may become true in future states. /// Like `verify_exit` but doesn't run checks which may become true in future states.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_exit_time_independent_only<T: EthSpec>( pub fn verify_exit_time_independent_only<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
exit: &SignedVoluntaryExit, exit: &SignedVoluntaryExit,
@ -37,7 +37,7 @@ pub fn verify_exit_time_independent_only<T: EthSpec>(
/// Parametric version of `verify_exit` that skips some checks if `time_independent_only` is true. /// Parametric version of `verify_exit` that skips some checks if `time_independent_only` is true.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn verify_exit_parametric<T: EthSpec>( fn verify_exit_parametric<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
signed_exit: &SignedVoluntaryExit, signed_exit: &SignedVoluntaryExit,

View File

@ -14,38 +14,40 @@ fn error(reason: Invalid) -> BlockOperationError<Invalid> {
/// ///
/// Returns `Ok(())` if the `ProposerSlashing` is valid, otherwise indicates the reason for invalidity. /// Returns `Ok(())` if the `ProposerSlashing` is valid, otherwise indicates the reason for invalidity.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn verify_proposer_slashing<T: EthSpec>( pub fn verify_proposer_slashing<T: EthSpec>(
proposer_slashing: &ProposerSlashing, proposer_slashing: &ProposerSlashing,
state: &BeaconState<T>, state: &BeaconState<T>,
verify_signatures: VerifySignatures, verify_signatures: VerifySignatures,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<()> { ) -> Result<()> {
let proposer = state let header_1 = &proposer_slashing.signed_header_1.message;
.validators let header_2 = &proposer_slashing.signed_header_2.message;
.get(proposer_slashing.proposer_index as usize)
.ok_or_else(|| error(Invalid::ProposerUnknown(proposer_slashing.proposer_index)))?;
// Verify slots match // Verify slots match
verify!( verify!(
proposer_slashing.signed_header_1.message.slot header_1.slot == header_2.slot,
== proposer_slashing.signed_header_2.message.slot, Invalid::ProposalSlotMismatch(header_1.slot, header_2.slot)
Invalid::ProposalSlotMismatch( );
proposer_slashing.signed_header_1.message.slot,
proposer_slashing.signed_header_2.message.slot // Verify header proposer indices match
) verify!(
header_1.proposer_index == header_2.proposer_index,
Invalid::ProposerIndexMismatch(header_1.proposer_index, header_2.proposer_index)
); );
// But the headers are different // But the headers are different
verify!( verify!(header_1 != header_2, Invalid::ProposalsIdentical);
proposer_slashing.signed_header_1 != proposer_slashing.signed_header_2,
Invalid::ProposalsIdentical
);
// Check proposer is slashable // Check proposer is slashable
let proposer = state
.validators
.get(header_1.proposer_index as usize)
.ok_or_else(|| error(Invalid::ProposerUnknown(header_1.proposer_index)))?;
verify!( verify!(
proposer.is_slashable_at(state.current_epoch()), proposer.is_slashable_at(state.current_epoch()),
Invalid::ProposerNotSlashable(proposer_slashing.proposer_index) Invalid::ProposerNotSlashable(header_1.proposer_index)
); );
if verify_signatures.is_true() { if verify_signatures.is_true() {

View File

@ -19,7 +19,7 @@ pub use validator_statuses::{TotalBalances, ValidatorStatus, ValidatorStatuses};
/// Mutates the given `BeaconState`, returning early if an error is encountered. If an error is /// Mutates the given `BeaconState`, returning early if an error is encountered. If an error is
/// returned, a state might be "half-processed" and therefore in an invalid state. /// returned, a state might be "half-processed" and therefore in an invalid state.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn per_epoch_processing<T: EthSpec>( pub fn per_epoch_processing<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
@ -45,7 +45,11 @@ pub fn per_epoch_processing<T: EthSpec>(
process_registry_updates(state, spec)?; process_registry_updates(state, spec)?;
// Slashings. // Slashings.
process_slashings(state, validator_statuses.total_balances.current_epoch, spec)?; process_slashings(
state,
validator_statuses.total_balances.current_epoch(),
spec,
)?;
// Final updates. // Final updates.
process_final_updates(state, spec)?; process_final_updates(state, spec)?;
@ -66,7 +70,7 @@ pub fn per_epoch_processing<T: EthSpec>(
/// - `finalized_epoch` /// - `finalized_epoch`
/// - `finalized_root` /// - `finalized_root`
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[allow(clippy::if_same_then_else)] // For readability and consistency with spec. #[allow(clippy::if_same_then_else)] // For readability and consistency with spec.
pub fn process_justification_and_finalization<T: EthSpec>( pub fn process_justification_and_finalization<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
@ -86,7 +90,7 @@ pub fn process_justification_and_finalization<T: EthSpec>(
state.previous_justified_checkpoint = state.current_justified_checkpoint.clone(); state.previous_justified_checkpoint = state.current_justified_checkpoint.clone();
state.justification_bits.shift_up(1)?; state.justification_bits.shift_up(1)?;
if total_balances.previous_epoch_target_attesters * 3 >= total_balances.current_epoch * 2 { if total_balances.previous_epoch_target_attesters() * 3 >= total_balances.current_epoch() * 2 {
state.current_justified_checkpoint = Checkpoint { state.current_justified_checkpoint = Checkpoint {
epoch: previous_epoch, epoch: previous_epoch,
root: *state.get_block_root_at_epoch(previous_epoch)?, root: *state.get_block_root_at_epoch(previous_epoch)?,
@ -94,7 +98,7 @@ pub fn process_justification_and_finalization<T: EthSpec>(
state.justification_bits.set(1, true)?; state.justification_bits.set(1, true)?;
} }
// If the current epoch gets justified, fill the last bit. // If the current epoch gets justified, fill the last bit.
if total_balances.current_epoch_target_attesters * 3 >= total_balances.current_epoch * 2 { if total_balances.current_epoch_target_attesters() * 3 >= total_balances.current_epoch() * 2 {
state.current_justified_checkpoint = Checkpoint { state.current_justified_checkpoint = Checkpoint {
epoch: current_epoch, epoch: current_epoch,
root: *state.get_block_root_at_epoch(current_epoch)?, root: *state.get_block_root_at_epoch(current_epoch)?,
@ -134,7 +138,7 @@ pub fn process_justification_and_finalization<T: EthSpec>(
/// Finish up an epoch update. /// Finish up an epoch update.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_final_updates<T: EthSpec>( pub fn process_final_updates<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
@ -148,11 +152,14 @@ pub fn process_final_updates<T: EthSpec>(
} }
// Update effective balances with hysteresis (lag). // Update effective balances with hysteresis (lag).
let hysteresis_increment = spec.effective_balance_increment / spec.hysteresis_quotient;
let downward_threshold = hysteresis_increment * spec.hysteresis_downward_multiplier;
let upward_threshold = hysteresis_increment * spec.hysteresis_upward_multiplier;
for (index, validator) in state.validators.iter_mut().enumerate() { for (index, validator) in state.validators.iter_mut().enumerate() {
let balance = state.balances[index]; let balance = state.balances[index];
let half_increment = spec.effective_balance_increment / 2;
if balance < validator.effective_balance if balance + downward_threshold < validator.effective_balance
|| validator.effective_balance + 3 * half_increment < balance || validator.effective_balance + upward_threshold < balance
{ {
validator.effective_balance = std::cmp::min( validator.effective_balance = std::cmp::min(
balance - balance % spec.effective_balance_increment, balance - balance % spec.effective_balance_increment,

View File

@ -33,7 +33,7 @@ impl std::ops::AddAssign for Delta {
/// Apply attester and proposer rewards. /// Apply attester and proposer rewards.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_rewards_and_penalties<T: EthSpec>( pub fn process_rewards_and_penalties<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
validator_statuses: &mut ValidatorStatuses, validator_statuses: &mut ValidatorStatuses,
@ -67,7 +67,7 @@ pub fn process_rewards_and_penalties<T: EthSpec>(
/// For each attesting validator, reward the proposer who was first to include their attestation. /// For each attesting validator, reward the proposer who was first to include their attestation.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_proposer_deltas<T: EthSpec>( fn get_proposer_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>, deltas: &mut Vec<Delta>,
state: &BeaconState<T>, state: &BeaconState<T>,
@ -83,7 +83,7 @@ fn get_proposer_deltas<T: EthSpec>(
let base_reward = get_base_reward( let base_reward = get_base_reward(
state, state,
index, index,
validator_statuses.total_balances.current_epoch, validator_statuses.total_balances.current_epoch(),
spec, spec,
)?; )?;
@ -100,7 +100,7 @@ fn get_proposer_deltas<T: EthSpec>(
/// Apply rewards for participation in attestations during the previous epoch. /// Apply rewards for participation in attestations during the previous epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_attestation_deltas<T: EthSpec>( fn get_attestation_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>, deltas: &mut Vec<Delta>,
state: &BeaconState<T>, state: &BeaconState<T>,
@ -113,7 +113,7 @@ fn get_attestation_deltas<T: EthSpec>(
let base_reward = get_base_reward( let base_reward = get_base_reward(
state, state,
index, index,
validator_statuses.total_balances.current_epoch, validator_statuses.total_balances.current_epoch(),
spec, spec,
)?; )?;
@ -133,7 +133,7 @@ fn get_attestation_deltas<T: EthSpec>(
/// Determine the delta for a single validator, sans proposer rewards. /// Determine the delta for a single validator, sans proposer rewards.
/// ///
/// Spec v0.11.0 /// Spec v0.11.1
fn get_attestation_delta<T: EthSpec>( fn get_attestation_delta<T: EthSpec>(
validator: &ValidatorStatus, validator: &ValidatorStatus,
total_balances: &TotalBalances, total_balances: &TotalBalances,
@ -157,13 +157,13 @@ fn get_attestation_delta<T: EthSpec>(
// - increment = EFFECTIVE_BALANCE_INCREMENT // - increment = EFFECTIVE_BALANCE_INCREMENT
// - reward_numerator = get_base_reward(state, index) * (attesting_balance // increment) // - reward_numerator = get_base_reward(state, index) * (attesting_balance // increment)
// - rewards[index] = reward_numerator // (total_balance // increment) // - rewards[index] = reward_numerator // (total_balance // increment)
let total_balance_ebi = total_balances.current_epoch / spec.effective_balance_increment; let total_balance_ebi = total_balances.current_epoch() / spec.effective_balance_increment;
let total_attesting_balance_ebi = let total_attesting_balance_ebi =
total_balances.previous_epoch_attesters / spec.effective_balance_increment; total_balances.previous_epoch_attesters() / spec.effective_balance_increment;
let matching_target_balance_ebi = let matching_target_balance_ebi =
total_balances.previous_epoch_target_attesters / spec.effective_balance_increment; total_balances.previous_epoch_target_attesters() / spec.effective_balance_increment;
let matching_head_balance_ebi = let matching_head_balance_ebi =
total_balances.previous_epoch_head_attesters / spec.effective_balance_increment; total_balances.previous_epoch_head_attesters() / spec.effective_balance_increment;
// Expected FFG source. // Expected FFG source.
// Spec: // Spec:

View File

@ -2,7 +2,7 @@ use types::{BeaconStateError as Error, *};
/// Process slashings. /// Process slashings.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_slashings<T: EthSpec>( pub fn process_slashings<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
total_balance: u64, total_balance: u64,

View File

@ -5,7 +5,7 @@ use types::*;
/// Performs a validator registry update, if required. /// Performs a validator registry update, if required.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_registry_updates<T: EthSpec>( pub fn process_registry_updates<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,

View File

@ -12,7 +12,7 @@ macro_rules! set_self_if_other_is_true {
} }
/// The information required to reward a block producer for including an attestation in a block. /// The information required to reward a block producer for including an attestation in a block.
#[derive(Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct InclusionInfo { pub struct InclusionInfo {
/// The distance between the attestation slot and the slot that attestation was included in a /// The distance between the attestation slot and the slot that attestation was included in a
/// block. /// block.
@ -43,7 +43,7 @@ impl InclusionInfo {
} }
/// Information required to reward some validator during the current and previous epoch. /// Information required to reward some validator during the current and previous epoch.
#[derive(Default, Clone)] #[derive(Debug, Default, Clone)]
pub struct ValidatorStatus { pub struct ValidatorStatus {
/// True if the validator has been slashed, ever. /// True if the validator has been slashed, ever.
pub is_slashed: bool, pub is_slashed: bool,
@ -107,30 +107,64 @@ impl ValidatorStatus {
/// The total effective balances for different sets of validators during the previous and current /// The total effective balances for different sets of validators during the previous and current
/// epochs. /// epochs.
#[derive(Default, Clone, Debug)] #[derive(Clone, Debug)]
pub struct TotalBalances { pub struct TotalBalances {
/// The effective balance increment from the spec.
effective_balance_increment: u64,
/// The total effective balance of all active validators during the _current_ epoch. /// The total effective balance of all active validators during the _current_ epoch.
pub current_epoch: u64, current_epoch: u64,
/// The total effective balance of all active validators during the _previous_ epoch. /// The total effective balance of all active validators during the _previous_ epoch.
pub previous_epoch: u64, previous_epoch: u64,
/// The total effective balance of all validators who attested during the _current_ epoch. /// The total effective balance of all validators who attested during the _current_ epoch.
pub current_epoch_attesters: u64, current_epoch_attesters: u64,
/// The total effective balance of all validators who attested during the _current_ epoch and /// The total effective balance of all validators who attested during the _current_ epoch and
/// agreed with the state about the beacon block at the first slot of the _current_ epoch. /// agreed with the state about the beacon block at the first slot of the _current_ epoch.
pub current_epoch_target_attesters: u64, current_epoch_target_attesters: u64,
/// The total effective balance of all validators who attested during the _previous_ epoch. /// The total effective balance of all validators who attested during the _previous_ epoch.
pub previous_epoch_attesters: u64, previous_epoch_attesters: u64,
/// The total effective balance of all validators who attested during the _previous_ epoch and /// The total effective balance of all validators who attested during the _previous_ epoch and
/// agreed with the state about the beacon block at the first slot of the _previous_ epoch. /// agreed with the state about the beacon block at the first slot of the _previous_ epoch.
pub previous_epoch_target_attesters: u64, previous_epoch_target_attesters: u64,
/// The total effective balance of all validators who attested during the _previous_ epoch and /// The total effective balance of all validators who attested during the _previous_ epoch and
/// agreed with the state about the beacon block at the time of attestation. /// agreed with the state about the beacon block at the time of attestation.
pub previous_epoch_head_attesters: u64, previous_epoch_head_attesters: u64,
}
// Generate a safe accessor for a balance in `TotalBalances`, as per spec `get_total_balance`.
macro_rules! balance_accessor {
($field_name:ident) => {
pub fn $field_name(&self) -> u64 {
std::cmp::max(self.effective_balance_increment, self.$field_name)
}
};
}
impl TotalBalances {
pub fn new(spec: &ChainSpec) -> Self {
Self {
effective_balance_increment: spec.effective_balance_increment,
current_epoch: 0,
previous_epoch: 0,
current_epoch_attesters: 0,
current_epoch_target_attesters: 0,
previous_epoch_attesters: 0,
previous_epoch_target_attesters: 0,
previous_epoch_head_attesters: 0,
}
}
balance_accessor!(current_epoch);
balance_accessor!(previous_epoch);
balance_accessor!(current_epoch_attesters);
balance_accessor!(current_epoch_target_attesters);
balance_accessor!(previous_epoch_attesters);
balance_accessor!(previous_epoch_target_attesters);
balance_accessor!(previous_epoch_head_attesters);
} }
/// Summarised information about validator participation in the _previous and _current_ epochs of /// Summarised information about validator participation in the _previous and _current_ epochs of
/// some `BeaconState`. /// some `BeaconState`.
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct ValidatorStatuses { pub struct ValidatorStatuses {
/// Information about each individual validator from the state's validator registry. /// Information about each individual validator from the state's validator registry.
pub statuses: Vec<ValidatorStatus>, pub statuses: Vec<ValidatorStatus>,
@ -144,13 +178,13 @@ impl ValidatorStatuses {
/// - Active validators /// - Active validators
/// - Total balances for the current and previous epochs. /// - Total balances for the current and previous epochs.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn new<T: EthSpec>( pub fn new<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<Self, BeaconStateError> { ) -> Result<Self, BeaconStateError> {
let mut statuses = Vec::with_capacity(state.validators.len()); let mut statuses = Vec::with_capacity(state.validators.len());
let mut total_balances = TotalBalances::default(); let mut total_balances = TotalBalances::new(spec);
for (i, validator) in state.validators.iter().enumerate() { for (i, validator) in state.validators.iter().enumerate() {
let effective_balance = state.get_effective_balance(i, spec)?; let effective_balance = state.get_effective_balance(i, spec)?;
@ -184,7 +218,7 @@ impl ValidatorStatuses {
/// Process some attestations from the given `state` updating the `statuses` and /// Process some attestations from the given `state` updating the `statuses` and
/// `total_balances` fields. /// `total_balances` fields.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn process_attestations<T: EthSpec>( pub fn process_attestations<T: EthSpec>(
&mut self, &mut self,
state: &BeaconState<T>, state: &BeaconState<T>,
@ -221,10 +255,10 @@ impl ValidatorStatuses {
if target_matches_epoch_start_block(a, state, state.previous_epoch())? { if target_matches_epoch_start_block(a, state, state.previous_epoch())? {
status.is_previous_epoch_target_attester = true; status.is_previous_epoch_target_attester = true;
}
if has_common_beacon_block_root(a, state)? { if has_common_beacon_block_root(a, state)? {
status.is_previous_epoch_head_attester = true; status.is_previous_epoch_head_attester = true;
}
} }
} }
@ -265,7 +299,7 @@ impl ValidatorStatuses {
/// Returns `true` if the attestation's FFG target is equal to the hash of the `state`'s first /// Returns `true` if the attestation's FFG target is equal to the hash of the `state`'s first
/// beacon block in the given `epoch`. /// beacon block in the given `epoch`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn target_matches_epoch_start_block<T: EthSpec>( fn target_matches_epoch_start_block<T: EthSpec>(
a: &PendingAttestation<T>, a: &PendingAttestation<T>,
state: &BeaconState<T>, state: &BeaconState<T>,
@ -280,7 +314,7 @@ fn target_matches_epoch_start_block<T: EthSpec>(
/// Returns `true` if a `PendingAttestation` and `BeaconState` share the same beacon block hash for /// Returns `true` if a `PendingAttestation` and `BeaconState` share the same beacon block hash for
/// the current slot of the `PendingAttestation`. /// the current slot of the `PendingAttestation`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn has_common_beacon_block_root<T: EthSpec>( fn has_common_beacon_block_root<T: EthSpec>(
a: &PendingAttestation<T>, a: &PendingAttestation<T>,
state: &BeaconState<T>, state: &BeaconState<T>,

View File

@ -13,7 +13,7 @@ pub enum Error {
/// `state_root` is `None`, the root of `state` will be computed using a cached tree hash. /// `state_root` is `None`, the root of `state` will be computed using a cached tree hash.
/// Providing the `state_root` makes this function several orders of magniude faster. /// Providing the `state_root` makes this function several orders of magniude faster.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn per_slot_processing<T: EthSpec>( pub fn per_slot_processing<T: EthSpec>(
state: &mut BeaconState<T>, state: &mut BeaconState<T>,
state_root: Option<Hash256>, state_root: Option<Hash256>,

View File

@ -62,7 +62,14 @@ impl<T: EthSpec> BlockBuilder<T> {
let proposer_keypair = &keypairs[proposer_index]; let proposer_keypair = &keypairs[proposer_index];
builder.set_randao_reveal(&proposer_keypair.sk, &state.fork, spec); builder.set_proposer_index(proposer_index as u64);
builder.set_randao_reveal(
&proposer_keypair.sk,
&state.fork,
state.genesis_validators_root,
spec,
);
let parent_root = state.latest_block_header.canonical_root(); let parent_root = state.latest_block_header.canonical_root();
builder.set_parent_root(parent_root); builder.set_parent_root(parent_root);
@ -79,6 +86,7 @@ impl<T: EthSpec> BlockBuilder<T> {
validator_index, validator_index,
&keypairs[validator_index as usize].sk, &keypairs[validator_index as usize].sk,
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
); );
} }
@ -106,6 +114,7 @@ impl<T: EthSpec> BlockBuilder<T> {
&attesters, &attesters,
&secret_keys, &secret_keys,
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
); );
} }
@ -161,9 +170,12 @@ impl<T: EthSpec> BlockBuilder<T> {
// Set the eth1 data to be different from the state. // Set the eth1 data to be different from the state.
self.block_builder.block.body.eth1_data.block_hash = Hash256::from_slice(&[42; 32]); self.block_builder.block.body.eth1_data.block_hash = Hash256::from_slice(&[42; 32]);
let block = self let block = self.block_builder.build(
.block_builder &proposer_keypair.sk,
.build(&proposer_keypair.sk, &state.fork, spec); &state.fork,
state.genesis_validators_root,
spec,
);
(block, state) (block, state)
} }

View File

@ -2,7 +2,7 @@ use super::{
AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey, AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey,
Signature, SignedRoot, Signature, SignedRoot,
}; };
use crate::test_utils::TestRandom; use crate::{test_utils::TestRandom, Hash256};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode}; use ssz_derive::{Decode, Encode};
@ -17,7 +17,7 @@ pub enum Error {
/// Details an attestation that can be slashable. /// Details an attestation that can be slashable.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct Attestation<T: EthSpec> { pub struct Attestation<T: EthSpec> {
@ -53,6 +53,7 @@ impl<T: EthSpec> Attestation<T> {
secret_key: &SecretKey, secret_key: &SecretKey,
committee_position: usize, committee_position: usize,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> Result<(), Error> { ) -> Result<(), Error> {
if self if self
@ -66,7 +67,12 @@ impl<T: EthSpec> Attestation<T> {
.set(committee_position, true) .set(committee_position, true)
.map_err(Error::SszTypesError)?; .map_err(Error::SszTypesError)?;
let domain = spec.get_domain(self.data.target.epoch, Domain::BeaconAttester, fork); let domain = spec.get_domain(
self.data.target.epoch,
Domain::BeaconAttester,
fork,
genesis_validators_root,
);
let message = self.data.signing_root(domain); let message = self.data.signing_root(domain);
self.signature self.signature

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// The data upon which an attestation is based. /// The data upon which an attestation is based.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive( #[derive(
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Encode, Decode, TreeHash, TestRandom, Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Encode, Decode, TreeHash, TestRandom,
)] )]

View File

@ -7,7 +7,7 @@ use tree_hash_derive::TreeHash;
/// Two conflicting attestations. /// Two conflicting attestations.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct AttesterSlashing<T: EthSpec> { pub struct AttesterSlashing<T: EthSpec> {

View File

@ -10,11 +10,12 @@ use tree_hash_derive::TreeHash;
/// A block of the `BeaconChain`. /// A block of the `BeaconChain`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct BeaconBlock<T: EthSpec> { pub struct BeaconBlock<T: EthSpec> {
pub slot: Slot, pub slot: Slot,
pub proposer_index: u64,
pub parent_root: Hash256, pub parent_root: Hash256,
pub state_root: Hash256, pub state_root: Hash256,
pub body: BeaconBlockBody<T>, pub body: BeaconBlockBody<T>,
@ -25,10 +26,11 @@ impl<T: EthSpec> SignedRoot for BeaconBlock<T> {}
impl<T: EthSpec> BeaconBlock<T> { impl<T: EthSpec> BeaconBlock<T> {
/// Returns an empty block to be used during genesis. /// Returns an empty block to be used during genesis.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn empty(spec: &ChainSpec) -> Self { pub fn empty(spec: &ChainSpec) -> Self {
BeaconBlock { BeaconBlock {
slot: spec.genesis_slot, slot: spec.genesis_slot,
proposer_index: 0,
parent_root: Hash256::zero(), parent_root: Hash256::zero(),
state_root: Hash256::zero(), state_root: Hash256::zero(),
body: BeaconBlockBody { body: BeaconBlockBody {
@ -55,7 +57,7 @@ impl<T: EthSpec> BeaconBlock<T> {
/// Returns the `tree_hash_root` of the block. /// Returns the `tree_hash_root` of the block.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 { pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.tree_hash_root()[..]) Hash256::from_slice(&self.tree_hash_root()[..])
} }
@ -67,10 +69,11 @@ impl<T: EthSpec> BeaconBlock<T> {
/// ///
/// Note: performs a full tree-hash of `self.body`. /// Note: performs a full tree-hash of `self.body`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn block_header(&self) -> BeaconBlockHeader { pub fn block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader { BeaconBlockHeader {
slot: self.slot, slot: self.slot,
proposer_index: self.proposer_index,
parent_root: self.parent_root, parent_root: self.parent_root,
state_root: self.state_root, state_root: self.state_root,
body_root: Hash256::from_slice(&self.body.tree_hash_root()[..]), body_root: Hash256::from_slice(&self.body.tree_hash_root()[..]),
@ -79,7 +82,7 @@ impl<T: EthSpec> BeaconBlock<T> {
/// Returns a "temporary" header, where the `state_root` is `Hash256::zero()`. /// Returns a "temporary" header, where the `state_root` is `Hash256::zero()`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn temporary_block_header(&self) -> BeaconBlockHeader { pub fn temporary_block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader { BeaconBlockHeader {
state_root: Hash256::zero(), state_root: Hash256::zero(),
@ -92,9 +95,15 @@ impl<T: EthSpec> BeaconBlock<T> {
self, self,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> SignedBeaconBlock<T> { ) -> SignedBeaconBlock<T> {
let domain = spec.get_domain(self.epoch(), Domain::BeaconProposer, fork); let domain = spec.get_domain(
self.epoch(),
Domain::BeaconProposer,
fork,
genesis_validators_root,
);
let message = self.signing_root(domain); let message = self.signing_root(domain);
let signature = Signature::new(message.as_bytes(), secret_key); let signature = Signature::new(message.as_bytes(), secret_key);
SignedBeaconBlock { SignedBeaconBlock {

View File

@ -10,7 +10,7 @@ use tree_hash_derive::TreeHash;
/// The body of a `BeaconChain` block, containing operations. /// The body of a `BeaconChain` block, containing operations.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct BeaconBlockBody<T: EthSpec> { pub struct BeaconBlockBody<T: EthSpec> {

View File

@ -9,10 +9,11 @@ use tree_hash_derive::TreeHash;
/// A header of a `BeaconBlock`. /// A header of a `BeaconBlock`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct BeaconBlockHeader { pub struct BeaconBlockHeader {
pub slot: Slot, pub slot: Slot,
pub proposer_index: u64,
pub parent_root: Hash256, pub parent_root: Hash256,
pub state_root: Hash256, pub state_root: Hash256,
pub body_root: Hash256, pub body_root: Hash256,
@ -23,17 +24,18 @@ impl SignedRoot for BeaconBlockHeader {}
impl BeaconBlockHeader { impl BeaconBlockHeader {
/// Returns the `tree_hash_root` of the header. /// Returns the `tree_hash_root` of the header.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 { pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.tree_hash_root()[..]) Hash256::from_slice(&self.tree_hash_root()[..])
} }
/// Given a `body`, consumes `self` and returns a complete `BeaconBlock`. /// Given a `body`, consumes `self` and returns a complete `BeaconBlock`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn into_block<T: EthSpec>(self, body: BeaconBlockBody<T>) -> BeaconBlock<T> { pub fn into_block<T: EthSpec>(self, body: BeaconBlockBody<T>) -> BeaconBlock<T> {
BeaconBlock { BeaconBlock {
slot: self.slot, slot: self.slot,
proposer_index: self.proposer_index,
parent_root: self.parent_root, parent_root: self.parent_root,
state_root: self.state_root, state_root: self.state_root,
body, body,
@ -45,10 +47,11 @@ impl BeaconBlockHeader {
self, self,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> SignedBeaconBlockHeader { ) -> SignedBeaconBlockHeader {
let epoch = self.slot.epoch(E::slots_per_epoch()); let epoch = self.slot.epoch(E::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::BeaconProposer, fork); let domain = spec.get_domain(epoch, Domain::BeaconProposer, fork, genesis_validators_root);
let message = self.signing_root(domain); let message = self.signing_root(domain);
let signature = Signature::new(message.as_bytes(), secret_key); let signature = Signature::new(message.as_bytes(), secret_key);
SignedBeaconBlockHeader { SignedBeaconBlockHeader {

View File

@ -91,7 +91,7 @@ impl AllowNextEpoch {
/// The state of the `BeaconChain` at some slot. /// The state of the `BeaconChain` at some slot.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive( #[derive(
Debug, Debug,
PartialEq, PartialEq,
@ -111,6 +111,7 @@ where
{ {
// Versioning // Versioning
pub genesis_time: u64, pub genesis_time: u64,
pub genesis_validators_root: Hash256,
pub slot: Slot, pub slot: Slot,
pub fork: Fork, pub fork: Fork,
@ -182,11 +183,12 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Not a complete genesis state, see `initialize_beacon_state_from_eth1`. /// Not a complete genesis state, see `initialize_beacon_state_from_eth1`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn new(genesis_time: u64, eth1_data: Eth1Data, spec: &ChainSpec) -> Self { pub fn new(genesis_time: u64, eth1_data: Eth1Data, spec: &ChainSpec) -> Self {
BeaconState { BeaconState {
// Versioning // Versioning
genesis_time, genesis_time,
genesis_validators_root: Hash256::zero(), // Set later.
slot: spec.genesis_slot, slot: spec.genesis_slot,
fork: Fork { fork: Fork {
previous_version: spec.genesis_fork_version, previous_version: spec.genesis_fork_version,
@ -239,7 +241,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Returns the `tree_hash_root` of the state. /// Returns the `tree_hash_root` of the state.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 { pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.tree_hash_root()[..]) Hash256::from_slice(&self.tree_hash_root()[..])
} }
@ -268,7 +270,7 @@ impl<T: EthSpec> BeaconState<T> {
/// The epoch corresponding to `self.slot`. /// The epoch corresponding to `self.slot`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn current_epoch(&self) -> Epoch { pub fn current_epoch(&self) -> Epoch {
self.slot.epoch(T::slots_per_epoch()) self.slot.epoch(T::slots_per_epoch())
} }
@ -277,7 +279,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// If the current epoch is the genesis epoch, the genesis_epoch is returned. /// If the current epoch is the genesis epoch, the genesis_epoch is returned.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn previous_epoch(&self) -> Epoch { pub fn previous_epoch(&self) -> Epoch {
let current_epoch = self.current_epoch(); let current_epoch = self.current_epoch();
if current_epoch > T::genesis_epoch() { if current_epoch > T::genesis_epoch() {
@ -289,7 +291,7 @@ impl<T: EthSpec> BeaconState<T> {
/// The epoch following `self.current_epoch()`. /// The epoch following `self.current_epoch()`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn next_epoch(&self) -> Epoch { pub fn next_epoch(&self) -> Epoch {
self.current_epoch() + 1 self.current_epoch() + 1
} }
@ -298,7 +300,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Makes use of the committee cache and will fail if no cache exists for the slot's epoch. /// Makes use of the committee cache and will fail if no cache exists for the slot's epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_committee_count_at_slot(&self, slot: Slot) -> Result<u64, Error> { pub fn get_committee_count_at_slot(&self, slot: Slot) -> Result<u64, Error> {
let cache = self.committee_cache_at_slot(slot)?; let cache = self.committee_cache_at_slot(slot)?;
Ok(cache.committees_per_slot() as u64) Ok(cache.committees_per_slot() as u64)
@ -306,7 +308,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Compute the number of committees in an entire epoch. /// Compute the number of committees in an entire epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_epoch_committee_count(&self, relative_epoch: RelativeEpoch) -> Result<u64, Error> { pub fn get_epoch_committee_count(&self, relative_epoch: RelativeEpoch) -> Result<u64, Error> {
let cache = self.committee_cache(relative_epoch)?; let cache = self.committee_cache(relative_epoch)?;
Ok(cache.epoch_committee_count() as u64) Ok(cache.epoch_committee_count() as u64)
@ -330,7 +332,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Does not utilize the cache, performs a full iteration over the validator registry. /// Does not utilize the cache, performs a full iteration over the validator registry.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec<usize> { pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec<usize> {
get_active_validator_indices(&self.validators, epoch) get_active_validator_indices(&self.validators, epoch)
} }
@ -350,7 +352,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Utilises the committee cache. /// Utilises the committee cache.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_beacon_committee( pub fn get_beacon_committee(
&self, &self,
slot: Slot, slot: Slot,
@ -369,7 +371,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Utilises the committee cache. /// Utilises the committee cache.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_beacon_committees_at_slot(&self, slot: Slot) -> Result<Vec<BeaconCommittee>, Error> { pub fn get_beacon_committees_at_slot(&self, slot: Slot) -> Result<Vec<BeaconCommittee>, Error> {
let cache = self.committee_cache_at_slot(slot)?; let cache = self.committee_cache_at_slot(slot)?;
cache.get_beacon_committees_at_slot(slot) cache.get_beacon_committees_at_slot(slot)
@ -379,7 +381,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Utilises the committee cache. /// Utilises the committee cache.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_beacon_committees_at_epoch( pub fn get_beacon_committees_at_epoch(
&self, &self,
relative_epoch: RelativeEpoch, relative_epoch: RelativeEpoch,
@ -390,7 +392,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Compute the proposer (not necessarily for the Beacon chain) from a list of indices. /// Compute the proposer (not necessarily for the Beacon chain) from a list of indices.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
// NOTE: be sure to test this bad boy. // NOTE: be sure to test this bad boy.
pub fn compute_proposer_index( pub fn compute_proposer_index(
&self, &self,
@ -429,7 +431,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Returns the beacon proposer index for the `slot` in the given `relative_epoch`. /// Returns the beacon proposer index for the `slot` in the given `relative_epoch`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_beacon_proposer_index(&self, slot: Slot, spec: &ChainSpec) -> Result<usize, Error> { pub fn get_beacon_proposer_index(&self, slot: Slot, spec: &ChainSpec) -> Result<usize, Error> {
let epoch = slot.epoch(T::slots_per_epoch()); let epoch = slot.epoch(T::slots_per_epoch());
let seed = self.get_beacon_proposer_seed(slot, spec)?; let seed = self.get_beacon_proposer_seed(slot, spec)?;
@ -440,7 +442,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Compute the seed to use for the beacon proposer selection at the given `slot`. /// Compute the seed to use for the beacon proposer selection at the given `slot`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_beacon_proposer_seed(&self, slot: Slot, spec: &ChainSpec) -> Result<Vec<u8>, Error> { fn get_beacon_proposer_seed(&self, slot: Slot, spec: &ChainSpec) -> Result<Vec<u8>, Error> {
let epoch = slot.epoch(T::slots_per_epoch()); let epoch = slot.epoch(T::slots_per_epoch());
let mut preimage = self let mut preimage = self
@ -455,7 +457,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// It needs filling in on all slots where there isn't a skip. /// It needs filling in on all slots where there isn't a skip.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_latest_block_root(&self, current_state_root: Hash256) -> Hash256 { pub fn get_latest_block_root(&self, current_state_root: Hash256) -> Hash256 {
if self.latest_block_header.state_root.is_zero() { if self.latest_block_header.state_root.is_zero() {
let mut latest_block_header = self.latest_block_header.clone(); let mut latest_block_header = self.latest_block_header.clone();
@ -468,7 +470,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for latest block roots, given some `slot`. /// Safely obtains the index for latest block roots, given some `slot`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_latest_block_roots_index(&self, slot: Slot) -> Result<usize, Error> { fn get_latest_block_roots_index(&self, slot: Slot) -> Result<usize, Error> {
if (slot < self.slot) && (self.slot <= slot + self.block_roots.len() as u64) { if (slot < self.slot) && (self.slot <= slot + self.block_roots.len() as u64) {
Ok(slot.as_usize() % self.block_roots.len()) Ok(slot.as_usize() % self.block_roots.len())
@ -479,7 +481,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the block root at a recent `slot`. /// Return the block root at a recent `slot`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_block_root(&self, slot: Slot) -> Result<&Hash256, BeaconStateError> { pub fn get_block_root(&self, slot: Slot) -> Result<&Hash256, BeaconStateError> {
let i = self.get_latest_block_roots_index(slot)?; let i = self.get_latest_block_roots_index(slot)?;
Ok(&self.block_roots[i]) Ok(&self.block_roots[i])
@ -487,7 +489,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the block root at a recent `epoch`. /// Return the block root at a recent `epoch`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
// NOTE: the spec calls this get_block_root // NOTE: the spec calls this get_block_root
pub fn get_block_root_at_epoch(&self, epoch: Epoch) -> Result<&Hash256, BeaconStateError> { pub fn get_block_root_at_epoch(&self, epoch: Epoch) -> Result<&Hash256, BeaconStateError> {
self.get_block_root(epoch.start_slot(T::slots_per_epoch())) self.get_block_root(epoch.start_slot(T::slots_per_epoch()))
@ -495,7 +497,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Sets the block root for some given slot. /// Sets the block root for some given slot.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn set_block_root( pub fn set_block_root(
&mut self, &mut self,
slot: Slot, slot: Slot,
@ -513,7 +515,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for `randao_mixes` /// Safely obtains the index for `randao_mixes`
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_randao_mix_index( fn get_randao_mix_index(
&self, &self,
epoch: Epoch, epoch: Epoch,
@ -535,7 +537,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// See `Self::get_randao_mix`. /// See `Self::get_randao_mix`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn update_randao_mix(&mut self, epoch: Epoch, signature: &Signature) -> Result<(), Error> { pub fn update_randao_mix(&mut self, epoch: Epoch, signature: &Signature) -> Result<(), Error> {
let i = epoch.as_usize() % T::EpochsPerHistoricalVector::to_usize(); let i = epoch.as_usize() % T::EpochsPerHistoricalVector::to_usize();
@ -548,7 +550,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the randao mix at a recent ``epoch``. /// Return the randao mix at a recent ``epoch``.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_randao_mix(&self, epoch: Epoch) -> Result<&Hash256, Error> { pub fn get_randao_mix(&self, epoch: Epoch) -> Result<&Hash256, Error> {
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::False)?; let i = self.get_randao_mix_index(epoch, AllowNextEpoch::False)?;
Ok(&self.randao_mixes[i]) Ok(&self.randao_mixes[i])
@ -556,7 +558,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Set the randao mix at a recent ``epoch``. /// Set the randao mix at a recent ``epoch``.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn set_randao_mix(&mut self, epoch: Epoch, mix: Hash256) -> Result<(), Error> { pub fn set_randao_mix(&mut self, epoch: Epoch, mix: Hash256) -> Result<(), Error> {
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::True)?; let i = self.get_randao_mix_index(epoch, AllowNextEpoch::True)?;
self.randao_mixes[i] = mix; self.randao_mixes[i] = mix;
@ -565,7 +567,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for latest state roots, given some `slot`. /// Safely obtains the index for latest state roots, given some `slot`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_latest_state_roots_index(&self, slot: Slot) -> Result<usize, Error> { fn get_latest_state_roots_index(&self, slot: Slot) -> Result<usize, Error> {
if (slot < self.slot) && (self.slot <= slot + Slot::from(self.state_roots.len())) { if (slot < self.slot) && (self.slot <= slot + Slot::from(self.state_roots.len())) {
Ok(slot.as_usize() % self.state_roots.len()) Ok(slot.as_usize() % self.state_roots.len())
@ -576,7 +578,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Gets the state root for some slot. /// Gets the state root for some slot.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_state_root(&self, slot: Slot) -> Result<&Hash256, Error> { pub fn get_state_root(&self, slot: Slot) -> Result<&Hash256, Error> {
let i = self.get_latest_state_roots_index(slot)?; let i = self.get_latest_state_roots_index(slot)?;
Ok(&self.state_roots[i]) Ok(&self.state_roots[i])
@ -584,7 +586,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Gets the oldest (earliest slot) state root. /// Gets the oldest (earliest slot) state root.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_oldest_state_root(&self) -> Result<&Hash256, Error> { pub fn get_oldest_state_root(&self) -> Result<&Hash256, Error> {
let i = let i =
self.get_latest_state_roots_index(self.slot - Slot::from(self.state_roots.len()))?; self.get_latest_state_roots_index(self.slot - Slot::from(self.state_roots.len()))?;
@ -593,7 +595,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Gets the oldest (earliest slot) block root. /// Gets the oldest (earliest slot) block root.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_oldest_block_root(&self) -> Result<&Hash256, Error> { pub fn get_oldest_block_root(&self) -> Result<&Hash256, Error> {
let i = self.get_latest_block_roots_index(self.slot - self.block_roots.len() as u64)?; let i = self.get_latest_block_roots_index(self.slot - self.block_roots.len() as u64)?;
Ok(&self.block_roots[i]) Ok(&self.block_roots[i])
@ -601,7 +603,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Sets the latest state root for slot. /// Sets the latest state root for slot.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn set_state_root(&mut self, slot: Slot, state_root: Hash256) -> Result<(), Error> { pub fn set_state_root(&mut self, slot: Slot, state_root: Hash256) -> Result<(), Error> {
let i = self.get_latest_state_roots_index(slot)?; let i = self.get_latest_state_roots_index(slot)?;
self.state_roots[i] = state_root; self.state_roots[i] = state_root;
@ -610,7 +612,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtain the index for `slashings`, given some `epoch`. /// Safely obtain the index for `slashings`, given some `epoch`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_slashings_index( fn get_slashings_index(
&self, &self,
epoch: Epoch, epoch: Epoch,
@ -630,14 +632,14 @@ impl<T: EthSpec> BeaconState<T> {
/// Get a reference to the entire `slashings` vector. /// Get a reference to the entire `slashings` vector.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_all_slashings(&self) -> &[u64] { pub fn get_all_slashings(&self) -> &[u64] {
&self.slashings &self.slashings
} }
/// Get the total slashed balances for some epoch. /// Get the total slashed balances for some epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_slashings(&self, epoch: Epoch) -> Result<u64, Error> { pub fn get_slashings(&self, epoch: Epoch) -> Result<u64, Error> {
let i = self.get_slashings_index(epoch, AllowNextEpoch::False)?; let i = self.get_slashings_index(epoch, AllowNextEpoch::False)?;
Ok(self.slashings[i]) Ok(self.slashings[i])
@ -645,7 +647,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Set the total slashed balances for some epoch. /// Set the total slashed balances for some epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn set_slashings(&mut self, epoch: Epoch, value: u64) -> Result<(), Error> { pub fn set_slashings(&mut self, epoch: Epoch, value: u64) -> Result<(), Error> {
let i = self.get_slashings_index(epoch, AllowNextEpoch::True)?; let i = self.get_slashings_index(epoch, AllowNextEpoch::True)?;
self.slashings[i] = value; self.slashings[i] = value;
@ -654,7 +656,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Get the attestations from the current or previous epoch. /// Get the attestations from the current or previous epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_matching_source_attestations( pub fn get_matching_source_attestations(
&self, &self,
epoch: Epoch, epoch: Epoch,
@ -670,7 +672,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Generate a seed for the given `epoch`. /// Generate a seed for the given `epoch`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_seed( pub fn get_seed(
&self, &self,
epoch: Epoch, epoch: Epoch,
@ -701,7 +703,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the effective balance (also known as "balance at stake") for a validator with the given ``index``. /// Return the effective balance (also known as "balance at stake") for a validator with the given ``index``.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_effective_balance( pub fn get_effective_balance(
&self, &self,
validator_index: usize, validator_index: usize,
@ -715,7 +717,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the epoch at which an activation or exit triggered in ``epoch`` takes effect. /// Return the epoch at which an activation or exit triggered in ``epoch`` takes effect.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn compute_activation_exit_epoch(&self, epoch: Epoch, spec: &ChainSpec) -> Epoch { pub fn compute_activation_exit_epoch(&self, epoch: Epoch, spec: &ChainSpec) -> Epoch {
epoch + 1 + spec.max_seed_lookahead epoch + 1 + spec.max_seed_lookahead
} }
@ -724,7 +726,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Uses the epoch cache, and will error if it isn't initialized. /// Uses the epoch cache, and will error if it isn't initialized.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> { pub fn get_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> {
Ok(std::cmp::max( Ok(std::cmp::max(
spec.min_per_epoch_churn_limit, spec.min_per_epoch_churn_limit,
@ -739,7 +741,7 @@ impl<T: EthSpec> BeaconState<T> {
/// ///
/// Note: Utilizes the cache and will fail if the appropriate cache is not initialized. /// Note: Utilizes the cache and will fail if the appropriate cache is not initialized.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_attestation_duties( pub fn get_attestation_duties(
&self, &self,
validator_index: usize, validator_index: usize,
@ -752,7 +754,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the combined effective balance of an array of validators. /// Return the combined effective balance of an array of validators.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_total_balance( pub fn get_total_balance(
&self, &self,
validator_indices: &[usize], validator_indices: &[usize],
@ -925,7 +927,26 @@ impl<T: EthSpec> BeaconState<T> {
if let Some(mut cache) = cache { if let Some(mut cache) = cache {
// Note: we return early if the tree hash fails, leaving `self.tree_hash_cache` as // Note: we return early if the tree hash fails, leaving `self.tree_hash_cache` as
// None. There's no need to keep a cache that fails. // None. There's no need to keep a cache that fails.
let root = cache.recalculate_tree_hash_root(self)?; let root = cache.recalculate_tree_hash_root(&self)?;
self.tree_hash_cache = Some(cache);
Ok(root)
} else {
Err(Error::TreeHashCacheNotInitialized)
}
}
/// Compute the tree hash root of the validators using the tree hash cache.
///
/// Initialize the tree hash cache if it isn't already initialized.
pub fn update_validators_tree_hash_cache(&mut self) -> Result<Hash256, Error> {
self.initialize_tree_hash_cache();
let cache = self.tree_hash_cache.take();
if let Some(mut cache) = cache {
// Note: we return early if the tree hash fails, leaving `self.tree_hash_cache` as
// None. There's no need to keep a cache that fails.
let root = cache.recalculate_validators_tree_hash_root(&self.validators)?;
self.tree_hash_cache = Some(cache); self.tree_hash_cache = Some(cache);
Ok(root) Ok(root)
} else { } else {
@ -959,6 +980,7 @@ impl<T: EthSpec> BeaconState<T> {
pub fn clone_with(&self, config: CloneConfig) -> Self { pub fn clone_with(&self, config: CloneConfig) -> Self {
BeaconState { BeaconState {
genesis_time: self.genesis_time, genesis_time: self.genesis_time,
genesis_validators_root: self.genesis_validators_root,
slot: self.slot, slot: self.slot,
fork: self.fork.clone(), fork: self.fork.clone(),
latest_block_header: self.latest_block_header.clone(), latest_block_header: self.latest_block_header.clone(),

View File

@ -22,7 +22,7 @@ pub struct CommitteeCache {
impl CommitteeCache { impl CommitteeCache {
/// Return a new, fully initialized cache. /// Return a new, fully initialized cache.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn initialized<T: EthSpec>( pub fn initialized<T: EthSpec>(
state: &BeaconState<T>, state: &BeaconState<T>,
epoch: Epoch, epoch: Epoch,
@ -87,7 +87,7 @@ impl CommitteeCache {
/// ///
/// Always returns `&[]` for a non-initialized epoch. /// Always returns `&[]` for a non-initialized epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn active_validator_indices(&self) -> &[usize] { pub fn active_validator_indices(&self) -> &[usize] {
&self.shuffling &self.shuffling
} }
@ -96,7 +96,7 @@ impl CommitteeCache {
/// ///
/// Always returns `&[]` for a non-initialized epoch. /// Always returns `&[]` for a non-initialized epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn shuffling(&self) -> &[usize] { pub fn shuffling(&self) -> &[usize] {
&self.shuffling &self.shuffling
} }
@ -202,7 +202,7 @@ impl CommitteeCache {
/// ///
/// Always returns `usize::default()` for a non-initialized epoch. /// Always returns `usize::default()` for a non-initialized epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn active_validator_count(&self) -> usize { pub fn active_validator_count(&self) -> usize {
self.shuffling.len() self.shuffling.len()
} }
@ -211,7 +211,7 @@ impl CommitteeCache {
/// ///
/// Always returns `usize::default()` for a non-initialized epoch. /// Always returns `usize::default()` for a non-initialized epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn epoch_committee_count(&self) -> usize { pub fn epoch_committee_count(&self) -> usize {
self.committees_per_slot as usize * self.slots_per_epoch as usize self.committees_per_slot as usize * self.slots_per_epoch as usize
} }
@ -223,7 +223,7 @@ impl CommitteeCache {
/// Returns a slice of `self.shuffling` that represents the `index`'th committee in the epoch. /// Returns a slice of `self.shuffling` that represents the `index`'th committee in the epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn compute_committee(&self, index: usize) -> Option<&[usize]> { fn compute_committee(&self, index: usize) -> Option<&[usize]> {
Some(&self.shuffling[self.compute_committee_range(index)?]) Some(&self.shuffling[self.compute_committee_range(index)?])
} }
@ -234,7 +234,7 @@ impl CommitteeCache {
/// ///
/// Will also return `None` if the index is out of bounds. /// Will also return `None` if the index is out of bounds.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn compute_committee_range(&self, index: usize) -> Option<Range<usize>> { fn compute_committee_range(&self, index: usize) -> Option<Range<usize>> {
let count = self.epoch_committee_count(); let count = self.epoch_committee_count();
if count == 0 || index >= count { if count == 0 || index >= count {
@ -261,7 +261,7 @@ impl CommitteeCache {
/// Returns a list of all `validators` indices where the validator is active at the given /// Returns a list of all `validators` indices where the validator is active at the given
/// `epoch`. /// `epoch`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> { pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
let mut active = Vec::with_capacity(validators.len()); let mut active = Vec::with_capacity(validators.len());

View File

@ -82,6 +82,7 @@ impl BeaconTreeHashCache {
let mut hasher = MerkleHasher::with_leaves(NUM_BEACON_STATE_HASHING_FIELDS); let mut hasher = MerkleHasher::with_leaves(NUM_BEACON_STATE_HASHING_FIELDS);
hasher.write(state.genesis_time.tree_hash_root().as_bytes())?; hasher.write(state.genesis_time.tree_hash_root().as_bytes())?;
hasher.write(state.genesis_validators_root.tree_hash_root().as_bytes())?;
hasher.write(state.slot.tree_hash_root().as_bytes())?; hasher.write(state.slot.tree_hash_root().as_bytes())?;
hasher.write(state.fork.tree_hash_root().as_bytes())?; hasher.write(state.fork.tree_hash_root().as_bytes())?;
hasher.write(state.latest_block_header.tree_hash_root().as_bytes())?; hasher.write(state.latest_block_header.tree_hash_root().as_bytes())?;
@ -153,6 +154,14 @@ impl BeaconTreeHashCache {
hasher.finish().map_err(Into::into) hasher.finish().map_err(Into::into)
} }
/// Updates the cache and provides the root of the given `validators`.
pub fn recalculate_validators_tree_hash_root(
&mut self,
validators: &[Validator],
) -> Result<Hash256, Error> {
self.validators.recalculate_tree_hash_root(validators)
}
} }
/// A specialized cache for computing the tree hash root of `state.validators`. /// A specialized cache for computing the tree hash root of `state.validators`.

View File

@ -3,6 +3,7 @@ use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::fs::File; use std::fs::File;
use std::path::Path; use std::path::Path;
use tree_hash::TreeHash;
use utils::{ use utils::{
fork_from_hex_str, fork_to_hex_str, u32_from_hex_str, u32_to_hex_str, u8_from_hex_str, fork_from_hex_str, fork_to_hex_str, u32_from_hex_str, u32_to_hex_str, u8_from_hex_str,
u8_to_hex_str, u8_to_hex_str,
@ -10,18 +11,21 @@ use utils::{
/// Each of the BLS signature domains. /// Each of the BLS signature domains.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Domain { pub enum Domain {
BeaconProposer, BeaconProposer,
BeaconAttester, BeaconAttester,
Randao, Randao,
Deposit, Deposit,
VoluntaryExit, VoluntaryExit,
SelectionProof,
AggregateAndProof,
} }
/// Holds all the "constants" for a BeaconChain. /// Holds all the "constants" for a BeaconChain.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)] #[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct ChainSpec { pub struct ChainSpec {
@ -44,6 +48,9 @@ pub struct ChainSpec {
pub shuffle_round_count: u8, pub shuffle_round_count: u8,
pub min_genesis_active_validator_count: u64, pub min_genesis_active_validator_count: u64,
pub min_genesis_time: u64, pub min_genesis_time: u64,
pub hysteresis_quotient: u64,
pub hysteresis_downward_multiplier: u64,
pub hysteresis_upward_multiplier: u64,
/* /*
* Gwei values * Gwei values
@ -93,6 +100,8 @@ pub struct ChainSpec {
domain_randao: u32, domain_randao: u32,
domain_deposit: u32, domain_deposit: u32,
domain_voluntary_exit: u32, domain_voluntary_exit: u32,
domain_selection_proof: u32,
domain_aggregate_and_proof: u32,
/* /*
* Fork choice * Fork choice
@ -112,7 +121,7 @@ pub struct ChainSpec {
impl ChainSpec { impl ChainSpec {
/// Get the domain number, unmodified by the fork. /// Get the domain number, unmodified by the fork.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_domain_constant(&self, domain: Domain) -> u32 { pub fn get_domain_constant(&self, domain: Domain) -> u32 {
match domain { match domain {
Domain::BeaconProposer => self.domain_beacon_proposer, Domain::BeaconProposer => self.domain_beacon_proposer,
@ -120,15 +129,23 @@ impl ChainSpec {
Domain::Randao => self.domain_randao, Domain::Randao => self.domain_randao,
Domain::Deposit => self.domain_deposit, Domain::Deposit => self.domain_deposit,
Domain::VoluntaryExit => self.domain_voluntary_exit, Domain::VoluntaryExit => self.domain_voluntary_exit,
Domain::SelectionProof => self.domain_selection_proof,
Domain::AggregateAndProof => self.domain_aggregate_and_proof,
} }
} }
/// Get the domain number that represents the fork meta and signature domain. /// Get the domain that represents the fork meta and signature domain.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 { pub fn get_domain(
&self,
epoch: Epoch,
domain: Domain,
fork: &Fork,
genesis_validators_root: Hash256,
) -> Hash256 {
let fork_version = fork.get_fork_version(epoch); let fork_version = fork.get_fork_version(epoch);
self.compute_domain(domain, fork_version) self.compute_domain(domain, fork_version, genesis_validators_root)
} }
/// Get the domain for a deposit signature. /// Get the domain for a deposit signature.
@ -136,29 +153,64 @@ impl ChainSpec {
/// Deposits are valid across forks, thus the deposit domain is computed /// Deposits are valid across forks, thus the deposit domain is computed
/// with the genesis fork version. /// with the genesis fork version.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_deposit_domain(&self) -> u64 { pub fn get_deposit_domain(&self) -> Hash256 {
self.compute_domain(Domain::Deposit, self.genesis_fork_version) self.compute_domain(Domain::Deposit, self.genesis_fork_version, Hash256::zero())
}
/// Return the 32-byte fork data root for the `current_version` and `genesis_validators_root`.
///
/// This is used primarily in signature domains to avoid collisions across forks/chains.
///
/// Spec v0.11.1
pub fn compute_fork_data_root(
current_version: [u8; 4],
genesis_validators_root: Hash256,
) -> Hash256 {
ForkData {
current_version,
genesis_validators_root,
}
.tree_hash_root()
}
/// Return the 4-byte fork digest for the `current_version` and `genesis_validators_root`.
///
/// This is a digest primarily used for domain separation on the p2p layer.
/// 4-bytes suffices for practical separation of forks/chains.
pub fn compute_fork_digest(
current_version: [u8; 4],
genesis_validators_root: Hash256,
) -> [u8; 4] {
let mut result = [0; 4];
let root = Self::compute_fork_data_root(current_version, genesis_validators_root);
result.copy_from_slice(&root.as_bytes()[0..4]);
result
} }
/// Compute a domain by applying the given `fork_version`. /// Compute a domain by applying the given `fork_version`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn compute_domain(&self, domain: Domain, fork_version: [u8; 4]) -> u64 { pub fn compute_domain(
&self,
domain: Domain,
fork_version: [u8; 4],
genesis_validators_root: Hash256,
) -> Hash256 {
let domain_constant = self.get_domain_constant(domain); let domain_constant = self.get_domain_constant(domain);
let mut bytes: Vec<u8> = int_to_bytes4(domain_constant); let mut domain = [0; 32];
bytes.append(&mut fork_version.to_vec()); domain[0..4].copy_from_slice(&int_to_bytes4(domain_constant));
domain[4..].copy_from_slice(
&Self::compute_fork_data_root(fork_version, genesis_validators_root)[..28],
);
let mut fork_and_domain = [0; 8]; Hash256::from(domain)
fork_and_domain.copy_from_slice(&bytes);
u64::from_le_bytes(fork_and_domain)
} }
/// Returns a `ChainSpec` compatible with the Ethereum Foundation specification. /// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn mainnet() -> Self { pub fn mainnet() -> Self {
Self { Self {
/* /*
@ -179,6 +231,9 @@ impl ChainSpec {
shuffle_round_count: 90, shuffle_round_count: 90,
min_genesis_active_validator_count: 16_384, min_genesis_active_validator_count: 16_384,
min_genesis_time: 1_578_009_600, // Jan 3, 2020 min_genesis_time: 1_578_009_600, // Jan 3, 2020
hysteresis_quotient: 4,
hysteresis_downward_multiplier: 1,
hysteresis_upward_multiplier: 5,
/* /*
* Gwei values * Gwei values
@ -223,6 +278,8 @@ impl ChainSpec {
domain_randao: 2, domain_randao: 2,
domain_deposit: 3, domain_deposit: 3,
domain_voluntary_exit: 4, domain_voluntary_exit: 4,
domain_selection_proof: 5,
domain_aggregate_and_proof: 6,
/* /*
* Fork choice * Fork choice
@ -245,7 +302,7 @@ impl ChainSpec {
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo. /// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn minimal() -> Self { pub fn minimal() -> Self {
// Note: bootnodes to be updated when static nodes exist. // Note: bootnodes to be updated when static nodes exist.
let boot_nodes = vec![]; let boot_nodes = vec![];
@ -257,6 +314,7 @@ impl ChainSpec {
min_genesis_active_validator_count: 64, min_genesis_active_validator_count: 64,
eth1_follow_distance: 16, eth1_follow_distance: 16,
genesis_fork_version: [0x00, 0x00, 0x00, 0x01], genesis_fork_version: [0x00, 0x00, 0x00, 0x01],
persistent_committee_period: 128,
min_genesis_delay: 300, min_genesis_delay: 300,
milliseconds_per_slot: 6_000, milliseconds_per_slot: 6_000,
network_id: 2, // lighthouse testnet network id network_id: 2, // lighthouse testnet network id
@ -291,7 +349,6 @@ impl Default for ChainSpec {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use int_to_bytes::int_to_bytes8;
#[test] #[test]
fn test_mainnet_spec_can_be_constructed() { fn test_mainnet_spec_can_be_constructed() {
@ -299,19 +356,27 @@ mod tests {
} }
fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) { fn test_domain(domain_type: Domain, raw_domain: u32, spec: &ChainSpec) {
let previous_version = [0, 0, 0, 1];
let current_version = [0, 0, 0, 2];
let genesis_validators_root = Hash256::from_low_u64_le(77);
let fork_epoch = Epoch::new(1024);
let fork = Fork { let fork = Fork {
previous_version: spec.genesis_fork_version, previous_version,
current_version: spec.genesis_fork_version, current_version,
epoch: MinimalEthSpec::genesis_epoch(), epoch: fork_epoch,
}; };
let epoch = Epoch::new(0);
let domain = spec.get_domain(epoch, domain_type, &fork); for (epoch, version) in vec![
(fork_epoch - 1, previous_version),
(fork_epoch, current_version),
(fork_epoch + 1, current_version),
] {
let domain1 = spec.get_domain(epoch, domain_type, &fork, genesis_validators_root);
let domain2 = spec.compute_domain(domain_type, version, genesis_validators_root);
let mut expected = int_to_bytes4(raw_domain); assert_eq!(domain1, domain2);
expected.append(&mut fork.get_fork_version(epoch).to_vec()); assert_eq!(&domain1.as_bytes()[0..4], &int_to_bytes4(raw_domain)[..]);
}
assert_eq!(int_to_bytes8(domain), expected);
} }
#[test] #[test]
@ -323,18 +388,25 @@ mod tests {
test_domain(Domain::Randao, spec.domain_randao, &spec); test_domain(Domain::Randao, spec.domain_randao, &spec);
test_domain(Domain::Deposit, spec.domain_deposit, &spec); test_domain(Domain::Deposit, spec.domain_deposit, &spec);
test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec); test_domain(Domain::VoluntaryExit, spec.domain_voluntary_exit, &spec);
test_domain(Domain::SelectionProof, spec.domain_selection_proof, &spec);
test_domain(
Domain::AggregateAndProof,
spec.domain_aggregate_and_proof,
&spec,
);
} }
} }
/// Union of a ChainSpec struct and an EthSpec struct that holds constants used for the configs /// Union of a ChainSpec struct and an EthSpec struct that holds constants used for the configs
/// from the Ethereum 2 specs repo (https://github.com/ethereum/eth2.0-specs/tree/dev/configs) /// from the Ethereum 2 specs repo (https://github.com/ethereum/eth2.0-specs/tree/dev/configs)
/// ///
/// Spec v0.10.1 /// Doesn't include fields of the YAML that we don't need yet (e.g. Phase 1 stuff).
///
/// Spec v0.11.1
// Yaml Config is declared here in order to access domain fields of ChainSpec which are private. // Yaml Config is declared here in order to access domain fields of ChainSpec which are private.
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")] #[serde(rename_all = "UPPERCASE")]
#[serde(default)] #[serde(default)]
#[serde(deny_unknown_fields)]
pub struct YamlConfig { pub struct YamlConfig {
// ChainSpec // ChainSpec
far_future_epoch: u64, far_future_epoch: u64,
@ -352,6 +424,9 @@ pub struct YamlConfig {
max_effective_balance: u64, max_effective_balance: u64,
ejection_balance: u64, ejection_balance: u64,
effective_balance_increment: u64, effective_balance_increment: u64,
hysteresis_quotient: u64,
hysteresis_downward_multiplier: u64,
hysteresis_upward_multiplier: u64,
genesis_slot: u64, genesis_slot: u64,
#[serde( #[serde(
serialize_with = "fork_to_hex_str", serialize_with = "fork_to_hex_str",
@ -403,12 +478,22 @@ pub struct YamlConfig {
deserialize_with = "u32_from_hex_str", deserialize_with = "u32_from_hex_str",
serialize_with = "u32_to_hex_str" serialize_with = "u32_to_hex_str"
)] )]
domain_selection_proof: u32,
#[serde(
deserialize_with = "u32_from_hex_str",
serialize_with = "u32_to_hex_str"
)]
domain_aggregate_and_proof: u32,
#[serde(
deserialize_with = "u32_from_hex_str",
serialize_with = "u32_to_hex_str"
)]
// EthSpec // EthSpec
justification_bits_length: u32, justification_bits_length: u32,
max_validators_per_committee: u32, max_validators_per_committee: u32,
genesis_epoch: Epoch, genesis_epoch: Epoch,
slots_per_epoch: u64, slots_per_epoch: u64,
slots_per_eth1_voting_period: usize, epochs_per_eth1_voting_period: u64,
slots_per_historical_root: usize, slots_per_historical_root: usize,
epochs_per_historical_vector: usize, epochs_per_historical_vector: usize,
epochs_per_slashings_vector: usize, epochs_per_slashings_vector: usize,
@ -426,34 +511,6 @@ pub struct YamlConfig {
random_subnets_per_validator: u64, random_subnets_per_validator: u64,
epochs_per_random_subnet_subscription: u64, epochs_per_random_subnet_subscription: u64,
seconds_per_eth1_block: u64, seconds_per_eth1_block: u64,
// Deposit Contract (unused)
#[serde(skip_serializing)]
deposit_contract_address: String,
// Phase 1
#[serde(skip_serializing)]
epochs_per_custody_period: u32,
#[serde(skip_serializing)]
custody_period_to_randao_padding: u32,
#[serde(skip_serializing)]
shard_slots_per_beacon_slot: u32,
#[serde(skip_serializing)]
epochs_per_shard_period: u32,
#[serde(skip_serializing)]
phase_1_fork_epoch: u32,
#[serde(skip_serializing)]
phase_1_fork_slot: u32,
#[serde(skip_serializing)]
domain_custody_bit_challenge: u32,
#[serde(skip_serializing)]
domain_shard_proposer: u32,
#[serde(skip_serializing)]
domain_shard_attester: u32,
#[serde(skip_serializing)]
max_epochs_per_crosslink: u64,
#[serde(skip_serializing)]
early_derived_secret_penalty_max_future_epochs: u32,
} }
impl Default for YamlConfig { impl Default for YamlConfig {
@ -463,7 +520,7 @@ impl Default for YamlConfig {
} }
} }
/// Spec v0.10.1 /// Spec v0.11.1
impl YamlConfig { impl YamlConfig {
pub fn from_spec<T: EthSpec>(spec: &ChainSpec) -> Self { pub fn from_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
Self { Self {
@ -483,6 +540,9 @@ impl YamlConfig {
max_effective_balance: spec.max_effective_balance, max_effective_balance: spec.max_effective_balance,
ejection_balance: spec.ejection_balance, ejection_balance: spec.ejection_balance,
effective_balance_increment: spec.effective_balance_increment, effective_balance_increment: spec.effective_balance_increment,
hysteresis_quotient: spec.hysteresis_quotient,
hysteresis_downward_multiplier: spec.hysteresis_downward_multiplier,
hysteresis_upward_multiplier: spec.hysteresis_upward_multiplier,
genesis_slot: spec.genesis_slot.into(), genesis_slot: spec.genesis_slot.into(),
bls_withdrawal_prefix: spec.bls_withdrawal_prefix_byte, bls_withdrawal_prefix: spec.bls_withdrawal_prefix_byte,
seconds_per_slot: spec.milliseconds_per_slot / 1000, seconds_per_slot: spec.milliseconds_per_slot / 1000,
@ -504,13 +564,15 @@ impl YamlConfig {
domain_randao: spec.domain_randao, domain_randao: spec.domain_randao,
domain_deposit: spec.domain_deposit, domain_deposit: spec.domain_deposit,
domain_voluntary_exit: spec.domain_voluntary_exit, domain_voluntary_exit: spec.domain_voluntary_exit,
domain_selection_proof: spec.domain_selection_proof,
domain_aggregate_and_proof: spec.domain_aggregate_and_proof,
// EthSpec // EthSpec
justification_bits_length: T::JustificationBitsLength::to_u32(), justification_bits_length: T::JustificationBitsLength::to_u32(),
max_validators_per_committee: T::MaxValidatorsPerCommittee::to_u32(), max_validators_per_committee: T::MaxValidatorsPerCommittee::to_u32(),
genesis_epoch: T::genesis_epoch(), genesis_epoch: T::genesis_epoch(),
slots_per_epoch: T::slots_per_epoch(), slots_per_epoch: T::slots_per_epoch(),
slots_per_eth1_voting_period: T::slots_per_eth1_voting_period(), epochs_per_eth1_voting_period: T::EpochsPerEth1VotingPeriod::to_u64(),
slots_per_historical_root: T::slots_per_historical_root(), slots_per_historical_root: T::slots_per_historical_root(),
epochs_per_historical_vector: T::epochs_per_historical_vector(), epochs_per_historical_vector: T::epochs_per_historical_vector(),
epochs_per_slashings_vector: T::EpochsPerSlashingsVector::to_usize(), epochs_per_slashings_vector: T::EpochsPerSlashingsVector::to_usize(),
@ -528,22 +590,6 @@ impl YamlConfig {
random_subnets_per_validator: 0, random_subnets_per_validator: 0,
epochs_per_random_subnet_subscription: 0, epochs_per_random_subnet_subscription: 0,
seconds_per_eth1_block: spec.seconds_per_eth1_block, seconds_per_eth1_block: spec.seconds_per_eth1_block,
// Deposit Contract (unused)
deposit_contract_address: String::new(),
// Phase 1
epochs_per_custody_period: 0,
custody_period_to_randao_padding: 0,
shard_slots_per_beacon_slot: 0,
epochs_per_shard_period: 0,
phase_1_fork_epoch: 0,
phase_1_fork_slot: 0,
domain_custody_bit_challenge: 0,
domain_shard_proposer: 0,
domain_shard_attester: 0,
max_epochs_per_crosslink: 0,
early_derived_secret_penalty_max_future_epochs: 0,
} }
} }
@ -560,7 +606,7 @@ impl YamlConfig {
|| self.max_validators_per_committee != T::MaxValidatorsPerCommittee::to_u32() || self.max_validators_per_committee != T::MaxValidatorsPerCommittee::to_u32()
|| self.genesis_epoch != T::genesis_epoch() || self.genesis_epoch != T::genesis_epoch()
|| self.slots_per_epoch != T::slots_per_epoch() || self.slots_per_epoch != T::slots_per_epoch()
|| self.slots_per_eth1_voting_period != T::slots_per_eth1_voting_period() || self.epochs_per_eth1_voting_period != T::EpochsPerEth1VotingPeriod::to_u64()
|| self.slots_per_historical_root != T::slots_per_historical_root() || self.slots_per_historical_root != T::slots_per_historical_root()
|| self.epochs_per_historical_vector != T::epochs_per_historical_vector() || self.epochs_per_historical_vector != T::epochs_per_historical_vector()
|| self.epochs_per_slashings_vector != T::EpochsPerSlashingsVector::to_usize() || self.epochs_per_slashings_vector != T::EpochsPerSlashingsVector::to_usize()
@ -589,6 +635,9 @@ impl YamlConfig {
min_deposit_amount: self.min_deposit_amount, min_deposit_amount: self.min_deposit_amount,
min_genesis_delay: self.min_genesis_delay, min_genesis_delay: self.min_genesis_delay,
max_effective_balance: self.max_effective_balance, max_effective_balance: self.max_effective_balance,
hysteresis_quotient: self.hysteresis_quotient,
hysteresis_downward_multiplier: self.hysteresis_downward_multiplier,
hysteresis_upward_multiplier: self.hysteresis_upward_multiplier,
ejection_balance: self.ejection_balance, ejection_balance: self.ejection_balance,
effective_balance_increment: self.effective_balance_increment, effective_balance_increment: self.effective_balance_increment,
genesis_slot: Slot::from(self.genesis_slot), genesis_slot: Slot::from(self.genesis_slot),
@ -608,6 +657,7 @@ impl YamlConfig {
inactivity_penalty_quotient: self.inactivity_penalty_quotient, inactivity_penalty_quotient: self.inactivity_penalty_quotient,
min_slashing_penalty_quotient: self.min_slashing_penalty_quotient, min_slashing_penalty_quotient: self.min_slashing_penalty_quotient,
domain_beacon_proposer: self.domain_beacon_proposer, domain_beacon_proposer: self.domain_beacon_proposer,
domain_beacon_attester: self.domain_beacon_attester,
domain_randao: self.domain_randao, domain_randao: self.domain_randao,
domain_deposit: self.domain_deposit, domain_deposit: self.domain_deposit,
domain_voluntary_exit: self.domain_voluntary_exit, domain_voluntary_exit: self.domain_voluntary_exit,

View File

@ -7,7 +7,7 @@ use tree_hash_derive::TreeHash;
/// Casper FFG checkpoint, used in attestations. /// Casper FFG checkpoint, used in attestations.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive( #[derive(
Debug, Debug,
Clone, Clone,

View File

@ -11,7 +11,7 @@ pub const DEPOSIT_TREE_DEPTH: usize = 32;
/// A deposit to potentially become a beacon chain validator. /// A deposit to potentially become a beacon chain validator.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct Deposit { pub struct Deposit {
pub proof: FixedVector<Hash256, U33>, pub proof: FixedVector<Hash256, U33>,

View File

@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// The data supplied by the user to the deposit contract. /// The data supplied by the user to the deposit contract.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct DepositData { pub struct DepositData {
pub pubkey: PublicKeyBytes, pub pubkey: PublicKeyBytes,
@ -21,7 +21,7 @@ pub struct DepositData {
impl DepositData { impl DepositData {
/// Create a `DepositMessage` corresponding to this `DepositData`, for signature verification. /// Create a `DepositMessage` corresponding to this `DepositData`, for signature verification.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn as_deposit_message(&self) -> DepositMessage { pub fn as_deposit_message(&self) -> DepositMessage {
DepositMessage { DepositMessage {
pubkey: self.pubkey.clone(), pubkey: self.pubkey.clone(),
@ -32,7 +32,7 @@ impl DepositData {
/// Generate the signature for a given DepositData details. /// Generate the signature for a given DepositData details.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn create_signature(&self, secret_key: &SecretKey, spec: &ChainSpec) -> SignatureBytes { pub fn create_signature(&self, secret_key: &SecretKey, spec: &ChainSpec) -> SignatureBytes {
let domain = spec.get_deposit_domain(); let domain = spec.get_deposit_domain();
let msg = self.as_deposit_message().signing_root(domain); let msg = self.as_deposit_message().signing_root(domain);

View File

@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// The data supplied by the user to the deposit contract. /// The data supplied by the user to the deposit contract.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct DepositMessage { pub struct DepositMessage {
pub pubkey: PublicKeyBytes, pub pubkey: PublicKeyBytes,

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// Contains data obtained from the Eth1 chain. /// Contains data obtained from the Eth1 chain.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive( #[derive(
Debug, Debug,
PartialEq, PartialEq,

View File

@ -1,7 +1,7 @@
use crate::*; use crate::*;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use ssz_types::typenum::{ use ssz_types::typenum::{
Unsigned, U0, U1, U1024, U1099511627776, U128, U16, U16777216, U2048, U32, U4, U4096, U64, Unsigned, U0, U1, U1024, U1099511627776, U128, U16, U16777216, U2, U2048, U32, U4, U4096, U64,
U65536, U8, U8192, U65536, U8, U8192,
}; };
use std::fmt::Debug; use std::fmt::Debug;
@ -20,7 +20,7 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
* Time parameters * Time parameters
*/ */
type SlotsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq; type SlotsPerEpoch: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type SlotsPerEth1VotingPeriod: Unsigned + Clone + Sync + Send + Debug + PartialEq; type EpochsPerEth1VotingPeriod: Unsigned + Clone + Sync + Send + Debug + PartialEq;
type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send + Debug + PartialEq; type SlotsPerHistoricalRoot: Unsigned + Clone + Sync + Send + Debug + PartialEq;
/* /*
* State list lengths * State list lengths
@ -43,9 +43,13 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// The length of the `{previous,current}_epoch_attestations` lists. /// The length of the `{previous,current}_epoch_attestations` lists.
/// ///
/// Must be set to `MaxAttestations * SlotsPerEpoch` /// Must be set to `MaxAttestations * SlotsPerEpoch`
// NOTE: we could safely instantiate this by using type-level arithmetic, but doing // NOTE: we could safely instantiate these by using type-level arithmetic, but doing
// so adds ~25s to the time required to type-check this crate // so adds ~25s to the time required to type-check this crate
type MaxPendingAttestations: Unsigned + Clone + Sync + Send + Debug + PartialEq; type MaxPendingAttestations: Unsigned + Clone + Sync + Send + Debug + PartialEq;
/// The length of `eth1_data_votes`.
///
/// Must be set to `EpochsPerEth1VotingPeriod * SlotsPerEpoch`
type SlotsPerEth1VotingPeriod: Unsigned + Clone + Sync + Send + Debug + PartialEq;
fn default_spec() -> ChainSpec; fn default_spec() -> ChainSpec;
@ -58,7 +62,7 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// Note: the number of committees per slot is constant in each epoch, and depends only on /// Note: the number of committees per slot is constant in each epoch, and depends only on
/// the `active_validator_count` during the slot's epoch. /// the `active_validator_count` during the slot's epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn get_committee_count_per_slot(active_validator_count: usize, spec: &ChainSpec) -> usize { fn get_committee_count_per_slot(active_validator_count: usize, spec: &ChainSpec) -> usize {
let slots_per_epoch = Self::SlotsPerEpoch::to_usize(); let slots_per_epoch = Self::SlotsPerEpoch::to_usize();
@ -82,28 +86,28 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
/// Returns the `SLOTS_PER_EPOCH` constant for this specification. /// Returns the `SLOTS_PER_EPOCH` constant for this specification.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn slots_per_epoch() -> u64 { fn slots_per_epoch() -> u64 {
Self::SlotsPerEpoch::to_u64() Self::SlotsPerEpoch::to_u64()
} }
/// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification. /// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn slots_per_historical_root() -> usize { fn slots_per_historical_root() -> usize {
Self::SlotsPerHistoricalRoot::to_usize() Self::SlotsPerHistoricalRoot::to_usize()
} }
/// Returns the `EPOCHS_PER_HISTORICAL_VECTOR` constant for this specification. /// Returns the `EPOCHS_PER_HISTORICAL_VECTOR` constant for this specification.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn epochs_per_historical_vector() -> usize { fn epochs_per_historical_vector() -> usize {
Self::EpochsPerHistoricalVector::to_usize() Self::EpochsPerHistoricalVector::to_usize()
} }
/// Returns the `SLOTS_PER_ETH1_VOTING_PERIOD` constant for this specification. /// Returns the `SLOTS_PER_ETH1_VOTING_PERIOD` constant for this specification.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
fn slots_per_eth1_voting_period() -> usize { fn slots_per_eth1_voting_period() -> usize {
Self::SlotsPerEth1VotingPeriod::to_usize() Self::SlotsPerEth1VotingPeriod::to_usize()
} }
@ -119,7 +123,7 @@ macro_rules! params_from_eth_spec {
/// Ethereum Foundation specifications. /// Ethereum Foundation specifications.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)] #[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct MainnetEthSpec; pub struct MainnetEthSpec;
@ -128,7 +132,7 @@ impl EthSpec for MainnetEthSpec {
type MaxValidatorsPerCommittee = U2048; type MaxValidatorsPerCommittee = U2048;
type GenesisEpoch = U0; type GenesisEpoch = U0;
type SlotsPerEpoch = U32; type SlotsPerEpoch = U32;
type SlotsPerEth1VotingPeriod = U1024; type EpochsPerEth1VotingPeriod = U32;
type SlotsPerHistoricalRoot = U8192; type SlotsPerHistoricalRoot = U8192;
type EpochsPerHistoricalVector = U65536; type EpochsPerHistoricalVector = U65536;
type EpochsPerSlashingsVector = U8192; type EpochsPerSlashingsVector = U8192;
@ -140,6 +144,7 @@ impl EthSpec for MainnetEthSpec {
type MaxDeposits = U16; type MaxDeposits = U16;
type MaxVoluntaryExits = U16; type MaxVoluntaryExits = U16;
type MaxPendingAttestations = U4096; // 128 max attestations * 32 slots per epoch type MaxPendingAttestations = U4096; // 128 max attestations * 32 slots per epoch
type SlotsPerEth1VotingPeriod = U1024; // 32 epochs * 32 slots per epoch
fn default_spec() -> ChainSpec { fn default_spec() -> ChainSpec {
ChainSpec::mainnet() ChainSpec::mainnet()
@ -150,17 +155,18 @@ pub type FoundationBeaconState = BeaconState<MainnetEthSpec>;
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo. /// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)] #[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct MinimalEthSpec; pub struct MinimalEthSpec;
impl EthSpec for MinimalEthSpec { impl EthSpec for MinimalEthSpec {
type SlotsPerEpoch = U8; type SlotsPerEpoch = U8;
type SlotsPerEth1VotingPeriod = U16; type EpochsPerEth1VotingPeriod = U2;
type SlotsPerHistoricalRoot = U64; type SlotsPerHistoricalRoot = U64;
type EpochsPerHistoricalVector = U64; type EpochsPerHistoricalVector = U64;
type EpochsPerSlashingsVector = U64; type EpochsPerSlashingsVector = U64;
type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
type SlotsPerEth1VotingPeriod = U16; // 2 epochs * 8 slots per epoch
params_from_eth_spec!(MainnetEthSpec { params_from_eth_spec!(MainnetEthSpec {
JustificationBitsLength, JustificationBitsLength,
@ -188,11 +194,12 @@ pub struct InteropEthSpec;
impl EthSpec for InteropEthSpec { impl EthSpec for InteropEthSpec {
type SlotsPerEpoch = U8; type SlotsPerEpoch = U8;
type EpochsPerEth1VotingPeriod = U2;
type SlotsPerHistoricalRoot = U64; type SlotsPerHistoricalRoot = U64;
type SlotsPerEth1VotingPeriod = U16;
type EpochsPerHistoricalVector = U64; type EpochsPerHistoricalVector = U64;
type EpochsPerSlashingsVector = U64; type EpochsPerSlashingsVector = U64;
type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
type SlotsPerEth1VotingPeriod = U16; // 2 epochs * 8 slots per epoch
params_from_eth_spec!(MainnetEthSpec { params_from_eth_spec!(MainnetEthSpec {
JustificationBitsLength, JustificationBitsLength,

View File

@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks. /// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive( #[derive(
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
)] )]
@ -30,7 +30,7 @@ pub struct Fork {
impl Fork { impl Fork {
/// Return the fork version of the given ``epoch``. /// Return the fork version of the given ``epoch``.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn get_fork_version(&self, epoch: Epoch) -> [u8; 4] { pub fn get_fork_version(&self, epoch: Epoch) -> [u8; 4] {
if epoch < self.epoch { if epoch < self.epoch {
return self.previous_version; return self.previous_version;

View File

@ -0,0 +1,32 @@
use crate::test_utils::TestRandom;
use crate::utils::{fork_from_hex_str, fork_to_hex_str};
use crate::{Hash256, SignedRoot};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
///
/// Spec v0.11.1
#[derive(
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
)]
pub struct ForkData {
#[serde(
serialize_with = "fork_to_hex_str",
deserialize_with = "fork_from_hex_str"
)]
pub current_version: [u8; 4],
pub genesis_validators_root: Hash256,
}
impl SignedRoot for ForkData {}
#[cfg(test)]
mod tests {
use super::*;
ssz_and_tree_hash_tests!(ForkData);
}

View File

@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// Historical block and state roots. /// Historical block and state roots.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct HistoricalBatch<T: EthSpec> { pub struct HistoricalBatch<T: EthSpec> {
pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>, pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// ///
/// To be included in an `AttesterSlashing`. /// To be included in an `AttesterSlashing`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")] #[serde(bound = "T: EthSpec")]
pub struct IndexedAttestation<T: EthSpec> { pub struct IndexedAttestation<T: EthSpec> {
@ -21,14 +21,14 @@ pub struct IndexedAttestation<T: EthSpec> {
impl<T: EthSpec> IndexedAttestation<T> { impl<T: EthSpec> IndexedAttestation<T> {
/// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target. /// Check if ``attestation_data_1`` and ``attestation_data_2`` have the same target.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn is_double_vote(&self, other: &Self) -> bool { pub fn is_double_vote(&self, other: &Self) -> bool {
self.data.target.epoch == other.data.target.epoch && self.data != other.data self.data.target.epoch == other.data.target.epoch && self.data != other.data
} }
/// Check if ``attestation_data_1`` surrounds ``attestation_data_2``. /// Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn is_surround_vote(&self, other: &Self) -> bool { pub fn is_surround_vote(&self, other: &Self) -> bool {
self.data.source.epoch < other.data.source.epoch self.data.source.epoch < other.data.source.epoch
&& other.data.target.epoch < self.data.target.epoch && other.data.target.epoch < self.data.target.epoch

View File

@ -23,6 +23,7 @@ pub mod deposit_message;
pub mod eth1_data; pub mod eth1_data;
pub mod eth_spec; pub mod eth_spec;
pub mod fork; pub mod fork;
pub mod fork_data;
pub mod free_attestation; pub mod free_attestation;
pub mod historical_batch; pub mod historical_batch;
pub mod indexed_attestation; pub mod indexed_attestation;
@ -59,6 +60,7 @@ pub use crate::deposit_data::DepositData;
pub use crate::deposit_message::DepositMessage; pub use crate::deposit_message::DepositMessage;
pub use crate::eth1_data::Eth1Data; pub use crate::eth1_data::Eth1Data;
pub use crate::fork::Fork; pub use crate::fork::Fork;
pub use crate::fork_data::ForkData;
pub use crate::free_attestation::FreeAttestation; pub use crate::free_attestation::FreeAttestation;
pub use crate::historical_batch::HistoricalBatch; pub use crate::historical_batch::HistoricalBatch;
pub use crate::indexed_attestation::IndexedAttestation; pub use crate::indexed_attestation::IndexedAttestation;

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// An attestation that has been included in the state but not yet fully processed. /// An attestation that has been included in the state but not yet fully processed.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct PendingAttestation<T: EthSpec> { pub struct PendingAttestation<T: EthSpec> {
pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>, pub aggregation_bits: BitList<T::MaxValidatorsPerCommittee>,

View File

@ -8,10 +8,9 @@ use tree_hash_derive::TreeHash;
/// Two conflicting proposals from the same proposer (validator). /// Two conflicting proposals from the same proposer (validator).
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct ProposerSlashing { pub struct ProposerSlashing {
pub proposer_index: u64,
pub signed_header_1: SignedBeaconBlockHeader, pub signed_header_1: SignedBeaconBlockHeader,
pub signed_header_2: SignedBeaconBlockHeader, pub signed_header_2: SignedBeaconBlockHeader,
} }

View File

@ -9,7 +9,7 @@ pub enum Error {
/// Defines the epochs relative to some epoch. Most useful when referring to the committees prior /// Defines the epochs relative to some epoch. Most useful when referring to the committees prior
/// to and following some epoch. /// to and following some epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum RelativeEpoch { pub enum RelativeEpoch {
/// The prior epoch. /// The prior epoch.
@ -23,7 +23,7 @@ pub enum RelativeEpoch {
impl RelativeEpoch { impl RelativeEpoch {
/// Returns the `epoch` that `self` refers to, with respect to the `base` epoch. /// Returns the `epoch` that `self` refers to, with respect to the `base` epoch.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn into_epoch(self, base: Epoch) -> Epoch { pub fn into_epoch(self, base: Epoch) -> Epoch {
match self { match self {
// Due to saturating nature of epoch, check for current first. // Due to saturating nature of epoch, check for current first.
@ -40,7 +40,7 @@ impl RelativeEpoch {
/// - `EpochTooLow` when `other` is more than 1 prior to `base`. /// - `EpochTooLow` when `other` is more than 1 prior to `base`.
/// - `EpochTooHigh` when `other` is more than 1 after `base`. /// - `EpochTooHigh` when `other` is more than 1 after `base`.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn from_epoch(base: Epoch, other: Epoch) -> Result<Self, Error> { pub fn from_epoch(base: Epoch, other: Epoch) -> Result<Self, Error> {
// Due to saturating nature of epoch, check for current first. // Due to saturating nature of epoch, check for current first.
if other == base { if other == base {

View File

@ -8,7 +8,7 @@ use tree_hash::TreeHash;
/// A `BeaconBlock` and a signature from its proposer. /// A `BeaconBlock` and a signature from its proposer.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TestRandom)]
#[serde(bound = "E: EthSpec")] #[serde(bound = "E: EthSpec")]
pub struct SignedBeaconBlock<E: EthSpec> { pub struct SignedBeaconBlock<E: EthSpec> {
@ -34,7 +34,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
/// Returns the `tree_hash_root` of the block. /// Returns the `tree_hash_root` of the block.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 { pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.message.tree_hash_root()[..]) Hash256::from_slice(&self.message.tree_hash_root()[..])
} }

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// An exit voluntarily submitted a validator who wishes to withdraw. /// An exit voluntarily submitted a validator who wishes to withdraw.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SignedBeaconBlockHeader { pub struct SignedBeaconBlockHeader {
pub message: BeaconBlockHeader, pub message: BeaconBlockHeader,

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// An exit voluntarily submitted a validator who wishes to withdraw. /// An exit voluntarily submitted a validator who wishes to withdraw.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SignedVoluntaryExit { pub struct SignedVoluntaryExit {
pub message: VoluntaryExit, pub message: VoluntaryExit,

View File

@ -9,11 +9,11 @@ use tree_hash_derive::TreeHash;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SigningRoot { pub struct SigningRoot {
pub object_root: Hash256, pub object_root: Hash256,
pub domain: u64, pub domain: Hash256,
} }
pub trait SignedRoot: TreeHash { pub trait SignedRoot: TreeHash {
fn signing_root(&self, domain: u64) -> Hash256 { fn signing_root(&self, domain: Hash256) -> Hash256 {
SigningRoot { SigningRoot {
object_root: self.tree_hash_root(), object_root: self.tree_hash_root(),
domain, domain,

View File

@ -55,6 +55,7 @@ impl<T: EthSpec> TestingAttestationBuilder<T> {
signing_validators: &[usize], signing_validators: &[usize],
secret_keys: &[&SecretKey], secret_keys: &[&SecretKey],
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> &mut Self { ) -> &mut Self {
assert_eq!( assert_eq!(
@ -77,15 +78,28 @@ impl<T: EthSpec> TestingAttestationBuilder<T> {
}; };
self.attestation self.attestation
.sign(secret_keys[index], committee_index, fork, spec) .sign(
secret_keys[index],
committee_index,
fork,
genesis_validators_root,
spec,
)
.expect("can sign attestation"); .expect("can sign attestation");
if let AttestationTestTask::BadIndexedAttestationBadSignature = test_task { self.attestation
self.attestation .aggregation_bits
.aggregation_bits .set(committee_index, true)
.set(committee_index, false) .unwrap();
.unwrap(); }
}
if test_task == AttestationTestTask::BadIndexedAttestationBadSignature {
// Flip an aggregation bit, to make the aggregate invalid
// (We also want to avoid making it completely empty)
self.attestation
.aggregation_bits
.set(0, !self.attestation.aggregation_bits.get(0).unwrap())
.unwrap();
} }
self self

View File

@ -22,6 +22,7 @@ impl TestingAttesterSlashingBuilder {
validator_indices: &[u64], validator_indices: &[u64],
signer: F, signer: F,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> AttesterSlashing<T> ) -> AttesterSlashing<T>
where where
@ -83,8 +84,12 @@ impl TestingAttesterSlashingBuilder {
}; };
let add_signatures = |attestation: &mut IndexedAttestation<T>| { let add_signatures = |attestation: &mut IndexedAttestation<T>| {
let domain = let domain = spec.get_domain(
spec.get_domain(attestation.data.target.epoch, Domain::BeaconAttester, fork); attestation.data.target.epoch,
Domain::BeaconAttester,
fork,
genesis_validators_root,
);
let message = attestation.data.signing_root(domain); let message = attestation.data.signing_root(domain);
for validator_index in validator_indices { for validator_index in validator_indices {

View File

@ -97,12 +97,23 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
self.block.slot = slot; self.block.slot = slot;
} }
/// Set the proposer index of the block.
pub fn set_proposer_index(&mut self, proposer_index: u64) {
self.block.proposer_index = proposer_index;
}
/// Sets the randao to be a signature across the blocks epoch. /// Sets the randao to be a signature across the blocks epoch.
/// ///
/// Modifying the block's slot after signing may invalidate the signature. /// Modifying the block's slot after signing may invalidate the signature.
pub fn set_randao_reveal(&mut self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) { pub fn set_randao_reveal(
&mut self,
sk: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) {
let epoch = self.block.slot.epoch(T::slots_per_epoch()); let epoch = self.block.slot.epoch(T::slots_per_epoch());
let domain = spec.get_domain(epoch, Domain::Randao, fork); let domain = spec.get_domain(epoch, Domain::Randao, fork, genesis_validators_root);
let message = epoch.signing_root(domain); let message = epoch.signing_root(domain);
self.block.body.randao_reveal = Signature::new(message.as_bytes(), sk); self.block.body.randao_reveal = Signature::new(message.as_bytes(), sk);
} }
@ -119,10 +130,17 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
validator_index: u64, validator_index: u64,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) { ) {
let proposer_slashing = let proposer_slashing = build_proposer_slashing::<T>(
build_proposer_slashing::<T>(test_task, validator_index, secret_key, fork, spec); test_task,
validator_index,
secret_key,
fork,
genesis_validators_root,
spec,
);
self.block self.block
.body .body
.proposer_slashings .proposer_slashings
@ -137,6 +155,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
validator_indices: &[u64], validator_indices: &[u64],
secret_keys: &[&SecretKey], secret_keys: &[&SecretKey],
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) { ) {
let attester_slashing = build_double_vote_attester_slashing( let attester_slashing = build_double_vote_attester_slashing(
@ -144,6 +163,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
validator_indices, validator_indices,
secret_keys, secret_keys,
fork, fork,
genesis_validators_root,
spec, spec,
); );
let _ = self.block.body.attester_slashings.push(attester_slashing); let _ = self.block.body.attester_slashings.push(attester_slashing);
@ -246,6 +266,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
signing_validators, signing_validators,
&signing_secret_keys, &signing_secret_keys,
&state.fork, &state.fork,
state.genesis_validators_root,
spec, spec,
); );
@ -355,14 +376,20 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
} }
let builder = TestingVoluntaryExitBuilder::new(exit_epoch, validator_index); let builder = TestingVoluntaryExitBuilder::new(exit_epoch, validator_index);
let exit = builder.build(sk, &state.fork, spec); let exit = builder.build(sk, &state.fork, state.genesis_validators_root, spec);
self.block.body.voluntary_exits.push(exit).unwrap(); self.block.body.voluntary_exits.push(exit).unwrap();
} }
/// Signs and returns the block, consuming the builder. /// Signs and returns the block, consuming the builder.
pub fn build(self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> SignedBeaconBlock<T> { pub fn build(
self.block.sign(sk, fork, spec) self,
sk: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> SignedBeaconBlock<T> {
self.block.sign(sk, fork, genesis_validators_root, spec)
} }
/// Returns the block, consuming the builder. /// Returns the block, consuming the builder.
@ -382,6 +409,7 @@ pub fn build_proposer_slashing<T: EthSpec>(
validator_index: u64, validator_index: u64,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> ProposerSlashing { ) -> ProposerSlashing {
TestingProposerSlashingBuilder::double_vote::<T>( TestingProposerSlashingBuilder::double_vote::<T>(
@ -389,6 +417,7 @@ pub fn build_proposer_slashing<T: EthSpec>(
validator_index, validator_index,
secret_key, secret_key,
fork, fork,
genesis_validators_root,
spec, spec,
) )
} }
@ -401,6 +430,7 @@ pub fn build_double_vote_attester_slashing<T: EthSpec>(
validator_indices: &[u64], validator_indices: &[u64],
secret_keys: &[&SecretKey], secret_keys: &[&SecretKey],
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> AttesterSlashing<T> { ) -> AttesterSlashing<T> {
let signer = |validator_index: u64, message: &[u8]| { let signer = |validator_index: u64, message: &[u8]| {
@ -411,5 +441,12 @@ pub fn build_double_vote_attester_slashing<T: EthSpec>(
Signature::new(message, secret_keys[key_index]) Signature::new(message, secret_keys[key_index])
}; };
TestingAttesterSlashingBuilder::double_vote(test_task, validator_indices, signer, fork, spec) TestingAttesterSlashingBuilder::double_vote(
test_task,
validator_indices,
signer,
fork,
genesis_validators_root,
spec,
)
} }

View File

@ -12,9 +12,10 @@ impl TestingProposerSlashingBuilder {
/// Where domain is a domain "constant" (e.g., `spec.domain_attestation`). /// Where domain is a domain "constant" (e.g., `spec.domain_attestation`).
pub fn double_vote<T>( pub fn double_vote<T>(
test_task: ProposerSlashingTestTask, test_task: ProposerSlashingTestTask,
mut proposer_index: u64, proposer_index: u64,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> ProposerSlashing ) -> ProposerSlashing
where where
@ -31,6 +32,7 @@ impl TestingProposerSlashingBuilder {
let mut signed_header_1 = SignedBeaconBlockHeader { let mut signed_header_1 = SignedBeaconBlockHeader {
message: BeaconBlockHeader { message: BeaconBlockHeader {
slot, slot,
proposer_index,
parent_root: hash_1, parent_root: hash_1,
state_root: hash_1, state_root: hash_1,
body_root: hash_1, body_root: hash_1,
@ -54,19 +56,25 @@ impl TestingProposerSlashingBuilder {
}; };
if test_task != ProposerSlashingTestTask::BadProposal1Signature { if test_task != ProposerSlashingTestTask::BadProposal1Signature {
signed_header_1 = signed_header_1.message.sign::<T>(secret_key, fork, spec); signed_header_1 =
signed_header_1
.message
.sign::<T>(secret_key, fork, genesis_validators_root, spec);
} }
if test_task != ProposerSlashingTestTask::BadProposal2Signature { if test_task != ProposerSlashingTestTask::BadProposal2Signature {
signed_header_2 = signed_header_2.message.sign::<T>(secret_key, fork, spec); signed_header_2 =
signed_header_2
.message
.sign::<T>(secret_key, fork, genesis_validators_root, spec);
} }
if test_task == ProposerSlashingTestTask::ProposerUnknown { if test_task == ProposerSlashingTestTask::ProposerUnknown {
proposer_index = 3_141_592; signed_header_1.message.proposer_index = 3_141_592;
signed_header_2.message.proposer_index = 3_141_592;
} }
ProposerSlashing { ProposerSlashing {
proposer_index,
signed_header_1, signed_header_1,
signed_header_2, signed_header_2,
} }

View File

@ -25,8 +25,10 @@ impl TestingVoluntaryExitBuilder {
self, self,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> SignedVoluntaryExit { ) -> SignedVoluntaryExit {
self.exit.sign(secret_key, fork, spec) self.exit
.sign(secret_key, fork, genesis_validators_root, spec)
} }
} }

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// Information about a `BeaconChain` validator. /// Information about a `BeaconChain` validator.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
pub struct Validator { pub struct Validator {
pub pubkey: PublicKeyBytes, pub pubkey: PublicKeyBytes,
@ -44,7 +44,7 @@ impl Validator {
/// Returns `true` if the validator is eligible to join the activation queue. /// Returns `true` if the validator is eligible to join the activation queue.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool { pub fn is_eligible_for_activation_queue(&self, spec: &ChainSpec) -> bool {
self.activation_eligibility_epoch == spec.far_future_epoch self.activation_eligibility_epoch == spec.far_future_epoch
&& self.effective_balance == spec.max_effective_balance && self.effective_balance == spec.max_effective_balance
@ -52,7 +52,7 @@ impl Validator {
/// Returns `true` if the validator is eligible to be activated. /// Returns `true` if the validator is eligible to be activated.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
pub fn is_eligible_for_activation<E: EthSpec>( pub fn is_eligible_for_activation<E: EthSpec>(
&self, &self,
state: &BeaconState<E>, state: &BeaconState<E>,

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
test_utils::TestRandom, ChainSpec, Domain, Epoch, Fork, SecretKey, Signature, SignedRoot, test_utils::TestRandom, ChainSpec, Domain, Epoch, Fork, Hash256, SecretKey, Signature,
SignedVoluntaryExit, SignedRoot, SignedVoluntaryExit,
}; };
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
@ -10,7 +10,7 @@ use tree_hash_derive::TreeHash;
/// An exit voluntarily submitted a validator who wishes to withdraw. /// An exit voluntarily submitted a validator who wishes to withdraw.
/// ///
/// Spec v0.10.1 /// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct VoluntaryExit { pub struct VoluntaryExit {
/// Earliest epoch when voluntary exit can be processed. /// Earliest epoch when voluntary exit can be processed.
@ -25,9 +25,15 @@ impl VoluntaryExit {
self, self,
secret_key: &SecretKey, secret_key: &SecretKey,
fork: &Fork, fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec, spec: &ChainSpec,
) -> SignedVoluntaryExit { ) -> SignedVoluntaryExit {
let domain = spec.get_domain(self.epoch, Domain::VoluntaryExit, fork); let domain = spec.get_domain(
self.epoch,
Domain::VoluntaryExit,
fork,
genesis_validators_root,
);
let message = self.signing_root(domain); let message = self.signing_root(domain);
let signature = Signature::new(message.as_bytes(), &secret_key); let signature = Signature::new(message.as_bytes(), &secret_key);
SignedVoluntaryExit { SignedVoluntaryExit {

View File

@ -9,9 +9,9 @@ use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
const TAG: &str = "v0.10.1"; const TAG: &str = "v0.11.1";
// NOTE: the version of the unsafe contract lags the main tag, but the v0.9.2.1 code is compatible // NOTE: the version of the unsafe contract lags the main tag, but the v0.9.2.1 code is compatible
// with the unmodified v0.10.1 contract // with the unmodified v0.11.1 contract
const UNSAFE_TAG: &str = "v0.9.2.1"; const UNSAFE_TAG: &str = "v0.9.2.1";
fn spec_url() -> String { fn spec_url() -> String {

View File

@ -23,15 +23,15 @@ impl From<ethabi::Error> for DecodeError {
pub const CONTRACT_DEPLOY_GAS: usize = 4_000_000; pub const CONTRACT_DEPLOY_GAS: usize = 4_000_000;
pub const DEPOSIT_GAS: usize = 4_000_000; pub const DEPOSIT_GAS: usize = 4_000_000;
pub const ABI: &[u8] = include_bytes!("../contracts/v0.10.1_validator_registration.json"); pub const ABI: &[u8] = include_bytes!("../contracts/v0.11.1_validator_registration.json");
pub const BYTECODE: &[u8] = include_bytes!("../contracts/v0.10.1_validator_registration.bytecode"); pub const BYTECODE: &[u8] = include_bytes!("../contracts/v0.11.1_validator_registration.bytecode");
pub const DEPOSIT_DATA_LEN: usize = 420; // lol pub const DEPOSIT_DATA_LEN: usize = 420; // lol
pub mod testnet { pub mod testnet {
pub const ABI: &[u8] = pub const ABI: &[u8] =
include_bytes!("../contracts/v0.10.1_testnet_validator_registration.json"); include_bytes!("../contracts/v0.11.1_testnet_validator_registration.json");
pub const BYTECODE: &[u8] = pub const BYTECODE: &[u8] =
include_bytes!("../contracts/v0.10.1_testnet_validator_registration.bytecode"); include_bytes!("../contracts/v0.11.1_testnet_validator_registration.bytecode");
} }
pub fn encode_eth1_tx_data(deposit_data: &DepositData) -> Result<Vec<u8>, Error> { pub fn encode_eth1_tx_data(deposit_data: &DepositData) -> Result<Vec<u8>, Error> {

View File

@ -202,6 +202,7 @@ mod tests {
type E = MainnetEthSpec; type E = MainnetEthSpec;
/* TODO: disabled until testnet config is updated for v0.11
#[test] #[test]
fn hard_coded_works() { fn hard_coded_works() {
let dir: Eth2TestnetConfig<E> = let dir: Eth2TestnetConfig<E> =
@ -211,6 +212,7 @@ mod tests {
assert!(dir.genesis_state.is_some()); assert!(dir.genesis_state.is_some());
assert!(dir.yaml_config.is_some()); assert!(dir.yaml_config.is_some());
} }
*/
#[test] #[test]
fn round_trip() { fn round_trip() {

View File

@ -32,10 +32,8 @@ pub fn int_to_bytes3(int: u32) -> Option<Vec<u8>> {
} }
/// Returns `int` as little-endian bytes with a length of 4. /// Returns `int` as little-endian bytes with a length of 4.
pub fn int_to_bytes4(int: u32) -> Vec<u8> { pub fn int_to_bytes4(int: u32) -> [u8; 4] {
let mut bytes = BytesMut::with_capacity(4); int.to_le_bytes()
bytes.put_u32_le(int);
bytes.to_vec()
} }
/// Returns `int` as little-endian bytes with a length of 8. /// Returns `int` as little-endian bytes with a length of 8.
@ -128,7 +126,7 @@ mod tests {
1 => assert_eq!(int_to_bytes1(int as u8), bytes), 1 => assert_eq!(int_to_bytes1(int as u8), bytes),
2 => assert_eq!(int_to_bytes2(int as u16), bytes), 2 => assert_eq!(int_to_bytes2(int as u16), bytes),
3 => assert_eq!(int_to_bytes3(int as u32), Some(bytes)), 3 => assert_eq!(int_to_bytes3(int as u32), Some(bytes)),
4 => assert_eq!(int_to_bytes4(int as u32), bytes), 4 => assert_eq!(&int_to_bytes4(int as u32)[..], &bytes[..]),
8 => assert_eq!(int_to_bytes8(int), bytes), 8 => assert_eq!(int_to_bytes8(int), bytes),
32 => assert_eq!(int_to_bytes32(int), bytes), 32 => assert_eq!(int_to_bytes32(int), bytes),
48 => assert_eq!(int_to_bytes48(int), bytes), 48 => assert_eq!(int_to_bytes48(int), bytes),

View File

@ -324,6 +324,14 @@ impl<E: EthSpec> Beacon<E> {
.and_then(move |url| client.json_get(url, vec![])) .and_then(move |url| client.json_get(url, vec![]))
} }
/// Returns the genesis validators root.
pub fn get_genesis_validators_root(&self) -> impl Future<Item = Hash256, Error = Error> {
let client = self.0.clone();
self.url("genesis_validators_root")
.into_future()
.and_then(move |url| client.json_get(url, vec![]))
}
/// Returns the fork at the head of the beacon chain. /// Returns the fork at the head of the beacon chain.
pub fn get_fork(&self) -> impl Future<Item = Fork, Error = Error> { pub fn get_fork(&self) -> impl Future<Item = Fork, Error = Error> {
let client = self.0.clone(); let client = self.0.clone();

View File

@ -2,8 +2,8 @@
//! format designed for use in Ethereum 2.0. //! format designed for use in Ethereum 2.0.
//! //!
//! Adheres to the Ethereum 2.0 [SSZ //! Adheres to the Ethereum 2.0 [SSZ
//! specification](https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/ssz/simple-serialize.md) //! specification](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/ssz/simple-serialize.md)
//! at v0.10.1. //! at v0.11.1.
//! //!
//! ## Example //! ## Example
//! //!

View File

@ -9,8 +9,8 @@
//! for padding and verification. //! for padding and verification.
//! //!
//! Adheres to the Ethereum 2.0 [SSZ //! Adheres to the Ethereum 2.0 [SSZ
//! specification](https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/ssz/simple-serialize.md) //! specification](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/ssz/simple-serialize.md)
//! at v0.10.1. //! at v0.11.1.
//! //!
//! ## Example //! ## Example
//! ``` //! ```

View File

@ -1,7 +1,7 @@
//! Provides list-shuffling functions matching the Ethereum 2.0 specification. //! Provides list-shuffling functions matching the Ethereum 2.0 specification.
//! //!
//! See //! See
//! [compute_shuffled_index](https://github.com/ethereum/eth2.0-specs/blob/v0.10.1/specs/phase0/beacon-chain.md#compute_shuffled_index) //! [compute_shuffled_index](https://github.com/ethereum/eth2.0-specs/blob/v0.11.1/specs/phase0/beacon-chain.md#compute_shuffled_index)
//! for specifications. //! for specifications.
//! //!
//! There are two functions exported by this crate: //! There are two functions exported by this crate:

View File

@ -1,5 +1,5 @@
# Bump the test tag here and in .gitlab-ci.yml and CI will take care of updating the cached tarballs # Bump the test tag here and in .gitlab-ci.yml and CI will take care of updating the cached tarballs
TESTS_TAG := v0.10.1 TESTS_TAG := v0.11.1
TESTS = general minimal mainnet TESTS = general minimal mainnet
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS)) TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))

View File

@ -81,7 +81,11 @@ impl<E: EthSpec> EpochTransition<E> for Slashings {
fn run(state: &mut BeaconState<E>, spec: &ChainSpec) -> Result<(), EpochProcessingError> { fn run(state: &mut BeaconState<E>, spec: &ChainSpec) -> Result<(), EpochProcessingError> {
let mut validator_statuses = ValidatorStatuses::new(&state, spec)?; let mut validator_statuses = ValidatorStatuses::new(&state, spec)?;
validator_statuses.process_attestations(&state, spec)?; validator_statuses.process_attestations(&state, spec)?;
process_slashings(state, validator_statuses.total_balances.current_epoch, spec)?; process_slashings(
state,
validator_statuses.total_balances.current_epoch(),
spec,
)?;
Ok(()) Ok(())
} }
} }

View File

@ -176,7 +176,6 @@ mod ssz_static {
ssz_static_test!(voluntary_exit, VoluntaryExit); ssz_static_test!(voluntary_exit, VoluntaryExit);
} }
/* NOTE: SSZ generic tests disabled, missing from v0.10.0
#[test] #[test]
fn ssz_generic() { fn ssz_generic() {
SszGenericHandler::<BasicVector>::run(); SszGenericHandler::<BasicVector>::run();
@ -186,7 +185,6 @@ fn ssz_generic() {
SszGenericHandler::<Uints>::run(); SszGenericHandler::<Uints>::run();
SszGenericHandler::<Containers>::run(); SszGenericHandler::<Containers>::run();
} }
*/
#[test] #[test]
fn epoch_processing_justification_and_finalization() { fn epoch_processing_justification_and_finalization() {

View File

@ -143,101 +143,125 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
box_future box_future
}) })
}) })
.and_then(move |(beacon_node, remote_eth2_config, genesis_time)| { .and_then(|(beacon_node, eth2_config, genesis_time)| {
let log = log_4.clone(); beacon_node
.http
.beacon()
.get_genesis_validators_root()
.map(move |genesis_validators_root| {
(
beacon_node,
eth2_config,
genesis_time,
genesis_validators_root,
)
})
.map_err(|e| {
format!(
"Unable to read genesis validators root from beacon node: {:?}",
e
)
})
})
.and_then(
move |(beacon_node, remote_eth2_config, genesis_time, genesis_validators_root)| {
let log = log_4.clone();
// Do not permit a connection to a beacon node using different spec constants. // Do not permit a connection to a beacon node using different spec constants.
if context.eth2_config.spec_constants != remote_eth2_config.spec_constants { if context.eth2_config.spec_constants != remote_eth2_config.spec_constants {
return Err(format!( return Err(format!(
"Beacon node is using an incompatible spec. Got {}, expected {}", "Beacon node is using an incompatible spec. Got {}, expected {}",
remote_eth2_config.spec_constants, context.eth2_config.spec_constants remote_eth2_config.spec_constants, context.eth2_config.spec_constants
)); ));
} }
// Note: here we just assume the spec variables of the remote node. This is very useful // Note: here we just assume the spec variables of the remote node. This is very useful
// for testnets, but perhaps a security issue when it comes to mainnet. // for testnets, but perhaps a security issue when it comes to mainnet.
// //
// A damaging attack would be for a beacon node to convince the validator client of a // A damaging attack would be for a beacon node to convince the validator client of a
// different `SLOTS_PER_EPOCH` variable. This could result in slashable messages being // different `SLOTS_PER_EPOCH` variable. This could result in slashable messages being
// produced. We are safe from this because `SLOTS_PER_EPOCH` is a type-level constant // produced. We are safe from this because `SLOTS_PER_EPOCH` is a type-level constant
// for Lighthouse. // for Lighthouse.
context.eth2_config = remote_eth2_config; context.eth2_config = remote_eth2_config;
let slot_clock = SystemTimeSlotClock::new( let slot_clock = SystemTimeSlotClock::new(
context.eth2_config.spec.genesis_slot, context.eth2_config.spec.genesis_slot,
Duration::from_secs(genesis_time), Duration::from_secs(genesis_time),
Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot), Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot),
); );
let fork_service = ForkServiceBuilder::new() let fork_service = ForkServiceBuilder::new()
.slot_clock(slot_clock.clone()) .slot_clock(slot_clock.clone())
.beacon_node(beacon_node.clone()) .beacon_node(beacon_node.clone())
.runtime_context(context.service_context("fork".into())) .runtime_context(context.service_context("fork".into()))
.build()?; .build()?;
let validator_store: ValidatorStore<SystemTimeSlotClock, T> = let validator_store: ValidatorStore<SystemTimeSlotClock, T> =
match &config.key_source { match &config.key_source {
// Load pre-existing validators from the data dir. // Load pre-existing validators from the data dir.
// //
// Use the `account_manager` to generate these files. // Use the `account_manager` to generate these files.
KeySource::Disk => ValidatorStore::load_from_disk( KeySource::Disk => ValidatorStore::load_from_disk(
config.data_dir.clone(), config.data_dir.clone(),
context.eth2_config.spec.clone(), genesis_validators_root,
fork_service.clone(),
log.clone(),
)?,
// Generate ephemeral insecure keypairs for testing purposes.
//
// Do not use in production.
KeySource::InsecureKeypairs(indices) => {
ValidatorStore::insecure_ephemeral_validators(
&indices,
context.eth2_config.spec.clone(), context.eth2_config.spec.clone(),
fork_service.clone(), fork_service.clone(),
log.clone(), log.clone(),
)? )?,
} // Generate ephemeral insecure keypairs for testing purposes.
}; //
// Do not use in production.
KeySource::InsecureKeypairs(indices) => {
ValidatorStore::insecure_ephemeral_validators(
&indices,
genesis_validators_root,
context.eth2_config.spec.clone(),
fork_service.clone(),
log.clone(),
)?
}
};
info!( info!(
log, log,
"Loaded validator keypair store"; "Loaded validator keypair store";
"voting_validators" => validator_store.num_voting_validators() "voting_validators" => validator_store.num_voting_validators()
); );
let duties_service = DutiesServiceBuilder::new() let duties_service = DutiesServiceBuilder::new()
.slot_clock(slot_clock.clone()) .slot_clock(slot_clock.clone())
.validator_store(validator_store.clone()) .validator_store(validator_store.clone())
.beacon_node(beacon_node.clone()) .beacon_node(beacon_node.clone())
.runtime_context(context.service_context("duties".into())) .runtime_context(context.service_context("duties".into()))
.allow_unsynced_beacon_node(config.allow_unsynced_beacon_node) .allow_unsynced_beacon_node(config.allow_unsynced_beacon_node)
.build()?; .build()?;
let block_service = BlockServiceBuilder::new() let block_service = BlockServiceBuilder::new()
.duties_service(duties_service.clone()) .duties_service(duties_service.clone())
.slot_clock(slot_clock.clone()) .slot_clock(slot_clock.clone())
.validator_store(validator_store.clone()) .validator_store(validator_store.clone())
.beacon_node(beacon_node.clone()) .beacon_node(beacon_node.clone())
.runtime_context(context.service_context("block".into())) .runtime_context(context.service_context("block".into()))
.build()?; .build()?;
let attestation_service = AttestationServiceBuilder::new() let attestation_service = AttestationServiceBuilder::new()
.duties_service(duties_service.clone()) .duties_service(duties_service.clone())
.slot_clock(slot_clock) .slot_clock(slot_clock)
.validator_store(validator_store) .validator_store(validator_store)
.beacon_node(beacon_node) .beacon_node(beacon_node)
.runtime_context(context.service_context("attestation".into())) .runtime_context(context.service_context("attestation".into()))
.build()?; .build()?;
Ok(Self { Ok(Self {
context, context,
duties_service, duties_service,
fork_service, fork_service,
block_service, block_service,
attestation_service, attestation_service,
exit_signals: vec![], exit_signals: vec![],
}) })
}) },
)
} }
pub fn start_service(&mut self) -> Result<(), String> { pub fn start_service(&mut self) -> Result<(), String> {

View File

@ -12,13 +12,14 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use tempdir::TempDir; use tempdir::TempDir;
use types::{ use types::{
Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, PublicKey, Signature, Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, Hash256, PublicKey,
SignedBeaconBlock, SignedRoot, Signature, SignedBeaconBlock, SignedRoot,
}; };
#[derive(Clone)] #[derive(Clone)]
pub struct ValidatorStore<T, E: EthSpec> { pub struct ValidatorStore<T, E: EthSpec> {
validators: Arc<RwLock<HashMap<PublicKey, ValidatorDirectory>>>, validators: Arc<RwLock<HashMap<PublicKey, ValidatorDirectory>>>,
genesis_validators_root: Hash256,
spec: Arc<ChainSpec>, spec: Arc<ChainSpec>,
log: Logger, log: Logger,
temp_dir: Option<Arc<TempDir>>, temp_dir: Option<Arc<TempDir>>,
@ -29,6 +30,7 @@ pub struct ValidatorStore<T, E: EthSpec> {
impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> { impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
pub fn load_from_disk( pub fn load_from_disk(
base_dir: PathBuf, base_dir: PathBuf,
genesis_validators_root: Hash256,
spec: ChainSpec, spec: ChainSpec,
fork_service: ForkService<T, E>, fork_service: ForkService<T, E>,
log: Logger, log: Logger,
@ -66,6 +68,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
Ok(Self { Ok(Self {
validators: Arc::new(RwLock::new(HashMap::from_par_iter(validator_key_values))), validators: Arc::new(RwLock::new(HashMap::from_par_iter(validator_key_values))),
genesis_validators_root,
spec: Arc::new(spec), spec: Arc::new(spec),
log, log,
temp_dir: None, temp_dir: None,
@ -76,6 +79,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
pub fn insecure_ephemeral_validators( pub fn insecure_ephemeral_validators(
validator_indices: &[usize], validator_indices: &[usize],
genesis_validators_root: Hash256,
spec: ChainSpec, spec: ChainSpec,
fork_service: ForkService<T, E>, fork_service: ForkService<T, E>,
log: Logger, log: Logger,
@ -107,6 +111,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
Ok(Self { Ok(Self {
validators: Arc::new(RwLock::new(HashMap::from_iter(validators))), validators: Arc::new(RwLock::new(HashMap::from_iter(validators))),
genesis_validators_root,
spec: Arc::new(spec), spec: Arc::new(spec),
log, log,
temp_dir: Some(Arc::new(temp_dir)), temp_dir: Some(Arc::new(temp_dir)),
@ -144,7 +149,12 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
.get(validator_pubkey) .get(validator_pubkey)
.and_then(|validator_dir| { .and_then(|validator_dir| {
let voting_keypair = validator_dir.voting_keypair.as_ref()?; let voting_keypair = validator_dir.voting_keypair.as_ref()?;
let domain = self.spec.get_domain(epoch, Domain::Randao, &self.fork()?); let domain = self.spec.get_domain(
epoch,
Domain::Randao,
&self.fork()?,
self.genesis_validators_root,
);
let message = epoch.signing_root(domain); let message = epoch.signing_root(domain);
Some(Signature::new(message.as_bytes(), &voting_keypair.sk)) Some(Signature::new(message.as_bytes(), &voting_keypair.sk))
@ -162,7 +172,12 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
.get(validator_pubkey) .get(validator_pubkey)
.and_then(|validator_dir| { .and_then(|validator_dir| {
let voting_keypair = validator_dir.voting_keypair.as_ref()?; let voting_keypair = validator_dir.voting_keypair.as_ref()?;
Some(block.sign(&voting_keypair.sk, &self.fork()?, &self.spec)) Some(block.sign(
&voting_keypair.sk,
&self.fork()?,
self.genesis_validators_root,
&self.spec,
))
}) })
} }
@ -184,6 +199,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
&voting_keypair.sk, &voting_keypair.sk,
validator_committee_position, validator_committee_position,
&self.fork()?, &self.fork()?,
self.genesis_validators_root,
&self.spec, &self.spec,
) )
.map_err(|e| { .map_err(|e| {