Skip to content
This repository has been archived by the owner on Apr 17, 2019. It is now read-only.

Yac gate propagates correct round to Synchronizer #2231

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions irohad/consensus/yac/impl/yac_gate_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ namespace iroha {
current_hash_.vote_round, current_ledger_state_, block));
}

current_hash_ = hash;
auto public_keys = boost::copy_range<
shared_model::interface::types::PublicKeyCollectionType>(
msg.votes | boost::adaptors::transformed([](auto &vote) {
Expand All @@ -141,17 +140,15 @@ namespace iroha {
// if consensus agreed on nothing for commit
log_->info("Consensus skipped round, voted for nothing");
current_block_ = boost::none;
return rxcpp::observable<>::just<GateObject>(
AgreementOnNone(current_hash_.vote_round,
current_ledger_state_,
std::move(public_keys)));
return rxcpp::observable<>::just<GateObject>(AgreementOnNone(
hash.vote_round, current_ledger_state_, std::move(public_keys)));
}

log_->info("Voted for another block, waiting for sync");
current_block_ = boost::none;
auto model_hash = hash_provider_->toModelHash(hash);
return rxcpp::observable<>::just<GateObject>(
VoteOther(current_hash_.vote_round,
VoteOther(hash.vote_round,
current_ledger_state_,
std::move(public_keys),
std::move(model_hash)));
Expand Down Expand Up @@ -182,16 +179,12 @@ namespace iroha {
});
if (not has_same_proposals) {
log_->info("Proposal reject since all hashes are different");
return rxcpp::observable<>::just<GateObject>(
ProposalReject(current_hash_.vote_round,
current_ledger_state_,
std::move(public_keys)));
return rxcpp::observable<>::just<GateObject>(ProposalReject(
hash.vote_round, current_ledger_state_, std::move(public_keys)));
}
log_->info("Block reject since proposal hashes match");
return rxcpp::observable<>::just<GateObject>(
BlockReject(current_hash_.vote_round,
current_ledger_state_,
std::move(public_keys)));
return rxcpp::observable<>::just<GateObject>(BlockReject(
hash.vote_round, current_ledger_state_, std::move(public_keys)));
}
} // namespace yac
} // namespace consensus
Expand Down
107 changes: 107 additions & 0 deletions test/module/irohad/consensus/yac/yac_gate_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,113 @@ TEST_F(YacGateTest, DifferentCommit) {
ASSERT_TRUE(gate_wrapper.validate());
}

/**
* The fixture checks the following case for different types of commit messages
* (VoteOther, AgreementOnNone, BlockReject, ProposalReject):
* @given yac gate, in round (i, j) -> last block height is (i - 1)
* @when reject for round (i, j + 1) is received
* @then peer goes to round (i, j + 1)
*/
class CommitFromTheFuture : public YacGateTest {
public:
void SetUp() override {
YacGateTest::SetUp();
// make hash from block
EXPECT_CALL(*hash_provider, makeHash(_)).WillOnce(Return(expected_hash));

// generate order of peers
EXPECT_CALL(*peer_orderer, getOrdering(_, _))
.WillOnce(Return(ClusterOrdering::create({makePeer("fake_node")})));

EXPECT_CALL(*hash_gate, vote(expected_hash, _)).Times(1);

block_notifier.get_subscriber().on_next(BlockCreatorEvent{
RoundData{expected_proposal, expected_block}, round, ledger_state});

Hash actual_hash("actual_hash");
PublicKey actual_pubkey("actual_pubkey");
auto signature = std::make_shared<MockSignature>();
EXPECT_CALL(*signature, publicKey())
.WillRepeatedly(ReturnRefOfCopy(actual_pubkey));

future_round =
iroha::consensus::Round(round.block_round, round.reject_round + 1);
message.hash = YacHash(future_round, "actual_proposal", "actual_block");
message.signature = signature;
}

template <typename CommitType>
void validate() {
// verify that yac gate emit expected block
auto gate_wrapper = make_test_subscriber<CallExact>(gate->onOutcome(), 1);
gate_wrapper.subscribe([this](auto outcome) {
auto concrete_outcome = boost::get<CommitType>(outcome);

ASSERT_EQ(future_round, concrete_outcome.round);
});

outcome_notifier.get_subscriber().on_next(expected_commit);
ASSERT_TRUE(gate_wrapper.validate());
}

iroha::consensus::Round future_round;
};

/**
* @given yac gate, in round (i, j) -> last block height is (i - 1)
* @when reject for round (i, j + 1) is received
* @then peer goes to round (i, j + 1)
*/
TEST_F(CommitFromTheFuture, BlockReject) {
expected_commit = RejectMessage({message});

validate<iroha::consensus::BlockReject>();
}

/**
* @given yac gate, in round (i, j) -> last block height is (i - 1)
* @when reject with two proposals for round (i, j + 1) is received
* @then peer goes to round (i, j + 1)
*/
TEST_F(CommitFromTheFuture, ProposalReject) {
PublicKey second_actual_pubkey("actual_pubkey_2");
auto second_signature = std::make_shared<MockSignature>();
EXPECT_CALL(*second_signature, publicKey())
.WillRepeatedly(ReturnRefOfCopy(second_actual_pubkey));

VoteMessage second_message;
second_message.hash =
YacHash(future_round, "actual_proposal_2", "actual_block_2");
second_message.signature = second_signature;
expected_commit = RejectMessage({message, second_message});

validate<iroha::consensus::ProposalReject>();
}

/**
* @given yac gate, in round (i, j) -> last block height is (i - 1)
* @when commit for round (i, j + 1) is received
* @then peer goes to round (i, j + 1)
*/
TEST_F(CommitFromTheFuture, VoteOther) {
expected_commit = CommitMessage({message});

validate<iroha::consensus::VoteOther>();
}

/**
* @given yac gate, in round (i, j) -> last block height is (i - 1)
* @when commit without proposal (empty proposal hash) for round (i, j + 1) is
* received
* @then peer goes to round (i, j + 1)
*/
TEST_F(CommitFromTheFuture, AgreementOnNone) {
message.hash = YacHash(future_round, "", "");
expected_commit = CommitMessage({message});

validate<iroha::consensus::AgreementOnNone>();
}

class YacGateOlderTest : public YacGateTest {
void SetUp() override {
YacGateTest::SetUp();
Expand Down