use core::{hash::Hash, fmt::Debug};
use std::{sync::Arc, collections::HashSet};
use async_trait::async_trait;
use thiserror::Error;
use parity_scale_codec::{Encode, Decode};
use crate::{SignedMessageFor, commit_msg};
pub trait ValidatorId:
Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + Encode + Decode
{
}
impl<V: Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + Encode + Decode> ValidatorId
for V
{
}
pub trait Signature: Send + Sync + Clone + PartialEq + Debug + Encode + Decode {}
impl<S: Send + Sync + Clone + PartialEq + Debug + Encode + Decode> Signature for S {}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
pub struct BlockNumber(pub u64);
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
pub struct RoundNumber(pub u32);
#[async_trait]
pub trait Signer: Send + Sync {
type ValidatorId: ValidatorId;
type Signature: Signature;
async fn validator_id(&self) -> Option<Self::ValidatorId>;
async fn sign(&self, msg: &[u8]) -> Self::Signature;
}
#[async_trait]
impl<S: Signer> Signer for Arc<S> {
type ValidatorId = S::ValidatorId;
type Signature = S::Signature;
async fn validator_id(&self) -> Option<Self::ValidatorId> {
self.as_ref().validator_id().await
}
async fn sign(&self, msg: &[u8]) -> Self::Signature {
self.as_ref().sign(msg).await
}
}
pub trait SignatureScheme: Send + Sync {
type ValidatorId: ValidatorId;
type Signature: Signature;
type AggregateSignature: Signature;
type Signer: Signer<ValidatorId = Self::ValidatorId, Signature = Self::Signature>;
#[must_use]
fn verify(&self, validator: Self::ValidatorId, msg: &[u8], sig: &Self::Signature) -> bool;
fn aggregate(sigs: &[Self::Signature]) -> Self::AggregateSignature;
#[must_use]
fn verify_aggregate(
&self,
signers: &[Self::ValidatorId],
msg: &[u8],
sig: &Self::AggregateSignature,
) -> bool;
}
impl<S: SignatureScheme> SignatureScheme for Arc<S> {
type ValidatorId = S::ValidatorId;
type Signature = S::Signature;
type AggregateSignature = S::AggregateSignature;
type Signer = S::Signer;
fn verify(&self, validator: Self::ValidatorId, msg: &[u8], sig: &Self::Signature) -> bool {
self.as_ref().verify(validator, msg, sig)
}
fn aggregate(sigs: &[Self::Signature]) -> Self::AggregateSignature {
S::aggregate(sigs)
}
#[must_use]
fn verify_aggregate(
&self,
signers: &[Self::ValidatorId],
msg: &[u8],
sig: &Self::AggregateSignature,
) -> bool {
self.as_ref().verify_aggregate(signers, msg, sig)
}
}
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
pub struct Commit<S: SignatureScheme> {
pub end_time: u64,
pub validators: Vec<S::ValidatorId>,
pub signature: S::AggregateSignature,
}
pub trait Weights: Send + Sync {
type ValidatorId: ValidatorId;
fn total_weight(&self) -> u64;
fn weight(&self, validator: Self::ValidatorId) -> u64;
fn threshold(&self) -> u64 {
((self.total_weight() * 2) / 3) + 1
}
fn fault_thresold(&self) -> u64 {
(self.total_weight() - self.threshold()) + 1
}
fn proposer(&self, block: BlockNumber, round: RoundNumber) -> Self::ValidatorId;
}
impl<W: Weights> Weights for Arc<W> {
type ValidatorId = W::ValidatorId;
fn total_weight(&self) -> u64 {
self.as_ref().total_weight()
}
fn weight(&self, validator: Self::ValidatorId) -> u64 {
self.as_ref().weight(validator)
}
fn proposer(&self, block: BlockNumber, round: RoundNumber) -> Self::ValidatorId {
self.as_ref().proposer(block, round)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Error, Encode, Decode)]
pub enum BlockError {
#[error("invalid block")]
Fatal,
#[error("invalid block under local view")]
Temporal,
}
pub trait Block: Send + Sync + Clone + PartialEq + Debug + Encode + Decode {
type Id: Send + Sync + Copy + Clone + PartialEq + AsRef<[u8]> + Debug + Encode + Decode;
fn id(&self) -> Self::Id;
}
#[cfg(feature = "substrate")]
impl<B: sp_runtime::traits::Block> Block for B {
type Id = B::Hash;
fn id(&self) -> B::Hash {
self.hash()
}
}
#[async_trait]
pub trait Network: Send + Sync {
type ValidatorId: ValidatorId;
type SignatureScheme: SignatureScheme<ValidatorId = Self::ValidatorId>;
type Weights: Weights<ValidatorId = Self::ValidatorId>;
type Block: Block;
const BLOCK_PROCESSING_TIME: u32;
const LATENCY_TIME: u32;
fn block_time() -> u32 {
Self::BLOCK_PROCESSING_TIME + (3 * Self::LATENCY_TIME)
}
fn signer(&self) -> <Self::SignatureScheme as SignatureScheme>::Signer;
fn signature_scheme(&self) -> Self::SignatureScheme;
fn weights(&self) -> Self::Weights;
#[must_use]
fn verify_commit(
&self,
id: <Self::Block as Block>::Id,
commit: &Commit<Self::SignatureScheme>,
) -> bool {
if commit.validators.iter().collect::<HashSet<_>>().len() != commit.validators.len() {
return false;
}
if !self.signature_scheme().verify_aggregate(
&commit.validators,
&commit_msg(commit.end_time, id.as_ref()),
&commit.signature,
) {
return false;
}
let weights = self.weights();
commit.validators.iter().map(|v| weights.weight(*v)).sum::<u64>() >= weights.threshold()
}
async fn broadcast(&mut self, msg: SignedMessageFor<Self>);
async fn slash(&mut self, validator: Self::ValidatorId);
async fn validate(&mut self, block: &Self::Block) -> Result<(), BlockError>;
async fn add_block(
&mut self,
block: Self::Block,
commit: Commit<Self::SignatureScheme>,
) -> Self::Block;
}