2019-03-26 04:26:05 +00:00
|
|
|
use crate::beacon_chain::BeaconChain;
|
2019-03-25 12:39:39 +00:00
|
|
|
use crossbeam_channel;
|
|
|
|
use eth2_libp2p::PubsubMessage;
|
2019-02-14 01:09:18 +00:00
|
|
|
use futures::Future;
|
2019-03-30 04:58:31 +00:00
|
|
|
use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink};
|
2019-03-25 12:39:39 +00:00
|
|
|
use network::NetworkMessage;
|
2019-02-14 01:09:18 +00:00
|
|
|
use protos::services::{
|
|
|
|
BeaconBlock as BeaconBlockProto, ProduceBeaconBlockRequest, ProduceBeaconBlockResponse,
|
|
|
|
PublishBeaconBlockRequest, PublishBeaconBlockResponse,
|
|
|
|
};
|
|
|
|
use protos::services_grpc::BeaconBlockService;
|
|
|
|
use slog::Logger;
|
2019-03-30 04:58:31 +00:00
|
|
|
use slog::{error, info, trace, warn};
|
2019-03-31 02:06:01 +00:00
|
|
|
use ssz::{ssz_encode, Decodable};
|
2019-03-26 04:26:05 +00:00
|
|
|
use std::sync::Arc;
|
2019-03-31 02:06:01 +00:00
|
|
|
use types::{BeaconBlock, Signature, Slot};
|
2019-02-14 01:09:18 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct BeaconBlockServiceInstance {
|
2019-03-26 04:26:05 +00:00
|
|
|
pub chain: Arc<BeaconChain>,
|
2019-03-25 12:39:39 +00:00
|
|
|
pub network_chan: crossbeam_channel::Sender<NetworkMessage>,
|
2019-02-14 01:09:18 +00:00
|
|
|
pub 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>,
|
|
|
|
) {
|
2019-03-30 04:58:31 +00:00
|
|
|
trace!(self.log, "Generating a beacon block"; "req" => format!("{:?}", req));
|
|
|
|
|
|
|
|
// decode the request
|
|
|
|
// TODO: requested slot currently unused, see: https://github.com/sigp/lighthouse/issues/336
|
|
|
|
let _requested_slot = Slot::from(req.get_slot());
|
2019-03-30 08:32:32 +00:00
|
|
|
let randao_reveal = match Signature::ssz_decode(req.get_randao_reveal(), 0) {
|
|
|
|
Ok((reveal, _index)) => reveal,
|
2019-03-30 04:58:31 +00:00
|
|
|
Err(_) => {
|
|
|
|
// decode error, incorrect signature
|
|
|
|
let log_clone = self.log.clone();
|
|
|
|
let f = sink
|
|
|
|
.fail(RpcStatus::new(
|
|
|
|
RpcStatusCode::InvalidArgument,
|
|
|
|
Some(format!("Invalid randao reveal signature")),
|
|
|
|
))
|
|
|
|
.map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e));
|
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let produced_block = match self.chain.produce_block(randao_reveal) {
|
|
|
|
Ok((block, _state)) => block,
|
|
|
|
Err(e) => {
|
|
|
|
// could not produce a block
|
|
|
|
let log_clone = self.log.clone();
|
|
|
|
warn!(self.log, "RPC Error"; "Error" => format!("Could not produce a block:{:?}",e));
|
|
|
|
let f = sink
|
|
|
|
.fail(RpcStatus::new(
|
|
|
|
RpcStatusCode::Unknown,
|
|
|
|
Some(format!("Could not produce a block: {:?}", e)),
|
|
|
|
))
|
|
|
|
.map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e));
|
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
|
|
|
};
|
2019-02-14 01:09:18 +00:00
|
|
|
|
|
|
|
let mut block = BeaconBlockProto::new();
|
2019-03-30 04:58:31 +00:00
|
|
|
block.set_ssz(ssz_encode(&produced_block));
|
2019-02-14 01:09:18 +00:00
|
|
|
|
|
|
|
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>,
|
|
|
|
) {
|
2019-03-30 08:32:32 +00:00
|
|
|
trace!(&self.log, "Attempting to publish a block");
|
|
|
|
|
2019-03-26 04:26:05 +00:00
|
|
|
let mut resp = PublishBeaconBlockResponse::new();
|
2019-03-26 01:32:38 +00:00
|
|
|
|
2019-03-26 04:26:05 +00:00
|
|
|
let ssz_serialized_block = req.get_block().get_ssz();
|
2019-03-25 11:00:11 +00:00
|
|
|
|
2019-03-26 04:26:05 +00:00
|
|
|
match BeaconBlock::ssz_decode(ssz_serialized_block, 0) {
|
2019-03-26 01:32:38 +00:00
|
|
|
Ok((block, _i)) => {
|
2019-03-26 04:26:05 +00:00
|
|
|
match self.chain.process_block(block.clone()) {
|
|
|
|
Ok(outcome) => {
|
|
|
|
if outcome.sucessfully_processed() {
|
|
|
|
// Block was successfully processed.
|
|
|
|
info!(
|
|
|
|
self.log,
|
|
|
|
"PublishBeaconBlock";
|
2019-03-27 00:25:15 +00:00
|
|
|
"type" => "valid_block",
|
|
|
|
"block_slot" => block.slot,
|
2019-03-26 04:26:05 +00:00
|
|
|
"outcome" => format!("{:?}", outcome)
|
|
|
|
);
|
|
|
|
|
|
|
|
// TODO: Obtain topics from the network service properly.
|
|
|
|
let topic =
|
|
|
|
types::TopicBuilder::new("beacon_chain".to_string()).build();
|
2019-03-31 01:28:35 +00:00
|
|
|
let message = PubsubMessage::Block(block);
|
2019-03-26 04:26:05 +00:00
|
|
|
|
2019-03-31 01:28:35 +00:00
|
|
|
// Publish the block to the p2p network via gossipsub.
|
|
|
|
self.network_chan
|
|
|
|
.send(NetworkMessage::Publish {
|
|
|
|
topics: vec![topic],
|
|
|
|
message,
|
|
|
|
})
|
|
|
|
.unwrap_or_else(|e| {
|
|
|
|
error!(
|
|
|
|
self.log,
|
|
|
|
"PublishBeaconBlock";
|
|
|
|
"type" => "failed to publish to gossipsub",
|
|
|
|
"error" => format!("{:?}", e)
|
|
|
|
);
|
|
|
|
});
|
2019-03-26 04:26:05 +00:00
|
|
|
|
|
|
|
resp.set_success(true);
|
|
|
|
} else if outcome.is_invalid() {
|
|
|
|
// Block was invalid.
|
|
|
|
warn!(
|
|
|
|
self.log,
|
|
|
|
"PublishBeaconBlock";
|
|
|
|
"type" => "invalid_block",
|
|
|
|
"outcome" => format!("{:?}", outcome)
|
|
|
|
);
|
|
|
|
|
|
|
|
resp.set_success(false);
|
|
|
|
resp.set_msg(
|
|
|
|
format!("InvalidBlock: {:?}", outcome).as_bytes().to_vec(),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// Some failure during processing.
|
2019-03-27 00:25:15 +00:00
|
|
|
warn!(
|
2019-03-26 04:26:05 +00:00
|
|
|
self.log,
|
|
|
|
"PublishBeaconBlock";
|
2019-03-27 00:25:15 +00:00
|
|
|
"type" => "unable_to_import",
|
2019-03-26 04:26:05 +00:00
|
|
|
"outcome" => format!("{:?}", outcome)
|
|
|
|
);
|
|
|
|
|
|
|
|
resp.set_success(false);
|
|
|
|
resp.set_msg(format!("other: {:?}", outcome).as_bytes().to_vec());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
// Some failure during processing.
|
|
|
|
error!(
|
|
|
|
self.log,
|
|
|
|
"PublishBeaconBlock";
|
|
|
|
"type" => "failed_to_process",
|
|
|
|
"error" => format!("{:?}", e)
|
|
|
|
);
|
|
|
|
|
|
|
|
resp.set_success(false);
|
|
|
|
resp.set_msg(format!("failed_to_process: {:?}", e).as_bytes().to_vec());
|
|
|
|
}
|
|
|
|
}
|
2019-03-26 01:32:38 +00:00
|
|
|
|
2019-03-26 04:26:05 +00:00
|
|
|
resp.set_success(true);
|
2019-03-26 01:32:38 +00:00
|
|
|
}
|
2019-03-26 04:26:05 +00:00
|
|
|
Err(_) => {
|
|
|
|
resp.set_success(false);
|
|
|
|
resp.set_msg(b"Invalid SSZ".to_vec());
|
2019-03-26 01:32:38 +00:00
|
|
|
}
|
2019-03-26 04:26:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let f = sink
|
|
|
|
.success(resp)
|
|
|
|
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
|
|
|
ctx.spawn(f)
|
2019-02-14 01:09:18 +00:00
|
|
|
}
|
|
|
|
}
|