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

View file

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

View file

@ -4,7 +4,7 @@ use parity_scale_codec::{Encode, Decode};
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tendermint_machine::{ext::*, Message, TendermintMachine, TendermintHandle}; use tendermint_machine::{ext::*, SignedMessage, TendermintMachine, TendermintHandle};
type TestValidatorId = u16; type TestValidatorId = u16;
type TestBlockId = u32; type TestBlockId = u32;
@ -80,7 +80,7 @@ impl Network for TestNetwork {
Arc::new(TestWeights) 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() { for handle in self.1.write().await.iter_mut() {
handle.messages.send(msg.clone()).await.unwrap(); handle.messages.send(msg.clone()).await.unwrap();
} }