Skip to content

Commit

Permalink
Merge pull request #2131 from AntelopeIO/accumulate_vote_weight
Browse files Browse the repository at this point in the history
IF: accumulate the weight in vote calculation
  • Loading branch information
linh2931 authored Jan 30, 2024
2 parents ee218c6 + 952a556 commit d8553e5
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 98 deletions.
7 changes: 4 additions & 3 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ block_state::block_state(const block_header_state& prev, signed_block_ptr b, con
, block(std::move(b))
, strong_digest(compute_finalizer_digest())
, weak_digest(compute_finalizer_digest())
, pending_qc(prev.active_finalizer_policy->finalizers.size(), prev.active_finalizer_policy->threshold)
, pending_qc(prev.active_finalizer_policy->finalizers.size(), prev.active_finalizer_policy->threshold, prev.active_finalizer_policy->max_weak_sum_before_weak_final())
{}

block_state::block_state(const block_header_state& bhs, deque<transaction_metadata_ptr>&& trx_metas,
Expand All @@ -22,7 +22,7 @@ block_state::block_state(const block_header_state& bhs, deque<transaction_metada
, block(std::make_shared<signed_block>(signed_block_header{bhs.header})) // [greg todo] do we need signatures?
, strong_digest(compute_finalizer_digest())
, weak_digest(compute_finalizer_digest())
, pending_qc(bhs.active_finalizer_policy->finalizers.size(), bhs.active_finalizer_policy->threshold)
, pending_qc(bhs.active_finalizer_policy->finalizers.size(), bhs.active_finalizer_policy->threshold, bhs.active_finalizer_policy->max_weak_sum_before_weak_final())
, pub_keys_recovered(true) // probably not needed
, cached_trxs(std::move(trx_metas))
{
Expand Down Expand Up @@ -83,7 +83,8 @@ std::pair<bool, std::optional<uint32_t>> block_state::aggregate_vote(const vote_
std::vector<uint8_t>{digest.data(), digest.data() + digest.data_size()},
index,
vote.finalizer_key,
vote.sig);
vote.sig,
finalizers[index].weight);
return {valid, strong ? core.final_on_strong_qc_block_num : std::optional<uint32_t>{}};
} else {
wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) );
Expand Down
59 changes: 19 additions & 40 deletions libraries/chain/hotstuff/hotstuff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,60 +45,39 @@ 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)
pending_quorum_certificate::pending_quorum_certificate(size_t num_finalizers, uint64_t quorum, uint64_t max_weak_sum_before_weak_final)
: _mtx(std::make_unique<std::mutex>())
, _quorum(quorum)
, _mtx(std::make_unique<std::mutex>()) {
, _max_weak_sum_before_weak_final(max_weak_sum_before_weak_final) {
_weak_votes.resize(num_finalizers);
_strong_votes.resize(num_finalizers);
}

pending_quorum_certificate::pending_quorum_certificate(const fc::sha256& proposal_id,
const digest_type& proposal_digest, size_t num_finalizers,
size_t quorum)
: pending_quorum_certificate(num_finalizers, quorum) {
_proposal_id = proposal_id;
_proposal_digest.assign(proposal_digest.data(), proposal_digest.data() + 32);
}

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;
_strong_votes.reset(num_finalizers);
_weak_votes.reset(num_finalizers);
_num_finalizers = num_finalizers;
_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);
const bls_public_key& pubkey, const bls_signature& sig,
uint64_t weight) {
if (!_strong_votes.add_vote(proposal_digest, index, pubkey, sig))
return false;
size_t weak = num_weak();
size_t strong = num_strong();
_strong_sum += weight;

switch (_state) {
case state_t::unrestricted:
case state_t::restricted:
if (strong >= _quorum) {
if (_strong_sum >= _quorum) {
assert(_state != state_t::restricted);
_state = state_t::strong;
} else if (weak + strong >= _quorum)
} else if (_weak_sum + _strong_sum >= _quorum)
_state = (_state == state_t::restricted) ? state_t::weak_final : state_t::weak_achieved;
break;

case state_t::weak_achieved:
if (strong >= _quorum)
if (_strong_sum >= _quorum)
_state = state_t::strong;
break;

Expand All @@ -112,20 +91,19 @@ bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& pro

// 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);
const bls_public_key& pubkey, const bls_signature& sig,
uint64_t weight) {
if (!_weak_votes.add_vote(proposal_digest, index, pubkey, sig))
return false;
size_t weak = num_weak();
size_t strong = num_strong();
_weak_sum += weight;

switch (_state) {
case state_t::unrestricted:
case state_t::restricted:
if (weak + strong >= _quorum)
if (_weak_sum + _strong_sum >= _quorum)
_state = state_t::weak_achieved;

if (weak > (_num_finalizers - _quorum)) {
if (_weak_sum > _max_weak_sum_before_weak_final) {
if (_state == state_t::weak_achieved)
_state = state_t::weak_final;
else if (_state == state_t::unrestricted)
Expand All @@ -134,7 +112,7 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& propo
break;

case state_t::weak_achieved:
if (weak >= (_num_finalizers - _quorum))
if (_weak_sum >= _max_weak_sum_before_weak_final)
_state = state_t::weak_final;
break;

Expand All @@ -148,10 +126,11 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& propo

// thread safe, <valid, strong>
std::pair<bool, 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) {
const bls_public_key& pubkey, const bls_signature& sig,
uint64_t weight) {
std::lock_guard g(*_mtx);
bool valid = strong ? add_strong_vote(proposal_digest, index, pubkey, sig)
: add_weak_vote(proposal_digest, index, pubkey, sig);
bool valid = strong ? add_strong_vote(proposal_digest, index, pubkey, sig, weight)
: add_weak_vote(proposal_digest, index, pubkey, sig, weight);
return {valid, _state == state_t::strong};
}

Expand Down
76 changes: 46 additions & 30 deletions libraries/chain/hotstuff/test/finality_misc_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,83 +50,93 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {
for (const auto& k : sk)
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_vote(false, digest, index, pubkey[index], sk[index].sign(digest)).first;
auto weak_vote = [&](pending_quorum_certificate& qc, const std::vector<uint8_t>& digest, size_t index, uint64_t weight) {
return qc.add_vote(false, digest, index, pubkey[index], sk[index].sign(digest), weight).first;
};

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

constexpr uint64_t weight = 1;

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

// add one weak vote
// -----------------
weak_vote(qc, digest, 0);
weak_vote(qc, digest, 0, weight);
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);
bool ok = weak_vote(qc, digest, 0, weight);
BOOST_CHECK(!ok); // vote was a duplicate
BOOST_CHECK_EQUAL(qc.state(), state_t::weak_achieved);
BOOST_CHECK(qc.is_quorum_met());

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

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

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

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

{
pending_quorum_certificate qc(2, 1); // 2 finalizers, quorum = 1
constexpr uint64_t quorum = 1;
constexpr uint64_t max_weak_sum_before_weak_final = 1;
pending_quorum_certificate qc(2, quorum, max_weak_sum_before_weak_final); // 2 finalizers, weight_sum_minus_quorum = 1
BOOST_CHECK_EQUAL(qc.state(), state_t::unrestricted);

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

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

{
pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2
constexpr uint64_t quorum = 2;
constexpr uint64_t max_weak_sum_before_weak_final = 1;
pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers

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

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

Expand All @@ -135,24 +145,26 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {

// add a weak vote
// ---------------
weak_vote(qc2, digest, 2);
weak_vote(qc2, digest, 2, weight);
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
constexpr uint64_t quorum = 2;
constexpr uint64_t max_weak_sum_before_weak_final = 1;
pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers, quorum = 2

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

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

Expand All @@ -161,24 +173,26 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {

// add a strong vote
// -----------------
strong_vote(qc2, digest, 2);
strong_vote(qc2, digest, 2, weight);
BOOST_CHECK_EQUAL(qc2.state(), state_t::strong);
BOOST_CHECK(qc2.is_quorum_met());
}
}

{
pending_quorum_certificate qc(3, 2); // 3 finalizers, quorum = 2
constexpr uint64_t quorum = 2;
constexpr uint64_t max_weak_sum_before_weak_final = 1;
pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers, quorum = 2

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

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

Expand All @@ -187,24 +201,26 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {

// add a weak vote
// ---------------
weak_vote(qc2, digest, 2);
weak_vote(qc2, digest, 2, weight);
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
constexpr uint64_t quorum = 2;
constexpr uint64_t max_weak_sum_before_weak_final = 1;
pending_quorum_certificate qc(3, quorum, max_weak_sum_before_weak_final); // 3 finalizers, quorum = 2

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

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

Expand All @@ -213,7 +229,7 @@ BOOST_AUTO_TEST_CASE(qc_state_transitions) try {

// add a strong vote
// -----------------
strong_vote(qc2, digest, 2);
strong_vote(qc2, digest, 2, weight);
BOOST_CHECK_EQUAL(qc2.state(), state_t::weak_final);
BOOST_CHECK(qc2.is_quorum_met());
}
Expand Down
11 changes: 11 additions & 0 deletions libraries/chain/include/eosio/chain/hotstuff/finalizer_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ namespace eosio::chain {
uint32_t generation = 0; ///< sequentially incrementing version number
uint64_t threshold = 0; ///< vote weight threshold to finalize blocks
std::vector<finalizer_authority> finalizers; ///< Instant Finality voter set

// max accumulated weak weight before becoming weak_final
uint64_t max_weak_sum_before_weak_final() const {
uint64_t sum = std::accumulate( finalizers.begin(), finalizers.end(), 0,
[](uint64_t acc, const finalizer_authority& f) {
return acc + f.weight;
}
);

return (sum - threshold);
}
};

using finalizer_policy_ptr = std::shared_ptr<finalizer_policy>;
Expand Down
Loading

0 comments on commit d8553e5

Please sign in to comment.