Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
686986e
Added placeholder svnn_finality_violation.cpp and updated cmake files
systemzax Jul 29, 2024
b345e76
Added placeholder finality_violation smart contract
systemzax Jul 29, 2024
920d7aa
Converted proof_test_cluster to use fixed size nodes, added vote_prop…
systemzax Jul 29, 2024
0f83dea
Added vote propagation tests
systemzax Jul 29, 2024
2eff199
Initial set up for finality violation tests
systemzax Jul 29, 2024
38ccb3b
Progress on initial tests
systemzax Jul 31, 2024
cbcbc27
Comments related to rule #1 violation
systemzax Jul 31, 2024
a686f00
Updated ibc_block_data_t structure to expose all level 2 and level 3 …
systemzax Jul 31, 2024
a82435a
Updated savanna contract common code to support level 3 commitments
systemzax Jul 31, 2024
e295f9d
Added rule #1 finality violation action to smart contract, tests
systemzax Jul 31, 2024
bca8c83
Remove commented out code
systemzax Jul 31, 2024
84f6c08
Removed unused parameter in svnn_ibc_tests
systemzax Jul 31, 2024
3fc7806
Changed pending_finalizer_policy to last_pending_finalizer_policy in …
systemzax Aug 1, 2024
5a26775
Updated finality violation tests to reflect new name
systemzax Aug 1, 2024
90f5f45
Renamed last_pending_finalizer_policy_generation to pending_finalizer…
systemzax Aug 1, 2024
e7d3263
Removed temporary checkpoints from svnn_ibc_tests
systemzax Aug 1, 2024
9e90bbf
Small refactor of finality violation tests
systemzax Aug 1, 2024
484c229
Prepared test for rule #2
systemzax Aug 1, 2024
4da02e7
Implemented rule #2 verification in savanna contracts, improved proof
systemzax Aug 1, 2024
5acaae2
Added savanna contract interface for weak QCs
systemzax Aug 1, 2024
7ea485e
Completed savanna contract support for weak QCs
systemzax Aug 1, 2024
1be2257
Reordered proof generation to ensure only the most recent information…
systemzax Aug 1, 2024
891207d
WIP
systemzax Aug 1, 2024
19d1b5d
Replaced policy digests and generations returned by process_result fu…
systemzax Aug 1, 2024
2f5a557
Modified tests to use light client data cache only
systemzax Aug 1, 2024
67440e4
Removed leftover comments
systemzax Aug 1, 2024
3559929
Minor code reorganization plus added comments for clarity
systemzax Aug 1, 2024
ec68dd5
Fixed incorrect assignement in savanna contract, recompiled contract
systemzax Aug 1, 2024
0ff0c8d
Corrected order and names of sub rules
systemzax Aug 1, 2024
a99e673
Desambiguated rule2 (now rule2a and rule2b) to differentiate between …
systemzax Aug 1, 2024
772eeb2
misc
systemzax Aug 6, 2024
792462d
Refactored light client data cache to properly evaluate finality rule…
systemzax Aug 6, 2024
00820b2
Rule 2 WIP
systemzax Aug 7, 2024
ead0837
Completed rule 2
systemzax Aug 7, 2024
f408f9f
Clean up
systemzax Aug 7, 2024
81bf80b
Renamed minimal_block_data to finality_block_data
systemzax Aug 8, 2024
18deabb
Adjusted order of events to more closely reflect the light client beh…
systemzax Aug 8, 2024
9c47427
Obtain reference to fake chain blocks via the list of reversible bloc…
systemzax Aug 8, 2024
26e809b
Added rule #3 to smart contract
systemzax Aug 8, 2024
b1761b2
Added proof of rule #3 finality violation test
systemzax Aug 8, 2024
e1c8e41
Added comments to smart contract, recompiled
systemzax Aug 8, 2024
19e5591
Fixed a few bugs, added additional rule #3 test where fake chain is a…
systemzax Aug 8, 2024
411adc2
Updated finality violation contract actions to return guilty vs innoc…
systemzax Aug 8, 2024
a62ab3f
Added bitset tests to ibc tests to cover the exact blame and exonerat…
systemzax Aug 8, 2024
fa81154
Removed unused return statements, added comments about bitset verific…
systemzax Aug 8, 2024
264a2b9
Resolved merge conflict
systemzax Aug 26, 2024
b10e275
Converted some static functions to inline functions in finality_proof
systemzax Aug 26, 2024
17355c8
Re-enabled action traces size check in finality_proof
systemzax Aug 26, 2024
14f8873
Pass result to process_result by const reference
systemzax Aug 26, 2024
b223247
Removed unnecessary check to process_finalizer_votes, removed comment…
systemzax Aug 26, 2024
e92e125
Updated functions svnn_finality_violation_tests to use const referenc…
systemzax Aug 26, 2024
52436cf
Simplified shouldPass function, removed unnecessary try catch
systemzax Aug 26, 2024
891296e
Updated savanna contracts to pass function parameters by const refere…
systemzax Aug 26, 2024
f07308f
Replaced find_if with lower_bound to perform binary search in svnn_fi…
systemzax Aug 26, 2024
1e1f0e4
bumped chainbase submodule
systemzax Aug 26, 2024
d1a4ee9
Merge branch 'release/1.0' into finality_violation_tests_1.0.0
systemzax Aug 26, 2024
d48f25c
Merge branch 'release/1.0' into finality_violation_tests_1.0.0
systemzax Aug 27, 2024
5e0953e
Merge branch 'release/1.0' into finality_violation_tests_1.0.0
systemzax Aug 27, 2024
9bdddce
Merge branch 'release/1.0' into finality_violation_tests_1.0.0
systemzax Aug 28, 2024
513c350
Merge branch 'release/1.0' of https://github.com/AntelopeIO/spring in…
systemzax Sep 1, 2024
d715a31
Replaced static functions with inline functions in finality_proof
systemzax Sep 1, 2024
e85e5f8
Removed default empty initializers in ibc_block_data_t
systemzax Sep 1, 2024
243c11d
Simplified the pruning function in data cache struct
systemzax Sep 1, 2024
8d8d4ba
Removed commented out code
systemzax Sep 1, 2024
4946954
Merge branch 'finality_violation_tests_1.0.0' of https://github.com/A…
systemzax Sep 1, 2024
68c2c1d
Moved finality digests comparison to the check_qcs function in finali…
systemzax Sep 3, 2024
bae1c27
Fixed lock violation check
systemzax Sep 3, 2024
6c253f5
Added bool flag to check_qc to control whether or not we verify the q…
systemzax Sep 3, 2024
1b7fb4f
Renamed finalizers to strong_votes in savanna quorum_certificate_input
systemzax Sep 3, 2024
eca9352
Modified _check_qc function to accomodate optional weak QC verification
systemzax Sep 22, 2024
b4b47f8
Added support for combined weak/strong bitset comparison
systemzax Sep 30, 2024
1b743a3
Clean up
systemzax Sep 30, 2024
18d1882
Reversed endianness of bytes and flipped byte representation in savan…
systemzax Dec 8, 2024
2ba9e04
Removed comment which no longer applies
systemzax Dec 8, 2024
cc20819
Updated finality_violation tests to reflect new bitset string format
systemzax Dec 9, 2024
ad56709
Adjustments to the finality violation contract to support conditional…
systemzax Dec 9, 2024
2d9202f
Fixed savanna finality_violation contract evaluation of rule 2 and ru…
systemzax Dec 15, 2024
fce30e8
Reworked rule 2 and rule 3 tests to correctly identify finality viola…
systemzax Dec 26, 2024
20090c6
Use shouldPass() semantics for first proof
systemzax Dec 26, 2024
c7ade59
Added tests for proofs being rejected due to low proof block being an…
systemzax Dec 28, 2024
c8fd55f
Added comments
systemzax Dec 28, 2024
955aa87
Adjusted comments
systemzax Dec 28, 2024
241af18
Merge branch 'release/1.0' into finality_violation_tests_1.0.0
systemzax Dec 28, 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 unittests/finality_proof.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,4 +359,4 @@ namespace finality_proof {

};

}
}
478 changes: 280 additions & 198 deletions unittests/svnn_finality_violation_tests.cpp

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions unittests/svnn_ibc_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_4_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_4_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_4_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -125,7 +125,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_4_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_4_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_4_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -160,7 +160,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_5_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_5_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_5_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -294,8 +294,8 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)

// onblock action proof
mutable_variant_object onblock_action_proof = mvo()
("target_block_index", 0)
("final_block_index", 3)
("target_action_index", 0)
("final_action_index", 3)
("target", mvo()
("action", mvo()
("account", block_7_result.onblock_trace.act.account)
Expand All @@ -313,8 +313,8 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)

// first action proof (check_heavy_proof_1)
mutable_variant_object action_proof_1 = mvo()
("target_block_index", 1)
("final_block_index", 3)
("target_action_index", 1)
("final_action_index", 3)
("target", mvo()
("action", mvo()
("account", check_heavy_proof_1_trace.act.account)
Expand All @@ -331,8 +331,8 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)

// second action proof (check_light_proof_1)
mutable_variant_object action_proof_2 = mvo()
("target_block_index", 2)
("final_block_index", 3)
("target_action_index", 2)
("final_action_index", 3)
("target", mvo()
("action", mvo()
("account", check_light_proof_1_trace.act.account)
Expand Down Expand Up @@ -360,7 +360,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_9_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_9_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_9_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -462,7 +462,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_11_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_11_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_11_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -521,11 +521,11 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_12_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_12_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_12_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
("pending_policy_qc", mvo()
("signature", block_12_result.qc_data.qc.value().pending_policy_sig.value().sig.to_string())
("finalizers", finality_proof::finalizers_string(block_12_result.qc_data.qc.value().pending_policy_sig.value().strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_12_result.qc_data.qc.value().pending_policy_sig.value().strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -574,7 +574,7 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
)
("active_policy_qc", mvo()
("signature", block_13_result.qc_data.qc.value().active_policy_sig.sig.to_string())
("finalizers", finality_proof::finalizers_string(block_13_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
("strong_votes", finality_proof::finalizers_string(block_13_result.qc_data.qc.value().active_policy_sig.strong_votes.value()))
)
)
("target_block_proof_of_inclusion", mvo()
Expand Down Expand Up @@ -666,43 +666,43 @@ BOOST_AUTO_TEST_SUITE(svnn_ibc)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "30") //bitset bytes are reversed, so we do the same to test
("bitset_string", "03")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still does not look correct to me.

If I want to check whether the third finalizer (i == 2) is present, I would expect to look at the i/4 == 0 nibble (using 0-based indexing and counting from left to right, i.e. most significant nibble to least significant nibble). Then converting that nibble into bits, I would expect the i%4 == 2 bit in that nibble (using 0-based indexing and counting from MSB to LSB) to represent the presence of that finalizer.

So, given a bit string of 011:
I would expect the 3rd most significant bit of the first nibble to be 1. Similarly for the 2nd most significant bit of the first nibble. But, I would expect the 1st most significant bit of the first nibble to be 0. Furthermore, I would expect all other bits that are needed for padding purposes to be 0.

So the first nibble should be the hex digit 6 (which has binary representation 0110). And if we need an even number of nibbles in the hex string, then we can pad with a 0 nibble at the end to get the hex representation 60 in this case.

("bitset_vector", bitset_2)
("finalizers_count", 3)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "ae00")
("bitset_string", "00ea")
("bitset_vector", bitset_3)
("finalizers_count", 11)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "1263")
("bitset_string", "3621")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As another example, I would expect this hex string to be d884 which has the bit representation 1101 1000 1000 0100 (notice this matches the original bit string of 11011000100001 except that there are two final padding bits).

("bitset_vector", bitset_4)
("finalizers_count", 14)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "fffff1")
("bitset_string", "1fffff")
("bitset_vector", bitset_5)
("finalizers_count", 21)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "fff700")
("bitset_string", "007fff")
("bitset_vector", bitset_6)
("finalizers_count", 21)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "30")
("bitset_string", "03")
("bitset_vector", bitset_7)
("finalizers_count", 4)
);

chain.push_action("ibc"_n, "testbitset"_n, "ibc"_n, mvo()
("bitset_string", "c0")
("bitset_string", "0c")
("bitset_vector", bitset_8)
("finalizers_count", 4)
);
Expand Down
4 changes: 2 additions & 2 deletions unittests/test-contracts/savanna/common/bitset.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ namespace savanna {
std::string result;
result.reserve(data.size() * 2); // Each byte will be represented by two hex characters
for (auto byte : data) {
result.push_back(hex_chars[byte & 0x0F]);
result.push_back(hex_chars[(byte >> 4) & 0x0F]);
result.insert(result.begin(), hex_chars[byte & 0x0F]);
result.insert(result.begin(), hex_chars[(byte >> 4) & 0x0F]);
}
return result;
}
Expand Down
149 changes: 107 additions & 42 deletions unittests/test-contracts/savanna/common/savanna.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ namespace savanna {
return std::string(res.begin(), res.end());
}

inline std::string create_strong_digest(const checksum256& digest){
std::array<uint8_t, 32> fd_data = digest.extract_as_byte_array();
return std::string(fd_data.begin(), fd_data.end());
}

struct quorum_certificate_input {
//representation of a bitset, where each bit represents the ordinal finalizer position according to canonical sorting rules of the finalizer policy
std::vector<uint8_t> finalizers;
//string representation of a BLS signature
std::string signature;
std::optional<bool> is_weak;
//representation of optional strong and weak bitsets, where each bit represents the ordinal finalizer position according to canonical sorting rules of the finalizer policy
std::optional<std::vector<uint8_t>> strong_votes;
std::optional<std::vector<uint8_t>> weak_votes;

//string representation of a BLS signature
std::string signature;
};

struct finalizer_authority_internal {
Expand Down Expand Up @@ -120,7 +126,8 @@ namespace savanna {
checksum256 _compute_root(const std::vector<checksum256>& proof_nodes, const checksum256& target, const uint64_t target_block_index, const uint64_t final_block_index){
checksum256 hash = target;
std::vector<bool> proof_path = _get_proof_path(target_block_index, final_block_index+1);
check(proof_path.size() == proof_nodes.size(), "internal error"); //should not happen

check(proof_path.size() == proof_nodes.size(), "proof path size and proof nodes size mismatch");
for (int i = 0 ; i < proof_nodes.size() ; i++){
const checksum256 node = proof_nodes[i];
hash = hash_pair(proof_path[i] ? std::make_pair(node, hash) : std::make_pair(hash, node));
Expand All @@ -134,54 +141,112 @@ namespace savanna {
bls_g1_add(op1, op2, r);
return r;
}

void check_duplicate_votes(const savanna::bitset& strong_votes, const savanna::bitset& weak_votes, const finalizer_policy_input& finalizer_policy){

auto fa_itr = finalizer_policy.finalizers.begin();
auto fa_end_itr = finalizer_policy.finalizers.end();

size_t index = 0;

while (fa_itr != fa_end_itr){
bool voted_strong = strong_votes.test(index);
bool voted_weak = weak_votes.test(index);
check (!(voted_strong && voted_weak), "conflicting finalizer votes detected in QC");
index++;
fa_itr++;
}

// verify signature
bool _verify(const std::string& public_key, const std::string& signature, const std::string& message){
return bls_signature_verify(decode_bls_public_key_to_g1(public_key), decode_bls_signature_to_g2(signature), message);
}
//verify that the quorum certificate over the finality digest is valid
void _check_qc(const quorum_certificate_input& qc, const checksum256& finality_digest, const finalizer_policy_input& finalizer_policy){

uint64_t aggregate_keys(const savanna::bitset& votes, const finalizer_policy_input& finalizer_policy, bls_g1& agg_pub_key){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to return a pair of the aggregate key and the total weight.

auto fa_itr = finalizer_policy.finalizers.begin();
auto fa_end_itr = finalizer_policy.finalizers.end();
size_t finalizer_count = finalizer_policy.finalizers.size();
savanna::bitset b(finalizer_count, qc.finalizers);

bool first = true;

size_t index = 0;
uint64_t weight = 0;

bls_g1 agg_pub_key;

while (fa_itr != fa_end_itr){
if (b.test(index)){
bls_g1 pub_key = decode_bls_public_key_to_g1(fa_itr->public_key);
if (first){
first=false;
agg_pub_key = pub_key;
}
else agg_pub_key = _g1add(agg_pub_key, pub_key);
weight+=fa_itr->weight;
}
index++;
fa_itr++;
if (votes.test(index)){
bls_g1 pub_key = decode_bls_public_key_to_g1(fa_itr->public_key);
if (first){
first=false;
agg_pub_key = pub_key;
}
else agg_pub_key = _g1add(agg_pub_key, pub_key);
weight+=fa_itr->weight;
}
index++;
fa_itr++;
}

//verify that we have enough vote weight to meet the quorum threshold of the target policy
check(weight>=finalizer_policy.threshold, "insufficient signatures to reach quorum");
return weight;

}

void _verify(const std::vector<std::string>& messages, const std::vector<bls_g1>& agg_pub_keys, const std::string& agg_sig){

std::string message;
check(messages.size() == agg_pub_keys.size(), "messages vector and pub key vectors must be of the same size");

if (qc.is_weak.has_value() && qc.is_weak.value() == true) message = create_weak_digest(finality_digest);
for (size_t i = 0 ; i < messages.size(); i++){
//verify signature validity
check(bls_signature_verify(agg_pub_keys[i], decode_bls_signature_to_g2(agg_sig), messages[i]), "signature verification failed");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make sense as a way to check the aggregate signature. See how Spring does it.

// validate aggregated signature
EOS_ASSERT( bls12_381::aggregate_verify(pubkeys, digests, sig.jacobian_montgomery_le()),
invalid_qc_signature, "qc signature validation failed" );

}

}

//verify that the quorum certificate over the finality digest is valid
void _check_qc(const quorum_certificate_input& qc, const checksum256& finality_digest, const finalizer_policy_input& finalizer_policy, const bool count_strong_only, const bool enforce_threshold_check){

check(qc.strong_votes.has_value() || qc.weak_votes.has_value(), "quorum certificate must have at least one bitset");

size_t finalizer_count = finalizer_policy.finalizers.size();

uint64_t weight = 0;

if (count_strong_only){
bls_g1 agg_pub_key;
check(qc.strong_votes.has_value(), "required strong votes are missing");
savanna::bitset strong_b(finalizer_count, qc.strong_votes.value());
weight = aggregate_keys(strong_b, finalizer_policy, agg_pub_key);
_verify({create_strong_digest(finality_digest)}, {agg_pub_key}, qc.signature);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only works if the weak bitset is empty. If it is not empty, then the QC signature would be an aggregate signature formed from the aggregate public key of the strong votes (calculated here) corresponding to the strong digest AND the aggregate public key to the weak votes corresponding to the weak digest.

I think Spring will never bother generating a QC with mixed strong and weak votes when the strong votes are sufficient to meet the threshold. But as far as the protocol is concerned, if weak votes are present, the QC is treated as a weak QC and the aggregate signature must incorporate the effect of those weak votes.

I think these contracts should not necessarily assume that and be able to handle validating the signature with count_strong_only == true even if weak votes are present in the QC.

}
else {
std::array<uint8_t, 32> fd_data = finality_digest.extract_as_byte_array();
message = std::string(fd_data.begin(), fd_data.end());

if (qc.strong_votes.has_value() && qc.weak_votes.has_value()){
//weak QC (composed of strong and weak votes)
bls_g1 strong_agg_pub_key;
bls_g1 weak_agg_pub_key;
savanna::bitset strong_b(finalizer_count, qc.strong_votes.value());
savanna::bitset weak_b(finalizer_count, qc.weak_votes.value());
check_duplicate_votes(strong_b, weak_b, finalizer_policy);
uint64_t strong_weight = aggregate_keys(strong_b, finalizer_policy, strong_agg_pub_key);
uint64_t weak_weight = aggregate_keys(strong_b, finalizer_policy, weak_agg_pub_key);
_verify({create_strong_digest(finality_digest), create_weak_digest(finality_digest)}, {strong_agg_pub_key, weak_agg_pub_key}, qc.signature);
weight=strong_weight+weak_weight;
}
else if (qc.weak_votes.has_value()){
//weak QC (composed of weak votes)
bls_g1 agg_pub_key;
savanna::bitset weak_b(finalizer_count, qc.weak_votes.value());
weight = aggregate_keys(weak_b, finalizer_policy, agg_pub_key);
_verify({create_weak_digest(finality_digest)}, {agg_pub_key}, qc.signature);
}
else {
//strong QC
bls_g1 agg_pub_key;
savanna::bitset strong_b(finalizer_count, qc.strong_votes.value());
weight = aggregate_keys(strong_b, finalizer_policy, agg_pub_key);
_verify({create_strong_digest(finality_digest)}, {agg_pub_key}, qc.signature);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically you just need the three cases within the largest else branch here. Although there is a cleaner way of structuring this code See:

void qc_sig_t::verify_signatures(const finalizer_policy_ptr& fin_policy,
const digest_type& strong_digest,
const weak_digest_t& weak_digest) const {
const auto& finalizers = fin_policy->finalizers;
auto num_finalizers = finalizers.size();
// 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( strong_votes ) {
pubkeys.emplace_back(aggregate_pubkeys(*strong_votes));
digests.emplace_back(std::vector<uint8_t>{strong_digest.data(), strong_digest.data() + strong_digest.data_size()});
}
if( weak_votes ) {
pubkeys.emplace_back(aggregate_pubkeys(*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, sig.jacobian_montgomery_le()),
invalid_qc_signature, "qc signature validation failed" );
}

I don't think there is even a reason to have the count_strong_only boolean. You may just want to add a bool is_strong() const member function to quorum_certificate_input so that the IBC contract can do a separate check to see if the submitted QC is strong.

}

std::string s_agg_pub_key = encode_g1_to_bls_public_key(agg_pub_key);
//verify signature validity
check(_verify(s_agg_pub_key, qc.signature, message), "signature verification failed");
if (enforce_threshold_check) check(weight>=finalizer_policy.threshold, "insufficient signatures to reach quorum");

}

checksum256 get_merkle_root(const std::vector<checksum256>& leaves) {
Expand Down Expand Up @@ -268,8 +333,8 @@ namespace savanna {
};

struct action_proof_of_inclusion {
uint64_t target_block_index = 0;
uint64_t final_block_index = 0;
uint64_t target_action_index = 0;
uint64_t final_action_index = 0;

action_data target;

Expand All @@ -278,7 +343,7 @@ namespace savanna {
//returns the merkle root obtained by hashing target.digest() with merkle_branches
checksum256 root() const {
checksum256 digest = action_data_internal(target).digest();
checksum256 root = _compute_root(merkle_branches, digest, target_block_index, final_block_index);
checksum256 root = _compute_root(merkle_branches, digest, target_action_index, final_action_index);
return root;
};
};
Expand Down Expand Up @@ -331,8 +396,8 @@ namespace savanna {
};

struct reversible_proof_of_inclusion {
uint64_t target_block_index = 0;
uint64_t final_block_index = 0;
uint64_t target_reversible_block_index = 0;
uint64_t final_reversible_block_index = 0;

block_ref_data target;

Expand All @@ -341,7 +406,7 @@ namespace savanna {
//returns the merkle root obtained by hashing target.digest() with merkle_branches
checksum256 root() const {
checksum256 digest = target.digest();
checksum256 root = _compute_root(merkle_branches, digest, target_block_index, final_block_index);
checksum256 root = _compute_root(merkle_branches, digest, target_reversible_block_index, final_reversible_block_index);
return root;
};
};
Expand Down
Loading
Loading