Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IF: accumulate the weight in vote calculation #2131

Merged
merged 9 commits into from
Jan 30, 2024
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) {
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
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
Loading