From 6155d12160a485fe628fb63faefdf817cf4501ba Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Mon, 17 Oct 2022 03:15:13 -0400 Subject: [PATCH] Dedicated Commit object Restores sig aggregation API. --- substrate/tendermint/src/ext.rs | 37 ++++++++++++++++++++++++++----- substrate/tendermint/src/lib.rs | 26 +++++++++++++--------- substrate/tendermint/tests/ext.rs | 20 +++++++++++++---- 3 files changed, 63 insertions(+), 20 deletions(-) diff --git a/substrate/tendermint/src/ext.rs b/substrate/tendermint/src/ext.rs index 56d4a20d..748150d7 100644 --- a/substrate/tendermint/src/ext.rs +++ b/substrate/tendermint/src/ext.rs @@ -31,6 +31,21 @@ pub trait SignatureScheme: Send + Sync { fn sign(&self, msg: &[u8]) -> 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, + msg: &[u8], + signers: &[Self::ValidatorId], + sig: Self::AggregateSignature, + ) -> bool; +} + +#[derive(Clone, PartialEq, Debug, Encode, Decode)] +pub struct Commit { + pub validators: Vec, + pub signature: S::AggregateSignature, } pub trait Weights: Send + Sync { @@ -76,6 +91,21 @@ pub trait Network: Send + Sync { fn signature_scheme(&self) -> Arc; fn weights(&self) -> Arc; + #[must_use] + fn verify_commit( + &self, + id: ::Id, + commit: Commit, + ) -> bool { + if !self.signature_scheme().verify_aggregate(&id.encode(), &commit.validators, commit.signature) + { + return false; + } + + let weights = self.weights(); + commit.validators.iter().map(|v| weights.weight(*v)).sum::() >= weights.threshold() + } + async fn broadcast( &mut self, msg: SignedMessage< @@ -90,9 +120,6 @@ pub trait Network: Send + Sync { fn validate(&mut self, block: &Self::Block) -> Result<(), BlockError>; // Add a block and return the proposal for the next one - fn add_block( - &mut self, - block: Self::Block, - sigs: Vec<(Self::ValidatorId, ::Signature)>, - ) -> Self::Block; + fn add_block(&mut self, block: Self::Block, commit: Commit) + -> Self::Block; } diff --git a/substrate/tendermint/src/lib.rs b/substrate/tendermint/src/lib.rs index a1b4d387..7b398bfc 100644 --- a/substrate/tendermint/src/lib.rs +++ b/substrate/tendermint/src/lib.rs @@ -253,15 +253,19 @@ impl TendermintMachine { match machine.message(msg.msg).await { Ok(None) => (), Ok(Some(block)) => { - let sigs = machine - .log - .precommitted - .iter() - .filter_map(|(k, (id, sig))| { - Some((*k, sig.clone())).filter(|_| id == &block.id()) - }) - .collect(); - let proposal = machine.network.write().await.add_block(block, sigs); + let mut validators = vec![]; + let mut sigs = vec![]; + for (v, sig) in machine.log.precommitted.iter().filter_map(|(k, (id, sig))| { + Some((*k, sig.clone())).filter(|_| id == &block.id()) + }) { + validators.push(v); + sigs.push(sig); + } + + let proposal = machine.network.write().await.add_block( + block, + Commit { validators, signature: N::SignatureScheme::aggregate(&sigs) }, + ); machine.reset(proposal).await } Err(TendermintError::Malicious(validator)) => { @@ -400,13 +404,13 @@ impl TendermintMachine { if self.step == Step::Prevote { let (participation, weight) = self.log.message_instances(self.round, Data::Prevote(None)); // 34-35 - if participation > self.weights.threshold() { + if participation >= self.weights.threshold() { let timeout = self.timeout(Step::Prevote); self.timeouts.entry(Step::Prevote).or_insert(timeout); } // 44-46 - if weight > self.weights.threshold() { + if weight >= self.weights.threshold() { debug_assert!(self.broadcast(Data::Precommit(None)).await.is_none()); } } diff --git a/substrate/tendermint/tests/ext.rs b/substrate/tendermint/tests/ext.rs index 31dfca0c..478e213e 100644 --- a/substrate/tendermint/tests/ext.rs +++ b/substrate/tendermint/tests/ext.rs @@ -22,9 +22,23 @@ impl SignatureScheme for TestSignatureScheme { sig } + #[must_use] fn verify(&self, validator: u16, msg: &[u8], sig: [u8; 32]) -> bool { (sig[.. 2] == validator.to_le_bytes()) && (&sig[2 ..] == &[msg, &[0; 30]].concat()[.. 30]) } + + fn aggregate(sigs: &[[u8; 32]]) -> Vec<[u8; 32]> { + sigs.to_vec() + } + + #[must_use] + fn verify_aggregate(&self, msg: &[u8], signers: &[TestValidatorId], sigs: Vec<[u8; 32]>) -> bool { + assert_eq!(signers.len(), sigs.len()); + for sig in signers.iter().zip(sigs.iter()) { + assert!(self.verify(*sig.0, msg, *sig.1)); + } + true + } } struct TestWeights; @@ -91,12 +105,10 @@ impl Network for TestNetwork { block.valid } - fn add_block(&mut self, block: TestBlock, sigs: Vec<(u16, [u8; 32])>) -> TestBlock { + fn add_block(&mut self, block: TestBlock, commit: Commit) -> TestBlock { dbg!("Adding ", &block); assert!(block.valid.is_ok()); - for sig in sigs { - assert!(TestSignatureScheme(u16::MAX).verify(sig.0, &block.id().encode(), sig.1)); - } + assert!(self.verify_commit(block.id(), commit)); TestBlock { id: block.id + 1, valid: Ok(()) } } }