Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
stringhandler committed May 2, 2024
1 parent cfbcd51 commit 2459cc7
Show file tree
Hide file tree
Showing 16 changed files with 149 additions and 197 deletions.
Expand Up @@ -29,14 +29,8 @@ impl ValidatorSignatureService for TariSignatureService {
}

impl VoteSignatureService for TariSignatureService {
fn verify(
&self,
signature: &ValidatorSignature,
leaf_hash: &FixedHash,
block_id: &BlockId,
decision: &QuorumDecision,
) -> bool {
let challenge = self.create_challenge(leaf_hash, block_id, decision);
fn verify(&self, signature: &ValidatorSignature, block_id: &BlockId, decision: &QuorumDecision) -> bool {
let challenge = self.create_challenge(block_id, decision);
signature.verify(challenge)
}
}
Expand Up @@ -1273,9 +1273,8 @@ where TConsensusSpec: ConsensusSpec
.epoch_manager
.get_validator_node(block.epoch(), &self.local_validator_addr)
.await?;
let leaf_hash = vn.get_node_hash(self.network);

let signature = self.vote_signing_service.sign_vote(&leaf_hash, block.id(), &decision);
let signature = self.vote_signing_service.sign_vote(block.id(), &decision);

Ok(VoteMessage {
epoch: block.epoch(),
Expand Down
56 changes: 8 additions & 48 deletions dan_layer/consensus/src/hotstuff/on_receive_foreign_proposal.rs
Expand Up @@ -22,6 +22,7 @@ use crate::{
hotstuff::{error::HotStuffError, pacemaker_handle::PaceMakerHandle, ProposalValidationError},
messages::ProposalMessage,
traits::ConsensusSpec,
validations,
};

const LOG_TARGET: &str = "tari::dan::consensus::hotstuff::on_receive_foreign_proposal";
Expand Down Expand Up @@ -73,13 +74,7 @@ where TConsensusSpec: ConsensusSpec
.await?;

let local_shard = self.epoch_manager.get_local_committee_shard(block.epoch()).await?;
if let Err(err) = self.validate_proposed_block(
&from,
&block,
committee_shard.shard(),
local_shard.shard(),
&foreign_receive_counter,
) {
if let Err(err) = self.validate_proposed_block(&from, &block, local_shard.shard(), &foreign_receive_counter) {
warn!(
target: LOG_TARGET,
"🔥 FOREIGN PROPOSAL: Invalid proposal from {}: {}. Ignoring.",
Expand Down Expand Up @@ -208,49 +203,14 @@ where TConsensusSpec: ConsensusSpec
&self,
from: &TConsensusSpec::Addr,
candidate_block: &Block,
foreign_shard: Shard,
local_shard: Shard,
foreign_receive_counter: &ForeignReceiveCounters,
) -> Result<(), ProposalValidationError> {
let Some(incoming_count) = candidate_block.get_foreign_counter(&local_shard) else {
debug!(target:LOG_TARGET, "Our bucket {local_shard:?} is missing reliability index in the proposed block {candidate_block:?}");
return Err(ProposalValidationError::MissingForeignCounters {
proposed_by: from.to_string(),
hash: *candidate_block.id(),
});
};
let current_count = foreign_receive_counter.get_count(&foreign_shard);
if current_count + 1 != incoming_count {
debug!(target:LOG_TARGET, "We were expecting the index to be {expected_count}, but the index was {incoming_count}", expected_count = current_count + 1);
return Err(ProposalValidationError::InvalidForeignCounters {
proposed_by: from.to_string(),
hash: *candidate_block.id(),
details: format!(
"Expected foreign receive count to be {} but it was {}",
current_count + 1,
incoming_count
),
});
}
if candidate_block.height().is_zero() || candidate_block.is_genesis() {
return Err(ProposalValidationError::ProposingGenesisBlock {
proposed_by: from.to_string(),
hash: *candidate_block.id(),
});
}

let calculated_hash = candidate_block.calculate_hash().into();
if calculated_hash != *candidate_block.id() {
return Err(ProposalValidationError::NodeHashMismatch {
proposed_by: from.to_string(),
hash: *candidate_block.id(),
calculated_hash,
});
}

// TODO: validate justify signatures
// self.validate_qc(candidate_block.justify(), committee)?;

Ok(())
validations::foreign_proposal_validations::check_foreign_proposal_message::<TConsensusSpec>(
from,
candidate_block,
local_shard,
foreign_receive_counter,
)
}
}
63 changes: 9 additions & 54 deletions dan_layer/consensus/src/hotstuff/vote_receiver.rs
Expand Up @@ -17,6 +17,7 @@ use crate::{
hotstuff::{error::HotStuffError, pacemaker_handle::PaceMakerHandle},
messages::VoteMessage,
traits::{ConsensusSpec, LeaderStrategy, VoteSignatureService},
validations,
};

const LOG_TARGET: &str = "tari::dan::consensus::hotstuff::on_receive_vote";
Expand Down Expand Up @@ -80,50 +81,24 @@ where TConsensusSpec: ConsensusSpec
message: VoteMessage,
check_leadership: bool,
) -> Result<bool, HotStuffError> {
// Is a committee member sending us this vote?
let committee = self.epoch_manager.get_local_committee(message.epoch).await?;
if !committee.contains(&from) {
return Err(HotStuffError::ReceivedMessageFromNonCommitteeMember {
epoch: message.epoch,
sender: from.to_string(),
context: "OnReceiveVote".to_string(),
});
}

// Are we the leader for the block being voted for?
let our_vn = self.epoch_manager.get_our_validator_node(message.epoch).await?;

let local_committee_shard = self.epoch_manager.get_local_committee_shard(message.epoch).await?;

// Get the sender shard, and check that they are in the local committee
let sender_vn = self.epoch_manager.get_validator_node(message.epoch, &from).await?;
if message.signature.public_key != sender_vn.public_key {
return Err(HotStuffError::RejectingVoteNotSentBySigner {
address: from.to_string(),
signer_public_key: message.signature.public_key.to_string(),
});
}

if !local_committee_shard.includes_substate_address(&sender_vn.shard_key) {
return Err(HotStuffError::ReceivedMessageFromNonCommitteeMember {
epoch: message.epoch,
sender: message.signature.public_key.to_string(),
context: "OnReceiveVote".to_string(),
});
}

let sender_leaf_hash = sender_vn.get_node_hash(self.network);

self.validate_vote_message(&message, &sender_leaf_hash)?;

let from = message.signature.public_key.clone();
validations::vote_validations::check_vote_message::<TConsensusSpec>(
&from,
&message,
&committee,
&local_committee_shard,
&our_vn,
&self.vote_signature_service,
)?;

let count = self.store.with_write_tx(|tx| {
Vote {
epoch: message.epoch,
block_id: message.block_id,
decision: message.decision,
sender_leaf_hash,
signature: message.signature,
}
.save(tx)?;
Expand Down Expand Up @@ -205,21 +180,18 @@ where TConsensusSpec: ConsensusSpec
}

let mut signatures = Vec::with_capacity(votes.len());
let mut leaf_hashes = Vec::with_capacity(votes.len());
for vote in votes {
if vote.decision != quorum_decision {
// We don't include votes that don't match the quorum decision
continue;
}
signatures.push(vote.signature);
leaf_hashes.push(vote.sender_leaf_hash);
}

signatures.sort_by(|a, b| a.public_key.cmp(&b.public_key));

vote_data = VoteData {
signatures,
leaf_hashes,
quorum_decision,
block,
};
Expand Down Expand Up @@ -255,26 +227,11 @@ where TConsensusSpec: ConsensusSpec

None
}

fn validate_vote_message(&self, message: &VoteMessage, sender_leaf_hash: &FixedHash) -> Result<(), HotStuffError> {
if !self.vote_signature_service.verify(
&message.signature,
sender_leaf_hash,
&message.block_id,
&message.decision,
) {
return Err(HotStuffError::InvalidVoteSignature {
signer_public_key: message.signature.public_key().to_string(),
});
}
Ok(())
}
}

fn create_qc(vote_data: VoteData) -> QuorumCertificate {
let VoteData {
signatures,
leaf_hashes,
quorum_decision,
block,
} = vote_data;
Expand All @@ -284,14 +241,12 @@ fn create_qc(vote_data: VoteData) -> QuorumCertificate {
block.epoch(),
block.shard(),
signatures,
leaf_hashes,
quorum_decision,
)
}

struct VoteData {
signatures: Vec<ValidatorSignature>,
leaf_hashes: Vec<FixedHash>,
quorum_decision: QuorumDecision,
block: Block,
}
25 changes: 5 additions & 20 deletions dan_layer/consensus/src/traits/signing_service.rs
Expand Up @@ -12,30 +12,15 @@ pub trait ValidatorSignatureService {
}

pub trait VoteSignatureService: ValidatorSignatureService {
fn create_challenge(
&self,
voter_leaf_hash: &FixedHash,
block_id: &BlockId,
decision: &QuorumDecision,
) -> FixedHash {
vote_signature_hasher()
.chain(voter_leaf_hash)
.chain(block_id)
.chain(decision)
.result()
fn create_challenge(&self, block_id: &BlockId, decision: &QuorumDecision) -> FixedHash {
vote_signature_hasher().chain(block_id).chain(decision).result()
}

fn sign_vote(&self, leaf_hash: &FixedHash, block_id: &BlockId, decision: &QuorumDecision) -> ValidatorSignature {
let challenge = self.create_challenge(leaf_hash, block_id, decision);
fn sign_vote(&self, block_id: &BlockId, decision: &QuorumDecision) -> ValidatorSignature {
let challenge = self.create_challenge(block_id, decision);
let signature = self.sign(challenge);
ValidatorSignature::new(self.public_key().clone(), signature)
}

fn verify(
&self,
signature: &ValidatorSignature,
leaf_hash: &FixedHash,
block_id: &BlockId,
decision: &QuorumDecision,
) -> bool;
fn verify(&self, signature: &ValidatorSignature, block_id: &BlockId, decision: &QuorumDecision) -> bool;
}
11 changes: 7 additions & 4 deletions dan_layer/consensus/src/validations/block_validations.rs
Expand Up @@ -6,6 +6,11 @@ use tari_dan_common_types::{committee::Committee, DerivableFromPublicKey};
use tari_dan_storage::consensus_models::Block;
use tari_epoch_manager::EpochManagerReader;

use crate::{
hotstuff::{HotStuffError, HotstuffConfig, ProposalValidationError},
traits::{ConsensusSpec, LeaderStrategy, VoteSignatureService},
};

pub async fn check_block<TConsensusSpec: ConsensusSpec>(
candidate_block: &Block,
epoch_manager: &TConsensusSpec::EpochManager,
Expand Down Expand Up @@ -172,7 +177,6 @@ pub async fn check_quorum_certificate<TConsensusSpec: ConsensusSpec>(
.into());
}

let mut vns = vec![];
for signature in qc.signatures() {
let vn = epoch_manager
.get_validator_node_by_public_key(qc.epoch(), signature.public_key())
Expand All @@ -189,11 +193,10 @@ pub async fn check_quorum_certificate<TConsensusSpec: ConsensusSpec>(
}
.into());
}
vns.push(vn.get_node_hash(candidate_block.network()));
}

for (sign, leaf) in qc.signatures().iter().zip(vns.iter()) {
let challenge = vote_signing_service.create_challenge(leaf, qc.block_id(), &qc.decision());
for sign in qc.signatures().iter() {
let challenge = vote_signing_service.create_challenge(qc.block_id(), &qc.decision());
if !sign.verify(challenge) {
return Err(ProposalValidationError::QCInvalidSignature { qc: qc.clone() }.into());
}
Expand Down

0 comments on commit 2459cc7

Please sign in to comment.