use borsh::{BorshDeserialize, BorshSerialize};
use ed25519_dalek::Verifier;
use crate::{
block_tree::{
accessors::internal::{BlockTreeError, BlockTreeSingleton},
pluggables::KVStore,
},
pacemaker::messages::TimeoutVote,
types::{
data_types::*,
signed_messages::{Certificate, Collector},
validator_set::*,
},
};
#[derive(Clone, BorshSerialize, BorshDeserialize, PartialEq, Eq)]
pub struct TimeoutCertificate {
pub chain_id: ChainID,
pub view: ViewNumber,
pub signatures: SignatureSet,
}
impl Certificate for TimeoutCertificate {
type Vote = TimeoutVote;
fn is_correct<K: KVStore>(
&self,
block_tree: &BlockTreeSingleton<K>,
) -> Result<bool, BlockTreeError> {
let validator_set_state = block_tree.validator_set_state()?;
if validator_set_state.update_decided() {
Ok(self.is_correctly_signed(validator_set_state.committed_validator_set()))
} else {
Ok(
self.is_correctly_signed(validator_set_state.committed_validator_set())
|| self.is_correctly_signed(validator_set_state.previous_validator_set()),
)
}
}
fn is_correctly_signed(&self, validator_set: &ValidatorSet) -> bool {
if self.signatures.len() != validator_set.len() {
return false;
}
let mut total_power: TotalPower = TotalPower::new(0);
for (signature, (signer, power)) in self
.signatures
.iter()
.zip(validator_set.validators_and_powers())
{
if let Some(signature) = signature {
if let Ok(signature) = Signature::from_slice(&signature.bytes()) {
if signer
.verify(
&(self.chain_id, self.view).try_to_vec().unwrap(),
&signature,
)
.is_ok()
{
total_power += power;
} else {
return false;
}
} else {
return false;
}
}
}
total_power >= validator_set.quorum()
}
}
#[derive(Clone, PartialEq)]
pub(crate) struct TimeoutVoteCollector {
chain_id: ChainID,
view: ViewNumber,
validator_set: ValidatorSet,
signature_set_power: TotalPower,
signature_set: SignatureSet,
}
impl Collector for TimeoutVoteCollector {
type Vote = TimeoutVote;
type Certificate = TimeoutCertificate;
fn new(chain_id: ChainID, view: ViewNumber, validator_set: ValidatorSet) -> Self {
let n = validator_set.len();
Self {
chain_id,
view,
validator_set,
signature_set_power: TotalPower::new(0),
signature_set: SignatureSet::new(n),
}
}
fn validator_set(&self) -> &ValidatorSet {
&self.validator_set
}
fn chain_id(&self) -> ChainID {
self.chain_id
}
fn view(&self) -> ViewNumber {
self.view
}
fn collect(&mut self, signer: &VerifyingKey, vote: TimeoutVote) -> Option<TimeoutCertificate> {
if self.chain_id != vote.chain_id || self.view != vote.view {
return None;
}
if let Some(pos) = self.validator_set.position(signer) {
if self.signature_set.get(pos).is_none() {
self.signature_set.set(pos, Some(vote.signature));
self.signature_set_power += *self.validator_set.power(signer).unwrap();
if self.signature_set_power >= self.validator_set.quorum() {
let collected_tc = TimeoutCertificate {
chain_id: self.chain_id,
view: self.view,
signatures: self.signature_set.clone(),
};
return Some(collected_tc);
}
}
}
None
}
}