Skip to content

Commit

Permalink
fix: Leader as transaction ordering service
Browse files Browse the repository at this point in the history
Signed-off-by: Sam H. Smith <[email protected]>
  • Loading branch information
SamHSmith committed Sep 11, 2024
1 parent 995da4e commit 619b997
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 180 deletions.
79 changes: 61 additions & 18 deletions core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ mod pending {
view_change_index: usize,
transactions: &[CommittedTransaction],
consensus_estimation: Duration,
now_time_ms: u64,
) -> BlockHeader {
let prev_block_time =
prev_block.map_or(Duration::ZERO, |block| block.header().creation_time());
Expand All @@ -168,9 +169,7 @@ mod pending {
.max()
.expect("INTERNAL BUG: Block empty");

let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
let now = Duration::from_millis(now_time_ms);

// NOTE: Lower time bound must always be upheld for a valid block
// If the clock has drifted too far this block will be rejected
Expand Down Expand Up @@ -246,6 +245,24 @@ mod pending {
self,
view_change_index: usize,
state: &mut StateBlock<'_>,
) -> BlockBuilder<Chained> {
self.chain_with_creation_time(
view_change_index,
state,
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("INTERNAL BUG: Failed to get the current system time")
.as_millis()
.try_into()
.expect("Time should fit into u64"),
)
}
/// Chain the block with existing blockchain.
pub fn chain_with_creation_time(
self,
view_change_index: usize,
state: &mut StateBlock<'_>,
creation_time_ms: u64,
) -> BlockBuilder<Chained> {
let transactions = Self::categorize_transactions(self.0.transactions, state);

Expand All @@ -255,6 +272,7 @@ mod pending {
view_change_index,
&transactions,
state.world.parameters().sumeragi.consensus_estimation(),
creation_time_ms,
),
transactions,
}))
Expand All @@ -270,9 +288,21 @@ mod chained {
pub struct Chained(pub(super) BlockPayload);

impl BlockBuilder<Chained> {
/// Sign this block and get [`SignedBlock`].
/// Sign this block as Leader and get [`SignedBlock`].
pub fn sign(self, private_key: &PrivateKey) -> WithEvents<ValidBlock> {
WithEvents::new(ValidBlock(self.0 .0.sign(private_key)))
self.sign_with_peer_topology_index(private_key, 0)
}
/// Sign this block and get [`SignedBlock`].
pub fn sign_with_peer_topology_index(
self,
private_key: &PrivateKey,
peer_topology_index: u64,
) -> WithEvents<ValidBlock> {
WithEvents::new(ValidBlock(
self.0
.0
.sign_with_peer_topology_index(private_key, peer_topology_index),
))
}
}
}
Expand All @@ -299,18 +329,16 @@ mod valid {
topology: &Topology,
) -> Result<(), SignatureVerificationError> {
let leader_index = topology.leader_index();
let mut block_signatures = block.signatures();
let mut leader_signatures =
topology.filter_signatures_by_roles(&[Role::Leader], block.signatures());

let leader_signature = match block_signatures.next() {
let leader_signature = match leader_signatures.next() {
Some(BlockSignature(signatory, signature))
if usize::try_from(*signatory)
.map_err(|_err| SignatureVerificationError::LeaderMissing)?
== leader_index =>
{
let mut additional_leader_signatures =
topology.filter_signatures_by_roles(&[Role::Leader], block_signatures);

if additional_leader_signatures.next().is_some() {
if leader_signatures.next().is_some() {
return Err(SignatureVerificationError::DuplicateSignatures {
signatory: leader_index,
});
Expand Down Expand Up @@ -390,9 +418,11 @@ mod valid {
topology: &Topology,
) -> Result<(), SignatureVerificationError> {
let proxy_tail_index = topology.proxy_tail_index();
let mut signatures = block.signatures().rev();
let mut signatures = block.signatures();

let proxy_tail_signature = match signatures.next() {
let proxy_tail_signature = match signatures
.find(|BlockSignature(signatory, _signature)| *signatory == proxy_tail_index as u64)
{
Some(BlockSignature(signatory, signature))
if usize::try_from(*signatory)
.map_err(|_err| SignatureVerificationError::ProxyTailMissing)?
Expand Down Expand Up @@ -645,7 +675,6 @@ mod valid {
.expect("INTERNAL BUG: Number of peers exceeds usize::MAX");
let signatory = &topology.as_ref()[signatory_idx];

assert_ne!(Role::Leader, topology.role(signatory));
if topology.view_change_index() == 0 {
assert_ne!(Role::ObservingPeer, topology.role(signatory),);
}
Expand All @@ -672,17 +701,31 @@ mod valid {
) -> WithEvents<Result<Vec<BlockSignature>, SignatureVerificationError>> {
let prev_signatures = self.0.replace_signatures_unchecked(signatures);

if let Err(err) = Self::verify_leader_signature(self.as_ref(), topology)
.and_then(|()| Self::verify_validator_signatures(self.as_ref(), topology))
.and_then(|()| Self::verify_no_undefined_signatures(self.as_ref(), topology))
{
if let Err(err) = self.verify_all_signatures(topology) {
self.0.replace_signatures_unchecked(prev_signatures);
WithEvents::new(Err(err))
} else {
WithEvents::new(Ok(prev_signatures))
}
}

/// Verify block signatures
///
/// # Errors
///
/// - Signatures don't contain the leader signature
/// - Signatures contain duplicate signatures
/// - Signatures contain unknown signatories
/// - Signatures contain incorrect signatures
pub fn verify_all_signatures(
&self,
topology: &Topology,
) -> Result<(), SignatureVerificationError> {
Self::verify_leader_signature(self.as_ref(), topology)
.and_then(|()| Self::verify_validator_signatures(self.as_ref(), topology))
.and_then(|()| Self::verify_no_undefined_signatures(self.as_ref(), topology))
}

/// commit block to the store.
///
/// # Errors
Expand Down
Loading

0 comments on commit 619b997

Please sign in to comment.