Skip to content

Commit

Permalink
Merge pull request #1616 from AntelopeIO/internal_wiring_of_finalizer…
Browse files Browse the repository at this point in the history
…s_in_qc_chain

IF: updated qc_chain to use bls_public_key as finalizer id, completed internal wiring for signing + verification
  • Loading branch information
systemzax authored Sep 27, 2023
2 parents 5d4fb21 + bfa240b commit b97c279
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 353 deletions.
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)
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

0 comments on commit b97c279

Please sign in to comment.