mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-11 18:04:18 +00:00
Merge latest master in v0.2.0
This commit is contained in:
@@ -438,7 +438,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>(
|
||||
|
||||
@@ -4,11 +4,12 @@ use crate::{ApiError, ApiResult, BoxFut, UrlQuery};
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use futures::{Future, Stream};
|
||||
use hyper::{Body, Request};
|
||||
use rest_types::{IndividualVotesRequest, IndividualVotesResponse};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use state_processing::per_epoch_processing::{TotalBalances, ValidatorStatus, ValidatorStatuses};
|
||||
use state_processing::per_epoch_processing::{TotalBalances, ValidatorStatuses};
|
||||
use std::sync::Arc;
|
||||
use types::{Epoch, EthSpec, PublicKeyBytes};
|
||||
use types::EthSpec;
|
||||
|
||||
/// The results of validators voting during an epoch.
|
||||
///
|
||||
@@ -37,13 +38,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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,68 +71,6 @@ pub fn get_vote_count<T: BeaconChainTypes>(
|
||||
ResponseBuilder::new(&req)?.body(&report)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
|
||||
pub struct IndividualVotesRequest {
|
||||
pub epoch: Epoch,
|
||||
pub pubkeys: Vec<PublicKeyBytes>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
|
||||
pub struct IndividualVote {
|
||||
/// True if the validator has been slashed, ever.
|
||||
pub is_slashed: bool,
|
||||
/// True if the validator can withdraw in the current epoch.
|
||||
pub is_withdrawable_in_current_epoch: bool,
|
||||
/// True if the validator was active in the state's _current_ epoch.
|
||||
pub is_active_in_current_epoch: bool,
|
||||
/// True if the validator was active in the state's _previous_ epoch.
|
||||
pub is_active_in_previous_epoch: bool,
|
||||
/// The validator's effective balance in the _current_ epoch.
|
||||
pub current_epoch_effective_balance_gwei: u64,
|
||||
/// True if the validator had an attestation included in the _current_ epoch.
|
||||
pub is_current_epoch_attester: bool,
|
||||
/// True if the validator's beacon block root attestation for the first slot of the _current_
|
||||
/// epoch matches the block root known to the state.
|
||||
pub is_current_epoch_target_attester: bool,
|
||||
/// True if the validator had an attestation included in the _previous_ epoch.
|
||||
pub is_previous_epoch_attester: bool,
|
||||
/// True if the validator's beacon block root attestation for the first slot of the _previous_
|
||||
/// epoch matches the block root known to the state.
|
||||
pub is_previous_epoch_target_attester: bool,
|
||||
/// True if the validator's beacon block root attestation in the _previous_ epoch at the
|
||||
/// attestation's slot (`attestation_data.slot`) matches the block root known to the state.
|
||||
pub is_previous_epoch_head_attester: bool,
|
||||
}
|
||||
|
||||
impl Into<IndividualVote> for ValidatorStatus {
|
||||
fn into(self) -> IndividualVote {
|
||||
IndividualVote {
|
||||
is_slashed: self.is_slashed,
|
||||
is_withdrawable_in_current_epoch: self.is_withdrawable_in_current_epoch,
|
||||
is_active_in_current_epoch: self.is_active_in_current_epoch,
|
||||
is_active_in_previous_epoch: self.is_active_in_previous_epoch,
|
||||
current_epoch_effective_balance_gwei: self.current_epoch_effective_balance,
|
||||
is_current_epoch_attester: self.is_current_epoch_attester,
|
||||
is_current_epoch_target_attester: self.is_current_epoch_target_attester,
|
||||
is_previous_epoch_attester: self.is_previous_epoch_attester,
|
||||
is_previous_epoch_target_attester: self.is_previous_epoch_target_attester,
|
||||
is_previous_epoch_head_attester: self.is_previous_epoch_head_attester,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
|
||||
pub struct IndividualVotesResponse {
|
||||
/// The epoch which is considered the "current" epoch.
|
||||
pub epoch: Epoch,
|
||||
/// The validators public key.
|
||||
pub pubkey: PublicKeyBytes,
|
||||
/// The index of the validator in state.validators.
|
||||
pub validator_index: Option<usize>,
|
||||
/// Voting statistics for the validator, if they voted in the given epoch.
|
||||
pub vote: Option<IndividualVote>,
|
||||
}
|
||||
|
||||
pub fn post_individual_votes<T: BeaconChainTypes>(
|
||||
req: Request<Body>,
|
||||
beacon_chain: Arc<BeaconChain<T>>,
|
||||
@@ -156,12 +95,16 @@ pub fn post_individual_votes<T: BeaconChainTypes>(
|
||||
// This is the last slot of the given epoch (one prior to the first slot of the next epoch).
|
||||
let target_slot = (epoch + 1).start_slot(T::EthSpec::slots_per_epoch()) - 1;
|
||||
|
||||
let (_root, state) = state_at_slot(&beacon_chain, target_slot)?;
|
||||
let (_root, mut state) = state_at_slot(&beacon_chain, target_slot)?;
|
||||
let spec = &beacon_chain.spec;
|
||||
|
||||
let mut validator_statuses = ValidatorStatuses::new(&state, spec)?;
|
||||
validator_statuses.process_attestations(&state, spec)?;
|
||||
|
||||
state.update_pubkey_cache().map_err(|e| {
|
||||
ApiError::ServerError(format!("Unable to build pubkey cache: {:?}", e))
|
||||
})?;
|
||||
|
||||
body.pubkeys
|
||||
.into_iter()
|
||||
.map(|pubkey| {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -209,19 +209,12 @@ fn return_validator_duties<T: BeaconChainTypes>(
|
||||
// The `beacon_chain` can return a validator index that does not exist in all states.
|
||||
// Therefore, we must check to ensure that the validator index is valid for our
|
||||
// `state`.
|
||||
let validator_index = if let Some(i) = beacon_chain
|
||||
let validator_index = beacon_chain
|
||||
.validator_index(&validator_pubkey)
|
||||
.map_err(|e| {
|
||||
ApiError::ServerError(format!("Unable to get validator index: {:?}", e))
|
||||
})? {
|
||||
if i < state.validators.len() {
|
||||
Some(i)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
ApiError::ServerError(format!("Unable to get validator index: {:?}", e))
|
||||
})?
|
||||
.filter(|i| *i < state.validators.len());
|
||||
|
||||
if let Some(validator_index) = validator_index {
|
||||
let duties = state
|
||||
@@ -554,6 +547,7 @@ pub fn publish_aggregate_and_proofs<T: BeaconChainTypes>(
|
||||
// TODO: More efficient way of getting a fork?
|
||||
let fork = &beacon_chain.head()?.beacon_state.fork;
|
||||
|
||||
// TODO: Update to shift this task to dedicated task using await
|
||||
signed_proofs.par_iter().try_for_each(|signed_proof| {
|
||||
let agg_proof = &signed_proof.message;
|
||||
let validator_pubkey = &beacon_chain.validator_pubkey(agg_proof.aggregator_index as usize)?.ok_or_else(|| {
|
||||
@@ -573,7 +567,7 @@ pub fn publish_aggregate_and_proofs<T: BeaconChainTypes>(
|
||||
* I (Paul H) will pick this up in a future PR.
|
||||
*/
|
||||
|
||||
if signed_proof.is_valid(validator_pubkey, fork, &beacon_chain.spec) {
|
||||
if signed_proof.is_valid(validator_pubkey, fork, beacon_chain.genesis_validators_root, &beacon_chain.spec) {
|
||||
let attestation = &agg_proof.aggregate;
|
||||
|
||||
match beacon_chain.process_attestation(attestation.clone(), AttestationType::Aggregated) {
|
||||
|
||||
@@ -48,17 +48,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)
|
||||
}
|
||||
@@ -69,16 +67,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]
|
||||
@@ -94,6 +90,7 @@ fn validator_produce_attestation() {
|
||||
.client
|
||||
.beacon_chain()
|
||||
.expect("client should have beacon chain");
|
||||
let genesis_validators_root = beacon_chain.genesis_validators_root;
|
||||
let state = beacon_chain.head().expect("should get head").beacon_state;
|
||||
|
||||
let validator_index = 0;
|
||||
@@ -192,6 +189,7 @@ fn validator_produce_attestation() {
|
||||
.attestation_committee_position
|
||||
.expect("should have committee position"),
|
||||
&state.fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
)
|
||||
.expect("should sign attestation");
|
||||
@@ -228,6 +226,7 @@ fn validator_produce_attestation() {
|
||||
aggregated_attestation,
|
||||
&keypair.sk,
|
||||
&state.fork,
|
||||
genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
@@ -635,6 +634,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();
|
||||
@@ -974,6 +998,7 @@ fn proposer_slashing() {
|
||||
proposer_index as u64,
|
||||
&key,
|
||||
fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
@@ -998,6 +1023,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();
|
||||
@@ -1052,6 +1078,7 @@ fn attester_slashing() {
|
||||
&validator_indices[..],
|
||||
&secret_keys[..],
|
||||
fork,
|
||||
state.genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
@@ -1077,6 +1104,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();
|
||||
|
||||
Reference in New Issue
Block a user