Builds attestation grpc implemention
This commit is contained in:
parent
145cabc427
commit
d12ddae247
@ -141,7 +141,11 @@ message ProduceAttestationDataResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message PublishAttestationRequest {
|
message PublishAttestationRequest {
|
||||||
FreeAttestation free_attestation = 1;
|
Attestation attestation = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Attestation {
|
||||||
|
bytes ssz = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PublishAttestationResponse {
|
message PublishAttestationResponse {
|
||||||
@ -149,26 +153,6 @@ message PublishAttestationResponse {
|
|||||||
bytes msg = 2;
|
bytes msg = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Crosslink {
|
|
||||||
uint64 epoch = 1;
|
|
||||||
bytes crosslink_data_root = 2;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message AttestationData {
|
message AttestationData {
|
||||||
uint64 slot = 1;
|
bytes ssz = 1;
|
||||||
uint64 shard = 2;
|
|
||||||
bytes beacon_block_root = 3;
|
|
||||||
bytes epoch_boundary_root = 4;
|
|
||||||
bytes crosslink_data_root = 5;
|
|
||||||
Crosslink latest_crosslink = 6;
|
|
||||||
uint64 justified_epoch = 7;
|
|
||||||
bytes justified_block_root = 8;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
message FreeAttestation {
|
|
||||||
AttestationData data = 1;
|
|
||||||
bytes signature = 2;
|
|
||||||
uint64 validator_index = 3;
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
//TODO: generalise these enums to the crate
|
|
||||||
use crate::block_producer::{BeaconNodeError, PublishOutcome};
|
|
||||||
use types::{Attestation, AttestationData, Slot};
|
|
||||||
|
|
||||||
/// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the
|
|
||||||
/// actual beacon node.
|
|
||||||
pub trait BeaconNodeAttestation: Send + Sync {
|
|
||||||
/// Request that the node produces the required attestation data.
|
|
||||||
///
|
|
||||||
fn produce_attestation_data(
|
|
||||||
&self,
|
|
||||||
slot: Slot,
|
|
||||||
shard: u64,
|
|
||||||
) -> Result<AttestationData, BeaconNodeError>;
|
|
||||||
|
|
||||||
/// Request that the node publishes a attestation.
|
|
||||||
///
|
|
||||||
/// Returns `true` if the publish was successful.
|
|
||||||
fn publish_attestation(
|
|
||||||
&self,
|
|
||||||
attestation: Attestation,
|
|
||||||
) -> Result<PublishOutcome, BeaconNodeError>;
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
use protos::services_grpc::AttestationServiceClient;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use attester::{BeaconNode, BeaconNodeError, PublishOutcome};
|
|
||||||
use protos::services::ProduceAttestationDataRequest;
|
|
||||||
use types::{Attestation, AttestationData, Slot};
|
|
||||||
|
|
||||||
pub struct AttestationGrpcClient {
|
|
||||||
client: Arc<AttestationServiceClient>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AttestationGrpcClient {
|
|
||||||
pub fn new(client: Arc<AttestationServiceClient>) -> Self {
|
|
||||||
Self { client }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
impl BeaconNode for AttestationGrpcClient {
|
|
||||||
fn produce_attestation_data(
|
|
||||||
&self,
|
|
||||||
slot: Slot,
|
|
||||||
shard: u64,
|
|
||||||
) -> Result<Option<AttestationData>, BeaconNodeError> {
|
|
||||||
let mut req = ProduceAttestationDataRequest::new();
|
|
||||||
req.set_slot(slot.as_u64());
|
|
||||||
req.set_shard(shard);
|
|
||||||
|
|
||||||
let reply = self
|
|
||||||
.client
|
|
||||||
.produce_attestation_data(&req)
|
|
||||||
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
|
|
||||||
|
|
||||||
// TODO: return correct Attestation
|
|
||||||
Err(BeaconNodeError::DecodeFailure)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn publish_attestation(
|
|
||||||
&self,
|
|
||||||
attestation: Attestation,
|
|
||||||
) -> Result<PublishOutcome, BeaconNodeError> {
|
|
||||||
// TODO: return correct PublishOutcome
|
|
||||||
Err(BeaconNodeError::DecodeFailure)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
@ -1,155 +0,0 @@
|
|||||||
mod beacon_node_attestation;
|
|
||||||
mod grpc;
|
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot};
|
|
||||||
//TODO: Move these higher up in the crate
|
|
||||||
use super::block_producer::{BeaconNodeError, ValidatorEvent};
|
|
||||||
use crate::signer::Signer;
|
|
||||||
use beacon_node_attestation::BeaconNodeAttestation;
|
|
||||||
use slog::{error, info, warn};
|
|
||||||
use ssz::TreeHash;
|
|
||||||
use types::{
|
|
||||||
AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit,
|
|
||||||
AttestationDuty, Bitfield,
|
|
||||||
};
|
|
||||||
|
|
||||||
//TODO: Group these errors at a crate level
|
|
||||||
#[derive(Debug, PartialEq)]
|
|
||||||
pub enum Error {
|
|
||||||
BeaconNodeError(BeaconNodeError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<BeaconNodeError> for Error {
|
|
||||||
fn from(e: BeaconNodeError) -> Error {
|
|
||||||
Error::BeaconNodeError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This struct contains the logic for requesting and signing beacon attestations for a validator. The
|
|
||||||
/// validator can abstractly sign via the Signer trait object.
|
|
||||||
pub struct AttestationProducer<'a, B: BeaconNodeAttestation, S: Signer> {
|
|
||||||
/// The current fork.
|
|
||||||
pub fork: Fork,
|
|
||||||
/// The attestation duty to perform.
|
|
||||||
pub duty: AttestationDuty,
|
|
||||||
/// The current epoch.
|
|
||||||
pub spec: Arc<ChainSpec>,
|
|
||||||
/// The beacon node to connect to.
|
|
||||||
pub beacon_node: Arc<B>,
|
|
||||||
/// The signer to sign the block.
|
|
||||||
pub signer: &'a S,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> {
|
|
||||||
/// Handle outputs and results from attestation production.
|
|
||||||
pub fn handle_produce_attestation(&mut self, log: slog::Logger) {
|
|
||||||
match self.produce_attestation() {
|
|
||||||
Ok(ValidatorEvent::AttestationProduced(_slot)) => {
|
|
||||||
info!(log, "Attestation produced"; "Validator" => format!("{}", self.signer))
|
|
||||||
}
|
|
||||||
Err(e) => error!(log, "Attestation production error"; "Error" => format!("{:?}", e)),
|
|
||||||
Ok(ValidatorEvent::SignerRejection(_slot)) => {
|
|
||||||
error!(log, "Attestation production error"; "Error" => format!("Signer could not sign the attestation"))
|
|
||||||
}
|
|
||||||
Ok(ValidatorEvent::SlashableAttestationNotProduced(_slot)) => {
|
|
||||||
error!(log, "Attestation production error"; "Error" => format!("Rejected the attestation as it could have been slashed"))
|
|
||||||
}
|
|
||||||
Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => {
|
|
||||||
error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation"))
|
|
||||||
}
|
|
||||||
Ok(v) => {
|
|
||||||
warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Produce an attestation, sign it and send it back
|
|
||||||
///
|
|
||||||
/// Assumes that an attestation 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.
|
|
||||||
pub fn produce_attestation(&mut self) -> Result<ValidatorEvent, Error> {
|
|
||||||
let epoch = self.duty.slot.epoch(self.spec.slots_per_epoch);
|
|
||||||
|
|
||||||
let attestation = self
|
|
||||||
.beacon_node
|
|
||||||
.produce_attestation_data(self.duty.slot, self.duty.shard)?;
|
|
||||||
if self.safe_to_produce(&attestation) {
|
|
||||||
let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork);
|
|
||||||
if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) {
|
|
||||||
self.beacon_node.publish_attestation(attestation)?;
|
|
||||||
Ok(ValidatorEvent::AttestationProduced(self.duty.slot))
|
|
||||||
} else {
|
|
||||||
Ok(ValidatorEvent::SignerRejection(self.duty.slot))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(ValidatorEvent::SlashableAttestationNotProduced(
|
|
||||||
self.duty.slot,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Consumes an attestation, returning the attestation signed by the validators private key.
|
|
||||||
///
|
|
||||||
/// Important: this function will not check to ensure the attestation is not slashable. This must be
|
|
||||||
/// done upstream.
|
|
||||||
fn sign_attestation(
|
|
||||||
&mut self,
|
|
||||||
mut attestation: AttestationData,
|
|
||||||
duties: AttestationDuty,
|
|
||||||
domain: u64,
|
|
||||||
) -> Option<Attestation> {
|
|
||||||
self.store_produce(&attestation);
|
|
||||||
|
|
||||||
// build the aggregate signature
|
|
||||||
let aggregate_signature = {
|
|
||||||
let message = AttestationDataAndCustodyBit {
|
|
||||||
data: attestation.clone(),
|
|
||||||
custody_bit: false,
|
|
||||||
}
|
|
||||||
.hash_tree_root();
|
|
||||||
|
|
||||||
let sig = self.signer.sign_message(&message, domain)?;
|
|
||||||
|
|
||||||
let mut agg_sig = AggregateSignature::new();
|
|
||||||
agg_sig.add(&sig);
|
|
||||||
agg_sig
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len);
|
|
||||||
let custody_bitfield = Bitfield::with_capacity(duties.committee_len);
|
|
||||||
aggregation_bitfield.set(duties.committee_index, true);
|
|
||||||
|
|
||||||
Some(Attestation {
|
|
||||||
aggregation_bitfield,
|
|
||||||
data: attestation,
|
|
||||||
custody_bitfield,
|
|
||||||
aggregate_signature,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if signing an attestation is safe (non-slashable).
|
|
||||||
///
|
|
||||||
/// !!! UNSAFE !!!
|
|
||||||
///
|
|
||||||
/// Important: this function is presently stubbed-out. It provides ZERO SAFETY.
|
|
||||||
fn safe_to_produce(&self, _attestation: &AttestationData) -> bool {
|
|
||||||
//TODO: Implement slash protection
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Record that an attestation 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, _attestation: &AttestationData) {
|
|
||||||
// TODO: Implement slash protection
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,7 @@ use ssz::{ssz_encode, Decodable};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{BeaconBlock, Signature, Slot};
|
use types::{BeaconBlock, Signature, Slot};
|
||||||
|
|
||||||
|
//TODO: Remove this new type. Do not need to wrap
|
||||||
/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be
|
/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be
|
||||||
/// implemented upon it.
|
/// implemented upon it.
|
||||||
pub struct BeaconBlockGrpcClient {
|
pub struct BeaconBlockGrpcClient {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
mod attester_service;
|
mod attestation_producer;
|
||||||
mod block_producer;
|
mod block_producer;
|
||||||
mod config;
|
mod config;
|
||||||
mod duties;
|
mod duties;
|
||||||
|
Loading…
Reference in New Issue
Block a user