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:
- 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.
- RESTful JSON API via HTTP server.
- Events via WebSocket.

View File

@ -153,6 +153,8 @@ pub struct HeadInfo {
pub current_justified_checkpoint: types::Checkpoint,
pub finalized_checkpoint: types::Checkpoint,
pub fork: Fork,
pub genesis_time: u64,
pub genesis_validators_root: Hash256,
}
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(),
finalized_checkpoint: head.beacon_state.finalized_checkpoint.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>>()?;
let fork = self
let (fork, genesis_validators_root) = self
.canonical_head
.try_read_for(HEAD_LOCK_TIMEOUT)
.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(
pubkeys,
&attestation.signature,
&indexed_attestation,
&fork,
genesis_validators_root,
&self.spec,
)
.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
// attestation for inclusion in a future block.
if self.eth1_chain.is_some() {
self.op_pool
.insert_attestation(attestation, &fork, &self.spec)?;
self.op_pool.insert_attestation(
attestation,
&fork,
genesis_validators_root,
&self.spec,
)?;
};
Ok(AttestationProcessingOutcome::Processed)
@ -1547,6 +1561,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut block = SignedBeaconBlock {
message: BeaconBlock {
slot: state.slot,
proposer_index: state.get_beacon_proposer_index(state.slot, &self.spec)? as u64,
parent_root,
state_root: Hash256::zero(),
body: BeaconBlockBody {

View File

@ -313,7 +313,9 @@ where
let randao_reveal = {
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);
Signature::new(message.as_bytes(), sk)
};
@ -323,7 +325,7 @@ where
.produce_block_on_state(state, slot, randao_reveal)
.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)
}
@ -408,6 +410,7 @@ where
attestation.data.target.epoch,
Domain::BeaconAttester,
fork,
state.genesis_validators_root,
);
let message = attestation.data.signing_root(domain);

View File

@ -494,7 +494,15 @@ pub fn get_genesis_time<T: BeaconChainTypes>(
req: Request<Body>,
beacon_chain: Arc<BeaconChain<T>>,
) -> 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>(

View File

@ -37,13 +37,13 @@ pub struct VoteCount {
impl Into<VoteCount> for TotalBalances {
fn into(self) -> VoteCount {
VoteCount {
current_epoch_active_gwei: self.current_epoch,
previous_epoch_active_gwei: self.previous_epoch,
current_epoch_attesting_gwei: self.current_epoch_attesters,
current_epoch_target_attesting_gwei: self.current_epoch_target_attesters,
previous_epoch_attesting_gwei: self.previous_epoch_attesters,
previous_epoch_target_attesting_gwei: self.previous_epoch_target_attesters,
previous_epoch_head_attesting_gwei: self.previous_epoch_head_attesters,
current_epoch_active_gwei: self.current_epoch(),
previous_epoch_active_gwei: self.previous_epoch(),
current_epoch_attesting_gwei: self.current_epoch_attesters(),
current_epoch_target_attesting_gwei: self.current_epoch_target_attesters(),
previous_epoch_attesting_gwei: self.previous_epoch_attesters(),
previous_epoch_target_attesting_gwei: self.previous_epoch_target_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") => {
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") => {
into_boxfut(beacon::get_validators::<T>(req, beacon_chain))
}

View File

@ -47,17 +47,15 @@ fn get_randao_reveal<T: BeaconChainTypes>(
slot: Slot,
spec: &ChainSpec,
) -> Signature {
let fork = beacon_chain
.head()
.expect("should get head")
.beacon_state
.fork;
let head = beacon_chain.head().expect("should get head");
let fork = head.beacon_state.fork;
let genesis_validators_root = head.beacon_state.genesis_validators_root;
let proposer_index = beacon_chain
.block_proposer(slot)
.expect("should get proposer index");
let keypair = generate_deterministic_keypair(proposer_index);
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);
Signature::new(message.as_bytes(), &keypair.sk)
}
@ -68,16 +66,14 @@ fn sign_block<T: BeaconChainTypes>(
block: BeaconBlock<T::EthSpec>,
spec: &ChainSpec,
) -> SignedBeaconBlock<T::EthSpec> {
let fork = beacon_chain
.head()
.expect("should get head")
.beacon_state
.fork;
let head = beacon_chain.head().expect("should get head");
let fork = head.beacon_state.fork;
let genesis_validators_root = head.beacon_state.genesis_validators_root;
let proposer_index = beacon_chain
.block_proposer(block.slot)
.expect("should get 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]
@ -156,6 +152,7 @@ fn validator_produce_attestation() {
.attestation_committee_position
.expect("should have committee position"),
&state.fork,
state.genesis_validators_root,
spec,
)
.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]
fn fork() {
let mut env = build_env();
@ -903,6 +925,7 @@ fn proposer_slashing() {
proposer_index as u64,
&key,
fork,
state.genesis_validators_root,
spec,
);
@ -927,6 +950,7 @@ fn proposer_slashing() {
proposer_index as u64,
&key,
fork,
state.genesis_validators_root,
spec,
);
invalid_proposer_slashing.signed_header_2 = invalid_proposer_slashing.signed_header_1.clone();
@ -981,6 +1005,7 @@ fn attester_slashing() {
&validator_indices[..],
&secret_keys[..],
fork,
state.genesis_validators_root,
spec,
);
@ -1006,6 +1031,7 @@ fn attester_slashing() {
&validator_indices[..],
&secret_keys[..],
fork,
state.genesis_validators_root,
spec,
);
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Encode, Decode)]
pub struct PartialBeaconState<T>
where
@ -19,6 +19,7 @@ where
{
// Versioning
pub genesis_time: u64,
pub genesis_validators_root: Hash256,
pub slot: Slot,
pub fork: Fork,
@ -72,6 +73,7 @@ impl<T: EthSpec> PartialBeaconState<T> {
// TODO: could use references/Cow for fields to avoid cloning
PartialBeaconState {
genesis_time: s.genesis_time,
genesis_validators_root: s.genesis_validators_root,
slot: s.slot,
fork: s.fork.clone(),
@ -181,6 +183,7 @@ impl<E: EthSpec> TryInto<BeaconState<E>> for PartialBeaconState<E> {
Ok(BeaconState {
genesis_time: self.genesis_time,
genesis_validators_root: self.genesis_validators_root,
slot: self.slot,
fork: self.fork,

View File

@ -166,6 +166,7 @@ Returns an object containing a single [`SignedBeaconBlock`](https://github.com/e
"beacon_block": {
"message": {
"slot": 0,
"proposer_index": 14,
"parent_root": "0x0000000000000000000000000000000000000000000000000000000000000000",
"state_root": "0xf15690b6be4ed42ea1ee0741eb4bfd4619d37be8229b84b4ddd480fb028dcc8f",
"body": {
@ -444,7 +445,7 @@ canonical chain.
### Returns
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.
### Example Response
@ -454,6 +455,7 @@ and its tree hash root.
"root": "0x528e54ca5d4c957729a73f40fc513ae312e054c7295775c4a2b21f423416a72b",
"beacon_state": {
"genesis_time": 1575652800,
"genesis_validators_root": "0xa8a9226edee1b2627fb4117d7dea4996e64dec2998f37f6e824f74f2ce39a538",
"slot": 18478
}
}
@ -505,7 +507,7 @@ Typical Responses | 200
### Returns
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
@ -565,7 +567,7 @@ Typical Responses | 200
### 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

View File

@ -1,8 +1,7 @@
use int_to_bytes::int_to_bytes8;
use serde_derive::{Deserialize, Serialize};
use ssz::ssz_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.
#[derive(
@ -13,21 +12,34 @@ pub struct AttestationId {
}
/// 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 {
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 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 }
}
pub fn compute_domain_bytes(epoch: Epoch, fork: &Fork, spec: &ChainSpec) -> Vec<u8> {
int_to_bytes8(spec.get_domain(epoch, Domain::BeaconAttester, fork))
pub fn compute_domain_bytes(
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 {
&self.v[self.v.len() - DOMAIN_BYTES_LEN..] == domain_bytes
pub fn domain_bytes_match(&self, domain_bytes: &Hash256) -> bool {
&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 types::{
typenum::Unsigned, Attestation, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec,
EthSpec, Fork, ProposerSlashing, RelativeEpoch, SignedVoluntaryExit, Validator,
EthSpec, Fork, Hash256, ProposerSlashing, RelativeEpoch, SignedVoluntaryExit, Validator,
};
#[derive(Default, Debug)]
@ -58,9 +58,10 @@ impl<T: EthSpec> OperationPool<T> {
&self,
attestation: Attestation<T>,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> 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.
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.
let prev_epoch = state.previous_epoch();
let current_epoch = state.current_epoch();
let prev_domain_bytes = AttestationId::compute_domain_bytes(prev_epoch, &state.fork, spec);
let curr_domain_bytes =
AttestationId::compute_domain_bytes(current_epoch, &state.fork, spec);
let prev_domain_bytes = AttestationId::compute_domain_bytes(
prev_epoch,
&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 active_indices = state
.get_cached_active_validator_indices(RelativeEpoch::Current)
@ -168,7 +178,7 @@ impl<T: EthSpec> OperationPool<T> {
verify_proposer_slashing(&slashing, state, VerifySignatures::True, spec)?;
self.proposer_slashings
.write()
.insert(slashing.proposer_index, slashing);
.insert(slashing.signed_header_1.message.proposer_index, slashing);
Ok(())
}
@ -181,8 +191,18 @@ impl<T: EthSpec> OperationPool<T> {
spec: &ChainSpec,
) -> (AttestationId, AttestationId) {
(
AttestationId::from_data(&slashing.attestation_1.data, &state.fork, spec),
AttestationId::from_data(&slashing.attestation_2.data, &state.fork, spec),
AttestationId::from_data(
&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| {
state
.validators
.get(slashing.proposer_index as usize)
.get(slashing.signed_header_1.message.proposer_index as usize)
.map_or(false, |validator| !validator.slashed)
},
T::MaxProposerSlashings::to_usize(),
@ -224,7 +244,7 @@ impl<T: EthSpec> OperationPool<T> {
// slashings.
let mut to_be_slashed = proposer_slashings
.iter()
.map(|s| s.proposer_index)
.map(|s| s.signed_header_1.message.proposer_index)
.collect::<HashSet<_>>();
let epoch = state.current_epoch();
@ -427,6 +447,7 @@ mod release_tests {
signers,
&committee_keys,
&state.fork,
state.genesis_validators_root,
spec,
);
extra_signer.map(|c_idx| {
@ -436,6 +457,7 @@ mod release_tests {
&[validator_index],
&[&keypairs[validator_index].sk],
&state.fork,
state.genesis_validators_root,
spec,
)
});
@ -548,7 +570,9 @@ mod release_tests {
spec,
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,
);
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();
op_pool.insert_attestation(att, &state.fork, spec).unwrap();
}
assert_eq!(op_pool.num_attestations(), committees.len());
@ -656,7 +687,9 @@ mod release_tests {
spec,
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,
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,
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(
self.proposer_slashings
.into_iter()
.map(|slashing| (slashing.proposer_index, slashing))
.map(|slashing| (slashing.signed_header_1.message.proposer_index, slashing))
.collect(),
);
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_attesting_indices<T: EthSpec>(
committee: &[usize],
bitlist: &BitList<T::MaxValidatorsPerCommittee>,

View File

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

View File

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

View File

@ -3,7 +3,7 @@ use types::{BeaconStateError as Error, *};
/// 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>(
state: &mut BeaconState<T>,
index: usize,

View File

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

View File

@ -6,7 +6,7 @@ use types::*;
/// 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
pub fn initialize_beacon_state_from_eth1<T: EthSpec>(
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)
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)
}
/// 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 {
state.genesis_time >= spec.min_genesis_time
&& 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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_activations<T: EthSpec>(state: &mut BeaconState<T>, spec: &ChainSpec) {
for (index, validator) in state.validators.iter_mut().enumerate() {
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
/// care of mixing in the domain.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn per_block_processing<T: EthSpec>(
mut state: &mut BeaconState<T>,
signed_block: &SignedBeaconBlock<T>,
@ -136,14 +136,26 @@ pub fn per_block_processing<T: EthSpec>(
/// Processes the block header.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_block_header<T: EthSpec>(
state: &mut BeaconState<T>,
block: &BeaconBlock<T>,
spec: &ChainSpec,
) -> Result<(), BlockOperationError<HeaderInvalid>> {
// Verify that the slots match
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();
verify!(
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();
// Verify proposer is not slashed
let proposer_idx = state.get_beacon_proposer_index(block.slot, spec)?;
let proposer = &state.validators[proposer_idx];
let proposer = &state.validators[proposer_index];
verify!(
!proposer.slashed,
HeaderInvalid::ProposerSlashed(proposer_idx)
HeaderInvalid::ProposerSlashed(proposer_index)
);
Ok(())
@ -168,7 +179,7 @@ pub fn process_block_header<T: EthSpec>(
/// Verifies the signature of a block.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_block_signature<T: EthSpec>(
state: &BeaconState<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
/// `state.latest_randao_mixes`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_randao<T: EthSpec>(
state: &mut BeaconState<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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_eth1_data<T: EthSpec>(
state: &mut BeaconState<T>,
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
/// result in a change to `state.eth1_data`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_new_eth1_data<T: EthSpec>(
state: &BeaconState<T>,
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
/// 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>(
state: &mut BeaconState<T>,
proposer_slashings: &[ProposerSlashing],
@ -268,7 +279,12 @@ pub fn process_proposer_slashings<T: EthSpec>(
// Update the state.
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(())
@ -279,7 +295,7 @@ pub fn process_proposer_slashings<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// 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>(
state: &mut BeaconState<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
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_attestations<T: EthSpec>(
state: &mut BeaconState<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
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_deposits<T: EthSpec>(
state: &mut BeaconState<T>,
deposits: &[Deposit],
@ -416,7 +432,7 @@ pub fn process_deposits<T: EthSpec>(
/// Process a single deposit, optionally verifying its merkle proof.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_deposit<T: EthSpec>(
state: &mut BeaconState<T>,
deposit: &Deposit,
@ -482,7 +498,7 @@ pub fn process_deposit<T: EthSpec>(
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
/// an `Err` describing the invalid object or cause of failure.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_exits<T: EthSpec>(
state: &mut BeaconState<T>,
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 keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
Some(sk) => {
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(
@ -70,7 +79,12 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
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)
}
@ -96,9 +110,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
Some(sk) => {
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 {
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)
}
@ -151,9 +179,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
Some(sk) => {
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();
@ -166,7 +203,12 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
spec,
)
.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)
}
@ -192,9 +234,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
Some(sk) => {
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![];
@ -210,10 +261,16 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
&validator_indices,
&secret_keys,
&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)
}
@ -239,9 +296,18 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
Some(sk) => {
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 {
@ -252,10 +318,16 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
validator_indices,
&secret_keys,
&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)
}
@ -279,12 +351,26 @@ impl<T: EthSpec> BlockProcessingBuilder<T> {
let proposer_index = state.get_beacon_proposer_index(state.slot, spec).unwrap();
let keypair = &keypairs[proposer_index];
builder.set_proposer_index(proposer_index as u64);
match randao_sk {
Some(sk) => builder.set_randao_reveal(&sk, &state.fork, spec),
None => builder.set_randao_reveal(&keypair.sk, &state.fork, spec),
Some(sk) => {
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)
}

View File

@ -159,7 +159,14 @@ impl<T> From<ssz_types::Error> for BlockOperationError<T> {
pub enum HeaderInvalid {
ProposalSignatureInvalid,
StateSlotMismatch,
ParentBlockRootMismatch { state: Hash256, block: Hash256 },
ProposerIndexMismatch {
block_proposer_index: usize,
state_proposer_index: usize,
},
ParentBlockRootMismatch {
state: Hash256,
block: Hash256,
},
ProposerSlashed(usize),
}
@ -171,6 +178,10 @@ pub enum ProposerSlashingInvalid {
///
/// (proposal_1_slot, proposal_2_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.
ProposalsIdentical,
/// 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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn is_valid_indexed_attestation<T: EthSpec>(
state: &BeaconState<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()),
Domain::BeaconProposer,
&state.fork,
state.genesis_validators_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()),
Domain::Randao,
&state.fork,
state.genesis_validators_root,
);
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,
spec: &'a ChainSpec,
) -> 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((
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()),
Domain::BeaconProposer,
&state.fork,
state.genesis_validators_root,
);
let message = signed_header
@ -162,6 +165,7 @@ pub fn indexed_attestation_signature_set<'a, 'b, T: EthSpec>(
indexed_attestation.data.target.epoch,
Domain::BeaconAttester,
&state.fork,
state.genesis_validators_root,
);
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,
indexed_attestation: &'b IndexedAttestation<T>,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>> {
let pubkeys = pubkeys
@ -188,6 +193,7 @@ pub fn indexed_attestation_signature_set_from_pubkeys<'a, 'b, T: EthSpec>(
indexed_attestation.data.target.epoch,
Domain::BeaconAttester,
&fork,
genesis_validators_root,
);
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 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();

View File

@ -10,7 +10,7 @@ use types::test_utils::{
use types::*;
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 EXIT_SLOT_OFFSET: u64 = 2048;
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
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
let result = per_block_processing(
@ -630,7 +635,7 @@ fn invalid_attestation_wrong_justified_checkpoint() {
#[test]
fn invalid_attestation_bad_indexed_attestation_bad_signature() {
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 (block, mut state) =
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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_attestation_for_block_inclusion<T: EthSpec>(
state: &BeaconState<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
/// prior blocks in `state`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_attestation_for_state<T: EthSpec>(
state: &BeaconState<T>,
attestation: &Attestation<T>,
@ -58,6 +58,13 @@ pub fn verify_attestation_for_state<T: EthSpec>(
) -> Result<()> {
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!(
data.index < state.get_committee_count_at_slot(data.slot)?,
Invalid::BadCommitteeIndex
@ -76,7 +83,7 @@ pub fn verify_attestation_for_state<T: EthSpec>(
/// Check target epoch and source checkpoint.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn verify_casper_ffg_vote<T: EthSpec>(
attestation: &Attestation<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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_attester_slashing<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing<T>,
@ -47,7 +47,7 @@ pub fn verify_attester_slashing<T: EthSpec>(
///
/// Returns Ok(indices) if `indices.len() > 0`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_slashable_indices<T: EthSpec>(
state: &BeaconState<T>,
attester_slashing: &AttesterSlashing<T>,

View File

@ -14,7 +14,7 @@ fn error(reason: DepositInvalid) -> BlockOperationError<DepositInvalid> {
/// 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<()> {
let deposit_signature_message = deposit_pubkey_signature_message(&deposit_data, spec)
.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
/// 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>(
state: &BeaconState<T>,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_exit<T: EthSpec>(
state: &BeaconState<T>,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_exit_time_independent_only<T: EthSpec>(
state: &BeaconState<T>,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn verify_exit_parametric<T: EthSpec>(
state: &BeaconState<T>,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn verify_proposer_slashing<T: EthSpec>(
proposer_slashing: &ProposerSlashing,
state: &BeaconState<T>,
verify_signatures: VerifySignatures,
spec: &ChainSpec,
) -> Result<()> {
let proposer = state
.validators
.get(proposer_slashing.proposer_index as usize)
.ok_or_else(|| error(Invalid::ProposerUnknown(proposer_slashing.proposer_index)))?;
let header_1 = &proposer_slashing.signed_header_1.message;
let header_2 = &proposer_slashing.signed_header_2.message;
// Verify slots match
verify!(
proposer_slashing.signed_header_1.message.slot
== proposer_slashing.signed_header_2.message.slot,
Invalid::ProposalSlotMismatch(
proposer_slashing.signed_header_1.message.slot,
proposer_slashing.signed_header_2.message.slot
)
header_1.slot == header_2.slot,
Invalid::ProposalSlotMismatch(header_1.slot, header_2.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
verify!(
proposer_slashing.signed_header_1 != proposer_slashing.signed_header_2,
Invalid::ProposalsIdentical
);
verify!(header_1 != header_2, Invalid::ProposalsIdentical);
// 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!(
proposer.is_slashable_at(state.current_epoch()),
Invalid::ProposerNotSlashable(proposer_slashing.proposer_index)
Invalid::ProposerNotSlashable(header_1.proposer_index)
);
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
/// 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>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
@ -45,7 +45,11 @@ pub fn per_epoch_processing<T: EthSpec>(
process_registry_updates(state, spec)?;
// Slashings.
process_slashings(state, validator_statuses.total_balances.current_epoch, spec)?;
process_slashings(
state,
validator_statuses.total_balances.current_epoch(),
spec,
)?;
// Final updates.
process_final_updates(state, spec)?;
@ -66,7 +70,7 @@ pub fn per_epoch_processing<T: EthSpec>(
/// - `finalized_epoch`
/// - `finalized_root`
///
/// Spec v0.10.1
/// Spec v0.11.1
#[allow(clippy::if_same_then_else)] // For readability and consistency with spec.
pub fn process_justification_and_finalization<T: EthSpec>(
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.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 {
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)?;
}
// 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 {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_final_updates<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
@ -148,11 +152,14 @@ pub fn process_final_updates<T: EthSpec>(
}
// 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() {
let balance = state.balances[index];
let half_increment = spec.effective_balance_increment / 2;
if balance < validator.effective_balance
|| validator.effective_balance + 3 * half_increment < balance
if balance + downward_threshold < validator.effective_balance
|| validator.effective_balance + upward_threshold < balance
{
validator.effective_balance = std::cmp::min(
balance - balance % spec.effective_balance_increment,

View File

@ -33,7 +33,7 @@ impl std::ops::AddAssign for Delta {
/// Apply attester and proposer rewards.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_rewards_and_penalties<T: EthSpec>(
state: &mut BeaconState<T>,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn get_proposer_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState<T>,
@ -83,7 +83,7 @@ fn get_proposer_deltas<T: EthSpec>(
let base_reward = get_base_reward(
state,
index,
validator_statuses.total_balances.current_epoch,
validator_statuses.total_balances.current_epoch(),
spec,
)?;
@ -100,7 +100,7 @@ fn get_proposer_deltas<T: EthSpec>(
/// Apply rewards for participation in attestations during the previous epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn get_attestation_deltas<T: EthSpec>(
deltas: &mut Vec<Delta>,
state: &BeaconState<T>,
@ -113,7 +113,7 @@ fn get_attestation_deltas<T: EthSpec>(
let base_reward = get_base_reward(
state,
index,
validator_statuses.total_balances.current_epoch,
validator_statuses.total_balances.current_epoch(),
spec,
)?;
@ -133,7 +133,7 @@ fn get_attestation_deltas<T: EthSpec>(
/// Determine the delta for a single validator, sans proposer rewards.
///
/// Spec v0.11.0
/// Spec v0.11.1
fn get_attestation_delta<T: EthSpec>(
validator: &ValidatorStatus,
total_balances: &TotalBalances,
@ -157,13 +157,13 @@ fn get_attestation_delta<T: EthSpec>(
// - increment = EFFECTIVE_BALANCE_INCREMENT
// - reward_numerator = get_base_reward(state, index) * (attesting_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 =
total_balances.previous_epoch_attesters / spec.effective_balance_increment;
total_balances.previous_epoch_attesters() / spec.effective_balance_increment;
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 =
total_balances.previous_epoch_head_attesters / spec.effective_balance_increment;
total_balances.previous_epoch_head_attesters() / spec.effective_balance_increment;
// Expected FFG source.
// Spec:

View File

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

View File

@ -5,7 +5,7 @@ use types::*;
/// Performs a validator registry update, if required.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_registry_updates<T: EthSpec>(
state: &mut BeaconState<T>,
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.
#[derive(Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct InclusionInfo {
/// The distance between the attestation slot and the slot that attestation was included in a
/// block.
@ -43,7 +43,7 @@ impl InclusionInfo {
}
/// Information required to reward some validator during the current and previous epoch.
#[derive(Default, Clone)]
#[derive(Debug, Default, Clone)]
pub struct ValidatorStatus {
/// True if the validator has been slashed, ever.
pub is_slashed: bool,
@ -107,30 +107,64 @@ impl ValidatorStatus {
/// The total effective balances for different sets of validators during the previous and current
/// epochs.
#[derive(Default, Clone, Debug)]
#[derive(Clone, Debug)]
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.
pub current_epoch: u64,
current_epoch: u64,
/// 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.
pub current_epoch_attesters: u64,
current_epoch_attesters: u64,
/// 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.
pub current_epoch_target_attesters: u64,
current_epoch_target_attesters: u64,
/// 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
/// 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
/// 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
/// some `BeaconState`.
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct ValidatorStatuses {
/// Information about each individual validator from the state's validator registry.
pub statuses: Vec<ValidatorStatus>,
@ -144,13 +178,13 @@ impl ValidatorStatuses {
/// - Active validators
/// - Total balances for the current and previous epochs.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn new<T: EthSpec>(
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<Self, BeaconStateError> {
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() {
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
/// `total_balances` fields.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn process_attestations<T: EthSpec>(
&mut self,
state: &BeaconState<T>,
@ -221,10 +255,10 @@ impl ValidatorStatuses {
if target_matches_epoch_start_block(a, state, state.previous_epoch())? {
status.is_previous_epoch_target_attester = true;
}
if has_common_beacon_block_root(a, state)? {
status.is_previous_epoch_head_attester = true;
if has_common_beacon_block_root(a, state)? {
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
/// beacon block in the given `epoch`.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn target_matches_epoch_start_block<T: EthSpec>(
a: &PendingAttestation<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
/// the current slot of the `PendingAttestation`.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn has_common_beacon_block_root<T: EthSpec>(
a: &PendingAttestation<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.
/// 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>(
state: &mut BeaconState<T>,
state_root: Option<Hash256>,

View File

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

View File

@ -2,7 +2,7 @@ use super::{
AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey,
Signature, SignedRoot,
};
use crate::test_utils::TestRandom;
use crate::{test_utils::TestRandom, Hash256};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
@ -17,7 +17,7 @@ pub enum Error {
/// 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)]
#[serde(bound = "T: EthSpec")]
pub struct Attestation<T: EthSpec> {
@ -53,6 +53,7 @@ impl<T: EthSpec> Attestation<T> {
secret_key: &SecretKey,
committee_position: usize,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> Result<(), Error> {
if self
@ -66,7 +67,12 @@ impl<T: EthSpec> Attestation<T> {
.set(committee_position, true)
.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);
self.signature

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// The data upon which an attestation is based.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct AttesterSlashing<T: EthSpec> {

View File

@ -10,11 +10,12 @@ use tree_hash_derive::TreeHash;
/// A block of the `BeaconChain`.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct BeaconBlock<T: EthSpec> {
pub slot: Slot,
pub proposer_index: u64,
pub parent_root: Hash256,
pub state_root: Hash256,
pub body: BeaconBlockBody<T>,
@ -25,10 +26,11 @@ impl<T: EthSpec> SignedRoot for BeaconBlock<T> {}
impl<T: EthSpec> BeaconBlock<T> {
/// Returns an empty block to be used during genesis.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn empty(spec: &ChainSpec) -> Self {
BeaconBlock {
slot: spec.genesis_slot,
proposer_index: 0,
parent_root: Hash256::zero(),
state_root: Hash256::zero(),
body: BeaconBlockBody {
@ -55,7 +57,7 @@ impl<T: EthSpec> BeaconBlock<T> {
/// Returns the `tree_hash_root` of the block.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 {
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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader {
slot: self.slot,
proposer_index: self.proposer_index,
parent_root: self.parent_root,
state_root: self.state_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()`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn temporary_block_header(&self) -> BeaconBlockHeader {
BeaconBlockHeader {
state_root: Hash256::zero(),
@ -92,9 +95,15 @@ impl<T: EthSpec> BeaconBlock<T> {
self,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> 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 signature = Signature::new(message.as_bytes(), secret_key);
SignedBeaconBlock {

View File

@ -10,7 +10,7 @@ use tree_hash_derive::TreeHash;
/// 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)]
#[serde(bound = "T: EthSpec")]
pub struct BeaconBlockBody<T: EthSpec> {

View File

@ -9,10 +9,11 @@ use tree_hash_derive::TreeHash;
/// A header of a `BeaconBlock`.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct BeaconBlockHeader {
pub slot: Slot,
pub proposer_index: u64,
pub parent_root: Hash256,
pub state_root: Hash256,
pub body_root: Hash256,
@ -23,17 +24,18 @@ impl SignedRoot for BeaconBlockHeader {}
impl BeaconBlockHeader {
/// Returns the `tree_hash_root` of the header.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.tree_hash_root()[..])
}
/// 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> {
BeaconBlock {
slot: self.slot,
proposer_index: self.proposer_index,
parent_root: self.parent_root,
state_root: self.state_root,
body,
@ -45,10 +47,11 @@ impl BeaconBlockHeader {
self,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> SignedBeaconBlockHeader {
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 signature = Signature::new(message.as_bytes(), secret_key);
SignedBeaconBlockHeader {

View File

@ -91,7 +91,7 @@ impl AllowNextEpoch {
/// The state of the `BeaconChain` at some slot.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(
Debug,
PartialEq,
@ -111,6 +111,7 @@ where
{
// Versioning
pub genesis_time: u64,
pub genesis_validators_root: Hash256,
pub slot: Slot,
pub fork: Fork,
@ -182,11 +183,12 @@ impl<T: EthSpec> BeaconState<T> {
///
/// 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 {
BeaconState {
// Versioning
genesis_time,
genesis_validators_root: Hash256::zero(), // Set later.
slot: spec.genesis_slot,
fork: Fork {
previous_version: spec.genesis_fork_version,
@ -239,7 +241,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Returns the `tree_hash_root` of the state.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 {
Hash256::from_slice(&self.tree_hash_root()[..])
}
@ -268,7 +270,7 @@ impl<T: EthSpec> BeaconState<T> {
/// The epoch corresponding to `self.slot`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn current_epoch(&self) -> 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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn previous_epoch(&self) -> Epoch {
let current_epoch = self.current_epoch();
if current_epoch > T::genesis_epoch() {
@ -289,7 +291,7 @@ impl<T: EthSpec> BeaconState<T> {
/// The epoch following `self.current_epoch()`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn next_epoch(&self) -> Epoch {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_committee_count_at_slot(&self, slot: Slot) -> Result<u64, Error> {
let cache = self.committee_cache_at_slot(slot)?;
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_epoch_committee_count(&self, relative_epoch: RelativeEpoch) -> Result<u64, Error> {
let cache = self.committee_cache(relative_epoch)?;
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_active_validator_indices(&self, epoch: Epoch) -> Vec<usize> {
get_active_validator_indices(&self.validators, epoch)
}
@ -350,7 +352,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Utilises the committee cache.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_beacon_committee(
&self,
slot: Slot,
@ -369,7 +371,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// 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> {
let cache = self.committee_cache_at_slot(slot)?;
cache.get_beacon_committees_at_slot(slot)
@ -379,7 +381,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// Utilises the committee cache.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_beacon_committees_at_epoch(
&self,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
// NOTE: be sure to test this bad boy.
pub fn compute_proposer_index(
&self,
@ -429,7 +431,7 @@ impl<T: EthSpec> BeaconState<T> {
/// 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> {
let epoch = slot.epoch(T::slots_per_epoch());
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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn get_beacon_proposer_seed(&self, slot: Slot, spec: &ChainSpec) -> Result<Vec<u8>, Error> {
let epoch = slot.epoch(T::slots_per_epoch());
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_latest_block_root(&self, current_state_root: Hash256) -> Hash256 {
if self.latest_block_header.state_root.is_zero() {
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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
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) {
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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_block_root(&self, slot: Slot) -> Result<&Hash256, BeaconStateError> {
let i = self.get_latest_block_roots_index(slot)?;
Ok(&self.block_roots[i])
@ -487,7 +489,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the block root at a recent `epoch`.
///
/// Spec v0.10.1
/// Spec v0.11.1
// NOTE: the spec calls this get_block_root
pub fn get_block_root_at_epoch(&self, epoch: Epoch) -> Result<&Hash256, BeaconStateError> {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn set_block_root(
&mut self,
slot: Slot,
@ -513,7 +515,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtains the index for `randao_mixes`
///
/// Spec v0.10.1
/// Spec v0.11.1
fn get_randao_mix_index(
&self,
epoch: Epoch,
@ -535,7 +537,7 @@ impl<T: EthSpec> BeaconState<T> {
///
/// 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> {
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``.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_randao_mix(&self, epoch: Epoch) -> Result<&Hash256, Error> {
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::False)?;
Ok(&self.randao_mixes[i])
@ -556,7 +558,7 @@ impl<T: EthSpec> BeaconState<T> {
/// 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> {
let i = self.get_randao_mix_index(epoch, AllowNextEpoch::True)?;
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`.
///
/// Spec v0.10.1
/// Spec v0.11.1
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())) {
Ok(slot.as_usize() % self.state_roots.len())
@ -576,7 +578,7 @@ impl<T: EthSpec> BeaconState<T> {
/// 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> {
let i = self.get_latest_state_roots_index(slot)?;
Ok(&self.state_roots[i])
@ -584,7 +586,7 @@ impl<T: EthSpec> BeaconState<T> {
/// 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> {
let i =
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
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)?;
Ok(&self.block_roots[i])
@ -601,7 +603,7 @@ impl<T: EthSpec> BeaconState<T> {
/// 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> {
let i = self.get_latest_state_roots_index(slot)?;
self.state_roots[i] = state_root;
@ -610,7 +612,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Safely obtain the index for `slashings`, given some `epoch`.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn get_slashings_index(
&self,
epoch: Epoch,
@ -630,14 +632,14 @@ impl<T: EthSpec> BeaconState<T> {
/// Get a reference to the entire `slashings` vector.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_all_slashings(&self) -> &[u64] {
&self.slashings
}
/// 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> {
let i = self.get_slashings_index(epoch, AllowNextEpoch::False)?;
Ok(self.slashings[i])
@ -645,7 +647,7 @@ impl<T: EthSpec> BeaconState<T> {
/// 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> {
let i = self.get_slashings_index(epoch, AllowNextEpoch::True)?;
self.slashings[i] = value;
@ -654,7 +656,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Get the attestations from the current or previous epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_matching_source_attestations(
&self,
epoch: Epoch,
@ -670,7 +672,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Generate a seed for the given `epoch`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_seed(
&self,
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``.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_effective_balance(
&self,
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn compute_activation_exit_epoch(&self, epoch: Epoch, spec: &ChainSpec) -> Epoch {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_churn_limit(&self, spec: &ChainSpec) -> Result<u64, Error> {
Ok(std::cmp::max(
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_attestation_duties(
&self,
validator_index: usize,
@ -752,7 +754,7 @@ impl<T: EthSpec> BeaconState<T> {
/// Return the combined effective balance of an array of validators.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_total_balance(
&self,
validator_indices: &[usize],
@ -925,7 +927,26 @@ impl<T: EthSpec> BeaconState<T> {
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_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);
Ok(root)
} else {
@ -959,6 +980,7 @@ impl<T: EthSpec> BeaconState<T> {
pub fn clone_with(&self, config: CloneConfig) -> Self {
BeaconState {
genesis_time: self.genesis_time,
genesis_validators_root: self.genesis_validators_root,
slot: self.slot,
fork: self.fork.clone(),
latest_block_header: self.latest_block_header.clone(),

View File

@ -22,7 +22,7 @@ pub struct CommitteeCache {
impl CommitteeCache {
/// Return a new, fully initialized cache.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn initialized<T: EthSpec>(
state: &BeaconState<T>,
epoch: Epoch,
@ -87,7 +87,7 @@ impl CommitteeCache {
///
/// Always returns `&[]` for a non-initialized epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn active_validator_indices(&self) -> &[usize] {
&self.shuffling
}
@ -96,7 +96,7 @@ impl CommitteeCache {
///
/// Always returns `&[]` for a non-initialized epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn shuffling(&self) -> &[usize] {
&self.shuffling
}
@ -202,7 +202,7 @@ impl CommitteeCache {
///
/// Always returns `usize::default()` for a non-initialized epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn active_validator_count(&self) -> usize {
self.shuffling.len()
}
@ -211,7 +211,7 @@ impl CommitteeCache {
///
/// Always returns `usize::default()` for a non-initialized epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn epoch_committee_count(&self) -> 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.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn compute_committee(&self, index: usize) -> Option<&[usize]> {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn compute_committee_range(&self, index: usize) -> Option<Range<usize>> {
let count = self.epoch_committee_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
/// `epoch`.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn get_active_validator_indices(validators: &[Validator], epoch: Epoch) -> Vec<usize> {
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);
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.fork.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)
}
/// 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`.

View File

@ -3,6 +3,7 @@ use int_to_bytes::int_to_bytes4;
use serde_derive::{Deserialize, Serialize};
use std::fs::File;
use std::path::Path;
use tree_hash::TreeHash;
use utils::{
fork_from_hex_str, fork_to_hex_str, u32_from_hex_str, u32_to_hex_str, u8_from_hex_str,
u8_to_hex_str,
@ -10,18 +11,21 @@ use utils::{
/// Each of the BLS signature domains.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Domain {
BeaconProposer,
BeaconAttester,
Randao,
Deposit,
VoluntaryExit,
SelectionProof,
AggregateAndProof,
}
/// Holds all the "constants" for a BeaconChain.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct ChainSpec {
@ -44,6 +48,9 @@ pub struct ChainSpec {
pub shuffle_round_count: u8,
pub min_genesis_active_validator_count: u64,
pub min_genesis_time: u64,
pub hysteresis_quotient: u64,
pub hysteresis_downward_multiplier: u64,
pub hysteresis_upward_multiplier: u64,
/*
* Gwei values
@ -93,6 +100,8 @@ pub struct ChainSpec {
domain_randao: u32,
domain_deposit: u32,
domain_voluntary_exit: u32,
domain_selection_proof: u32,
domain_aggregate_and_proof: u32,
/*
* Fork choice
@ -112,7 +121,7 @@ pub struct ChainSpec {
impl ChainSpec {
/// 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 {
match domain {
Domain::BeaconProposer => self.domain_beacon_proposer,
@ -120,15 +129,23 @@ impl ChainSpec {
Domain::Randao => self.domain_randao,
Domain::Deposit => self.domain_deposit,
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
pub fn get_domain(&self, epoch: Epoch, domain: Domain, fork: &Fork) -> u64 {
/// Spec v0.11.1
pub fn get_domain(
&self,
epoch: Epoch,
domain: Domain,
fork: &Fork,
genesis_validators_root: Hash256,
) -> Hash256 {
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.
@ -136,29 +153,64 @@ impl ChainSpec {
/// Deposits are valid across forks, thus the deposit domain is computed
/// with the genesis fork version.
///
/// Spec v0.10.1
pub fn get_deposit_domain(&self) -> u64 {
self.compute_domain(Domain::Deposit, self.genesis_fork_version)
/// Spec v0.11.1
pub fn get_deposit_domain(&self) -> Hash256 {
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`.
///
/// Spec v0.10.1
pub fn compute_domain(&self, domain: Domain, fork_version: [u8; 4]) -> u64 {
/// Spec v0.11.1
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 mut bytes: Vec<u8> = int_to_bytes4(domain_constant);
bytes.append(&mut fork_version.to_vec());
let mut domain = [0; 32];
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];
fork_and_domain.copy_from_slice(&bytes);
u64::from_le_bytes(fork_and_domain)
Hash256::from(domain)
}
/// Returns a `ChainSpec` compatible with the Ethereum Foundation specification.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn mainnet() -> Self {
Self {
/*
@ -179,6 +231,9 @@ impl ChainSpec {
shuffle_round_count: 90,
min_genesis_active_validator_count: 16_384,
min_genesis_time: 1_578_009_600, // Jan 3, 2020
hysteresis_quotient: 4,
hysteresis_downward_multiplier: 1,
hysteresis_upward_multiplier: 5,
/*
* Gwei values
@ -223,6 +278,8 @@ impl ChainSpec {
domain_randao: 2,
domain_deposit: 3,
domain_voluntary_exit: 4,
domain_selection_proof: 5,
domain_aggregate_and_proof: 6,
/*
* Fork choice
@ -245,7 +302,7 @@ impl ChainSpec {
/// Ethereum Foundation minimal spec, as defined in the eth2.0-specs repo.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn minimal() -> Self {
// Note: bootnodes to be updated when static nodes exist.
let boot_nodes = vec![];
@ -257,6 +314,7 @@ impl ChainSpec {
min_genesis_active_validator_count: 64,
eth1_follow_distance: 16,
genesis_fork_version: [0x00, 0x00, 0x00, 0x01],
persistent_committee_period: 128,
min_genesis_delay: 300,
milliseconds_per_slot: 6_000,
network_id: 2, // lighthouse testnet network id
@ -291,7 +349,6 @@ impl Default for ChainSpec {
#[cfg(test)]
mod tests {
use super::*;
use int_to_bytes::int_to_bytes8;
#[test]
fn test_mainnet_spec_can_be_constructed() {
@ -299,19 +356,27 @@ mod tests {
}
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 {
previous_version: spec.genesis_fork_version,
current_version: spec.genesis_fork_version,
epoch: MinimalEthSpec::genesis_epoch(),
previous_version,
current_version,
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);
expected.append(&mut fork.get_fork_version(epoch).to_vec());
assert_eq!(int_to_bytes8(domain), expected);
assert_eq!(domain1, domain2);
assert_eq!(&domain1.as_bytes()[0..4], &int_to_bytes4(raw_domain)[..]);
}
}
#[test]
@ -323,18 +388,25 @@ mod tests {
test_domain(Domain::Randao, spec.domain_randao, &spec);
test_domain(Domain::Deposit, spec.domain_deposit, &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
/// 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.
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(rename_all = "UPPERCASE")]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct YamlConfig {
// ChainSpec
far_future_epoch: u64,
@ -352,6 +424,9 @@ pub struct YamlConfig {
max_effective_balance: u64,
ejection_balance: u64,
effective_balance_increment: u64,
hysteresis_quotient: u64,
hysteresis_downward_multiplier: u64,
hysteresis_upward_multiplier: u64,
genesis_slot: u64,
#[serde(
serialize_with = "fork_to_hex_str",
@ -403,12 +478,22 @@ pub struct YamlConfig {
deserialize_with = "u32_from_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
justification_bits_length: u32,
max_validators_per_committee: u32,
genesis_epoch: Epoch,
slots_per_epoch: u64,
slots_per_eth1_voting_period: usize,
epochs_per_eth1_voting_period: u64,
slots_per_historical_root: usize,
epochs_per_historical_vector: usize,
epochs_per_slashings_vector: usize,
@ -426,34 +511,6 @@ pub struct YamlConfig {
random_subnets_per_validator: u64,
epochs_per_random_subnet_subscription: 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 {
@ -463,7 +520,7 @@ impl Default for YamlConfig {
}
}
/// Spec v0.10.1
/// Spec v0.11.1
impl YamlConfig {
pub fn from_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
Self {
@ -483,6 +540,9 @@ impl YamlConfig {
max_effective_balance: spec.max_effective_balance,
ejection_balance: spec.ejection_balance,
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(),
bls_withdrawal_prefix: spec.bls_withdrawal_prefix_byte,
seconds_per_slot: spec.milliseconds_per_slot / 1000,
@ -504,13 +564,15 @@ impl YamlConfig {
domain_randao: spec.domain_randao,
domain_deposit: spec.domain_deposit,
domain_voluntary_exit: spec.domain_voluntary_exit,
domain_selection_proof: spec.domain_selection_proof,
domain_aggregate_and_proof: spec.domain_aggregate_and_proof,
// EthSpec
justification_bits_length: T::JustificationBitsLength::to_u32(),
max_validators_per_committee: T::MaxValidatorsPerCommittee::to_u32(),
genesis_epoch: T::genesis_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(),
epochs_per_historical_vector: T::epochs_per_historical_vector(),
epochs_per_slashings_vector: T::EpochsPerSlashingsVector::to_usize(),
@ -528,22 +590,6 @@ impl YamlConfig {
random_subnets_per_validator: 0,
epochs_per_random_subnet_subscription: 0,
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.genesis_epoch != T::genesis_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.epochs_per_historical_vector != T::epochs_per_historical_vector()
|| self.epochs_per_slashings_vector != T::EpochsPerSlashingsVector::to_usize()
@ -589,6 +635,9 @@ impl YamlConfig {
min_deposit_amount: self.min_deposit_amount,
min_genesis_delay: self.min_genesis_delay,
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,
effective_balance_increment: self.effective_balance_increment,
genesis_slot: Slot::from(self.genesis_slot),
@ -608,6 +657,7 @@ impl YamlConfig {
inactivity_penalty_quotient: self.inactivity_penalty_quotient,
min_slashing_penalty_quotient: self.min_slashing_penalty_quotient,
domain_beacon_proposer: self.domain_beacon_proposer,
domain_beacon_attester: self.domain_beacon_attester,
domain_randao: self.domain_randao,
domain_deposit: self.domain_deposit,
domain_voluntary_exit: self.domain_voluntary_exit,

View File

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

View File

@ -11,7 +11,7 @@ pub const DEPOSIT_TREE_DEPTH: usize = 32;
/// 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)]
pub struct Deposit {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct DepositData {
pub pubkey: PublicKeyBytes,
@ -21,7 +21,7 @@ pub struct DepositData {
impl DepositData {
/// 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 {
DepositMessage {
pubkey: self.pubkey.clone(),
@ -32,7 +32,7 @@ impl DepositData {
/// 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 {
let domain = spec.get_deposit_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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct DepositMessage {
pub pubkey: PublicKeyBytes,

View File

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

View File

@ -1,7 +1,7 @@
use crate::*;
use serde_derive::{Deserialize, Serialize};
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,
};
use std::fmt::Debug;
@ -20,7 +20,7 @@ pub trait EthSpec: 'static + Default + Sync + Send + Clone + Debug + PartialEq {
* Time parameters
*/
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;
/*
* 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.
///
/// 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
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;
@ -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
/// 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 {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn slots_per_epoch() -> u64 {
Self::SlotsPerEpoch::to_u64()
}
/// Returns the `SLOTS_PER_HISTORICAL_ROOT` constant for this specification.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn slots_per_historical_root() -> usize {
Self::SlotsPerHistoricalRoot::to_usize()
}
/// Returns the `EPOCHS_PER_HISTORICAL_VECTOR` constant for this specification.
///
/// Spec v0.10.1
/// Spec v0.11.1
fn epochs_per_historical_vector() -> usize {
Self::EpochsPerHistoricalVector::to_usize()
}
/// 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 {
Self::SlotsPerEth1VotingPeriod::to_usize()
}
@ -119,7 +123,7 @@ macro_rules! params_from_eth_spec {
/// Ethereum Foundation specifications.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
pub struct MainnetEthSpec;
@ -128,7 +132,7 @@ impl EthSpec for MainnetEthSpec {
type MaxValidatorsPerCommittee = U2048;
type GenesisEpoch = U0;
type SlotsPerEpoch = U32;
type SlotsPerEth1VotingPeriod = U1024;
type EpochsPerEth1VotingPeriod = U32;
type SlotsPerHistoricalRoot = U8192;
type EpochsPerHistoricalVector = U65536;
type EpochsPerSlashingsVector = U8192;
@ -140,6 +144,7 @@ impl EthSpec for MainnetEthSpec {
type MaxDeposits = U16;
type MaxVoluntaryExits = U16;
type MaxPendingAttestations = U4096; // 128 max attestations * 32 slots per epoch
type SlotsPerEth1VotingPeriod = U1024; // 32 epochs * 32 slots per epoch
fn default_spec() -> ChainSpec {
ChainSpec::mainnet()
@ -150,17 +155,18 @@ pub type FoundationBeaconState = BeaconState<MainnetEthSpec>;
/// 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)]
pub struct MinimalEthSpec;
impl EthSpec for MinimalEthSpec {
type SlotsPerEpoch = U8;
type SlotsPerEth1VotingPeriod = U16;
type EpochsPerEth1VotingPeriod = U2;
type SlotsPerHistoricalRoot = U64;
type EpochsPerHistoricalVector = U64;
type EpochsPerSlashingsVector = U64;
type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
type SlotsPerEth1VotingPeriod = U16; // 2 epochs * 8 slots per epoch
params_from_eth_spec!(MainnetEthSpec {
JustificationBitsLength,
@ -188,11 +194,12 @@ pub struct InteropEthSpec;
impl EthSpec for InteropEthSpec {
type SlotsPerEpoch = U8;
type EpochsPerEth1VotingPeriod = U2;
type SlotsPerHistoricalRoot = U64;
type SlotsPerEth1VotingPeriod = U16;
type EpochsPerHistoricalVector = U64;
type EpochsPerSlashingsVector = U64;
type MaxPendingAttestations = U1024; // 128 max attestations * 8 slots per epoch
type SlotsPerEth1VotingPeriod = U16; // 2 epochs * 8 slots per epoch
params_from_eth_spec!(MainnetEthSpec {
JustificationBitsLength,

View File

@ -9,7 +9,7 @@ use tree_hash_derive::TreeHash;
/// Specifies a fork of the `BeaconChain`, to prevent replay attacks.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(
Debug, Clone, PartialEq, Default, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom,
)]
@ -30,7 +30,7 @@ pub struct Fork {
impl Fork {
/// 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] {
if epoch < self.epoch {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct HistoricalBatch<T: EthSpec> {
pub block_roots: FixedVector<Hash256, T::SlotsPerHistoricalRoot>,

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
///
/// To be included in an `AttesterSlashing`.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct IndexedAttestation<T: EthSpec> {
@ -21,14 +21,14 @@ pub struct IndexedAttestation<T: EthSpec> {
impl<T: EthSpec> IndexedAttestation<T> {
/// 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 {
self.data.target.epoch == other.data.target.epoch && self.data != other.data
}
/// 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 {
self.data.source.epoch < other.data.source.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 eth_spec;
pub mod fork;
pub mod fork_data;
pub mod free_attestation;
pub mod historical_batch;
pub mod indexed_attestation;
@ -59,6 +60,7 @@ pub use crate::deposit_data::DepositData;
pub use crate::deposit_message::DepositMessage;
pub use crate::eth1_data::Eth1Data;
pub use crate::fork::Fork;
pub use crate::fork_data::ForkData;
pub use crate::free_attestation::FreeAttestation;
pub use crate::historical_batch::HistoricalBatch;
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct PendingAttestation<T: EthSpec> {
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).
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct ProposerSlashing {
pub proposer_index: u64,
pub signed_header_1: 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
/// to and following some epoch.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum RelativeEpoch {
/// The prior epoch.
@ -23,7 +23,7 @@ pub enum RelativeEpoch {
impl RelativeEpoch {
/// 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 {
match self {
// 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`.
/// - `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> {
// Due to saturating nature of epoch, check for current first.
if other == base {

View File

@ -8,7 +8,7 @@ use tree_hash::TreeHash;
/// 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)]
#[serde(bound = "E: EthSpec")]
pub struct SignedBeaconBlock<E: EthSpec> {
@ -34,7 +34,7 @@ impl<E: EthSpec> SignedBeaconBlock<E> {
/// Returns the `tree_hash_root` of the block.
///
/// Spec v0.10.1
/// Spec v0.11.1
pub fn canonical_root(&self) -> Hash256 {
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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom)]
pub struct SignedBeaconBlockHeader {
pub message: BeaconBlockHeader,

View File

@ -8,7 +8,7 @@ use tree_hash_derive::TreeHash;
/// 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)]
pub struct SignedVoluntaryExit {
pub message: VoluntaryExit,

View File

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

View File

@ -55,6 +55,7 @@ impl<T: EthSpec> TestingAttestationBuilder<T> {
signing_validators: &[usize],
secret_keys: &[&SecretKey],
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> &mut Self {
assert_eq!(
@ -77,15 +78,28 @@ impl<T: EthSpec> TestingAttestationBuilder<T> {
};
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");
if let AttestationTestTask::BadIndexedAttestationBadSignature = test_task {
self.attestation
.aggregation_bits
.set(committee_index, false)
.unwrap();
}
self.attestation
.aggregation_bits
.set(committee_index, true)
.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

View File

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

View File

@ -97,12 +97,23 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
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.
///
/// 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 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);
self.block.body.randao_reveal = Signature::new(message.as_bytes(), sk);
}
@ -119,10 +130,17 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
validator_index: u64,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) {
let proposer_slashing =
build_proposer_slashing::<T>(test_task, validator_index, secret_key, fork, spec);
let proposer_slashing = build_proposer_slashing::<T>(
test_task,
validator_index,
secret_key,
fork,
genesis_validators_root,
spec,
);
self.block
.body
.proposer_slashings
@ -137,6 +155,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
validator_indices: &[u64],
secret_keys: &[&SecretKey],
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) {
let attester_slashing = build_double_vote_attester_slashing(
@ -144,6 +163,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
validator_indices,
secret_keys,
fork,
genesis_validators_root,
spec,
);
let _ = self.block.body.attester_slashings.push(attester_slashing);
@ -246,6 +266,7 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
signing_validators,
&signing_secret_keys,
&state.fork,
state.genesis_validators_root,
spec,
);
@ -355,14 +376,20 @@ impl<T: EthSpec> TestingBeaconBlockBuilder<T> {
}
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();
}
/// Signs and returns the block, consuming the builder.
pub fn build(self, sk: &SecretKey, fork: &Fork, spec: &ChainSpec) -> SignedBeaconBlock<T> {
self.block.sign(sk, fork, spec)
pub fn build(
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.
@ -382,6 +409,7 @@ pub fn build_proposer_slashing<T: EthSpec>(
validator_index: u64,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> ProposerSlashing {
TestingProposerSlashingBuilder::double_vote::<T>(
@ -389,6 +417,7 @@ pub fn build_proposer_slashing<T: EthSpec>(
validator_index,
secret_key,
fork,
genesis_validators_root,
spec,
)
}
@ -401,6 +430,7 @@ pub fn build_double_vote_attester_slashing<T: EthSpec>(
validator_indices: &[u64],
secret_keys: &[&SecretKey],
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> AttesterSlashing<T> {
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])
};
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`).
pub fn double_vote<T>(
test_task: ProposerSlashingTestTask,
mut proposer_index: u64,
proposer_index: u64,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> ProposerSlashing
where
@ -31,6 +32,7 @@ impl TestingProposerSlashingBuilder {
let mut signed_header_1 = SignedBeaconBlockHeader {
message: BeaconBlockHeader {
slot,
proposer_index,
parent_root: hash_1,
state_root: hash_1,
body_root: hash_1,
@ -54,19 +56,25 @@ impl TestingProposerSlashingBuilder {
};
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 {
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 {
proposer_index = 3_141_592;
signed_header_1.message.proposer_index = 3_141_592;
signed_header_2.message.proposer_index = 3_141_592;
}
ProposerSlashing {
proposer_index,
signed_header_1,
signed_header_2,
}

View File

@ -25,8 +25,10 @@ impl TestingVoluntaryExitBuilder {
self,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> 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.
///
/// Spec v0.10.1
/// Spec v0.11.1
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash)]
pub struct Validator {
pub pubkey: PublicKeyBytes,
@ -44,7 +44,7 @@ impl Validator {
/// 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 {
self.activation_eligibility_epoch == spec.far_future_epoch
&& self.effective_balance == spec.max_effective_balance
@ -52,7 +52,7 @@ impl Validator {
/// 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>(
&self,
state: &BeaconState<E>,

View File

@ -1,6 +1,6 @@
use crate::{
test_utils::TestRandom, ChainSpec, Domain, Epoch, Fork, SecretKey, Signature, SignedRoot,
SignedVoluntaryExit,
test_utils::TestRandom, ChainSpec, Domain, Epoch, Fork, Hash256, SecretKey, Signature,
SignedRoot, SignedVoluntaryExit,
};
use serde_derive::{Deserialize, Serialize};
@ -10,7 +10,7 @@ use tree_hash_derive::TreeHash;
/// 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)]
pub struct VoluntaryExit {
/// Earliest epoch when voluntary exit can be processed.
@ -25,9 +25,15 @@ impl VoluntaryExit {
self,
secret_key: &SecretKey,
fork: &Fork,
genesis_validators_root: Hash256,
spec: &ChainSpec,
) -> 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 signature = Signature::new(message.as_bytes(), &secret_key);
SignedVoluntaryExit {

View File

@ -9,9 +9,9 @@ use std::fs::File;
use std::io::Write;
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
// with the unmodified v0.10.1 contract
// with the unmodified v0.11.1 contract
const UNSAFE_TAG: &str = "v0.9.2.1";
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 DEPOSIT_GAS: usize = 4_000_000;
pub const ABI: &[u8] = include_bytes!("../contracts/v0.10.1_validator_registration.json");
pub const BYTECODE: &[u8] = include_bytes!("../contracts/v0.10.1_validator_registration.bytecode");
pub const ABI: &[u8] = include_bytes!("../contracts/v0.11.1_validator_registration.json");
pub const BYTECODE: &[u8] = include_bytes!("../contracts/v0.11.1_validator_registration.bytecode");
pub const DEPOSIT_DATA_LEN: usize = 420; // lol
pub mod testnet {
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] =
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> {

View File

@ -202,6 +202,7 @@ mod tests {
type E = MainnetEthSpec;
/* TODO: disabled until testnet config is updated for v0.11
#[test]
fn hard_coded_works() {
let dir: Eth2TestnetConfig<E> =
@ -211,6 +212,7 @@ mod tests {
assert!(dir.genesis_state.is_some());
assert!(dir.yaml_config.is_some());
}
*/
#[test]
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.
pub fn int_to_bytes4(int: u32) -> Vec<u8> {
let mut bytes = BytesMut::with_capacity(4);
bytes.put_u32_le(int);
bytes.to_vec()
pub fn int_to_bytes4(int: u32) -> [u8; 4] {
int.to_le_bytes()
}
/// 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),
2 => assert_eq!(int_to_bytes2(int as u16), 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),
32 => assert_eq!(int_to_bytes32(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![]))
}
/// 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.
pub fn get_fork(&self) -> impl Future<Item = Fork, Error = Error> {
let client = self.0.clone();

View File

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

View File

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

View File

@ -1,7 +1,7 @@
//! Provides list-shuffling functions matching the Ethereum 2.0 specification.
//!
//! 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.
//!
//! 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
TESTS_TAG := v0.10.1
TESTS_TAG := v0.11.1
TESTS = general minimal mainnet
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> {
let mut validator_statuses = ValidatorStatuses::new(&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(())
}
}

View File

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

View File

@ -143,101 +143,125 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
box_future
})
})
.and_then(move |(beacon_node, remote_eth2_config, genesis_time)| {
let log = log_4.clone();
.and_then(|(beacon_node, eth2_config, genesis_time)| {
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.
if context.eth2_config.spec_constants != remote_eth2_config.spec_constants {
return Err(format!(
"Beacon node is using an incompatible spec. Got {}, expected {}",
remote_eth2_config.spec_constants, context.eth2_config.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 {
return Err(format!(
"Beacon node is using an incompatible spec. Got {}, expected {}",
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
// 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
// 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
// for Lighthouse.
context.eth2_config = remote_eth2_config;
// 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.
//
// 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
// produced. We are safe from this because `SLOTS_PER_EPOCH` is a type-level constant
// for Lighthouse.
context.eth2_config = remote_eth2_config;
let slot_clock = SystemTimeSlotClock::new(
context.eth2_config.spec.genesis_slot,
Duration::from_secs(genesis_time),
Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot),
);
let slot_clock = SystemTimeSlotClock::new(
context.eth2_config.spec.genesis_slot,
Duration::from_secs(genesis_time),
Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot),
);
let fork_service = ForkServiceBuilder::new()
.slot_clock(slot_clock.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("fork".into()))
.build()?;
let fork_service = ForkServiceBuilder::new()
.slot_clock(slot_clock.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("fork".into()))
.build()?;
let validator_store: ValidatorStore<SystemTimeSlotClock, T> =
match &config.key_source {
// Load pre-existing validators from the data dir.
//
// Use the `account_manager` to generate these files.
KeySource::Disk => ValidatorStore::load_from_disk(
config.data_dir.clone(),
context.eth2_config.spec.clone(),
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,
let validator_store: ValidatorStore<SystemTimeSlotClock, T> =
match &config.key_source {
// Load pre-existing validators from the data dir.
//
// Use the `account_manager` to generate these files.
KeySource::Disk => ValidatorStore::load_from_disk(
config.data_dir.clone(),
genesis_validators_root,
context.eth2_config.spec.clone(),
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,
genesis_validators_root,
context.eth2_config.spec.clone(),
fork_service.clone(),
log.clone(),
)?
}
};
info!(
log,
"Loaded validator keypair store";
"voting_validators" => validator_store.num_voting_validators()
);
info!(
log,
"Loaded validator keypair store";
"voting_validators" => validator_store.num_voting_validators()
);
let duties_service = DutiesServiceBuilder::new()
.slot_clock(slot_clock.clone())
.validator_store(validator_store.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("duties".into()))
.allow_unsynced_beacon_node(config.allow_unsynced_beacon_node)
.build()?;
let duties_service = DutiesServiceBuilder::new()
.slot_clock(slot_clock.clone())
.validator_store(validator_store.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("duties".into()))
.allow_unsynced_beacon_node(config.allow_unsynced_beacon_node)
.build()?;
let block_service = BlockServiceBuilder::new()
.duties_service(duties_service.clone())
.slot_clock(slot_clock.clone())
.validator_store(validator_store.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("block".into()))
.build()?;
let block_service = BlockServiceBuilder::new()
.duties_service(duties_service.clone())
.slot_clock(slot_clock.clone())
.validator_store(validator_store.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("block".into()))
.build()?;
let attestation_service = AttestationServiceBuilder::new()
.duties_service(duties_service.clone())
.slot_clock(slot_clock)
.validator_store(validator_store)
.beacon_node(beacon_node)
.runtime_context(context.service_context("attestation".into()))
.build()?;
let attestation_service = AttestationServiceBuilder::new()
.duties_service(duties_service.clone())
.slot_clock(slot_clock)
.validator_store(validator_store)
.beacon_node(beacon_node)
.runtime_context(context.service_context("attestation".into()))
.build()?;
Ok(Self {
context,
duties_service,
fork_service,
block_service,
attestation_service,
exit_signals: vec![],
})
})
Ok(Self {
context,
duties_service,
fork_service,
block_service,
attestation_service,
exit_signals: vec![],
})
},
)
}
pub fn start_service(&mut self) -> Result<(), String> {

View File

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