Add doc comments for validator service.
This commit is contained in:
parent
4fd5424fca
commit
14dfc3223a
@ -7,6 +7,10 @@ use ssz::{ssz_encode, Decodable};
|
|||||||
use types::{BeaconBlock, BeaconBlockBody, Hash256, Signature};
|
use types::{BeaconBlock, BeaconBlockBody, Hash256, Signature};
|
||||||
|
|
||||||
impl BeaconNode for BeaconBlockServiceClient {
|
impl BeaconNode for BeaconBlockServiceClient {
|
||||||
|
/// Request a Beacon Node (BN) to produce a new block at the supplied slot.
|
||||||
|
///
|
||||||
|
/// Returns `None` if it is not possible to produce at the supplied slot. For example, if the
|
||||||
|
/// BN is unable to find a parent block.
|
||||||
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError> {
|
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError> {
|
||||||
let mut req = ProduceBeaconBlockRequest::new();
|
let mut req = ProduceBeaconBlockRequest::new();
|
||||||
req.set_slot(slot);
|
req.set_slot(slot);
|
||||||
@ -42,6 +46,10 @@ impl BeaconNode for BeaconBlockServiceClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request a Beacon Node (BN) to publish a block.
|
||||||
|
///
|
||||||
|
/// Generally, this will be called after a `produce_beacon_block` call with a block that has
|
||||||
|
/// been completed (signed) by the validator client.
|
||||||
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError> {
|
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError> {
|
||||||
let mut req = PublishBeaconBlockRequest::new();
|
let mut req = PublishBeaconBlockRequest::new();
|
||||||
|
|
||||||
|
@ -15,11 +15,17 @@ pub use self::service::BlockProducerService;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum PollOutcome {
|
pub enum PollOutcome {
|
||||||
|
/// A new block was produced.
|
||||||
BlockProduced(u64),
|
BlockProduced(u64),
|
||||||
|
/// A block was not produced as it would have been slashable.
|
||||||
SlashableBlockNotProduced(u64),
|
SlashableBlockNotProduced(u64),
|
||||||
|
/// The validator duties did not require a block to be produced.
|
||||||
BlockProductionNotRequired(u64),
|
BlockProductionNotRequired(u64),
|
||||||
|
/// The duties for the present epoch were not found.
|
||||||
ProducerDutiesUnknown(u64),
|
ProducerDutiesUnknown(u64),
|
||||||
|
/// The slot has already been processed, execution was skipped.
|
||||||
SlotAlreadyProcessed(u64),
|
SlotAlreadyProcessed(u64),
|
||||||
|
/// The Beacon Node was unable to produce a block at that slot.
|
||||||
BeaconNodeUnableToProduceBlock(u64),
|
BeaconNodeUnableToProduceBlock(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +39,12 @@ pub enum Error {
|
|||||||
BeaconNodeError(BeaconNodeError),
|
BeaconNodeError(BeaconNodeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A polling state machine which performs block production duties, based upon some epoch duties
|
||||||
|
/// (`EpochDutiesMap`) and a concept of time (`SlotClock`).
|
||||||
|
///
|
||||||
|
/// Ensures that messages are not slashable.
|
||||||
|
///
|
||||||
|
/// Relies upon an external service to keep the `EpochDutiesMap` updated.
|
||||||
pub struct BlockProducer<T: SlotClock, U: BeaconNode> {
|
pub struct BlockProducer<T: SlotClock, U: BeaconNode> {
|
||||||
pub last_processed_slot: u64,
|
pub last_processed_slot: u64,
|
||||||
spec: Arc<ChainSpec>,
|
spec: Arc<ChainSpec>,
|
||||||
@ -42,6 +54,7 @@ pub struct BlockProducer<T: SlotClock, U: BeaconNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SlotClock, U: BeaconNode> BlockProducer<T, U> {
|
impl<T: SlotClock, U: BeaconNode> BlockProducer<T, U> {
|
||||||
|
/// Returns a new instance where `last_processed_slot == 0`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
spec: Arc<ChainSpec>,
|
spec: Arc<ChainSpec>,
|
||||||
epoch_map: Arc<RwLock<EpochDutiesMap>>,
|
epoch_map: Arc<RwLock<EpochDutiesMap>>,
|
||||||
@ -97,6 +110,16 @@ impl<T: SlotClock, U: BeaconNode> BlockProducer<T, U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Produce a block at some slot.
|
||||||
|
///
|
||||||
|
/// Assumes that a block is required at this slot (does not check the duties).
|
||||||
|
///
|
||||||
|
/// Ensures the message is not slashable.
|
||||||
|
///
|
||||||
|
/// !!! UNSAFE !!!
|
||||||
|
///
|
||||||
|
/// The slash-protection code is not yet implemented. There is zero protection against
|
||||||
|
/// slashing.
|
||||||
fn produce_block(&mut self, slot: u64) -> Result<PollOutcome, Error> {
|
fn produce_block(&mut self, slot: u64) -> Result<PollOutcome, Error> {
|
||||||
if let Some(block) = self.beacon_node.produce_beacon_block(slot)? {
|
if let Some(block) = self.beacon_node.produce_beacon_block(slot)? {
|
||||||
if self.safe_to_produce(&block) {
|
if self.safe_to_produce(&block) {
|
||||||
@ -111,19 +134,36 @@ impl<T: SlotClock, U: BeaconNode> BlockProducer<T, U> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes a block, returning that block signed by the validators private key.
|
||||||
|
///
|
||||||
|
/// Important: this function will not check to ensure the block is not slashable. This must be
|
||||||
|
/// done upstream.
|
||||||
fn sign_block(&mut self, block: BeaconBlock) -> BeaconBlock {
|
fn sign_block(&mut self, block: BeaconBlock) -> BeaconBlock {
|
||||||
// TODO: sign the block
|
// TODO: sign the block
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
self.store_produce(&block);
|
self.store_produce(&block);
|
||||||
block
|
block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if signing a block is safe (non-slashable).
|
||||||
|
///
|
||||||
|
/// !!! UNSAFE !!!
|
||||||
|
///
|
||||||
|
/// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
|
||||||
fn safe_to_produce(&self, _block: &BeaconBlock) -> bool {
|
fn safe_to_produce(&self, _block: &BeaconBlock) -> bool {
|
||||||
// TODO: ensure the producer doesn't produce slashable blocks.
|
// TODO: ensure the producer doesn't produce slashable blocks.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Record that a block was produced so that slashable votes may not be made in the future.
|
||||||
|
///
|
||||||
|
/// !!! UNSAFE !!!
|
||||||
|
///
|
||||||
|
/// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
|
||||||
fn store_produce(&mut self, _block: &BeaconBlock) {
|
fn store_produce(&mut self, _block: &BeaconBlock) {
|
||||||
// TODO: record this block production to prevent future slashings.
|
// TODO: record this block production to prevent future slashings.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +182,7 @@ mod tests {
|
|||||||
use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
use types::test_utils::{SeedableRng, TestRandom, XorShiftRng};
|
||||||
|
|
||||||
// TODO: implement more thorough testing.
|
// TODO: implement more thorough testing.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
//
|
//
|
||||||
// These tests should serve as a good example for future tests.
|
// These tests should serve as a good example for future tests.
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ pub struct BlockProducerService<T: SlotClock, U: BeaconNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SlotClock, U: BeaconNode> BlockProducerService<T, U> {
|
impl<T: SlotClock, U: BeaconNode> BlockProducerService<T, U> {
|
||||||
|
/// Run a loop which polls the block producer each `poll_interval_millis` millseconds.
|
||||||
|
///
|
||||||
|
/// Logs the results of the polls.
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
match self.block_producer.poll() {
|
match self.block_producer.poll() {
|
||||||
|
@ -5,6 +5,7 @@ use types::BeaconBlock;
|
|||||||
type ProduceResult = Result<Option<BeaconBlock>, BeaconNodeError>;
|
type ProduceResult = Result<Option<BeaconBlock>, BeaconNodeError>;
|
||||||
type PublishResult = Result<bool, BeaconNodeError>;
|
type PublishResult = Result<bool, BeaconNodeError>;
|
||||||
|
|
||||||
|
/// A test-only struct used to simulate a Beacon Node.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TestBeaconNode {
|
pub struct TestBeaconNode {
|
||||||
pub produce_input: RwLock<Option<u64>>,
|
pub produce_input: RwLock<Option<u64>>,
|
||||||
@ -14,16 +15,19 @@ pub struct TestBeaconNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TestBeaconNode {
|
impl TestBeaconNode {
|
||||||
|
/// Set the result to be returned when `produce_beacon_block` is called.
|
||||||
pub fn set_next_produce_result(&self, result: ProduceResult) {
|
pub fn set_next_produce_result(&self, result: ProduceResult) {
|
||||||
*self.produce_result.write().unwrap() = Some(result);
|
*self.produce_result.write().unwrap() = Some(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the result to be returned when `publish_beacon_block` is called.
|
||||||
pub fn set_next_publish_result(&self, result: PublishResult) {
|
pub fn set_next_publish_result(&self, result: PublishResult) {
|
||||||
*self.publish_result.write().unwrap() = Some(result);
|
*self.publish_result.write().unwrap() = Some(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BeaconNode for TestBeaconNode {
|
impl BeaconNode for TestBeaconNode {
|
||||||
|
/// Returns the value specified by the `set_next_produce_result`.
|
||||||
fn produce_beacon_block(&self, slot: u64) -> ProduceResult {
|
fn produce_beacon_block(&self, slot: u64) -> ProduceResult {
|
||||||
*self.produce_input.write().unwrap() = Some(slot);
|
*self.produce_input.write().unwrap() = Some(slot);
|
||||||
match *self.produce_result.read().unwrap() {
|
match *self.produce_result.read().unwrap() {
|
||||||
@ -32,6 +36,7 @@ impl BeaconNode for TestBeaconNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the value specified by the `set_next_publish_result`.
|
||||||
fn publish_beacon_block(&self, block: BeaconBlock) -> PublishResult {
|
fn publish_beacon_block(&self, block: BeaconBlock) -> PublishResult {
|
||||||
*self.publish_input.write().unwrap() = Some(block);
|
*self.publish_input.write().unwrap() = Some(block);
|
||||||
match *self.publish_result.read().unwrap() {
|
match *self.publish_result.read().unwrap() {
|
||||||
|
@ -6,7 +6,14 @@ pub enum BeaconNodeError {
|
|||||||
DecodeFailure,
|
DecodeFailure,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines the methods required to produce and publish blocks on a Beacon Node.
|
||||||
pub trait BeaconNode: Send + Sync {
|
pub trait BeaconNode: Send + Sync {
|
||||||
|
/// Request that the node produces a block.
|
||||||
|
///
|
||||||
|
/// Returns Ok(None) if the Beacon Node is unable to produce at the given slot.
|
||||||
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError>;
|
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError>;
|
||||||
|
/// Request that the node publishes a block.
|
||||||
|
///
|
||||||
|
/// Returns `true` if the publish was sucessful.
|
||||||
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError>;
|
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError>;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ pub struct ClientConfig {
|
|||||||
const DEFAULT_LIGHTHOUSE_DIR: &str = ".lighthouse-validators";
|
const DEFAULT_LIGHTHOUSE_DIR: &str = ".lighthouse-validators";
|
||||||
|
|
||||||
impl ClientConfig {
|
impl ClientConfig {
|
||||||
/// Build a new lighthouse configuration from defaults.
|
/// Build a new configuration from defaults.
|
||||||
pub fn default() -> Self {
|
pub fn default() -> Self {
|
||||||
let data_dir = {
|
let data_dir = {
|
||||||
let home = dirs::home_dir().expect("Unable to determine home dir.");
|
let home = dirs::home_dir().expect("Unable to determine home dir.");
|
||||||
|
@ -6,6 +6,12 @@ use ssz::ssz_encode;
|
|||||||
use types::PublicKey;
|
use types::PublicKey;
|
||||||
|
|
||||||
impl BeaconNode for ValidatorServiceClient {
|
impl BeaconNode for ValidatorServiceClient {
|
||||||
|
/// Request the shuffling from the Beacon Node (BN).
|
||||||
|
///
|
||||||
|
/// As this function takes a `PublicKey`, it will first attempt to resolve the public key into
|
||||||
|
/// a validator index, then call the BN for production/attestation duties.
|
||||||
|
///
|
||||||
|
/// Note: presently only block production information is returned.
|
||||||
fn request_shuffling(
|
fn request_shuffling(
|
||||||
&self,
|
&self,
|
||||||
epoch: u64,
|
epoch: u64,
|
||||||
|
@ -13,6 +13,11 @@ use std::sync::{Arc, RwLock};
|
|||||||
|
|
||||||
pub use self::service::DutiesManagerService;
|
pub use self::service::DutiesManagerService;
|
||||||
|
|
||||||
|
/// The information required for a validator to propose and attest during some epoch.
|
||||||
|
///
|
||||||
|
/// Generally obtained from a Beacon Node, this information contains the validators canonical index
|
||||||
|
/// (thier sequence in the global validator induction process) and the "shuffling" for that index
|
||||||
|
/// for some epoch.
|
||||||
#[derive(Debug, PartialEq, Clone, Copy, Default)]
|
#[derive(Debug, PartialEq, Clone, Copy, Default)]
|
||||||
pub struct EpochDuties {
|
pub struct EpochDuties {
|
||||||
pub validator_index: u64,
|
pub validator_index: u64,
|
||||||
@ -21,6 +26,8 @@ pub struct EpochDuties {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EpochDuties {
|
impl EpochDuties {
|
||||||
|
/// Returns `true` if the supplied `slot` is a slot in which the validator should produce a
|
||||||
|
/// block.
|
||||||
pub fn is_block_production_slot(&self, slot: u64) -> bool {
|
pub fn is_block_production_slot(&self, slot: u64) -> bool {
|
||||||
match self.block_production_slot {
|
match self.block_production_slot {
|
||||||
Some(s) if s == slot => true,
|
Some(s) if s == slot => true,
|
||||||
@ -29,13 +36,20 @@ impl EpochDuties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Maps an `epoch` to some `EpochDuties` for a single validator.
|
||||||
pub type EpochDutiesMap = HashMap<u64, EpochDuties>;
|
pub type EpochDutiesMap = HashMap<u64, EpochDuties>;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum PollOutcome {
|
pub enum PollOutcome {
|
||||||
|
/// The `EpochDuties` were not updated during this poll.
|
||||||
NoChange(u64),
|
NoChange(u64),
|
||||||
|
/// The `EpochDuties` for the `epoch` were previously unknown, but obtained in the poll.
|
||||||
NewDuties(u64, EpochDuties),
|
NewDuties(u64, EpochDuties),
|
||||||
|
/// New `EpochDuties` were obtained, different to those which were previously known. This is
|
||||||
|
/// likely to be the result of chain re-organisation.
|
||||||
DutiesChanged(u64, EpochDuties),
|
DutiesChanged(u64, EpochDuties),
|
||||||
|
/// The Beacon Node was unable to return the duties as the validator is unknown, or the
|
||||||
|
/// shuffling for the epoch is unknown.
|
||||||
UnknownValidatorOrEpoch(u64),
|
UnknownValidatorOrEpoch(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,8 +63,13 @@ pub enum Error {
|
|||||||
BeaconNodeError(BeaconNodeError),
|
BeaconNodeError(BeaconNodeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A polling state machine which ensures the latest `EpochDuties` are obtained from the Beacon
|
||||||
|
/// Node.
|
||||||
|
///
|
||||||
|
/// There is a single `DutiesManager` per validator instance.
|
||||||
pub struct DutiesManager<T: SlotClock, U: BeaconNode> {
|
pub struct DutiesManager<T: SlotClock, U: BeaconNode> {
|
||||||
pub duties_map: Arc<RwLock<EpochDutiesMap>>,
|
pub duties_map: Arc<RwLock<EpochDutiesMap>>,
|
||||||
|
/// The validator's public key.
|
||||||
pub pubkey: PublicKey,
|
pub pubkey: PublicKey,
|
||||||
pub spec: Arc<ChainSpec>,
|
pub spec: Arc<ChainSpec>,
|
||||||
pub slot_clock: Arc<RwLock<T>>,
|
pub slot_clock: Arc<RwLock<T>>,
|
||||||
@ -58,6 +77,10 @@ pub struct DutiesManager<T: SlotClock, U: BeaconNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SlotClock, U: BeaconNode> DutiesManager<T, U> {
|
impl<T: SlotClock, U: BeaconNode> DutiesManager<T, U> {
|
||||||
|
/// Poll the Beacon Node for `EpochDuties`.
|
||||||
|
///
|
||||||
|
/// The present `epoch` will be learned from the supplied `SlotClock`. In production this will
|
||||||
|
/// be a wall-clock (e.g., system time, remote server time, etc.).
|
||||||
pub fn poll(&self) -> Result<PollOutcome, Error> {
|
pub fn poll(&self) -> Result<PollOutcome, Error> {
|
||||||
let slot = self
|
let slot = self
|
||||||
.slot_clock
|
.slot_clock
|
||||||
@ -109,6 +132,7 @@ mod tests {
|
|||||||
use slot_clock::TestingSlotClock;
|
use slot_clock::TestingSlotClock;
|
||||||
|
|
||||||
// TODO: implement more thorough testing.
|
// TODO: implement more thorough testing.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
//
|
//
|
||||||
// These tests should serve as a good example for future tests.
|
// These tests should serve as a good example for future tests.
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@ pub struct DutiesManagerService<T: SlotClock, U: BeaconNode> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SlotClock, U: BeaconNode> DutiesManagerService<T, U> {
|
impl<T: SlotClock, U: BeaconNode> DutiesManagerService<T, U> {
|
||||||
|
/// Run a loop which polls the manager each `poll_interval_millis` milliseconds.
|
||||||
|
///
|
||||||
|
/// Logs the results of the polls.
|
||||||
pub fn run(&mut self) {
|
pub fn run(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
match self.manager.poll() {
|
match self.manager.poll() {
|
||||||
|
@ -5,6 +5,7 @@ use std::sync::RwLock;
|
|||||||
|
|
||||||
type ShufflingResult = Result<Option<EpochDuties>, BeaconNodeError>;
|
type ShufflingResult = Result<Option<EpochDuties>, BeaconNodeError>;
|
||||||
|
|
||||||
|
/// A test-only struct used to simulate a Beacon Node.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TestBeaconNode {
|
pub struct TestBeaconNode {
|
||||||
pub request_shuffling_input: RwLock<Option<(u64, PublicKey)>>,
|
pub request_shuffling_input: RwLock<Option<(u64, PublicKey)>>,
|
||||||
@ -12,12 +13,14 @@ pub struct TestBeaconNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TestBeaconNode {
|
impl TestBeaconNode {
|
||||||
|
/// Set the result to be returned when `request_shuffling` is called.
|
||||||
pub fn set_next_shuffling_result(&self, result: ShufflingResult) {
|
pub fn set_next_shuffling_result(&self, result: ShufflingResult) {
|
||||||
*self.request_shuffling_result.write().unwrap() = Some(result);
|
*self.request_shuffling_result.write().unwrap() = Some(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BeaconNode for TestBeaconNode {
|
impl BeaconNode for TestBeaconNode {
|
||||||
|
/// Returns the value specified by the `set_next_shuffling_result`.
|
||||||
fn request_shuffling(&self, epoch: u64, public_key: &PublicKey) -> ShufflingResult {
|
fn request_shuffling(&self, epoch: u64, public_key: &PublicKey) -> ShufflingResult {
|
||||||
*self.request_shuffling_input.write().unwrap() = Some((epoch, public_key.clone()));
|
*self.request_shuffling_input.write().unwrap() = Some((epoch, public_key.clone()));
|
||||||
match *self.request_shuffling_result.read().unwrap() {
|
match *self.request_shuffling_result.read().unwrap() {
|
||||||
|
@ -6,7 +6,11 @@ pub enum BeaconNodeError {
|
|||||||
RemoteFailure(String),
|
RemoteFailure(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines the methods required to obtain a validators shuffling from a Beacon Node.
|
||||||
pub trait BeaconNode: Send + Sync {
|
pub trait BeaconNode: Send + Sync {
|
||||||
|
/// Get the shuffling for the given epoch and public key.
|
||||||
|
///
|
||||||
|
/// Returns Ok(None) if the public key is unknown, or the shuffling for that epoch is unknown.
|
||||||
fn request_shuffling(
|
fn request_shuffling(
|
||||||
&self,
|
&self,
|
||||||
epoch: u64,
|
epoch: u64,
|
||||||
|
@ -83,6 +83,7 @@ fn main() {
|
|||||||
// Ethereum
|
// Ethereum
|
||||||
//
|
//
|
||||||
// TODO: Permit loading a custom spec from file.
|
// TODO: Permit loading a custom spec from file.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
let spec = Arc::new(ChainSpec::foundation());
|
let spec = Arc::new(ChainSpec::foundation());
|
||||||
|
|
||||||
// Clock for determining the present slot.
|
// Clock for determining the present slot.
|
||||||
@ -99,13 +100,16 @@ fn main() {
|
|||||||
/*
|
/*
|
||||||
* Start threads.
|
* Start threads.
|
||||||
*/
|
*/
|
||||||
let keypairs = vec![Keypair::random()];
|
|
||||||
let mut threads = vec![];
|
let mut threads = vec![];
|
||||||
|
// TODO: keypairs are randomly generated; they should be loaded from a file or generated.
|
||||||
|
// https://github.com/sigp/lighthouse/issues/160
|
||||||
|
let keypairs = vec![Keypair::random()];
|
||||||
|
|
||||||
for keypair in keypairs {
|
for keypair in keypairs {
|
||||||
info!(log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());
|
info!(log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());
|
||||||
let duties_map = Arc::new(RwLock::new(EpochDutiesMap::new()));
|
let duties_map = Arc::new(RwLock::new(EpochDutiesMap::new()));
|
||||||
|
|
||||||
|
// Spawn a new thread to maintain the validator's `EpochDuties`.
|
||||||
let duties_manager_thread = {
|
let duties_manager_thread = {
|
||||||
let spec = spec.clone();
|
let spec = spec.clone();
|
||||||
let duties_map = duties_map.clone();
|
let duties_map = duties_map.clone();
|
||||||
@ -131,6 +135,7 @@ fn main() {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Spawn a new thread to perform block production for the validator.
|
||||||
let producer_thread = {
|
let producer_thread = {
|
||||||
let spec = spec.clone();
|
let spec = spec.clone();
|
||||||
let duties_map = duties_map.clone();
|
let duties_map = duties_map.clone();
|
||||||
@ -152,6 +157,7 @@ fn main() {
|
|||||||
threads.push((duties_manager_thread, producer_thread));
|
threads.push((duties_manager_thread, producer_thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Naively wait for all the threads to complete.
|
||||||
for tuple in threads {
|
for tuple in threads {
|
||||||
let (manager, producer) = tuple;
|
let (manager, producer) = tuple;
|
||||||
let _ = producer.join();
|
let _ = producer.join();
|
||||||
|
Loading…
Reference in New Issue
Block a user