Update /validator/subscribe (#969)
* Add progress on duties refactor * Add simple is_aggregator bool to val subscription * Remove unused function
This commit is contained in:
parent
cf2cb26caa
commit
aa6f838c3c
@ -122,12 +122,7 @@ pub fn route<T: BeaconChainTypes>(
|
|||||||
into_boxfut(response)
|
into_boxfut(response)
|
||||||
}
|
}
|
||||||
(&Method::POST, "/validator/subscribe") => {
|
(&Method::POST, "/validator/subscribe") => {
|
||||||
validator::post_validator_subscriptions::<T>(
|
validator::post_validator_subscriptions::<T>(req, network_channel)
|
||||||
req,
|
|
||||||
beacon_chain,
|
|
||||||
network_channel,
|
|
||||||
log,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
(&Method::GET, "/validator/duties/all") => {
|
(&Method::GET, "/validator/duties/all") => {
|
||||||
into_boxfut(validator::get_all_validator_duties::<T>(req, beacon_chain))
|
into_boxfut(validator::get_all_validator_duties::<T>(req, beacon_chain))
|
||||||
|
@ -59,9 +59,7 @@ pub fn post_validator_duties<T: BeaconChainTypes>(
|
|||||||
/// organise peer discovery and topic subscription for known validators.
|
/// organise peer discovery and topic subscription for known validators.
|
||||||
pub fn post_validator_subscriptions<T: BeaconChainTypes>(
|
pub fn post_validator_subscriptions<T: BeaconChainTypes>(
|
||||||
req: Request<Body>,
|
req: Request<Body>,
|
||||||
beacon_chain: Arc<BeaconChain<T>>,
|
|
||||||
mut network_chan: NetworkChannel<T::EthSpec>,
|
mut network_chan: NetworkChannel<T::EthSpec>,
|
||||||
log: Logger,
|
|
||||||
) -> BoxFut {
|
) -> BoxFut {
|
||||||
try_future!(check_content_type_for_json(&req));
|
try_future!(check_content_type_for_json(&req));
|
||||||
let response_builder = ResponseBuilder::new(&req);
|
let response_builder = ResponseBuilder::new(&req);
|
||||||
@ -79,41 +77,6 @@ pub fn post_validator_subscriptions<T: BeaconChainTypes>(
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.and_then(move |subscriptions: Vec<ValidatorSubscription>| {
|
.and_then(move |subscriptions: Vec<ValidatorSubscription>| {
|
||||||
let fork = beacon_chain
|
|
||||||
.wall_clock_state()
|
|
||||||
.map(|state| state.fork.clone())
|
|
||||||
.map_err(|e| {
|
|
||||||
error!(log, "Unable to get current beacon state");
|
|
||||||
ApiError::ServerError(format!("Error getting current beacon state {:?}", e))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// verify the signatures in parallel
|
|
||||||
subscriptions.par_iter().try_for_each(|subscription| {
|
|
||||||
if let Some(pubkey) =
|
|
||||||
&beacon_chain.validator_pubkey(subscription.validator_index as usize)?
|
|
||||||
{
|
|
||||||
if subscription.verify(
|
|
||||||
pubkey,
|
|
||||||
&beacon_chain.spec,
|
|
||||||
&fork,
|
|
||||||
T::EthSpec::slots_per_epoch(),
|
|
||||||
) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
error!(log, "HTTP RPC sent invalid signatures");
|
|
||||||
Err(ApiError::ProcessingError(format!(
|
|
||||||
"Could not verify signatures"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error!(log, "HTTP RPC sent unknown validator");
|
|
||||||
Err(ApiError::ProcessingError(format!(
|
|
||||||
"Could not verify signatures"
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// subscriptions are verified, send them to the network thread
|
|
||||||
network_chan
|
network_chan
|
||||||
.try_send(NetworkMessage::Subscribe { subscriptions })
|
.try_send(NetworkMessage::Subscribe { subscriptions })
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
Attestation, ChainSpec, Domain, EthSpec, Fork, PublicKey, SecretKey, Signature, SignedRoot,
|
Attestation, ChainSpec, Domain, EthSpec, Fork, PublicKey, SecretKey, SelectionProof, Signature,
|
||||||
|
SignedRoot,
|
||||||
};
|
};
|
||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
@ -32,20 +33,13 @@ impl<T: EthSpec> AggregateAndProof<T> {
|
|||||||
fork: &Fork,
|
fork: &Fork,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let slot = aggregate.data.slot;
|
let selection_proof =
|
||||||
|
SelectionProof::new::<T>(aggregate.data.slot, secret_key, fork, spec).into();
|
||||||
let domain = spec.get_domain(
|
|
||||||
slot.epoch(T::slots_per_epoch()),
|
|
||||||
Domain::SelectionProof,
|
|
||||||
fork,
|
|
||||||
);
|
|
||||||
|
|
||||||
let message = slot.signing_root(domain);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
aggregator_index,
|
aggregator_index,
|
||||||
aggregate,
|
aggregate,
|
||||||
selection_proof: Signature::new(message.as_bytes(), secret_key),
|
selection_proof,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ pub mod indexed_attestation;
|
|||||||
pub mod pending_attestation;
|
pub mod pending_attestation;
|
||||||
pub mod proposer_slashing;
|
pub mod proposer_slashing;
|
||||||
pub mod relative_epoch;
|
pub mod relative_epoch;
|
||||||
|
pub mod selection_proof;
|
||||||
pub mod signed_aggregate_and_proof;
|
pub mod signed_aggregate_and_proof;
|
||||||
pub mod signed_beacon_block;
|
pub mod signed_beacon_block;
|
||||||
pub mod signed_beacon_block_header;
|
pub mod signed_beacon_block_header;
|
||||||
@ -72,6 +73,7 @@ pub use crate::indexed_attestation::IndexedAttestation;
|
|||||||
pub use crate::pending_attestation::PendingAttestation;
|
pub use crate::pending_attestation::PendingAttestation;
|
||||||
pub use crate::proposer_slashing::ProposerSlashing;
|
pub use crate::proposer_slashing::ProposerSlashing;
|
||||||
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||||
|
pub use crate::selection_proof::SelectionProof;
|
||||||
pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
|
pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof;
|
||||||
pub use crate::signed_beacon_block::SignedBeaconBlock;
|
pub use crate::signed_beacon_block::SignedBeaconBlock;
|
||||||
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader;
|
||||||
|
42
eth2/types/src/selection_proof.rs
Normal file
42
eth2/types/src/selection_proof.rs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
use crate::{ChainSpec, Domain, EthSpec, Fork, SecretKey, Signature, SignedRoot, Slot};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use tree_hash::TreeHash;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
pub struct SelectionProof(Signature);
|
||||||
|
|
||||||
|
impl SelectionProof {
|
||||||
|
pub fn new<T: EthSpec>(
|
||||||
|
slot: Slot,
|
||||||
|
secret_key: &SecretKey,
|
||||||
|
fork: &Fork,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> Self {
|
||||||
|
let domain = spec.get_domain(
|
||||||
|
slot.epoch(T::slots_per_epoch()),
|
||||||
|
Domain::SelectionProof,
|
||||||
|
fork,
|
||||||
|
);
|
||||||
|
let message = slot.signing_root(domain);
|
||||||
|
|
||||||
|
Self(Signature::new(message.as_bytes(), secret_key))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_aggregator(&self, modulo: u64) -> bool {
|
||||||
|
let signature_hash = self.0.tree_hash_root();
|
||||||
|
let signature_hash_int = u64::from_le_bytes(
|
||||||
|
signature_hash[0..8]
|
||||||
|
.as_ref()
|
||||||
|
.try_into()
|
||||||
|
.expect("first 8 bytes of signature should always convert to fixed array"),
|
||||||
|
);
|
||||||
|
|
||||||
|
signature_hash_int % modulo == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<Signature> for SelectionProof {
|
||||||
|
fn into(self) -> Signature {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ use eth2_hashing::hash;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use types::{ChainSpec, CommitteeIndex, Domain, Epoch, Fork, SignedRoot, Slot};
|
use types::{CommitteeIndex, Epoch, Slot};
|
||||||
|
|
||||||
/// A Validator duty with the validator public key represented a `PublicKeyBytes`.
|
/// A Validator duty with the validator public key represented a `PublicKeyBytes`.
|
||||||
pub type ValidatorDutyBytes = ValidatorDutyBase<PublicKeyBytes>;
|
pub type ValidatorDutyBytes = ValidatorDutyBase<PublicKeyBytes>;
|
||||||
@ -64,45 +64,9 @@ pub struct ValidatorSubscription {
|
|||||||
/// The index of the committee within `slot` of which the validator is a member. Used by the
|
/// The index of the committee within `slot` of which the validator is a member. Used by the
|
||||||
/// beacon node to quickly evaluate the associated `SubnetId`.
|
/// beacon node to quickly evaluate the associated `SubnetId`.
|
||||||
pub attestation_committee_index: CommitteeIndex,
|
pub attestation_committee_index: CommitteeIndex,
|
||||||
/// The slot the validator is signing.
|
/// The slot in which to subscribe.
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
/// The signature of the slot by the validator.
|
/// If true, the validator is an aggregator and the beacon node should aggregate attestations
|
||||||
pub slot_signature: Signature,
|
/// for this slot.
|
||||||
}
|
pub is_aggregator: bool,
|
||||||
|
|
||||||
impl ValidatorSubscription {
|
|
||||||
pub fn new(
|
|
||||||
validator_index: u64,
|
|
||||||
attestation_committee_index: CommitteeIndex,
|
|
||||||
slot: Slot,
|
|
||||||
slot_signature: Signature,
|
|
||||||
) -> Self {
|
|
||||||
ValidatorSubscription {
|
|
||||||
validator_index,
|
|
||||||
attestation_committee_index,
|
|
||||||
slot,
|
|
||||||
slot_signature,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verifies the subscription signature.
|
|
||||||
pub fn verify(
|
|
||||||
&self,
|
|
||||||
pubkey: &PublicKey,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
fork: &Fork,
|
|
||||||
slots_per_epoch: u64,
|
|
||||||
) -> bool {
|
|
||||||
let domain = spec.get_domain(
|
|
||||||
self.slot.epoch(slots_per_epoch),
|
|
||||||
Domain::SelectionProof,
|
|
||||||
&fork,
|
|
||||||
);
|
|
||||||
let message = self.slot.signing_root(domain);
|
|
||||||
if self.slot_signature.verify(message.as_bytes(), pubkey) {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -256,48 +256,34 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
|
|||||||
/// slot allowing the beacon node to connect to the required subnet and determine
|
/// slot allowing the beacon node to connect to the required subnet and determine
|
||||||
/// if attestations need to be aggregated.
|
/// if attestations need to be aggregated.
|
||||||
fn send_subscriptions(&self, duties: Vec<DutyAndState>) -> impl Future<Item = (), Error = ()> {
|
fn send_subscriptions(&self, duties: Vec<DutyAndState>) -> impl Future<Item = (), Error = ()> {
|
||||||
let mut validator_subscriptions = Vec::new();
|
|
||||||
let mut successful_duties = Vec::new();
|
|
||||||
|
|
||||||
let service_1 = self.clone();
|
let service_1 = self.clone();
|
||||||
let duties_no = duties.len();
|
let num_duties = duties.len();
|
||||||
|
|
||||||
let log_1 = self.context.log.clone();
|
let log_1 = self.context.log.clone();
|
||||||
let log_2 = self.context.log.clone();
|
let log_2 = self.context.log.clone();
|
||||||
|
|
||||||
// builds a list of subscriptions
|
let (validator_subscriptions, successful_duties): (Vec<_>, Vec<_>) = duties
|
||||||
for duty in duties {
|
.into_iter()
|
||||||
if let Some((slot, attestation_committee_index, _, validator_index)) =
|
.filter_map(|duty| {
|
||||||
duty.attestation_duties()
|
let (slot, attestation_committee_index, _, validator_index) =
|
||||||
{
|
duty.attestation_duties()?;
|
||||||
if let Some(slot_signature) = self
|
let selection_proof = self
|
||||||
.validator_store
|
.validator_store
|
||||||
.sign_slot(duty.validator_pubkey(), slot)
|
.produce_selection_proof(duty.validator_pubkey(), slot)?;
|
||||||
{
|
let modulo = duty.duty.aggregator_modulo?;
|
||||||
let is_aggregator_proof = if duty.is_aggregator() {
|
|
||||||
Some(slot_signature.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let subscription = ValidatorSubscription::new(
|
let subscription = ValidatorSubscription {
|
||||||
validator_index,
|
validator_index,
|
||||||
attestation_committee_index,
|
attestation_committee_index,
|
||||||
slot,
|
slot,
|
||||||
slot_signature,
|
is_aggregator: selection_proof.is_aggregator(modulo),
|
||||||
);
|
};
|
||||||
validator_subscriptions.push(subscription);
|
|
||||||
|
|
||||||
// add successful duties to the list, along with whether they are aggregation
|
Some((subscription, (duty, selection_proof)))
|
||||||
// duties or not
|
})
|
||||||
successful_duties.push((duty, is_aggregator_proof));
|
.unzip();
|
||||||
}
|
|
||||||
} else {
|
|
||||||
crit!(log_2, "Validator duty doesn't have required fields");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let failed_duties = duties_no - successful_duties.len();
|
let num_failed_duties = num_duties - successful_duties.len();
|
||||||
|
|
||||||
self.beacon_node
|
self.beacon_node
|
||||||
.http
|
.http
|
||||||
@ -308,8 +294,8 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
|
|||||||
PublishStatus::Valid => info!(
|
PublishStatus::Valid => info!(
|
||||||
log_1,
|
log_1,
|
||||||
"Successfully subscribed validators";
|
"Successfully subscribed validators";
|
||||||
"validators" => duties_no,
|
"validators" => num_duties,
|
||||||
"failed_validators" => failed_duties,
|
"failed_validators" => num_failed_duties,
|
||||||
),
|
),
|
||||||
PublishStatus::Invalid(msg) => crit!(
|
PublishStatus::Invalid(msg) => crit!(
|
||||||
log_1,
|
log_1,
|
||||||
@ -321,10 +307,10 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(move |_| {
|
.and_then(move |_| {
|
||||||
for (duty, is_aggregator_proof) in successful_duties {
|
for (duty, selection_proof) in successful_duties {
|
||||||
service_1
|
service_1
|
||||||
.duties_service
|
.duties_service
|
||||||
.subscribe_duty(&duty.duty, is_aggregator_proof);
|
.subscribe_duty(&duty.duty, selection_proof);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::validator_store::ValidatorStore;
|
use crate::validator_store::ValidatorStore;
|
||||||
use bls::Signature;
|
|
||||||
use environment::RuntimeContext;
|
use environment::RuntimeContext;
|
||||||
use exit_future::Signal;
|
use exit_future::Signal;
|
||||||
use futures::{future, Future, IntoFuture, Stream};
|
use futures::{future, Future, IntoFuture, Stream};
|
||||||
@ -14,7 +13,7 @@ use std::ops::Deref;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use tokio::timer::Interval;
|
use tokio::timer::Interval;
|
||||||
use types::{ChainSpec, CommitteeIndex, Epoch, EthSpec, PublicKey, Slot};
|
use types::{ChainSpec, CommitteeIndex, Epoch, EthSpec, PublicKey, SelectionProof, Slot};
|
||||||
|
|
||||||
/// Delay this period of time after the slot starts. This allows the node to process the new slot.
|
/// Delay this period of time after the slot starts. This allows the node to process the new slot.
|
||||||
const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100);
|
const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100);
|
||||||
@ -28,11 +27,9 @@ type BaseHashMap = HashMap<PublicKey, HashMap<Epoch, DutyAndState>>;
|
|||||||
pub enum DutyState {
|
pub enum DutyState {
|
||||||
/// This duty has not been subscribed to the beacon node.
|
/// This duty has not been subscribed to the beacon node.
|
||||||
NotSubscribed,
|
NotSubscribed,
|
||||||
/// The duty has been subscribed to the beacon node.
|
|
||||||
Subscribed,
|
|
||||||
/// The duty has been subscribed and the validator is an aggregator for this duty. The
|
/// The duty has been subscribed and the validator is an aggregator for this duty. The
|
||||||
/// selection proof is provided to construct the `AggregateAndProof` struct.
|
/// selection proof is provided to construct the `AggregateAndProof` struct.
|
||||||
SubscribedAggregator(Signature),
|
SubscribedAggregator(SelectionProof),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -49,13 +46,12 @@ impl DutyAndState {
|
|||||||
pub fn is_aggregator(&self) -> bool {
|
pub fn is_aggregator(&self) -> bool {
|
||||||
match self.state {
|
match self.state {
|
||||||
DutyState::NotSubscribed => false,
|
DutyState::NotSubscribed => false,
|
||||||
DutyState::Subscribed => false,
|
|
||||||
DutyState::SubscribedAggregator(_) => true,
|
DutyState::SubscribedAggregator(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the selection proof if the duty is an aggregation duty.
|
/// Returns the selection proof if the duty is an aggregation duty.
|
||||||
pub fn selection_proof(&self) -> Option<Signature> {
|
pub fn selection_proof(&self) -> Option<SelectionProof> {
|
||||||
match &self.state {
|
match &self.state {
|
||||||
DutyState::SubscribedAggregator(proof) => Some(proof.clone()),
|
DutyState::SubscribedAggregator(proof) => Some(proof.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -66,7 +62,6 @@ impl DutyAndState {
|
|||||||
pub fn is_subscribed(&self) -> bool {
|
pub fn is_subscribed(&self) -> bool {
|
||||||
match self.state {
|
match self.state {
|
||||||
DutyState::NotSubscribed => false,
|
DutyState::NotSubscribed => false,
|
||||||
DutyState::Subscribed => true,
|
|
||||||
DutyState::SubscribedAggregator(_) => true,
|
DutyState::SubscribedAggregator(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -425,14 +420,14 @@ impl<T: SlotClock + 'static, E: EthSpec> DutiesService<T, E> {
|
|||||||
/// Marks the duty as being subscribed to the beacon node.
|
/// Marks the duty as being subscribed to the beacon node.
|
||||||
///
|
///
|
||||||
/// If the duty is to be marked as an aggregator duty, a selection proof is also provided.
|
/// If the duty is to be marked as an aggregator duty, a selection proof is also provided.
|
||||||
pub fn subscribe_duty(&self, duty: &ValidatorDuty, aggregator_proof: Option<Signature>) {
|
pub fn subscribe_duty(&self, duty: &ValidatorDuty, proof: SelectionProof) {
|
||||||
let state = match aggregator_proof {
|
|
||||||
Some(proof) => DutyState::SubscribedAggregator(proof),
|
|
||||||
None => DutyState::Subscribed,
|
|
||||||
};
|
|
||||||
if let Some(slot) = duty.attestation_slot {
|
if let Some(slot) = duty.attestation_slot {
|
||||||
self.store
|
self.store.set_duty_state(
|
||||||
.set_duty_state(&duty.validator_pubkey, slot, state, E::slots_per_epoch())
|
&duty.validator_pubkey,
|
||||||
|
slot,
|
||||||
|
DutyState::SubscribedAggregator(proof),
|
||||||
|
E::slots_per_epoch(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ use std::path::PathBuf;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use types::{
|
use types::{
|
||||||
Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, PublicKey, Signature,
|
Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, PublicKey, SelectionProof,
|
||||||
SignedAggregateAndProof, SignedBeaconBlock, SignedRoot, Slot,
|
Signature, SignedAggregateAndProof, SignedBeaconBlock, SignedRoot, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -221,22 +221,21 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signs a slot for a given validator.
|
/// Produces a `SelectionProof` for the `slot`, signed by with corresponding secret key to
|
||||||
///
|
/// `validator_pubkey`.
|
||||||
/// This is used to subscribe a validator to a beacon node and is used to determine if the
|
pub fn produce_selection_proof(
|
||||||
/// validator is to aggregate attestations for this slot.
|
&self,
|
||||||
pub fn sign_slot(&self, validator_pubkey: &PublicKey, slot: Slot) -> Option<Signature> {
|
validator_pubkey: &PublicKey,
|
||||||
|
slot: Slot,
|
||||||
|
) -> Option<SelectionProof> {
|
||||||
let validators = self.validators.read();
|
let validators = self.validators.read();
|
||||||
let voting_keypair = validators.get(validator_pubkey)?.voting_keypair.as_ref()?;
|
let voting_keypair = validators.get(validator_pubkey)?.voting_keypair.as_ref()?;
|
||||||
|
|
||||||
let domain = self.spec.get_domain(
|
Some(SelectionProof::new::<E>(
|
||||||
slot.epoch(E::slots_per_epoch()),
|
slot,
|
||||||
Domain::SelectionProof,
|
&voting_keypair.sk,
|
||||||
&self.fork()?,
|
&self.fork()?,
|
||||||
);
|
&self.spec,
|
||||||
|
))
|
||||||
let message = slot.signing_root(domain);
|
|
||||||
|
|
||||||
Some(Signature::new(message.as_bytes(), &voting_keypair.sk))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user