vrf-pbft 0.1.0

A Rust implementation of VRF-enhanced PBFT consensus protocol
Documentation
use vrf_pbft::pbft::stage::validate_transition;
use vrf_pbft::pbft::{Message, Round};
use vrf_pbft::types::Block;
use vrf_pbft::{Role, Stage};

#[test]
fn valid_stage_transitions() {
    assert!(validate_transition(Stage::Idle, Stage::PrePrepare).is_ok());
    assert!(validate_transition(Stage::PrePrepare, Stage::Prepare).is_ok());
    assert!(validate_transition(Stage::Prepare, Stage::Commit).is_ok());
    assert!(validate_transition(Stage::Commit, Stage::Reply).is_ok());
    assert!(validate_transition(Stage::Reply, Stage::Done).is_ok());
}

#[test]
fn invalid_stage_transitions() {
    assert!(validate_transition(Stage::Idle, Stage::Commit).is_err());
    assert!(validate_transition(Stage::Prepare, Stage::PrePrepare).is_err());
    assert!(validate_transition(Stage::Reply, Stage::Prepare).is_err());
    assert!(validate_transition(Stage::Done, Stage::Idle).is_err());
}

#[test]
fn round_vote_counting() {
    let mut round = Round::new(1, Role::Proposer, 3);
    assert_eq!(round.prepare_count(), 0);
    assert!(!round.has_prepare_quorum());

    round.add_prepare_vote(1);
    round.add_prepare_vote(2);
    assert_eq!(round.prepare_count(), 2);
    assert!(!round.has_prepare_quorum());

    round.add_prepare_vote(3);
    assert_eq!(round.prepare_count(), 3);
    assert!(round.has_prepare_quorum());
}

#[test]
fn round_commit_quorum() {
    let mut round = Round::new(1, Role::Proposer, 2);
    round.add_commit_vote(1);
    assert!(!round.has_commit_quorum());
    round.add_commit_vote(2);
    assert!(round.has_commit_quorum());
}

#[test]
fn round_stage_advancement() {
    let mut round = Round::new(1, Role::Proposer, 3);
    assert_eq!(round.stage(), Stage::PrePrepare);

    round.advance(Stage::Prepare).unwrap();
    assert_eq!(round.stage(), Stage::Prepare);

    round.advance(Stage::Commit).unwrap();
    assert_eq!(round.stage(), Stage::Commit);

    round.advance(Stage::Reply).unwrap();
    assert_eq!(round.stage(), Stage::Reply);

    round.advance(Stage::Done).unwrap();
    assert_eq!(round.stage(), Stage::Done);
}

#[test]
fn message_pre_prepare_contains_block() {
    let block = Block::genesis();
    let msg = Message::pre_prepare(1, 1, block.clone());
    assert_eq!(msg.source, 1);
    assert_eq!(msg.round, 1);
    assert!(msg.block.is_some());
    assert!(msg.vote.is_none());
}

#[test]
fn message_prepare_contains_vote() {
    let block = Block::genesis();
    let msg = Message::prepare(2, 1, block.hash(), true);
    assert_eq!(msg.source, 2);
    assert!(msg.vote.as_ref().unwrap().approve);
    assert!(msg.block.is_none());
}

#[test]
fn message_hashing_is_deterministic() {
    let block = Block::genesis();
    let msg1 = Message::pre_prepare(1, 1, block.clone());
    let msg2 = Message::pre_prepare(1, 1, block);
    assert_eq!(msg1.hash(), msg2.hash());
}