Implement usage of the signature scheme

This commit is contained in:
Luke Parker 2022-10-16 10:20:29 -04:00
parent 987aa5189a
commit 329a48c19d
No known key found for this signature in database
GPG key ID: F9F1386DB1E119B6
3 changed files with 48 additions and 19 deletions

View file

@ -3,7 +3,7 @@ use std::sync::Arc;
use parity_scale_codec::{Encode, Decode};
use crate::Message;
use crate::SignedMessage;
pub trait ValidatorId:
Send + Sync + Clone + Copy + PartialEq + Eq + Hash + Debug + Encode + Decode
@ -20,10 +20,10 @@ pub struct BlockNumber(pub u32);
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode)]
pub struct Round(pub u16);
pub trait SignatureScheme {
pub trait SignatureScheme: Send + Sync {
type ValidatorId: ValidatorId;
type Signature: Clone + Copy + PartialEq;
type AggregateSignature: Clone + PartialEq;
type Signature: Send + Sync + Clone + Copy + PartialEq + Debug + Encode + Decode;
type AggregateSignature: Send + Sync + Clone + PartialEq + Debug + Encode + Decode;
fn sign(&self, msg: &[u8]) -> Self::Signature;
#[must_use]
@ -65,7 +65,7 @@ pub trait Block: Send + Sync + Clone + PartialEq + Debug + Encode + Decode {
#[async_trait::async_trait]
pub trait Network: Send + Sync {
type ValidatorId: ValidatorId;
type SignatureScheme: SignatureScheme;
type SignatureScheme: SignatureScheme<ValidatorId = Self::ValidatorId>;
type Weights: Weights<ValidatorId = Self::ValidatorId>;
type Block: Block;
@ -75,7 +75,14 @@ pub trait Network: Send + Sync {
fn signature_scheme(&self) -> Arc<Self::SignatureScheme>;
fn weights(&self) -> Arc<Self::Weights>;
async fn broadcast(&mut self, msg: Message<Self::ValidatorId, Self::Block>);
async fn broadcast(
&mut self,
msg: SignedMessage<
Self::ValidatorId,
Self::Block,
<Self::SignatureScheme as SignatureScheme>::Signature,
>,
);
// TODO: Should this take a verifiable reason?
async fn slash(&mut self, validator: Self::ValidatorId);

View file

@ -1,3 +1,5 @@
use core::fmt::Debug;
use std::{
sync::Arc,
time::{Instant, Duration},
@ -54,6 +56,12 @@ pub struct Message<V: ValidatorId, B: Block> {
data: Data<B>,
}
#[derive(Clone, PartialEq, Debug, Encode, Decode)]
pub struct SignedMessage<V: ValidatorId, B: Block, S: Clone + PartialEq + Debug + Encode + Decode> {
msg: Message<V, B>,
sig: S,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode)]
pub enum TendermintError<V: ValidatorId> {
Malicious(V),
@ -62,6 +70,7 @@ pub enum TendermintError<V: ValidatorId> {
pub struct TendermintMachine<N: Network> {
network: Arc<RwLock<N>>,
signer: Arc<N::SignatureScheme>,
weights: Arc<N::Weights>,
proposer: N::ValidatorId,
@ -81,7 +90,9 @@ pub struct TendermintMachine<N: Network> {
pub struct TendermintHandle<N: Network> {
// Messages received
pub messages: mpsc::Sender<Message<N::ValidatorId, N::Block>>,
pub messages: mpsc::Sender<
SignedMessage<N::ValidatorId, N::Block, <N::SignatureScheme as SignatureScheme>::Signature>,
>,
// Async task executing the machine
pub handle: JoinHandle<()>,
}
@ -106,7 +117,9 @@ impl<N: Network + 'static> TendermintMachine<N> {
let msg = Message { sender: self.proposer, number: self.number, round: self.round, data };
let res = self.message(msg.clone()).await.unwrap();
self.step = step; // TODO: Before or after the above handling call?
self.network.write().await.broadcast(msg).await;
let sig = self.signer.sign(&msg.encode());
self.network.write().await.broadcast(SignedMessage { msg, sig }).await;
res
}
@ -167,10 +180,12 @@ impl<N: Network + 'static> TendermintMachine<N> {
TendermintHandle {
messages: msg_send,
handle: tokio::spawn(async move {
let signer = network.signature_scheme();
let weights = network.weights();
let network = Arc::new(RwLock::new(network));
let mut machine = TendermintMachine {
network,
signer,
weights: weights.clone(),
proposer,
@ -214,17 +229,24 @@ impl<N: Network + 'static> TendermintMachine<N> {
// If there's a message, handle it
match msg_recv.try_recv() {
Ok(msg) => match machine.message(msg).await {
Ok(None) => (),
Ok(Some(block)) => {
let proposal = machine.network.write().await.add_block(block);
machine.reset(proposal).await
Ok(msg) => {
if !machine.signer.verify(msg.msg.sender, &msg.msg.encode(), msg.sig) {
yield_now().await;
continue;
}
Err(TendermintError::Malicious(validator)) => {
machine.network.write().await.slash(validator).await
match machine.message(msg.msg).await {
Ok(None) => (),
Ok(Some(block)) => {
let proposal = machine.network.write().await.add_block(block);
machine.reset(proposal).await
}
Err(TendermintError::Malicious(validator)) => {
machine.network.write().await.slash(validator).await
}
Err(TendermintError::Temporal) => (),
}
Err(TendermintError::Temporal) => (),
},
}
Err(TryRecvError::Empty) => yield_now().await,
Err(TryRecvError::Disconnected) => break,
}

View file

@ -4,7 +4,7 @@ use parity_scale_codec::{Encode, Decode};
use tokio::sync::RwLock;
use tendermint_machine::{ext::*, Message, TendermintMachine, TendermintHandle};
use tendermint_machine::{ext::*, SignedMessage, TendermintMachine, TendermintHandle};
type TestValidatorId = u16;
type TestBlockId = u32;
@ -80,7 +80,7 @@ impl Network for TestNetwork {
Arc::new(TestWeights)
}
async fn broadcast(&mut self, msg: Message<TestValidatorId, Self::Block>) {
async fn broadcast(&mut self, msg: SignedMessage<TestValidatorId, Self::Block, [u8; 32]>) {
for handle in self.1.write().await.iter_mut() {
handle.messages.send(msg.clone()).await.unwrap();
}