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

Finalizer transition requires QCs on both finalizer policy sets #391

Merged
merged 46 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
e80b4b4
GH-376 Rename valid_quorum_certificate to quorum_certificate_sig
heifner Jul 18, 2024
71a58a3
GH-376 Rename many qc types and added support for getting qc sigs on …
heifner Jul 20, 2024
7846f43
GH-376 Disable test
heifner Jul 20, 2024
120511d
GH-376 Update for new member of qc
heifner Jul 20, 2024
76b5737
GH-376 Refactor qc logic into qc for better encapsulation
heifner Jul 20, 2024
1856e17
GH-376 Add additional tests for pending finalizers
heifner Jul 22, 2024
10d2d7e
GH-376 Fix test
heifner Jul 22, 2024
4749a19
GH-376 Replace get_votes with vote_metrics() and missing_votes()
heifner Jul 22, 2024
4360347
Merge remote-tracking branch 'spring/main' into GH-376-joint-qcs
heifner Jul 23, 2024
d174017
Adapted svnn_ibc_tests to work with new joint QC structure
systemzax Jul 23, 2024
d35023d
Added tests to verify presence of joint policies QCs on finalizer pol…
systemzax Jul 23, 2024
789e322
GH-376 Avoid cache line false sharing
heifner Jul 23, 2024
e5f5707
Added test to verify joint QCs only begin upon change in pending policy
systemzax Jul 23, 2024
13642e2
Added tests to verify presence of joint policies QCs on finalizer pol…
systemzax Jul 23, 2024
57ff7ec
Merge commit 'e5f57079b9a08face4b2fb6882bb1903cef39a3a' into GH-376-j…
systemzax Jul 23, 2024
91bb585
GH-376 Add last_pending_finalizer_policy_start_num
heifner Jul 23, 2024
ab607cc
GH-376 Add constructor to simplify code
heifner Jul 23, 2024
1b005b1
Merge branch 'GH-376-joint-qcs' of https://github.com/antelopeIO/spri…
systemzax Jul 23, 2024
19a9ea8
GH-376 Fix logic in get_best_qc. Also changes names to be clearer.
heifner Jul 23, 2024
973a452
GH-376 Simplify logic
heifner Jul 23, 2024
606c940
Merge remote-tracking branch 'spring/main' into GH-376-joint-qcs
heifner Jul 23, 2024
950b0ab
Updated svnn ibc tests and smart contract to support joint policies QCs
systemzax Jul 23, 2024
a777b60
Merge branch 'GH-376-joint-qcs' of https://github.com/antelopeIO/spri…
systemzax Jul 23, 2024
d03d750
GH-376 Set better received qc if a better qc is received then current…
heifner Jul 23, 2024
8d26607
Merge branch 'GH-376-joint-qcs' of https://github.com/AntelopeIO/spri…
heifner Jul 23, 2024
f0246f0
GH-376 Remove unused
heifner Jul 23, 2024
8b65f7e
GH-376 Replace cout with ilog
heifner Jul 23, 2024
035055e
GH-376 Provide less for set of finalizer_authority_ptr
heifner Jul 23, 2024
104bb14
GH-376 Simplify and optimize logic
heifner Jul 23, 2024
65f5167
Removed checkpoints from svnn_ibc_test
systemzax Jul 23, 2024
917efb8
Changed the return semantics of proof_test_cluster::process_result to…
systemzax Jul 23, 2024
d00c767
GH-376 Do not include vote count in received qc comparison
heifner Jul 23, 2024
e2da709
GH-376 Fix comparator
heifner Jul 24, 2024
4d627ba
Merge branch 'GH-376-joint-qcs' of https://github.com/AntelopeIO/spri…
heifner Jul 24, 2024
386c2ea
GH-376 Rename vote_status to vote_result_t. Rename has_vote_status_t …
heifner Jul 24, 2024
1da5de8
GH-376 Rename vote_bitset to vote_bitset_t. Rename fin_auth_set to fi…
heifner Jul 24, 2024
6d88cdc
GH-376 Use EOS_ASSERT instead of assert
heifner Jul 24, 2024
9e0dc88
GH-376 maybe_update_fsi for received qc even if not better as it migh…
heifner Jul 24, 2024
9823a00
GH-376 Use EOS_ASSERT instead of assert and simplify logic
heifner Jul 24, 2024
e90f89b
GH-376 Do not allow either a weak or strong vote if already voted.
heifner Jul 24, 2024
fea71ac
GH-376 Avoid finality_extension copy
heifner Jul 24, 2024
058b457
GH-376 Renamed claimed to claimed_bsp
heifner Jul 24, 2024
eccecad
GH-376 Renamed open_qc_sig_t to in_progress_qc_sig_t and open_qc_t to…
heifner Jul 24, 2024
492a79a
GH-376 Renamed in_progress_qc_sig_t to aggregating_qc_sig_t and in_pr…
heifner Jul 24, 2024
77e9f7e
Merge remote-tracking branch 'spring/main' into GH-376-joint-qcs
heifner Jul 24, 2024
8994ac0
GH-376 Move check into EOS_ASSERT instead of hard-coding false
heifner Jul 24, 2024
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
2 changes: 1 addition & 1 deletion libraries/chain/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ set(CHAIN_WEBASSEMBLY_SOURCES

set(CHAIN_FINALITY_SOURCES
finality/finalizer.cpp
finality/quorum_certificate.cpp
finality/qc.cpp
finality/finality_core.cpp
)

Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/block_header_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ digest_type block_header_state::compute_finality_digest() const {
// compute commitments related to finalizer policy transitions
level_2_commitments_t level_2_commitments {
.last_pending_fin_pol_digest = last_pending_finalizer_policy_digest,
.last_pending_fin_pol_start_num = last_pending_finalizer_policy_start_num,
.l3_commitments_digest = fc::sha256::hash(level_3_commitments)
};

Expand Down Expand Up @@ -164,6 +165,7 @@ void evaluate_finalizer_policies_for_promotion(const block_header_state& prev,
// promote the target to pending
auto block_num = next_header_state.block_num();
next_pending.emplace(block_num, target->second);
next_header_state.last_pending_finalizer_policy_start_num = block_num;
} else {
// leave the target alone in the proposed policies
next_proposed.emplace_back(*target);
Expand Down
141 changes: 16 additions & 125 deletions libraries/chain/block_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ block_state::block_state(const block_header_state& prev, signed_block_ptr b, con
, block(std::move(b))
, strong_digest(compute_finality_digest())
, weak_digest(create_weak_digest(strong_digest))
, pending_qc(active_finalizer_policy->finalizers.size(),
active_finalizer_policy->threshold,
active_finalizer_policy->max_weak_sum_before_weak_final())
, aggregating_qc(active_finalizer_policy, pending_finalizer_policy ? pending_finalizer_policy->second : finalizer_policy_ptr{})
{
// ASSUMPTION FROM controller_impl::apply_block = all untrusted blocks will have their signatures pre-validated here
if( !skip_validate_signee ) {
Expand All @@ -31,17 +29,15 @@ block_state::block_state(const block_header_state& bhs,
deque<transaction_metadata_ptr>&& trx_metas,
deque<transaction_receipt>&& trx_receipts,
const std::optional<valid_t>& valid,
const std::optional<quorum_certificate>& qc,
const std::optional<qc_t>& qc,
const signer_callback_type& signer,
const block_signing_authority& valid_block_signing_authority,
const digest_type& action_mroot)
: block_header_state(bhs)
, block(std::make_shared<signed_block>(signed_block_header{bhs.header}))
, strong_digest(compute_finality_digest())
, weak_digest(create_weak_digest(strong_digest))
, pending_qc(active_finalizer_policy->finalizers.size(),
active_finalizer_policy->threshold,
active_finalizer_policy->max_weak_sum_before_weak_final())
, aggregating_qc(active_finalizer_policy, pending_finalizer_policy ? pending_finalizer_policy->second : finalizer_policy_ptr{})
, valid(valid)
, pub_keys_recovered(true) // called by produce_block so signature recovery of trxs must have been done
, cached_trxs(std::move(trx_metas))
Expand Down Expand Up @@ -82,6 +78,7 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b
result.core = finality_core::create_core_for_genesis_block(genesis_block_ref);

result.last_pending_finalizer_policy_digest = fc::sha256::hash(*result.active_finalizer_policy);
result.last_pending_finalizer_policy_start_num = bsp.block_num();
result.active_proposer_policy = std::make_shared<proposer_policy>();
result.active_proposer_policy->active_time = bsp.timestamp();
result.active_proposer_policy->proposer_schedule = bsp.active_schedule;
Expand All @@ -96,10 +93,8 @@ block_state_ptr block_state::create_if_genesis_block(const block_state_legacy& b
result.strong_digest = result.compute_finality_digest(); // all block_header_state data populated in result at this point
result.weak_digest = create_weak_digest(result.strong_digest);

// pending_qc will not be used in the genesis block as finalizers will not vote on it, but still create it for consistency.
result.pending_qc = pending_quorum_certificate{result.active_finalizer_policy->finalizers.size(),
result.active_finalizer_policy->threshold,
result.active_finalizer_policy->max_weak_sum_before_weak_final()};
// aggregating_qc will not be used in the genesis block as finalizers will not vote on it, but still create it for consistency.
result.aggregating_qc = aggregating_qc_t{result.active_finalizer_policy, finalizer_policy_ptr{}};

// build leaf_node and validation_tree
valid_t::finality_leaf_node_t leaf_node {
Expand Down Expand Up @@ -156,12 +151,12 @@ block_state::block_state(snapshot_detail::snapshot_block_state_v7&& sbs)
.proposed_finalizer_policies = std::move(sbs.proposed_finalizer_policies),
.pending_finalizer_policy = std::move(sbs.pending_finalizer_policy),
.finalizer_policy_generation = sbs.finalizer_policy_generation,
.last_pending_finalizer_policy_digest = sbs.last_pending_finalizer_policy_digest
.last_pending_finalizer_policy_digest = sbs.last_pending_finalizer_policy_digest,
.last_pending_finalizer_policy_start_num = sbs.last_pending_finalizer_policy_start_num
}
, strong_digest(compute_finality_digest())
, weak_digest(create_weak_digest(strong_digest))
, pending_qc(active_finalizer_policy->finalizers.size(), active_finalizer_policy->threshold,
active_finalizer_policy->max_weak_sum_before_weak_final()) // just in case we receive votes
, aggregating_qc(active_finalizer_policy, pending_finalizer_policy ? pending_finalizer_policy->second : finalizer_policy_ptr{}) // just in case we receive votes
, valid(std::move(sbs.valid))
{
header_exts = header.validate_and_extract_header_extensions();
Expand All @@ -180,123 +175,19 @@ void block_state::set_trxs_metas( deque<transaction_metadata_ptr>&& trxs_metas,
}

// Called from vote threads
vote_status block_state::aggregate_vote(uint32_t connection_id, const 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);
auto digest = vote.strong ? strong_digest.to_uint8_span() : std::span<const uint8_t>(weak_digest);
return pending_qc.add_vote(connection_id,
block_num(),
vote.strong,
digest,
index,
vote.finalizer_key,
vote.sig,
finalizers[index].weight);
} else {
fc_wlog(vote_logger, "connection - ${c} finalizer_key ${k} in vote is not in finalizer policy",
("c", connection_id)("k", vote.finalizer_key.to_string().substr(8,16)));
return vote_status::unknown_public_key;
}
vote_result_t block_state::aggregate_vote(uint32_t connection_id, const vote_message& vote) {
auto finalizer_digest = vote.strong ? strong_digest.to_uint8_span() : std::span<const uint8_t>(weak_digest);
return aggregating_qc.aggregate_vote(connection_id, vote, block_num(), finalizer_digest);
}

// Only used for testing
vote_status_t block_state::has_voted(const bls_public_key& key) const {
const auto& finalizers = active_finalizer_policy->finalizers;
auto it = std::find_if(finalizers.begin(),
finalizers.end(),
[&](const auto& finalizer) { return finalizer.public_key == key; });

if (it != finalizers.end()) {
auto index = std::distance(finalizers.begin(), it);
return pending_qc.has_voted(index) ? vote_status_t::voted : vote_status_t::not_voted;
}
return vote_status_t::irrelevant_finalizer;
}

vote_info_vec block_state::get_votes() const {
const auto& finalizers = active_finalizer_policy->finalizers;
vote_info_vec res;
res.reserve(finalizers.size());
pending_qc.visit_votes([&](size_t idx, bool strong) { res.emplace_back(finalizers[idx].public_key, strong); });
return res;
return aggregating_qc.has_voted(key);
}

// Called from net threads
void block_state::verify_qc(const valid_quorum_certificate& qc) const {
const auto& finalizers = active_finalizer_policy->finalizers;
auto num_finalizers = finalizers.size();

// utility to accumulate voted weights
auto weights = [&] ( const vote_bitset& votes_bitset ) -> uint64_t {
EOS_ASSERT( num_finalizers == votes_bitset.size(),
invalid_qc_claim,
"vote bitset size is not the same as the number of finalizers for the policy it refers to, vote bitset size: ${s}, num of finalizers for the policy: ${n}",
("s", votes_bitset.size())("n", num_finalizers) );

uint64_t sum = 0;
for (auto i = 0u; i < num_finalizers; ++i) {
if( votes_bitset[i] ) { // ith finalizer voted
sum += finalizers[i].weight;
}
}
return sum;
};

// compute strong and weak accumulated weights
auto strong_weights = qc.strong_votes ? weights( *qc.strong_votes ) : 0;
auto weak_weights = qc.weak_votes ? weights( *qc.weak_votes ) : 0;

// verfify quorum is met
if( qc.is_strong() ) {
EOS_ASSERT( strong_weights >= active_finalizer_policy->threshold,
invalid_qc_claim,
"strong quorum is not met, strong_weights: ${s}, threshold: ${t}",
("s", strong_weights)("t", active_finalizer_policy->threshold) );
} else {
EOS_ASSERT( strong_weights + weak_weights >= active_finalizer_policy->threshold,
invalid_qc_claim,
"weak quorum is not met, strong_weights: ${s}, weak_weights: ${w}, threshold: ${t}",
("s", strong_weights)("w", weak_weights)("t", active_finalizer_policy->threshold) );
}

// no reason to use bls_public_key wrapper
std::vector<bls12_381::g1> pubkeys;
pubkeys.reserve(2);
std::vector<std::vector<uint8_t>> digests;
digests.reserve(2);

// utility to aggregate public keys for verification
auto aggregate_pubkeys = [&](const auto& votes_bitset) -> bls12_381::g1 {
const auto n = std::min(num_finalizers, votes_bitset.size());
std::vector<bls12_381::g1> pubkeys_to_aggregate;
pubkeys_to_aggregate.reserve(n);
for(auto i = 0u; i < n; ++i) {
if (votes_bitset[i]) { // ith finalizer voted
pubkeys_to_aggregate.emplace_back(finalizers[i].public_key.jacobian_montgomery_le());
}
}

return bls12_381::aggregate_public_keys(pubkeys_to_aggregate);
};

// aggregate public keys and digests for strong and weak votes
if( qc.strong_votes ) {
pubkeys.emplace_back(aggregate_pubkeys(*qc.strong_votes));
digests.emplace_back(std::vector<uint8_t>{strong_digest.data(), strong_digest.data() + strong_digest.data_size()});
}

if( qc.weak_votes ) {
pubkeys.emplace_back(aggregate_pubkeys(*qc.weak_votes));
digests.emplace_back(std::vector<uint8_t>{weak_digest.begin(), weak_digest.end()});
}

// validate aggregated signature
EOS_ASSERT( bls12_381::aggregate_verify(pubkeys, digests, qc.sig.jacobian_montgomery_le()),
invalid_qc_claim, "signature validation failed" );
void block_state::verify_qc(const qc_t& qc) const {
aggregating_qc.verify_qc(qc, strong_digest, weak_digest);
}

qc_claim_t block_state::extract_qc_claim() const {
Expand Down
Loading