2019-03-30 05:34:43 +00:00
|
|
|
use super::beacon_node_block::*;
|
2019-02-14 01:09:18 +00:00
|
|
|
use protos::services::{
|
|
|
|
BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest,
|
|
|
|
};
|
|
|
|
use protos::services_grpc::BeaconBlockServiceClient;
|
2019-03-18 07:11:46 +00:00
|
|
|
use ssz::{decode, ssz_encode};
|
2019-02-14 01:09:18 +00:00
|
|
|
use std::sync::Arc;
|
2019-03-26 01:32:38 +00:00
|
|
|
use types::{BeaconBlock, Signature, Slot};
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-30 07:14:04 +00:00
|
|
|
//TODO: Remove this new type. Do not need to wrap
|
2019-02-14 01:09:18 +00:00
|
|
|
/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be
|
|
|
|
/// implemented upon it.
|
|
|
|
pub struct BeaconBlockGrpcClient {
|
|
|
|
client: Arc<BeaconBlockServiceClient>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BeaconBlockGrpcClient {
|
|
|
|
pub fn new(client: Arc<BeaconBlockServiceClient>) -> Self {
|
|
|
|
Self { client }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-30 05:34:43 +00:00
|
|
|
impl BeaconNodeBlock for BeaconBlockGrpcClient {
|
2019-02-14 01:09:18 +00:00
|
|
|
/// 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: Slot,
|
2019-03-29 12:45:53 +00:00
|
|
|
randao_reveal: &Signature,
|
2019-02-14 01:09:18 +00:00
|
|
|
) -> Result<Option<BeaconBlock>, BeaconNodeError> {
|
2019-03-29 12:45:53 +00:00
|
|
|
// request a beacon block from the node
|
2019-02-14 01:09:18 +00:00
|
|
|
let mut req = ProduceBeaconBlockRequest::new();
|
|
|
|
req.set_slot(slot.as_u64());
|
2019-03-29 12:45:53 +00:00
|
|
|
req.set_randao_reveal(ssz_encode(randao_reveal));
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-29 12:45:53 +00:00
|
|
|
//TODO: Determine if we want an explicit timeout
|
2019-02-14 01:09:18 +00:00
|
|
|
let reply = self
|
|
|
|
.client
|
|
|
|
.produce_beacon_block(&req)
|
|
|
|
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
|
|
|
|
|
2019-03-29 12:45:53 +00:00
|
|
|
// format the reply
|
2019-02-14 01:09:18 +00:00
|
|
|
if reply.has_block() {
|
|
|
|
let block = reply.get_block();
|
2019-03-26 01:32:38 +00:00
|
|
|
let ssz = block.get_ssz();
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-29 00:47:22 +00:00
|
|
|
let block = decode::<BeaconBlock>(&ssz).map_err(|_| BeaconNodeError::DecodeFailure)?;
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-26 01:32:38 +00:00
|
|
|
Ok(Some(block))
|
2019-02-14 01:09:18 +00:00
|
|
|
} else {
|
|
|
|
Ok(None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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<PublishOutcome, BeaconNodeError> {
|
|
|
|
let mut req = PublishBeaconBlockRequest::new();
|
|
|
|
|
2019-03-26 01:32:38 +00:00
|
|
|
let ssz = ssz_encode(&block);
|
|
|
|
|
2019-02-14 01:09:18 +00:00
|
|
|
let mut grpc_block = GrpcBeaconBlock::new();
|
2019-03-26 01:32:38 +00:00
|
|
|
grpc_block.set_ssz(ssz);
|
2019-02-14 01:09:18 +00:00
|
|
|
|
|
|
|
req.set_block(grpc_block);
|
|
|
|
|
|
|
|
let reply = self
|
|
|
|
.client
|
|
|
|
.publish_beacon_block(&req)
|
|
|
|
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
|
|
|
|
|
|
|
|
if reply.get_success() {
|
2019-03-30 05:34:43 +00:00
|
|
|
Ok(PublishOutcome::Valid)
|
2019-02-14 01:09:18 +00:00
|
|
|
} else {
|
|
|
|
// TODO: distinguish between different errors
|
|
|
|
Ok(PublishOutcome::InvalidBlock("Publish failed".to_string()))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|