Skip to content

Commit

Permalink
Updated threshold logic to use weights instead of amount of signers
Browse files Browse the repository at this point in the history
  • Loading branch information
ElFantasma committed Mar 21, 2024
1 parent 283ae7c commit 4c8e981
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 37 deletions.
7 changes: 4 additions & 3 deletions node/actors/bft/src/leader/replica_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ impl StateMachine {
});
}

// Check that the message signer is in the validator set.
// Check that the message signer is in the validator committee.
if !self.config.genesis().validators.contains(author) {
return Err(Error::NonValidatorSigner {
signer: author.clone(),
Expand Down Expand Up @@ -140,8 +140,9 @@ impl StateMachine {
by_proposal.entry(msg.msg.proposal).or_default().push(msg);
}
let threshold = self.config.genesis().validators.threshold();
let Some((_, replica_messages)) =
by_proposal.into_iter().find(|(_, v)| v.len() >= threshold)
let Some((_, replica_messages)) = by_proposal
.into_iter()
.find(|(_, v)| self.config.genesis().validators.weight_from_msgs(v) >= threshold)
else {
return Ok(());
};
Expand Down
11 changes: 7 additions & 4 deletions node/actors/bft/src/leader/replica_prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,21 +144,24 @@ impl StateMachine {
.insert(author.clone(), signed_message);

// Now we check if we have enough messages to continue.
let num_messages = self
let messages: Vec<&validator::Signed<validator::ReplicaPrepare>> = self
.prepare_message_cache
.get(&message.view.number)
.unwrap()
.len();
.values()
.collect();

if num_messages < self.config.genesis().validators.threshold() {
let weight = self.config.genesis().validators.weight_from_msgs(&messages);
let threshold = self.config.genesis().validators.threshold();
if weight < threshold {
return Ok(());
}

// Remove replica prepare messages for this view, so that we don't create a new block proposal
// for this same view if we receive another replica prepare message after this.
self.prepare_message_cache.remove(&message.view.number);

debug_assert_eq!(num_messages, self.config.genesis().validators.threshold());
debug_assert!(weight >= threshold);

// ----------- Update the state machine --------------

Expand Down
19 changes: 17 additions & 2 deletions node/libs/roles/src/validator/messages/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ pub struct ValidatorCommittee {
}

impl ValidatorCommittee {
/// Required weight to verify signatures.
const THRESHOLD: usize = 100_00;

/// Creates a new ValidatorCommittee from a list of validator public keys.
pub fn new(validators: impl IntoIterator<Item = WeightedValidator>) -> anyhow::Result<Self> {
let mut set = BTreeSet::new();
Expand Down Expand Up @@ -155,7 +158,7 @@ impl ValidatorCommittee {

/// Signature threshold for this validator set.
pub fn threshold(&self) -> usize {
threshold(self.len())
Self::THRESHOLD
}

/// Maximal number of faulty replicas allowed in this validator set.
Expand All @@ -164,14 +167,26 @@ impl ValidatorCommittee {
}

/// Compute the sum of signers weights.
pub fn weight(&self, signers: Signers) -> usize {
pub fn weight_from_signers(&self, signers: Signers) -> usize {
self.weights
.iter()
.enumerate()
.filter(|(i, _)| signers.0[*i])
.map(|(_, weight)| weight)
.sum()
}

/// Compute the sum of signers weights.
pub fn weight_from_msgs<T: Variant<Msg>>(&self, signed: &Vec<&validator::Signed<T>>) -> usize {
signed
.iter()
.map(|s| {
self.weights[self
.index(&s.key)
.expect("Signer is not in validator committee")]
})
.sum()
}
}

/// Calculate the consensus threshold, the minimum number of votes for any consensus action to be valid,
Expand Down
22 changes: 9 additions & 13 deletions node/libs/roles/src/validator/messages/leader_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ pub enum CommitQCVerifyError {
/// Bad signer set.
#[error("signers set doesn't match genesis")]
BadSignersSet,
/// Not enough signers.
#[error("not enough signers: got {got}, want {want}")]
NotEnoughSigners {
/// Got signers.
/// Weight not reached.
#[error("Signers have not reached wanted weight: got {got}, want {want}")]
WeightNotReached {
/// Got weight.
got: usize,
/// Want signers.
/// Want weight.
want: usize,
},
/// Bad signature.
Expand Down Expand Up @@ -101,15 +101,11 @@ impl CommitQC {
}

// Verify the signer's weights is enough.
// TODO replace threshold check
let _weight = genesis.validators.weight(self.signers.clone());

// Verify that we have enough signers.
let num_signers = self.signers.count();
let weight = genesis.validators.weight_from_signers(self.signers.clone());
let threshold = genesis.validators.threshold();
if num_signers < threshold {
return Err(Error::NotEnoughSigners {
got: num_signers,
if weight < threshold {
return Err(Error::WeightNotReached {
got: weight,
want: threshold,
});
}
Expand Down
22 changes: 10 additions & 12 deletions node/libs/roles/src/validator/messages/leader_prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ pub enum PrepareQCVerifyError {
/// Bad message format.
#[error(transparent)]
BadFormat(anyhow::Error),
/// Not enough signers.
#[error("not enough signers: got {got}, want {want}")]
NotEnoughSigners {
/// Got signers.
/// Weight not reached.
#[error("Signers have not reached wanted weight: got {got}, want {want}")]
WeightNotReached {
/// Got weight.
got: usize,
/// Want signers.
/// Want weight.
want: usize,
},
/// Bad signature.
Expand Down Expand Up @@ -127,14 +127,12 @@ impl PrepareQC {
sum |= signers;
}

let weight = genesis.validators.weight(sum.clone());
dbg!(weight);

// Verify that we have enough signers.
// Verify the signer's weights is enough.
let weight = genesis.validators.weight_from_signers(sum.clone());
let threshold = genesis.validators.threshold();
if sum.count() < threshold {
return Err(Error::NotEnoughSigners {
got: sum.count(),
if weight < threshold {
return Err(Error::WeightNotReached {
got: weight,
want: threshold,
});
}
Expand Down
9 changes: 6 additions & 3 deletions node/libs/roles/src/validator/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ fn test_commit_qc() {
} else {
assert_matches!(
qc.verify(&setup1.genesis),
Err(Error::NotEnoughSigners { .. })
Err(Error::WeightNotReached { .. })
);
}

Expand Down Expand Up @@ -265,7 +265,7 @@ fn test_prepare_qc() {
} else {
assert_matches!(
qc.verify(&setup1.genesis),
Err(Error::NotEnoughSigners { .. })
Err(Error::WeightNotReached { .. })
);
}

Expand Down Expand Up @@ -306,6 +306,9 @@ fn test_validator_committee_weights() {
let key = &setup.keys[n];
qc.add(&key.sign_msg(msg.clone()), &setup.genesis);
let signers = &qc.map[&msg];
assert_eq!(genesis.validators.weight(signers.clone()), *weight);
assert_eq!(
genesis.validators.weight_from_signers(signers.clone()),
*weight
);
}
}

0 comments on commit 4c8e981

Please sign in to comment.