Skip to content

Commit

Permalink
Merge pull request #2073 from AntelopeIO/vote_message_receive
Browse files Browse the repository at this point in the history
IF:Unification: Process received Vote message
  • Loading branch information
linh2931 authored Jan 17, 2024
2 parents 0013034 + 6242336 commit 8cf39ec
Show file tree
Hide file tree
Showing 10 changed files with 300 additions and 106 deletions.
25 changes: 23 additions & 2 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,28 @@ void block_state::set_trxs_metas( deque<transaction_metadata_ptr>&& trxs_metas,
cached_trxs = std::move( trxs_metas );
}

// Called from net threads
bool block_state::aggregate_vote(const hs_vote_message& vote) {
const auto& finalizers = active_finalizer_policy->finalizers;
auto it = std::find_if(finalizers.begin(),
finalizers.end(),
[&](const auto& finalizer) { return finalizer.public_key == vote.finalizer_key; });

if (it != finalizers.end()) {
auto index = std::distance(finalizers.begin(), it);
const digest_type& digest = vote.strong ? strong_digest : weak_digest;
return pending_qc.add_vote(vote.strong,
#warning TODO change to use std::span if possible
std::vector<uint8_t>{digest.data(), digest.data() + digest.data_size()},
index,
vote.finalizer_key,
vote.sig);
} else {
wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) );
return false;
}
}

std::optional<quorum_certificate> block_state::get_best_qc() const {
auto block_number = block_num();

Expand All @@ -69,9 +91,8 @@ std::optional<quorum_certificate> block_state::get_best_qc() const {
}
}

#warning TODO valid_quorum_certificate constructor can assert. Implement an extract method in pending_quorum_certificate for this.
// extract valid QC from pending_qc
valid_quorum_certificate valid_qc_from_pending(pending_qc);
valid_quorum_certificate valid_qc_from_pending = pending_qc.to_valid_quorum_certificate();

// if valid_qc does not have value, consider valid_qc_from_pending only
if( !valid_qc ) {
Expand Down
18 changes: 16 additions & 2 deletions libraries/chain/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,20 @@ struct block_data_t {
}, v);
}

// called from net thread
bool aggregate_vote(const hs_vote_message& vote) {
return std::visit(
overloaded{[](const block_data_legacy_t&) {
// We can be late in switching to Instant Finality
// and receive votes from those already having switched.
return false; },
[&](const block_data_new_t& bd) {
auto bsp = bd.fork_db.get_block(vote.proposal_id);
return bsp && bsp->aggregate_vote(vote); }
},
v);
}

signed_block_ptr fork_db_fetch_block_by_num(uint32_t block_num) const {
return std::visit([&](const auto& bd) -> signed_block_ptr {
auto bsp = bd.fork_db.search_on_branch(bd.fork_db.head()->id(), block_num);
Expand Down Expand Up @@ -4194,8 +4208,8 @@ void controller::get_finalizer_state( finalizer_state& fs ) const {
}

// called from net threads
void controller::notify_hs_message( const uint32_t connection_id, const hs_message& msg ) {
my->pacemaker->on_hs_msg(connection_id, msg);
bool controller::process_vote_message( const hs_vote_message& vote ) {
return my->block_data.aggregate_vote(vote);
};

const producer_authority_schedule& controller::active_producers()const {
Expand Down
56 changes: 38 additions & 18 deletions libraries/chain/hotstuff/hotstuff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ inline std::vector<uint32_t> bitset_to_vector(const hs_bitset& bs) {

bool pending_quorum_certificate::votes_t::add_vote(const std::vector<uint8_t>& proposal_digest, size_t index,
const bls_public_key& pubkey, const bls_signature& new_sig) {
if (_bitset[index])
if (_bitset[index]) {
return false; // shouldn't be already present
if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig))
}
if (!fc::crypto::blslib::verify(pubkey, proposal_digest, new_sig)) {
wlog( "signature from finalizer ${i} cannot be verified", ("i", index) );
return false;
}
_bitset.set(index);
_sig = fc::crypto::blslib::aggregate({_sig, new_sig}); // works even if _sig is default initialized (fp2::zero())
return true;
Expand All @@ -38,9 +41,14 @@ void pending_quorum_certificate::votes_t::reset(size_t num_finalizers) {
_sig = bls_signature();
}

pending_quorum_certificate::pending_quorum_certificate()
: _mtx(std::make_unique<std::mutex>()) {
}

pending_quorum_certificate::pending_quorum_certificate(size_t num_finalizers, size_t quorum)
: _num_finalizers(num_finalizers)
, _quorum(quorum) {
, _quorum(quorum)
, _mtx(std::make_unique<std::mutex>()) {
_weak_votes.resize(num_finalizers);
_strong_votes.resize(num_finalizers);
}
Expand All @@ -54,11 +62,13 @@ pending_quorum_certificate::pending_quorum_certificate(const fc::sha256& propos
}

bool pending_quorum_certificate::is_quorum_met() const {
std::lock_guard g(*_mtx);
return _state == state_t::weak_achieved || _state == state_t::weak_final || _state == state_t::strong;
}

void pending_quorum_certificate::reset(const fc::sha256& proposal_id, const digest_type& proposal_digest,
size_t num_finalizers, size_t quorum) {
std::lock_guard g(*_mtx);
_proposal_id = proposal_id;
_proposal_digest.assign(proposal_digest.data(), proposal_digest.data() + 32);
_quorum = quorum;
Expand All @@ -68,6 +78,7 @@ void pending_quorum_certificate::reset(const fc::sha256& proposal_id, const dige
_state = state_t::unrestricted;
}

// called by add_vote, already protected by mutex
bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& proposal_digest, size_t index,
const bls_public_key& pubkey, const bls_signature& sig) {
assert(index < _num_finalizers);
Expand Down Expand Up @@ -99,6 +110,7 @@ bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& pro
return true;
}

// called by add_vote, already protected by mutex
bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& proposal_digest, size_t index,
const bls_public_key& pubkey, const bls_signature& sig) {
assert(index < _num_finalizers);
Expand Down Expand Up @@ -134,12 +146,35 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& propo
return true;
}

// thread safe
bool pending_quorum_certificate::add_vote(bool strong, const std::vector<uint8_t>& proposal_digest, size_t index,
const bls_public_key& pubkey, const bls_signature& sig) {
std::lock_guard g(*_mtx);
return strong ? add_strong_vote(proposal_digest, index, pubkey, sig)
: add_weak_vote(proposal_digest, index, pubkey, sig);
}

// thread safe
valid_quorum_certificate pending_quorum_certificate::to_valid_quorum_certificate() const {
std::lock_guard g(*_mtx);

valid_quorum_certificate valid_qc;

valid_qc._proposal_id = _proposal_id;
valid_qc._proposal_digest = _proposal_digest;
if( _state == state_t::strong ) {
valid_qc._strong_votes = _strong_votes._bitset;
valid_qc._sig = _strong_votes._sig;
} else if (is_quorum_met()) {
valid_qc._strong_votes = _strong_votes._bitset;
valid_qc._weak_votes = _weak_votes._bitset;
valid_qc._sig = fc::crypto::blslib::aggregate({_strong_votes._sig, _weak_votes._sig});
} else
assert(0); // this should be called only when we have a valid qc.

return valid_qc;
}

// ================== begin compatibility functions =======================
// these are present just to make the tests still work. will be removed.
// these assume *only* strong votes.
Expand All @@ -155,21 +190,6 @@ std::string pending_quorum_certificate::get_votes_string() const {
}
// ================== end compatibility functions =======================


valid_quorum_certificate::valid_quorum_certificate(const pending_quorum_certificate& qc)
: _proposal_id(qc._proposal_id)
, _proposal_digest(qc._proposal_digest) {
if (qc._state == pending_quorum_certificate::state_t::strong) {
_strong_votes = qc._strong_votes._bitset;
_sig = qc._strong_votes._sig;
} else if (qc.is_quorum_met()) {
_strong_votes = qc._strong_votes._bitset;
_weak_votes = qc._weak_votes._bitset;
_sig = fc::crypto::blslib::aggregate({qc._strong_votes._sig, qc._weak_votes._sig});
} else
assert(0); // this should be called only when we have a valid qc.
}

valid_quorum_certificate::valid_quorum_certificate(
const fc::sha256& proposal_id, const std::vector<uint8_t>& proposal_digest,
const std::vector<uint32_t>& strong_votes, // bitset encoding, following canonical order
Expand Down
2 changes: 1 addition & 1 deletion libraries/chain/hotstuff/qc_chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ namespace eosio::chain {
("id", _id));

//fc_tlog(_logger, " === update_high_qc : _current_qc ===");
update_high_qc(_current_qc);
update_high_qc(_current_qc.to_valid_quorum_certificate());
fc_dlog(_logger, " === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ",
("block_num", p->block_num())
("phase_counter", p->phase_counter)
Expand Down
80 changes: 56 additions & 24 deletions libraries/chain/hotstuff/test/hotstuff_tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,67 +100,67 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
pubkey.push_back(k.get_public_key());

auto weak_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index) {
return qc.add_weak_vote(digest, index, pubkey[index], sk[index].sign(digest));
return qc.add_vote(false, digest, index, pubkey[index], sk[index].sign(digest));
};

auto strong_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index) {
return qc.add_strong_vote(digest, index, pubkey[index], sk[index].sign(digest));
return qc.add_vote(true, digest, index, pubkey[index], sk[index].sign(digest));
};

{
pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);

// add one weak vote
// -----------------
weak_vote(qc, digest, 0);
BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
BOOST_CHECK(qc.is_quorum_met());

// add duplicate weak vote
// -----------------------
bool ok = weak_vote(qc, digest, 0);
BOOST_CHECK(!ok); // vote was a duplicate
BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
BOOST_CHECK(qc.is_quorum_met());

// add another weak vote
// ---------------------
weak_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc._state, state_t::weak_final);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final);
}

{
pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);

// add a weak vote
// ---------------
weak_vote(qc, digest, 0);
BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
BOOST_CHECK(qc.is_quorum_met());

// add a strong vote
// -----------------
strong_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc._state, state_t::strong);
BOOST_CHECK_EQUAL(qc.state(), state_t::strong);
BOOST_CHECK(qc.is_quorum_met());
}

{
pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);

// add a strong vote
// -----------------
strong_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc._state, state_t::strong);
BOOST_CHECK_EQUAL(qc.state(), state_t::strong);
BOOST_CHECK(qc.is_quorum_met());

// add a strong vote
// -----------------
strong_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc._state, state_t::strong);
BOOST_CHECK_EQUAL(qc.state(), state_t::strong);
BOOST_CHECK(qc.is_quorum_met());
}

Expand All @@ -170,32 +170,48 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
// add a weak vote
// ---------------
weak_vote(qc, digest, 0);
BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
BOOST_CHECK(!qc.is_quorum_met());

// add a strong vote
// -----------------
strong_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc._state, state_t::weak_achieved);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
BOOST_CHECK(qc.is_quorum_met());

{
pending_quorum_certificate qc2(qc);
pending_quorum_certificate qc2(std::move(qc));

// add a weak vote
// ---------------
weak_vote(qc2, digest, 2);
BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final);
BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
BOOST_CHECK(qc2.is_quorum_met());
}
}

{
pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2

// add a weak vote
// ---------------
weak_vote(qc, digest, 0);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
BOOST_CHECK(!qc.is_quorum_met());

// add a strong vote
// -----------------
strong_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
BOOST_CHECK(qc.is_quorum_met());

{
pending_quorum_certificate qc2(qc);
pending_quorum_certificate qc2(std::move(qc));

// add a strong vote
// -----------------
strong_vote(qc2, digest, 2);
BOOST_CHECK_EQUAL(qc2._state, state_t::strong);
BOOST_CHECK_EQUAL(qc2.state(), state_t::strong);
BOOST_CHECK(qc2.is_quorum_met());
}
}
Expand All @@ -206,32 +222,48 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
// add a weak vote
// ---------------
weak_vote(qc, digest, 0);
BOOST_CHECK_EQUAL(qc._state, state_t::unrestricted);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
BOOST_CHECK(!qc.is_quorum_met());

// add a weak vote
// ---------------
weak_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc._state, state_t::weak_final);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final);
BOOST_CHECK(qc.is_quorum_met());

{
pending_quorum_certificate qc2(qc);
pending_quorum_certificate qc2(std::move(qc));

// add a weak vote
// ---------------
weak_vote(qc2, digest, 2);
BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final);
BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
BOOST_CHECK(qc2.is_quorum_met());
}
}

{
pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2

// add a weak vote
// ---------------
weak_vote(qc, digest, 0);
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);
BOOST_CHECK(!qc.is_quorum_met());

// add a weak vote
// ---------------
weak_vote(qc, digest, 1);
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_final);
BOOST_CHECK(qc.is_quorum_met());

{
pending_quorum_certificate qc2(qc);
pending_quorum_certificate qc2(std::move(qc));

// add a strong vote
// -----------------
strong_vote(qc2, digest, 2);
BOOST_CHECK_EQUAL(qc2._state, state_t::weak_final);
BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
BOOST_CHECK(qc2.is_quorum_met());
}
}
Expand Down
Loading

0 comments on commit 8cf39ec

Please sign in to comment.