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: updated qc_chain to use bls_public_key as finalizer id, completed internal wiring for signing + verification #1616

Merged
Merged
6 changes: 3 additions & 3 deletions libraries/chain/include/eosio/chain/hotstuff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace eosio::chain {

using hs_bitset = boost::dynamic_bitset<uint32_t>;
using hs_bitset = boost::dynamic_bitset<uint8_t>;
using bls_key_map_t = std::map<fc::crypto::blslib::bls_public_key, fc::crypto::blslib::bls_private_key>;

inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) {
Expand All @@ -30,7 +30,7 @@ namespace eosio::chain {

struct hs_vote_message {
fc::sha256 proposal_id; //vote on proposal
name finalizer;
fc::crypto::blslib::bls_public_key finalizer_key;
fc::crypto::blslib::bls_signature sig;
};

Expand Down Expand Up @@ -91,7 +91,7 @@ namespace eosio::chain {
// // @ignore quorum_met
FC_REFLECT(eosio::chain::quorum_certificate_message, (proposal_id)(active_finalizers)(active_agg_sig));
FC_REFLECT(eosio::chain::extended_schedule, (producer_schedule)(bls_pub_keys));
FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig));
FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer_key)(sig));
FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter));
FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify));
FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc));
Expand Down
30 changes: 8 additions & 22 deletions libraries/hotstuff/chain_pacemaker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ namespace eosio { namespace hotstuff {
bls_key_map_t finalizer_keys,
fc::logger& logger)
: _chain(chain),
_qc_chain("default"_n, this, std::move(my_producers), std::move(finalizer_keys), logger),
_qc_chain("default", this, std::move(my_producers), std::move(finalizer_keys), logger),
_logger(logger)
{
_accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) {
Expand Down Expand Up @@ -266,23 +266,8 @@ namespace eosio { namespace hotstuff {
return n;
}

std::vector<name> chain_pacemaker::get_finalizers() {

#warning FIXME: Use _active_finalizer_set in pacemaker/qc_chain.
// _active_finalizer_set should be used

std::unique_lock g( _chain_state_mutex );
block_state_ptr hbs = _head_block_state;
g.unlock();

// Old code: get eosio::name from the producer schedule
const std::vector<producer_authority>& pa_list = hbs->active_schedule.producers;
std::vector<name> pn_list;
pn_list.reserve(pa_list.size());
std::transform(pa_list.begin(), pa_list.end(),
std::back_inserter(pn_list),
[](const producer_authority& p) { return p.producer_name; });
return pn_list;
const finalizer_set& chain_pacemaker::get_finalizer_set(){
return _active_finalizer_set;
}

block_id_type chain_pacemaker::get_current_block_id() {
Expand All @@ -303,24 +288,25 @@ namespace eosio { namespace hotstuff {
prof.core_out();
}

void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id, const std::optional<uint32_t>& exclude_peer) {
void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer) {
bcast_hs_message(exclude_peer, msg);
}

void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id, const std::optional<uint32_t>& exclude_peer) {
void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer) {
bcast_hs_message(exclude_peer, msg);
}

void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id, const std::optional<uint32_t>& exclude_peer) {
void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer) {
bcast_hs_message(exclude_peer, msg);
}

void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id, const std::optional<uint32_t>& exclude_peer) {
void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer) {
bcast_hs_message(exclude_peer, msg);
}

void chain_pacemaker::send_hs_message_warning(const uint32_t sender_peer, const chain::hs_message_warning code) {
warn_hs_message(sender_peer, code);

}

// called from net threads
Expand Down
17 changes: 12 additions & 5 deletions libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
#include <eosio/chain/name.hpp>
#include <eosio/chain/hotstuff.hpp>

#include <fc/crypto/bls_utils.hpp>

#include <eosio/chain/finalizer_set.hpp>

#include <vector>

namespace eosio::hotstuff {
Expand All @@ -27,15 +31,18 @@ namespace eosio::hotstuff {
virtual chain::name get_proposer() = 0;
virtual chain::name get_leader() = 0;
virtual chain::name get_next_leader() = 0;
virtual std::vector<chain::name> get_finalizers() = 0;
virtual const eosio::chain::finalizer_set& get_finalizer_set() = 0;


//outbound communications; 'id' is the producer name (can be ignored if/when irrelevant to the implementer)
greg7mdp marked this conversation as resolved.
Show resolved Hide resolved
virtual void send_hs_proposal_msg(const chain::hs_proposal_message& msg, chain::name id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;
virtual void send_hs_vote_msg(const chain::hs_vote_message& msg, chain::name id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;
virtual void send_hs_new_view_msg(const chain::hs_new_view_message& msg, chain::name id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;
virtual void send_hs_new_block_msg(const chain::hs_new_block_message& msg, chain::name id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;

virtual void send_hs_proposal_msg(const chain::hs_proposal_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;
virtual void send_hs_vote_msg(const chain::hs_vote_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;
virtual void send_hs_new_view_msg(const chain::hs_new_view_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;
virtual void send_hs_new_block_msg(const chain::hs_new_block_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer = std::nullopt) = 0;

virtual void send_hs_message_warning(const uint32_t sender_peer, const chain::hs_message_warning code) = 0;

};

} // namespace eosio::hotstuff
12 changes: 5 additions & 7 deletions libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#include <eosio/hotstuff/base_pacemaker.hpp>
#include <eosio/hotstuff/qc_chain.hpp>

#include <eosio/chain/finalizer_set.hpp>

#include <boost/signals2/connection.hpp>

#include <shared_mutex>
Expand Down Expand Up @@ -38,16 +36,16 @@ namespace eosio::hotstuff {
name get_proposer();
name get_leader() ;
name get_next_leader() ;
std::vector<name> get_finalizers();
const finalizer_set& get_finalizer_set();

block_id_type get_current_block_id();

uint32_t get_quorum_threshold();

void send_hs_proposal_msg(const hs_proposal_message& msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_vote_msg(const hs_vote_message& msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_view_msg(const hs_new_view_message& msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_block_msg(const hs_new_block_message& msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_proposal_msg(const hs_proposal_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);
void send_hs_vote_msg(const hs_vote_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_view_msg(const hs_new_view_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_block_msg(const hs_new_block_message& msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);

void send_hs_message_warning(const uint32_t sender_peer, const chain::hs_message_warning code);

Expand Down
34 changes: 14 additions & 20 deletions libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include <eosio/chain/block_state.hpp>
#include <eosio/hotstuff/base_pacemaker.hpp>

#include <eosio/chain/finalizer_set.hpp>
#include <eosio/chain/finalizer_authority.hpp>

#include <fc/crypto/bls_utils.hpp>
#include <fc/crypto/sha256.hpp>

Expand All @@ -18,6 +21,7 @@

#include <boost/dynamic_bitset.hpp>


#include <exception>
#include <stdexcept>

Expand All @@ -36,10 +40,11 @@ namespace eosio::hotstuff {
active_finalizers.resize(finalizer_size);
}

explicit quorum_certificate(const quorum_certificate_message& msg)
explicit quorum_certificate(const quorum_certificate_message& msg, size_t finalizer_count)
: proposal_id(msg.proposal_id)
, active_finalizers(msg.active_finalizers.cbegin(), msg.active_finalizers.cend())
, active_agg_sig(msg.active_agg_sig) {
active_finalizers.resize(finalizer_count);
}

quorum_certificate_message to_msg() const {
Expand Down Expand Up @@ -95,14 +100,14 @@ namespace eosio::hotstuff {

qc_chain() = delete;

qc_chain(name id, base_pacemaker* pacemaker,
qc_chain(std::string id, base_pacemaker* pacemaker,
std::set<name> my_producers,
chain::bls_key_map_t finalizer_keys,
fc::logger& logger);

uint64_t get_state_version() const { return _state_version; } // no lock required

name get_id_i() const { return _id; } // only for testing
const std::string& get_id_i() const { return _id; } // so far, only ever relevant in a test environment and for logging (no sync)

// Calls to the following methods should be thread-synchronized externally:

Expand All @@ -124,18 +129,17 @@ namespace eosio::hotstuff {

uint32_t positive_bits_count(const hs_bitset& finalizers);

hs_bitset update_bitset(const hs_bitset& finalizer_set, name finalizer);
hs_bitset update_bitset(const hs_bitset& finalizer_set, const fc::crypto::blslib::bls_public_key& finalizer_key);

//get digest to sign from proposal data
digest_type get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc);

void reset_qc(const fc::sha256& proposal_id);

//evaluate quorum for a proposal
bool evaluate_quorum(const extended_schedule& es, const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal);
bool evaluate_quorum(const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal

//check if quorum has been met over a proposal
bool is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal);
// qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method
bool is_quorum_met(const quorum_certificate& qc, const hs_proposal_message& proposal); //check if quorum has been met over a proposal

hs_proposal_message new_proposal_candidate(const block_id_type& block_id, uint8_t phase_counter);
hs_new_block_message new_block_candidate(const block_id_type& block_id);
Expand All @@ -150,7 +154,7 @@ namespace eosio::hotstuff {
void process_new_view(const std::optional<uint32_t>& connection_id, const hs_new_view_message& msg);
void process_new_block(const std::optional<uint32_t>& connection_id, const hs_new_block_message& msg);

hs_vote_message sign_proposal(const hs_proposal_message& proposal, name finalizer);
hs_vote_message sign_proposal(const hs_proposal_message& proposal, const fc::crypto::blslib::bls_private_key& finalizer_priv_key);

//verify that a proposal descends from another
bool extends(const fc::sha256& descendant, const fc::sha256& ancestor);
Expand Down Expand Up @@ -180,15 +184,6 @@ namespace eosio::hotstuff {

void gc_proposals(uint64_t cutoff);

#warning remove. bls12-381 key used for testing purposes
//todo : remove. bls12-381 key used for testing purposes
std::vector<uint8_t> _seed =
{ 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192,
19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82,
12, 62, 89, 110, 182, 9, 44, 20, 254, 22 };

fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed);

enum msg_type {
new_view = 1,
new_block = 2,
Expand All @@ -206,11 +201,10 @@ namespace eosio::hotstuff {
quorum_certificate _high_qc;
quorum_certificate _current_qc;
uint32_t _v_height = 0;
eosio::chain::extended_schedule _schedule;
base_pacemaker* _pacemaker = nullptr;
std::set<name> _my_producers;
chain::bls_key_map_t _my_finalizer_keys;
name _id;
std::string _id;

mutable std::atomic<uint64_t> _state_version = 1;

Expand Down
38 changes: 20 additions & 18 deletions libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
#include <eosio/hotstuff/base_pacemaker.hpp>
#include <eosio/hotstuff/qc_chain.hpp>

//#include <eosio/chain/finalizer_set.hpp>

namespace eosio { namespace hotstuff {

class test_pacemaker : public base_pacemaker {
public:

using hotstuff_message = std::pair<name, std::variant<hs_proposal_message, hs_vote_message, hs_new_block_message, hs_new_view_message>>;
using hotstuff_message = std::pair<std::string, std::variant<hs_proposal_message, hs_vote_message, hs_new_block_message, hs_new_view_message>>;

enum hotstuff_message_index {
hs_proposal = 0,
hs_vote = 1,
Expand All @@ -18,27 +21,27 @@ namespace eosio { namespace hotstuff {

//class-specific functions

bool is_qc_chain_active(const name & qcc_name) { return _qcc_deactivated.find(qcc_name) == _qcc_deactivated.end(); }
bool is_qc_chain_active(const name& qcc_name) { return _qcc_deactivated.find(qcc_name) == _qcc_deactivated.end(); }

void set_proposer(name proposer);

void set_leader(name leader);

void set_next_leader(name next_leader);

void set_finalizers(const std::vector<name>& finalizers);
void set_finalizer_set(const eosio::chain::finalizer_set& finalizer_set);

void set_current_block_id(block_id_type id);

void set_quorum_threshold(uint32_t threshold);

void add_message_to_queue(const hotstuff_message& msg);

void connect(const std::vector<name>& nodes);
void connect(const std::vector<std::string>& nodes);

void disconnect(const std::vector<name>& nodes);
void disconnect(const std::vector<std::string>& nodes);

bool is_connected(name node1, name node2);
bool is_connected(std::string node1, std::string node2);

void pipe(const std::vector<test_pacemaker::hotstuff_message>& messages);

Expand All @@ -56,26 +59,26 @@ namespace eosio { namespace hotstuff {

void beat();

void on_hs_vote_msg(const hs_vote_message & msg, name id); //confirmation msg event handler
void on_hs_proposal_msg(const hs_proposal_message & msg, name id); //consensus msg event handler
void on_hs_new_view_msg(const hs_new_view_message & msg, name id); //new view msg event handler
void on_hs_new_block_msg(const hs_new_block_message & msg, name id); //new block msg event handler
void on_hs_vote_msg(const hs_vote_message & msg, const std::string& id); //confirmation msg event handler
void on_hs_proposal_msg(const hs_proposal_message & msg, const std::string& id); //consensus msg event handler
void on_hs_new_view_msg(const hs_new_view_message & msg, const std::string& id); //new view msg event handler
void on_hs_new_block_msg(const hs_new_block_message & msg, const std::string& id); //new block msg event handler

//base_pacemaker interface functions

name get_proposer();
name get_leader();
name get_next_leader();
std::vector<name> get_finalizers();
const finalizer_set& get_finalizer_set();

block_id_type get_current_block_id();

uint32_t get_quorum_threshold();

void send_hs_proposal_msg(const hs_proposal_message & msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_vote_msg(const hs_vote_message & msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_block_msg(const hs_new_block_message & msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_view_msg(const hs_new_view_message & msg, name id, const std::optional<uint32_t>& exclude_peer);
void send_hs_proposal_msg(const hs_proposal_message & msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);
void send_hs_vote_msg(const hs_vote_message & msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_block_msg(const hs_new_block_message & msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);
void send_hs_new_view_msg(const hs_new_view_message & msg, const std::string& id, const std::optional<uint32_t>& exclude_peer);

void send_hs_message_warning(const uint32_t sender_peer, const chain::hs_message_warning code);

Expand All @@ -92,17 +95,16 @@ namespace eosio { namespace hotstuff {
// network topology: key (node name) is connected to all nodes in the mapped set.
// double mapping, so if _net[a] yields b, then _net[b] yields a.
// this is a filter; messages to self won't happen even if _net[x] yields x.
map<name, std::set<name>> _net;
map<std::string, std::set<std::string>> _net;

name _proposer;
name _leader;
name _next_leader;

std::vector<name> _finalizers;
finalizer_set _finalizer_set;

block_id_type _current_block_id;

std::vector<name> _unique_replicas;
#warning calculate from schedule
uint32_t _quorum_threshold = 15; //todo : calculate from schedule
};
Expand Down
Loading