-
Notifications
You must be signed in to change notification settings - Fork 73
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:Unification: Integrate vote message signatures into new fork database #2067
Changes from 5 commits
ab8fcc2
8a67d01
ee7f45f
b7265db
2545523
dc83521
03cc7b1
cb6fd13
2c3e163
c474e03
d6fba94
0e49022
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ | |
#include <eosio/chain/hotstuff/finalizer_authority.hpp> | ||
#include <eosio/chain/hotstuff/hotstuff.hpp> | ||
#include <eosio/chain/hotstuff/chain_pacemaker.hpp> | ||
#include <eosio/chain/hotstuff/finality_controller.hpp> | ||
|
||
#include <chainbase/chainbase.hpp> | ||
#include <eosio/vm/allocator.hpp> | ||
|
@@ -764,6 +765,17 @@ struct controller_impl { | |
return std::visit(overloaded{[&](block_data_legacy_t& bd) -> R { return bd.template apply<R>(f); }, | ||
[&](block_data_new_t& bd) -> R { return {}; }}, v); | ||
} | ||
|
||
template <class R, class F> | ||
R apply_block_data_new(F& f) { | ||
if constexpr (std::is_same_v<void, R>) | ||
std::visit(overloaded{[&](block_data_legacy_t& bd) {}, | ||
[&](block_data_new_t& bd) { bd.template apply<R>(f); }}, v); | ||
else | ||
return std::visit(overloaded{[&](block_data_legacy_t& bd) -> R { return {}; }, | ||
[&](block_data_new_t& bd) -> R { return bd.template apply<R>(f); }}, v); | ||
} | ||
|
||
}; | ||
|
||
reset_new_handler rnh; // placed here to allow for this to be set before constructing the other fields | ||
|
@@ -774,6 +786,7 @@ struct controller_impl { | |
std::optional<pending_state> pending; | ||
block_data_t block_data; // includes `head` aand `fork_db` | ||
std::optional<chain_pacemaker> pacemaker; | ||
finality_controller finality_control; | ||
std::atomic<uint32_t> hs_irreversible_block_num{0}; | ||
resource_limits_manager resource_limits; | ||
subjective_billing subjective_bill; | ||
|
@@ -3856,10 +3869,10 @@ std::optional<signed_block_header> controller::fetch_block_header_by_number( uin | |
} FC_CAPTURE_AND_RETHROW( (block_num) ) } | ||
|
||
|
||
block_state_legacy_ptr controller::fetch_block_state_by_id( block_id_type id )const { | ||
// returns nullptr when in IF mode | ||
auto get_block_state = [&](auto& fork_db, auto& head) -> block_state_legacy_ptr { return fork_db.get_block(id); }; | ||
return my->block_data.apply_dpos<block_state_legacy_ptr>(get_block_state); | ||
block_state_ptr controller::fetch_block_state_by_id( block_id_type id )const { | ||
// returns nullptr when in legacy mode | ||
auto get_block_state = [&](auto& fork_db, auto& head) -> block_state_ptr { return fork_db.get_block(id); }; | ||
return my->block_data.apply_block_data_new<block_state_ptr>(get_block_state); | ||
} | ||
|
||
block_state_legacy_ptr controller::fetch_block_state_by_number( uint32_t block_num )const { | ||
|
@@ -3975,8 +3988,13 @@ 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); | ||
void controller::notify_vote_message( const hs_vote_message& vote ) { | ||
auto bsp = fetch_block_state_by_id(vote.proposal_id); | ||
if( bsp ) { | ||
my->finality_control.aggregate_vote(bsp, vote); | ||
} else { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Block data and the other structs with variants should contain, as much as possible, any code that does something different for It is perfectly fine to add new members like The |
||
wlog( "no block exists for the vote (proposal_id: ${id}", ("id", vote.proposal_id) ); | ||
} | ||
}; | ||
|
||
const producer_authority_schedule& controller::active_producers()const { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include <eosio/chain/hotstuff/finality_controller.hpp> | ||
|
||
namespace eosio::chain { | ||
|
||
struct finality_controller_impl { | ||
bool aggregate_vote(const block_state_ptr& bsp, const hs_vote_message& vote) { | ||
const auto& finalizers = bsp->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); | ||
return bsp->pending_qc.add_vote( vote.strong, | ||
index, | ||
vote.finalizer_key, | ||
vote.sig ); | ||
} else { | ||
wlog( "finalizer_key (${k}) in vote is not in finalizer policy", ("k", vote.finalizer_key) ); | ||
return false; | ||
} | ||
} | ||
}; // finality_controller_impl | ||
|
||
finality_controller::finality_controller() | ||
:my( new finality_controller_impl() ) | ||
{ | ||
} | ||
|
||
finality_controller::~finality_controller() | ||
{ | ||
} | ||
|
||
bool finality_controller::aggregate_vote(const block_state_ptr& bsp, const hs_vote_message& vote) { | ||
return my->aggregate_vote(bsp, vote); | ||
} | ||
|
||
} // namespace eosio::chain |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -22,10 +22,14 @@ 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]) { | ||||||
wlog( "finalizer ${i} has already voted", ("i", 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( "sinature from finalizer ${i} cannot be verified", ("i", index) ); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
return false; | ||||||
} | ||||||
_bitset.set(index); | ||||||
_sig = fc::crypto::blslib::aggregate({_sig, new_sig}); // works even if _sig is default initialized (fp2::zero()) | ||||||
return true; | ||||||
|
@@ -68,10 +72,10 @@ void pending_quorum_certificate::reset(const fc::sha256& proposal_id, const dige | |||||
_state = state_t::unrestricted; | ||||||
} | ||||||
|
||||||
bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& proposal_digest, size_t index, | ||||||
bool pending_quorum_certificate::add_strong_vote(size_t index, | ||||||
const bls_public_key& pubkey, const bls_signature& sig) { | ||||||
assert(index < _num_finalizers); | ||||||
if (!_strong_votes.add_vote(proposal_digest, index, pubkey, sig)) | ||||||
if (!_strong_votes.add_vote(_proposal_digest, index, pubkey, sig)) | ||||||
return false; | ||||||
size_t weak = num_weak(); | ||||||
size_t strong = num_strong(); | ||||||
|
@@ -99,10 +103,10 @@ bool pending_quorum_certificate::add_strong_vote(const std::vector<uint8_t>& pro | |||||
return true; | ||||||
} | ||||||
|
||||||
bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& proposal_digest, size_t index, | ||||||
bool pending_quorum_certificate::add_weak_vote(size_t index, | ||||||
const bls_public_key& pubkey, const bls_signature& sig) { | ||||||
assert(index < _num_finalizers); | ||||||
if (!_weak_votes.add_vote(proposal_digest, index, pubkey, sig)) | ||||||
if (!_weak_votes.add_vote(_proposal_digest, index, pubkey, sig)) | ||||||
return false; | ||||||
size_t weak = num_weak(); | ||||||
size_t strong = num_strong(); | ||||||
|
@@ -134,10 +138,10 @@ bool pending_quorum_certificate::add_weak_vote(const std::vector<uint8_t>& propo | |||||
return true; | ||||||
} | ||||||
|
||||||
bool pending_quorum_certificate::add_vote(bool strong, const std::vector<uint8_t>& proposal_digest, size_t index, | ||||||
bool pending_quorum_certificate::add_vote(bool strong, size_t index, | ||||||
const bls_public_key& pubkey, const bls_signature& sig) { | ||||||
return strong ? add_strong_vote(proposal_digest, index, pubkey, sig) | ||||||
: add_weak_vote(proposal_digest, index, pubkey, sig); | ||||||
return strong ? add_strong_vote(index, pubkey, sig) | ||||||
: add_weak_vote(index, pubkey, sig); | ||||||
Comment on lines
+141
to
+144
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as discussed in the meeting, you'll have to pass the |
||||||
} | ||||||
|
||||||
// ================== begin compatibility functions ======================= | ||||||
|
@@ -192,4 +196,4 @@ quorum_certificate_message valid_quorum_certificate::to_msg() const { | |||||
}; | ||||||
} | ||||||
|
||||||
} // namespace eosio::chain | ||||||
} // namespace eosio::chain |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
#include <eosio/chain/hotstuff/finality_controller.hpp> | ||
|
||
#include <fc/exception/exception.hpp> | ||
#include <fc/crypto/bls_private_key.hpp> | ||
#include <fc/crypto/bls_utils.hpp> | ||
|
||
#include <boost/test/unit_test.hpp> | ||
|
||
BOOST_AUTO_TEST_SUITE(finality_controller_tests) | ||
|
||
BOOST_AUTO_TEST_CASE(aggregate_vote_test) try { | ||
using namespace eosio::chain; | ||
using namespace fc::crypto::blslib; | ||
|
||
digest_type proposal_id(fc::sha256("0000000000000000000000000000001")); | ||
|
||
digest_type proposal_digest(fc::sha256("0000000000000000000000000000002")); | ||
std::vector<uint8_t> proposal_digest_data(proposal_digest.data(), proposal_digest.data() + proposal_digest.data_size()); | ||
|
||
const size_t num_finalizers = 3; | ||
|
||
// initialize a set of private keys | ||
std::vector<bls_private_key> private_key { | ||
bls_private_key("PVT_BLS_r4ZpChd87ooyzl6MIkw23k7PRX8xptp7TczLJHCIIW88h/hS"), | ||
bls_private_key("PVT_BLS_/l7xzXANaB+GrlTsbZEuTiSOiWTtpBoog+TZnirxUUSaAfCo"), | ||
bls_private_key("PVT_BLS_3FoY73Q/gED3ejyg8cvnGqHrMmx4cLKwh/e0sbcsCxpCeqn3"), | ||
}; | ||
|
||
// construct finalizers | ||
std::vector<bls_public_key> public_key(num_finalizers); | ||
std::vector<finalizer_authority> finalizers(num_finalizers); | ||
for (size_t i = 0; i < num_finalizers; ++i) { | ||
public_key[i] = private_key[i].get_public_key(); | ||
finalizers[i] = finalizer_authority{ "test", 1, public_key[i] }; | ||
} | ||
|
||
finality_controller finality_control; | ||
|
||
{ // all finalizers can aggregate votes | ||
block_state_ptr bsp = std::make_shared<block_state>(); | ||
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers ); | ||
bsp->pending_qc = pending_quorum_certificate{ proposal_id, proposal_digest, num_finalizers, 1 }; | ||
|
||
for (size_t i = 0; i < num_finalizers; ++i) { | ||
bool strong = (i % 2 == 0); // alternate strong and weak | ||
hs_vote_message vote {proposal_id, strong, public_key[i], private_key[i].sign(proposal_digest_data) }; | ||
BOOST_REQUIRE(finality_control.aggregate_vote(bsp, vote)); | ||
} | ||
} | ||
|
||
{ // public and private keys mismatched | ||
block_state_ptr bsp = std::make_shared<block_state>(); | ||
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers ); | ||
bsp->pending_qc = pending_quorum_certificate{ proposal_id, proposal_digest, num_finalizers, 1 }; | ||
|
||
hs_vote_message vote {proposal_id, true, public_key[0], private_key[1].sign(proposal_digest_data) }; | ||
BOOST_REQUIRE(!finality_control.aggregate_vote(bsp, vote)); | ||
} | ||
|
||
{ // duplicate votes | ||
block_state_ptr bsp = std::make_shared<block_state>(); | ||
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers ); | ||
bsp->pending_qc = pending_quorum_certificate{ proposal_id, proposal_digest, num_finalizers, 1 }; | ||
|
||
hs_vote_message vote {proposal_id, true, public_key[0], private_key[0].sign(proposal_digest_data) }; | ||
BOOST_REQUIRE(finality_control.aggregate_vote(bsp, vote)); | ||
BOOST_REQUIRE(!finality_control.aggregate_vote(bsp, vote)); | ||
} | ||
|
||
{ // public key does not exit in finalizer set | ||
block_state_ptr bsp = std::make_shared<block_state>(); | ||
bsp->finalizer_policy = std::make_shared<finalizer_policy>( 10, 15, finalizers ); | ||
bsp->pending_qc = pending_quorum_certificate{ proposal_id, proposal_digest, num_finalizers, 1 }; | ||
|
||
bls_private_key new_private_key{ "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId" }; | ||
bls_public_key new_public_key{ new_private_key.get_public_key() }; | ||
|
||
hs_vote_message vote {proposal_id, true, new_public_key, private_key[0].sign(proposal_digest_data) }; | ||
BOOST_REQUIRE(!finality_control.aggregate_vote(bsp, vote)); | ||
} | ||
} FC_LOG_AND_RETHROW(); | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#pragma once | ||
|
||
#include <eosio/chain/hotstuff/hotstuff.hpp> | ||
#include <eosio/chain/block_state.hpp> | ||
|
||
namespace eosio::chain { | ||
struct finality_controller_impl; | ||
|
||
class finality_controller { | ||
public: | ||
finality_controller(); | ||
~finality_controller(); | ||
|
||
bool aggregate_vote(const block_state_ptr& bsp, const hs_vote_message& vote); | ||
|
||
private: | ||
std::unique_ptr<finality_controller_impl> my; | ||
}; | ||
|
||
} // eosio::chain |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please change the function name to
process_vote_message
oraggregate_vote_message
or something like that.