mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-03 00:31:50 +00:00
Merged Age's changes and ripped out heaps of now obsolete stuff in the validator client.
- Replaced most instances of PublicKey with KeyPair, since they need to be passed into each validator thread now. - Pulled out a bunch of FreeAttestations, and replaced with regular Attestations (as per Paul's suggestion) - Started generalising pubkeys to 'signers' (though they are still just Keypairs) - Added validator_index into a few structs where relevant - Removed the SlotClock and DutiesReader from the BlockProducer and Attester services, since this logic is now abstracted to the higher level process. - Added a Hash trait to the Keypair (rather than just pubkey) which assumes the Pubkey uniquely defines it.
This commit is contained in:
@@ -7,6 +7,8 @@ edition = "2018"
|
||||
[dependencies]
|
||||
bls = { path = "../../eth2/utils/bls" }
|
||||
beacon_chain = { path = "../beacon_chain" }
|
||||
network = { path = "../network" }
|
||||
eth2-libp2p = { path = "../eth2-libp2p" }
|
||||
version = { path = "../version" }
|
||||
types = { path = "../../eth2/types" }
|
||||
ssz = { path = "../../eth2/utils/ssz" }
|
||||
@@ -23,3 +25,4 @@ slog-term = "^2.4.0"
|
||||
slog-async = "^2.3.0"
|
||||
tokio = "0.1.17"
|
||||
exit-future = "0.1.4"
|
||||
crossbeam-channel = "0.3.8"
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
use crossbeam_channel;
|
||||
use eth2_libp2p::rpc::methods::BlockRootSlot;
|
||||
use eth2_libp2p::PubsubMessage;
|
||||
use futures::Future;
|
||||
use grpcio::{RpcContext, UnarySink};
|
||||
use network::NetworkMessage;
|
||||
use protos::services::{
|
||||
BeaconBlock as BeaconBlockProto, ProduceBeaconBlockRequest, ProduceBeaconBlockResponse,
|
||||
PublishBeaconBlockRequest, PublishBeaconBlockResponse,
|
||||
};
|
||||
use protos::services_grpc::BeaconBlockService;
|
||||
use slog::Logger;
|
||||
use types::{Hash256, Slot};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BeaconBlockServiceInstance {
|
||||
pub network_chan: crossbeam_channel::Sender<NetworkMessage>,
|
||||
pub log: Logger,
|
||||
}
|
||||
|
||||
@@ -43,7 +49,22 @@ impl BeaconBlockService for BeaconBlockServiceInstance {
|
||||
req: PublishBeaconBlockRequest,
|
||||
sink: UnarySink<PublishBeaconBlockResponse>,
|
||||
) {
|
||||
println!("publishing {:?}", req.get_block());
|
||||
let block = req.get_block();
|
||||
let block_root = Hash256::from_slice(block.get_block_root());
|
||||
let block_slot = BlockRootSlot {
|
||||
block_root,
|
||||
slot: Slot::from(block.get_slot()),
|
||||
};
|
||||
println!("publishing block with root {:?}", block_root);
|
||||
|
||||
// TODO: Obtain topics from the network service properly.
|
||||
let topic = types::TopicBuilder::new("beacon_chain".to_string()).build();
|
||||
let message = PubsubMessage::Block(block_slot);
|
||||
println!("Sending beacon block to gossipsub");
|
||||
self.network_chan.send(NetworkMessage::Publish {
|
||||
topics: vec![topic],
|
||||
message,
|
||||
});
|
||||
|
||||
// TODO: actually process the block.
|
||||
let mut resp = PublishBeaconBlockResponse::new();
|
||||
|
||||
@@ -11,6 +11,7 @@ use self::validator::ValidatorServiceInstance;
|
||||
pub use config::Config as RPCConfig;
|
||||
use futures::{future, Future};
|
||||
use grpcio::{Environment, Server, ServerBuilder};
|
||||
use network::NetworkMessage;
|
||||
use protos::services_grpc::{
|
||||
create_beacon_block_service, create_beacon_node_service, create_validator_service,
|
||||
};
|
||||
@@ -21,6 +22,7 @@ use tokio::runtime::TaskExecutor;
|
||||
pub fn start_server(
|
||||
config: &RPCConfig,
|
||||
executor: &TaskExecutor,
|
||||
network_chan: crossbeam_channel::Sender<NetworkMessage>,
|
||||
beacon_chain: Arc<BeaconChain>,
|
||||
log: &slog::Logger,
|
||||
) -> exit_future::Signal {
|
||||
@@ -40,11 +42,17 @@ pub fn start_server(
|
||||
};
|
||||
|
||||
let beacon_block_service = {
|
||||
let instance = BeaconBlockServiceInstance { log: log.clone() };
|
||||
let instance = BeaconBlockServiceInstance {
|
||||
network_chan,
|
||||
log: log.clone(),
|
||||
};
|
||||
create_beacon_block_service(instance)
|
||||
};
|
||||
let validator_service = {
|
||||
let instance = ValidatorServiceInstance { log: log.clone() };
|
||||
let instance = ValidatorServiceInstance {
|
||||
chain: beacon_chain.clone(),
|
||||
log: log.clone(),
|
||||
};
|
||||
create_validator_service(instance)
|
||||
};
|
||||
|
||||
|
||||
@@ -1,60 +1,139 @@
|
||||
use crate::beacon_chain::BeaconChain;
|
||||
use bls::PublicKey;
|
||||
use futures::Future;
|
||||
use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink};
|
||||
use protos::services::{
|
||||
IndexResponse, ProposeBlockSlotRequest, ProposeBlockSlotResponse, PublicKey as PublicKeyRequest,
|
||||
};
|
||||
use protos::services::{ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty};
|
||||
use protos::services_grpc::ValidatorService;
|
||||
use slog::{debug, Logger};
|
||||
use ssz::Decodable;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ValidatorServiceInstance {
|
||||
pub chain: Arc<BeaconChain>,
|
||||
pub log: Logger,
|
||||
}
|
||||
//TODO: Refactor Errors
|
||||
|
||||
impl ValidatorService for ValidatorServiceInstance {
|
||||
fn validator_index(
|
||||
/// For a list of validator public keys, this function returns the slot at which each
|
||||
/// validator must propose a block, attest to a shard, their shard committee and the shard they
|
||||
/// need to attest to.
|
||||
fn get_validator_duties(
|
||||
&mut self,
|
||||
ctx: RpcContext,
|
||||
req: PublicKeyRequest,
|
||||
sink: UnarySink<IndexResponse>,
|
||||
req: GetDutiesRequest,
|
||||
sink: UnarySink<GetDutiesResponse>,
|
||||
) {
|
||||
if let Ok((public_key, _)) = PublicKey::ssz_decode(req.get_public_key(), 0) {
|
||||
debug!(self.log, "RPC request"; "endpoint" => "ValidatorIndex", "public_key" => public_key.concatenated_hex_id());
|
||||
let validators = req.get_validators();
|
||||
debug!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch());
|
||||
|
||||
let mut resp = IndexResponse::new();
|
||||
let epoch = req.get_epoch();
|
||||
let mut resp = GetDutiesResponse::new();
|
||||
let resp_validators = resp.mut_active_validators();
|
||||
|
||||
// TODO: return a legit value.
|
||||
resp.set_index(1);
|
||||
let spec = self.chain.get_spec();
|
||||
let state = self.chain.get_state();
|
||||
|
||||
let f = sink
|
||||
.success(resp)
|
||||
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
||||
ctx.spawn(f)
|
||||
} else {
|
||||
let f = sink
|
||||
.fail(RpcStatus::new(
|
||||
RpcStatusCode::InvalidArgument,
|
||||
Some("Invalid public_key".to_string()),
|
||||
))
|
||||
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
||||
ctx.spawn(f)
|
||||
//TODO: Decide whether to rebuild the cache
|
||||
//TODO: Get the active validator indicies
|
||||
//let active_validator_indices = self.chain.state.read().get_cached_active_validator_indices(
|
||||
let active_validator_indices = vec![1, 2, 3, 4, 5, 6, 7, 8];
|
||||
// TODO: Is this the most efficient? Perhaps we cache this data structure.
|
||||
|
||||
// this is an array of validators who are to propose this epoch
|
||||
// TODO: RelativeEpoch?
|
||||
//let validator_proposers = [0..spec.slots_per_epoch].iter().map(|slot| state.get_beacon_proposer_index(Slot::from(slot), epoch, &spec)).collect();
|
||||
let validator_proposers: Vec<u64> = vec![1, 2, 3, 4, 5];
|
||||
|
||||
// get the duties for each validator
|
||||
for validator_pk in validators.get_public_keys() {
|
||||
let mut active_validator = ActiveValidator::new();
|
||||
|
||||
let public_key = match PublicKey::ssz_decode(validator_pk, 0) {
|
||||
Ok((v, _index)) => v,
|
||||
Err(_) => {
|
||||
let f = sink
|
||||
.fail(RpcStatus::new(
|
||||
RpcStatusCode::InvalidArgument,
|
||||
Some("Invalid public_key".to_string()),
|
||||
))
|
||||
//TODO: Handle error correctly
|
||||
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
||||
return ctx.spawn(f);
|
||||
}
|
||||
};
|
||||
|
||||
// is the validator active
|
||||
let val_index = match state.get_validator_index(&public_key) {
|
||||
Ok(Some(index)) => {
|
||||
if active_validator_indices.contains(&index) {
|
||||
// validator is active, return the index
|
||||
index
|
||||
} else {
|
||||
// validator is inactive, go to the next validator
|
||||
active_validator.set_none(false);
|
||||
resp_validators.push(active_validator);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// validator index is not known, skip it
|
||||
Ok(_) => {
|
||||
active_validator.set_none(false);
|
||||
resp_validators.push(active_validator);
|
||||
break;
|
||||
}
|
||||
// the cache is not built, throw an error
|
||||
Err(_) => {
|
||||
let f = sink
|
||||
.fail(RpcStatus::new(
|
||||
RpcStatusCode::FailedPrecondition,
|
||||
Some("Beacon state cache is not built".to_string()),
|
||||
))
|
||||
//TODO: Handle error correctly
|
||||
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
||||
return ctx.spawn(f);
|
||||
}
|
||||
};
|
||||
|
||||
// we have an active validator, set its duties
|
||||
let mut duty = ValidatorDuty::new();
|
||||
|
||||
// check if the validator needs to propose a block
|
||||
if let Some(slot) = validator_proposers
|
||||
.iter()
|
||||
.position(|&v| val_index as u64 == v)
|
||||
{
|
||||
duty.set_block_production_slot(epoch * spec.slots_per_epoch + slot as u64);
|
||||
} else {
|
||||
// no blocks to propose this epoch
|
||||
duty.set_none(false)
|
||||
}
|
||||
|
||||
// get attestation duties
|
||||
let attestation_duties = match state.get_attestation_duties(val_index, &spec) {
|
||||
Ok(Some(v)) => v,
|
||||
Ok(_) => unreachable!(), //we've checked the validator index
|
||||
// the cache is not built, throw an error
|
||||
Err(_) => {
|
||||
let f = sink
|
||||
.fail(RpcStatus::new(
|
||||
RpcStatusCode::FailedPrecondition,
|
||||
Some("Beacon state cache is not built".to_string()),
|
||||
))
|
||||
//TODO: Handle error correctly
|
||||
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
||||
return ctx.spawn(f);
|
||||
}
|
||||
};
|
||||
|
||||
duty.set_committee_index(attestation_duties.committee_index as u64);
|
||||
duty.set_attestation_slot(attestation_duties.slot.as_u64());
|
||||
duty.set_attestation_shard(attestation_duties.shard);
|
||||
|
||||
active_validator.set_duty(duty);
|
||||
resp_validators.push(active_validator);
|
||||
}
|
||||
}
|
||||
|
||||
fn propose_block_slot(
|
||||
&mut self,
|
||||
ctx: RpcContext,
|
||||
req: ProposeBlockSlotRequest,
|
||||
sink: UnarySink<ProposeBlockSlotResponse>,
|
||||
) {
|
||||
debug!(self.log, "RPC request"; "endpoint" => "ProposeBlockSlot", "epoch" => req.get_epoch(), "validator_index" => req.get_validator_index());
|
||||
|
||||
let mut resp = ProposeBlockSlotResponse::new();
|
||||
|
||||
// TODO: return a legit value.
|
||||
resp.set_slot(1);
|
||||
|
||||
let f = sink
|
||||
.success(resp)
|
||||
|
||||
Reference in New Issue
Block a user