Add validator_node, restructure binaries, gRPC.

This is a massive commit which restructures the workspace, adds a very
basic, untested, validator client and some very basic, non-functioning
gRPC endpoints to the beacon-node.
This commit is contained in:
Paul Hauner committed 2019-01-14 12:55:55 +11:00
1 parent de3ea2a64b
commit 40cf650563
35 files changed
+1654 -73

No files matched your search

+4 -35
View File
@@ -1,36 +1,3 @@
[package]
name = "lighthouse"
version = "0.0.1"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
blake2-rfc = "0.2.18"
bls-aggregates = { git = "https://github.com/sigp/signature-schemes" }
bytes = ""
crypto-mac = "^0.6.2"
clap = "2.32.0"
db = { path = "lighthouse/db" }
dirs = "1.0.3"
futures = "0.1.23"
rand = "0.3"
rlp = { git = "https://github.com/paritytech/parity-common" }
slog = "^2.2.3"
slog-term = "^2.4.0"
slog-async = "^2.3.0"
tokio = "0.1"
[dependencies.pairing]
git = "https://github.com/mmaker/pairing"
branch = "feature/hashing"
[patch.crates-io]
ring = { git = "https://github.com/paritytech/ring" }
[[bin]]
path = "lighthouse/main.rs"
name = "lighthouse"
[workspace]
members = [
"beacon_chain/attestation_validation",
@@ -47,6 +14,8 @@ members = [
"beacon_chain/utils/vec_shuffle",
"beacon_chain/validator_induction",
"beacon_chain/validator_shuffling",
"lighthouse/beacon_chain",
"lighthouse/db",
"beacon_node",
"beacon_node/db",
"protos",
"validator_client",
]
@@ -6,7 +6,7 @@ edition = "2018"
[dependencies]
bls = { path = "../utils/bls" }
db = { path = "../../lighthouse/db" }
db = { path = "../../beacon_node/db" }
hashing = { path = "../utils/hashing" }
ssz = { path = "../utils/ssz" }
types = { path = "../types" }
+1 -1
View File
@@ -5,6 +5,6 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
db = { path = "../../lighthouse/db" }
db = { path = "../../beacon_node/db" }
ssz = { path = "../utils/ssz" }
types = { path = "../types" }
+2
View File
@@ -63,3 +63,5 @@ pub type AttesterMap = HashMap<(u64, u64), Vec<usize>>;
/// Maps a slot to a block proposer.
pub type ProposerMap = HashMap<u64, usize>;
pub use bls::{AggregatePublicKey, AggregateSignature, PublicKey, Signature};
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "beacon_node"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
protobuf = "2.0.2"
protos = { path = "../protos" }
clap = "2.32.0"
db = { path = "db" }
dirs = "1.0.3"
futures = "0.1.23"
slog = "^2.2.3"
slog-term = "^2.4.0"
slog-async = "^2.3.0"
tokio = "0.1"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,3 @@
extern crate dirs;
use std::fs;
use std::path::PathBuf;
+12 -17
View File
@@ -1,20 +1,14 @@
#[macro_use]
extern crate slog;
extern crate slog_async;
extern crate slog_term;
// extern crate ssz;
extern crate clap;
extern crate futures;
extern crate db;
mod config;
mod rpc;
use std::path::PathBuf;
use clap::{App, Arg};
use crate::config::LighthouseConfig;
use slog::Drain;
use crate::rpc::start_server;
use clap::{App, Arg};
use slog::{error, info, o, Drain};
fn main() {
let decorator = slog_term::TermDecorator::new().build();
@@ -32,13 +26,15 @@ fn main() {
.value_name("DIR")
.help("Data directory for keys and databases.")
.takes_value(true),
).arg(
)
.arg(
Arg::with_name("port")
.long("port")
.value_name("PORT")
.help("Network listen port for p2p connections.")
.takes_value(true),
).get_matches();
)
.get_matches();
let mut config = LighthouseConfig::default();
@@ -62,10 +58,9 @@ fn main() {
"data_dir" => &config.data_dir.to_str(),
"port" => &config.p2p_listen_port);
error!(
log,
"Lighthouse under development and does not provide a user demo."
);
let _server = start_server(log.clone());
info!(log, "Exiting.");
loop {}
// info!(log, "Exiting.");
}
+79
View File
@@ -0,0 +1,79 @@
use std::sync::Arc;
use futures::Future;
use grpcio::{Environment, RpcContext, Server, ServerBuilder, UnarySink};
use protos::services::{
BeaconBlock as BeaconBlockProto, ProduceBeaconBlockRequest, ProduceBeaconBlockResponse,
PublishBeaconBlockRequest, PublishBeaconBlockResponse,
};
use protos::services_grpc::{create_beacon_block_service, BeaconBlockService};
use slog::{info, Logger};
#[derive(Clone)]
struct BeaconBlockServiceInstance {
log: Logger,
}
impl BeaconBlockService for BeaconBlockServiceInstance {
/// Produce a `BeaconBlock` for signing by a validator.
fn produce_beacon_block(
&mut self,
ctx: RpcContext,
req: ProduceBeaconBlockRequest,
sink: UnarySink<ProduceBeaconBlockResponse>,
) {
println!("producing at slot {}", req.get_slot());
// TODO: build a legit block.
let mut block = BeaconBlockProto::new();
block.set_slot(req.get_slot());
block.set_block_root("cats".as_bytes().to_vec());
let mut resp = ProduceBeaconBlockResponse::new();
resp.set_block(block);
let f = sink
.success(resp)
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
ctx.spawn(f)
}
/// Accept some fully-formed `BeaconBlock`, process and publish it.
fn publish_beacon_block(
&mut self,
ctx: RpcContext,
req: PublishBeaconBlockRequest,
sink: UnarySink<PublishBeaconBlockResponse>,
) {
println!("publishing {:?}", req.get_block());
// TODO: actually process the block.
let mut resp = PublishBeaconBlockResponse::new();
resp.set_success(true);
let f = sink
.success(resp)
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
ctx.spawn(f)
}
}
pub fn start_server(log: Logger) -> Server {
let log_clone = log.clone();
let env = Arc::new(Environment::new(1));
let instance = BeaconBlockServiceInstance { log };
let service = create_beacon_block_service(instance);
let mut server = ServerBuilder::new(env)
.register_service(service)
.bind("127.0.0.1", 50_051)
.build()
.unwrap();
server.start();
for &(ref host, port) in server.bind_addrs() {
info!(log_clone, "gRPC listening on {}:{}", host, port);
}
server
}
-17
View File
@@ -1,17 +0,0 @@
[package]
name = "chain"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
bls = { path = "../../beacon_chain/utils/bls" }
db = { path = "../db" }
genesis = { path = "../../beacon_chain/genesis" }
naive_fork_choice = { path = "../../beacon_chain/naive_fork_choice" }
slot_clock = { path = "../../beacon_chain/utils/slot_clock" }
spec = { path = "../../beacon_chain/spec" }
ssz = { path = "../../beacon_chain/utils/ssz" }
types = { path = "../../beacon_chain/types" }
validator_induction = { path = "../../beacon_chain/validator_induction" }
validator_shuffling = { path = "../../beacon_chain/validator_shuffling" }
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "protos"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
futures = "0.1.16"
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
protobuf = "2.0.2"
[build-dependencies]
protoc-grpcio = "0.3.1"
+8
View File
@@ -0,0 +1,8 @@
extern crate protoc_grpcio;
fn main() {
let proto_root = "src/";
println!("cargo:rerun-if-changed={}", proto_root);
protoc_grpcio::compile_grpc_protos(&["services.proto"], &[proto_root], &proto_root)
.expect("Failed to compile gRPC definitions!");
}
+2
View File
@@ -0,0 +1,2 @@
pub mod services;
pub mod services_grpc;
+46
View File
@@ -0,0 +1,46 @@
// TODO: This setup requires that the BN (beacon node) holds the block in state
// during the interval between the `GenerateProposalRequest` and the
// `SubmitProposalRequest`.
//
// This is sub-optimal as if a validator client switches BN during this process
// the block will be lost.
//
// This "stateful" method is being used presently because it's easier and
// requires less maintainence as the `BeaconBlock` definition changes.
syntax = "proto3";
package ethereum.beacon.rpc.v1;
service BeaconBlockService {
rpc ProduceBeaconBlock(ProduceBeaconBlockRequest) returns (ProduceBeaconBlockResponse);
rpc PublishBeaconBlock(PublishBeaconBlockRequest) returns (PublishBeaconBlockResponse);
}
message BeaconBlock {
uint64 slot = 1;
bytes block_root = 2;
bytes randao_reveal = 3;
bytes signature = 4;
}
// Validator requests an unsigned proposal.
message ProduceBeaconBlockRequest {
uint64 slot = 1;
}
// Beacon node returns an unsigned proposal.
message ProduceBeaconBlockResponse {
BeaconBlock block = 1;
}
// Validator submits a signed proposal.
message PublishBeaconBlockRequest {
BeaconBlock block = 1;
}
// Beacon node indicates a sucessfully submitted proposal.
message PublishBeaconBlockResponse {
bool success = 1;
bytes msg = 2;
}
File diff suppressed because it is too large. Load diff
+99
View File
@@ -0,0 +1,99 @@
// This file is generated. Do not edit
// @generated
// https://github.com/Manishearth/rust-clippy/issues/702
#![allow(unknown_lints)]
#![allow(clippy)]
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(box_pointers)]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(trivial_casts)]
#![allow(unsafe_code)]
#![allow(unused_imports)]
#![allow(unused_results)]
const METHOD_BEACON_BLOCK_SERVICE_PRODUCE_BEACON_BLOCK: ::grpcio::Method<super::services::ProduceBeaconBlockRequest, super::services::ProduceBeaconBlockResponse> = ::grpcio::Method {
ty: ::grpcio::MethodType::Unary,
name: "/ethereum.beacon.rpc.v1.BeaconBlockService/ProduceBeaconBlock",
req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
};
const METHOD_BEACON_BLOCK_SERVICE_PUBLISH_BEACON_BLOCK: ::grpcio::Method<super::services::PublishBeaconBlockRequest, super::services::PublishBeaconBlockResponse> = ::grpcio::Method {
ty: ::grpcio::MethodType::Unary,
name: "/ethereum.beacon.rpc.v1.BeaconBlockService/PublishBeaconBlock",
req_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
resp_mar: ::grpcio::Marshaller { ser: ::grpcio::pb_ser, de: ::grpcio::pb_de },
};
#[derive(Clone)]
pub struct BeaconBlockServiceClient {
client: ::grpcio::Client,
}
impl BeaconBlockServiceClient {
pub fn new(channel: ::grpcio::Channel) -> Self {
BeaconBlockServiceClient {
client: ::grpcio::Client::new(channel),
}
}
pub fn produce_beacon_block_opt(&self, req: &super::services::ProduceBeaconBlockRequest, opt: ::grpcio::CallOption) -> ::grpcio::Result<super::services::ProduceBeaconBlockResponse> {
self.client.unary_call(&METHOD_BEACON_BLOCK_SERVICE_PRODUCE_BEACON_BLOCK, req, opt)
}
pub fn produce_beacon_block(&self, req: &super::services::ProduceBeaconBlockRequest) -> ::grpcio::Result<super::services::ProduceBeaconBlockResponse> {
self.produce_beacon_block_opt(req, ::grpcio::CallOption::default())
}
pub fn produce_beacon_block_async_opt(&self, req: &super::services::ProduceBeaconBlockRequest, opt: ::grpcio::CallOption) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::services::ProduceBeaconBlockResponse>> {
self.client.unary_call_async(&METHOD_BEACON_BLOCK_SERVICE_PRODUCE_BEACON_BLOCK, req, opt)
}
pub fn produce_beacon_block_async(&self, req: &super::services::ProduceBeaconBlockRequest) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::services::ProduceBeaconBlockResponse>> {
self.produce_beacon_block_async_opt(req, ::grpcio::CallOption::default())
}
pub fn publish_beacon_block_opt(&self, req: &super::services::PublishBeaconBlockRequest, opt: ::grpcio::CallOption) -> ::grpcio::Result<super::services::PublishBeaconBlockResponse> {
self.client.unary_call(&METHOD_BEACON_BLOCK_SERVICE_PUBLISH_BEACON_BLOCK, req, opt)
}
pub fn publish_beacon_block(&self, req: &super::services::PublishBeaconBlockRequest) -> ::grpcio::Result<super::services::PublishBeaconBlockResponse> {
self.publish_beacon_block_opt(req, ::grpcio::CallOption::default())
}
pub fn publish_beacon_block_async_opt(&self, req: &super::services::PublishBeaconBlockRequest, opt: ::grpcio::CallOption) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::services::PublishBeaconBlockResponse>> {
self.client.unary_call_async(&METHOD_BEACON_BLOCK_SERVICE_PUBLISH_BEACON_BLOCK, req, opt)
}
pub fn publish_beacon_block_async(&self, req: &super::services::PublishBeaconBlockRequest) -> ::grpcio::Result<::grpcio::ClientUnaryReceiver<super::services::PublishBeaconBlockResponse>> {
self.publish_beacon_block_async_opt(req, ::grpcio::CallOption::default())
}
pub fn spawn<F>(&self, f: F) where F: ::futures::Future<Item = (), Error = ()> + Send + 'static {
self.client.spawn(f)
}
}
pub trait BeaconBlockService {
fn produce_beacon_block(&mut self, ctx: ::grpcio::RpcContext, req: super::services::ProduceBeaconBlockRequest, sink: ::grpcio::UnarySink<super::services::ProduceBeaconBlockResponse>);
fn publish_beacon_block(&mut self, ctx: ::grpcio::RpcContext, req: super::services::PublishBeaconBlockRequest, sink: ::grpcio::UnarySink<super::services::PublishBeaconBlockResponse>);
}
pub fn create_beacon_block_service<S: BeaconBlockService + Send + Clone + 'static>(s: S) -> ::grpcio::Service {
let mut builder = ::grpcio::ServiceBuilder::new();
let mut instance = s.clone();
builder = builder.add_unary_handler(&METHOD_BEACON_BLOCK_SERVICE_PRODUCE_BEACON_BLOCK, move |ctx, req, resp| {
instance.produce_beacon_block(ctx, req, resp)
});
let mut instance = s.clone();
builder = builder.add_unary_handler(&METHOD_BEACON_BLOCK_SERVICE_PUBLISH_BEACON_BLOCK, move |ctx, req, resp| {
instance.publish_beacon_block(ctx, req, resp)
});
builder.build()
}
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "validator_client"
version = "0.1.0"
authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018"
[dependencies]
grpcio = { version = "0.4", default-features = false, features = ["protobuf-codec"] }
protobuf = "2.0.2"
protos = { path = "../protos" }
slot_clock = { path = "../beacon_chain/utils/slot_clock" }
spec = { path = "../beacon_chain/spec" }
tokio = "0.1.14"
types = { path = "../beacon_chain/types" }
slog = "^2.2.3"
slog-term = "^2.4.0"
slog-async = "^2.3.0"
ssz = { path = "../beacon_chain/utils/ssz" }
+127
View File
@@ -0,0 +1,127 @@
mod traits;
use self::traits::{BeaconNode, BeaconNodeError};
use crate::EpochDuties;
use slot_clock::SlotClock;
use spec::ChainSpec;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use types::BeaconBlock;
#[derive(Debug, PartialEq)]
pub enum PollOutcome {
BlockProduced,
SlashableBlockNotProduced,
BlockProductionNotRequired,
ProducerDutiesUnknown,
SlotAlreadyProcessed,
BeaconNodeUnableToProduceBlock,
}
#[derive(Debug, PartialEq)]
pub enum PollError {
SlotClockError,
SlotUnknowable,
EpochMapPoisoned,
SlotClockPoisoned,
BeaconNodeError(BeaconNodeError),
}
pub struct BlockProducer<T: SlotClock, U: BeaconNode> {
pub last_processed_slot: u64,
_spec: Arc<ChainSpec>,
epoch_map: Arc<RwLock<HashMap<u64, EpochDuties>>>,
slot_clock: Arc<RwLock<T>>,
beacon_node: U,
}
impl<T: SlotClock, U: BeaconNode> BlockProducer<T, U> {
pub fn new(
spec: Arc<ChainSpec>,
epoch_map: Arc<RwLock<HashMap<u64, EpochDuties>>>,
slot_clock: Arc<RwLock<T>>,
beacon_node: U,
) -> Self {
Self {
last_processed_slot: 0,
_spec: spec,
epoch_map,
slot_clock,
beacon_node,
}
}
}
impl<T: SlotClock, U: BeaconNode> BlockProducer<T, U> {
/// "Poll" to see if the validator is required to take any action.
///
/// The slot clock will be read and any new actions undertaken.
pub fn poll(&mut self) -> Result<PollOutcome, PollError> {
let slot = self
.slot_clock
.read()
.map_err(|_| PollError::SlotClockPoisoned)?
.present_slot()
.map_err(|_| PollError::SlotClockError)?
.ok_or(PollError::SlotUnknowable)?;
// If this is a new slot.
if slot > self.last_processed_slot {
let is_block_production_slot = {
let epoch_map = self
.epoch_map
.read()
.map_err(|_| PollError::EpochMapPoisoned)?;
match epoch_map.get(&slot) {
None => return Ok(PollOutcome::ProducerDutiesUnknown),
Some(duties) => duties.is_block_production_slot(slot)
}
};
if is_block_production_slot {
self.last_processed_slot = slot;
self.produce_block(slot)
} else {
Ok(PollOutcome::BlockProductionNotRequired)
}
} else {
Ok(PollOutcome::SlotAlreadyProcessed)
}
}
fn produce_block(&mut self, slot: u64) -> Result<PollOutcome, PollError> {
if let Some(block) = self.beacon_node.produce_beacon_block(slot)? {
if self.safe_to_produce(&block) {
let block = self.sign_block(block);
self.beacon_node.publish_beacon_block(block)?;
Ok(PollOutcome::BlockProduced)
} else {
Ok(PollOutcome::SlashableBlockNotProduced)
}
} else {
Ok(PollOutcome::BeaconNodeUnableToProduceBlock)
}
}
fn sign_block(&mut self, block: BeaconBlock) -> BeaconBlock {
// TODO: sign the block
self.store_produce(&block);
block
}
fn safe_to_produce(&self, _block: &BeaconBlock) -> bool {
// TODO: ensure the producer doesn't produce slashable blocks.
true
}
fn store_produce(&mut self, _block: &BeaconBlock) {
// TODO: record this block production to prevent future slashings.
}
}
impl From<BeaconNodeError> for PollError {
fn from(e: BeaconNodeError) -> PollError {
PollError::BeaconNodeError(e)
}
}
@@ -0,0 +1,73 @@
use protos::services::{
BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest,
};
use protos::services_grpc::BeaconBlockServiceClient;
use ssz::{ssz_encode, Decodable};
use types::{BeaconBlock, BeaconBlockBody, Hash256, Signature};
#[derive(Debug, PartialEq)]
pub enum BeaconNodeError {
RemoteFailure(String),
DecodeFailure,
}
pub trait BeaconNode {
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError>;
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError>;
}
impl BeaconNode for BeaconBlockServiceClient {
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError> {
let mut req = ProduceBeaconBlockRequest::new();
req.set_slot(slot);
let reply = self
.produce_beacon_block(&req)
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
if reply.has_block() {
let block = reply.get_block();
let (signature, _) = Signature::ssz_decode(block.get_signature(), 0)
.map_err(|_| BeaconNodeError::DecodeFailure)?;
// TODO: this conversion is incomplete; fix it.
Ok(Some(BeaconBlock {
slot: block.get_slot(),
parent_root: Hash256::zero(),
state_root: Hash256::zero(),
randao_reveal: Hash256::from(block.get_randao_reveal()),
candidate_pow_receipt_root: Hash256::zero(),
signature,
body: BeaconBlockBody {
proposer_slashings: vec![],
casper_slashings: vec![],
attestations: vec![],
deposits: vec![],
exits: vec![],
},
}))
} else {
Ok(None)
}
}
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError> {
let mut req = PublishBeaconBlockRequest::new();
// TODO: this conversion is incomplete; fix it.
let mut grpc_block = GrpcBeaconBlock::new();
grpc_block.set_slot(block.slot);
grpc_block.set_block_root(vec![0]);
grpc_block.set_randao_reveal(block.randao_reveal.to_vec());
grpc_block.set_signature(ssz_encode(&block.signature));
req.set_block(grpc_block);
let reply = self
.publish_beacon_block(&req)
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
Ok(reply.get_success())
}
}
+102
View File
@@ -0,0 +1,102 @@
mod block_producer;
use spec::ChainSpec;
use tokio::prelude::*;
use tokio::timer::Interval;
use crate::block_producer::{BlockProducer, PollOutcome as BlockProducerPollOutcome};
use std::time::{Duration, Instant};
use std::sync::{Arc, RwLock};
use std::collections::HashMap;
use slot_clock::SystemTimeSlotClock;
use grpcio::{ChannelBuilder, EnvBuilder};
use protos::services_grpc::BeaconBlockServiceClient;
use slog::{error, info, o, warn, Drain};
fn main() {
// gRPC
let env = Arc::new(EnvBuilder::new().build());
let ch = ChannelBuilder::new(env).connect("localhost:50051");
let client = BeaconBlockServiceClient::new(ch);
// Logging
let decorator = slog_term::TermDecorator::new().build();
let drain = slog_term::CompactFormat::new(decorator).build().fuse();
let drain = slog_async::Async::new(drain).build().fuse();
let log = slog::Logger::root(drain, o!());
// Ethereum
let spec = Arc::new(ChainSpec::foundation());
let duration = spec
.slot_duration
.checked_mul(1_000)
.expect("Slot duration overflow when converting from seconds to millis.");
let epoch_map = Arc::new(RwLock::new(HashMap::new()));
let slot_clock = {
info!(log, "Genesis time"; "unix_epoch_seconds" => spec.genesis_time);
let clock = SystemTimeSlotClock::new(spec.genesis_time, spec.slot_duration)
.expect("Unable to instantiate SystemTimeSlotClock.");
Arc::new(RwLock::new(clock))
};
let mut block_producer =
BlockProducer::new(spec.clone(), epoch_map.clone(), slot_clock.clone(), client);
info!(log, "Slot duration"; "milliseconds" => duration);
let task = Interval::new(Instant::now(), Duration::from_millis(duration))
// .take(10)
.for_each(move |_instant| {
match block_producer.poll() {
Err(error) => {
error!(log, "Block producer poll error"; "error" => format!("{:?}", error))
}
Ok(BlockProducerPollOutcome::BlockProduced) => info!(log, "Produced block"),
Ok(BlockProducerPollOutcome::SlashableBlockNotProduced) => {
warn!(log, "Slashable block was not signed")
}
Ok(BlockProducerPollOutcome::BlockProductionNotRequired) => {
info!(log, "Block production not required")
}
Ok(BlockProducerPollOutcome::ProducerDutiesUnknown) => {
error!(log, "Block production duties unknown")
}
Ok(BlockProducerPollOutcome::SlotAlreadyProcessed) => {
warn!(log, "Attempted to re-process slot")
}
Ok(BlockProducerPollOutcome::BeaconNodeUnableToProduceBlock) => {
error!(log, "Beacon node unable to produce block")
}
};
Ok(())
})
.map_err(|e| panic!("Block producer interval errored; err={:?}", e));
tokio::run(task);
}
pub struct EpochDuties {
block_production_slot: Option<u64>,
shard: Option<u64>,
}
impl EpochDuties {
pub fn is_block_production_slot(&self, slot: u64) -> bool {
match self.block_production_slot {
Some(s) if s == slot => true,
_ => false,
}
}
pub fn has_shard(&self) -> bool {
self.shard.is_some()
}
}