Skip to content

Commit

Permalink
Merge pull request #1560 from AntelopeIO/GH-1547-finalizer-set
Browse files Browse the repository at this point in the history
IF: Support larger number of finalizers
  • Loading branch information
heifner authored Aug 29, 2023
2 parents ddb9ac4 + c2c0446 commit 4ef68bd
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 106 deletions.
30 changes: 14 additions & 16 deletions libraries/chain/include/eosio/chain/hotstuff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
#include <fc/crypto/bls_signature.hpp>
#include <fc/crypto/bls_utils.hpp>

#include <boost/dynamic_bitset.hpp>

namespace eosio::chain {

const block_id_type NULL_BLOCK_ID = block_id_type("00");
const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00");

using hs_bitset = boost::dynamic_bitset<uint32_t>;

inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) {
return (uint64_t{block_height} << 32) | phase_counter;
}
Expand All @@ -20,11 +24,10 @@ namespace eosio::chain {
std::map<name, fc::crypto::blslib::bls_public_key> bls_pub_keys;
};

struct quorum_certificate {
struct quorum_certificate_message {
fc::sha256 proposal_id = NULL_PROPOSAL_ID;
fc::unsigned_int active_finalizers = 0; //bitset encoding, following canonical order
std::vector<unsigned_int> active_finalizers; //bitset encoding, following canonical order
fc::crypto::blslib::bls_signature active_agg_sig;
bool quorum_met = false;
};

struct hs_vote_message {
Expand All @@ -38,26 +41,25 @@ namespace eosio::chain {
block_id_type block_id = NULL_BLOCK_ID;
fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal
fc::sha256 final_on_qc = NULL_PROPOSAL_ID;
quorum_certificate justify; //justification
quorum_certificate_message justify; //justification
uint8_t phase_counter = 0;

uint32_t block_num() const { return block_header::num_from_id(block_id); }
uint64_t get_height() const { return compute_height(block_header::num_from_id(block_id), phase_counter); };
};

struct hs_new_block_message {
block_id_type block_id = NULL_BLOCK_ID; //new proposal
quorum_certificate justify; //justification
block_id_type block_id = NULL_BLOCK_ID; //new proposal
quorum_certificate_message justify; //justification
};

struct hs_new_view_message {
quorum_certificate high_qc; //justification
quorum_certificate_message high_qc; //justification
};

using hs_message = std::variant<hs_vote_message, hs_proposal_message, hs_new_block_message, hs_new_view_message>;

struct finalizer_state {

bool chained_mode = false;
fc::sha256 b_leaf = NULL_PROPOSAL_ID;
fc::sha256 b_lock = NULL_PROPOSAL_ID;
Expand All @@ -66,8 +68,8 @@ namespace eosio::chain {
block_id_type block_exec = NULL_BLOCK_ID;
block_id_type pending_proposal_block = NULL_BLOCK_ID;
uint32_t v_height = 0;
eosio::chain::quorum_certificate high_qc;
eosio::chain::quorum_certificate current_qc;
eosio::chain::quorum_certificate_message high_qc;
eosio::chain::quorum_certificate_message current_qc;
eosio::chain::extended_schedule schedule;
map<fc::sha256, hs_proposal_message> proposals;

Expand All @@ -79,14 +81,10 @@ namespace eosio::chain {
}
};

using hs_proposal_message_ptr = std::shared_ptr<hs_proposal_message>;
using hs_vote_message_ptr = std::shared_ptr<hs_vote_message>;
using hs_new_view_message_ptr = std::shared_ptr<hs_new_view_message>;
using hs_new_block_message_ptr = std::shared_ptr<hs_new_block_message>;

} //eosio::chain

FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig));
// // @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_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter));
Expand Down
74 changes: 65 additions & 9 deletions libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,64 @@ namespace eosio::hotstuff {
using namespace boost::multi_index;
using namespace eosio::chain;

class quorum_certificate {
public:
explicit quorum_certificate(size_t finalizer_size = 0) {
active_finalizers.resize(finalizer_size);
}

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

quorum_certificate_message to_msg() const {
return {.proposal_id = proposal_id,
.active_finalizers = [this]() {
std::vector<unsigned_int> r;
r.resize(active_finalizers.num_blocks());
boost::to_block_range(active_finalizers, r.begin());
return r;
}(),
.active_agg_sig = active_agg_sig};
}

void reset(const fc::sha256& proposal, size_t finalizer_size) {
proposal_id = proposal;
active_finalizers = hs_bitset{finalizer_size};
active_agg_sig = fc::crypto::blslib::bls_signature();
quorum_met = false;
}

const hs_bitset& get_active_finalizers() const {
assert(!active_finalizers.empty());
return active_finalizers;
}
void set_active_finalizers(const hs_bitset& bs) {
assert(!bs.empty());
active_finalizers = bs;
}
std::string get_active_finalizers_string() const {
std::string r;
boost::to_string(active_finalizers, r);
return r;
}

const fc::sha256& get_proposal_id() const { return proposal_id; }
const fc::crypto::blslib::bls_signature& get_active_agg_sig() const { return active_agg_sig; }
void set_active_agg_sig( const fc::crypto::blslib::bls_signature& sig) { active_agg_sig = sig; }
bool is_quorum_met() const { return quorum_met; }
void set_quorum_met() { quorum_met = true; }

private:
friend struct fc::reflector<quorum_certificate>;
fc::sha256 proposal_id = NULL_PROPOSAL_ID;
hs_bitset active_finalizers; //bitset encoding, following canonical order
fc::crypto::blslib::bls_signature active_agg_sig;
bool quorum_met = false; // not serialized across network
};

// Concurrency note: qc_chain is a single-threaded and lock-free decision engine.
// All thread synchronization, if any, is external.
class qc_chain {
Expand Down Expand Up @@ -61,18 +119,18 @@ namespace eosio::hotstuff {
// returns false if proposal with that same ID already exists at the store of its height
bool insert_proposal(const hs_proposal_message& proposal);

uint32_t positive_bits_count(fc::unsigned_int value);
uint32_t positive_bits_count(const hs_bitset& finalizers);

fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer);
hs_bitset update_bitset(const hs_bitset& finalizer_set, name finalizer);

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

void reset_qc(const fc::sha256& proposal_id); //reset current internal qc

bool evaluate_quorum(const extended_schedule& es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //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); //evaluate quorum for a 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 eosio::chain::quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& 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); //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); //create new proposal message
hs_new_block_message new_block_candidate(const block_id_type& block_id); //create new block message
Expand All @@ -90,7 +148,7 @@ namespace eosio::hotstuff {

bool extends(const fc::sha256& descendant, const fc::sha256& ancestor); //verify that a proposal descends from another

bool update_high_qc(const eosio::chain::quorum_certificate& high_qc); //check if update to our high qc is required
bool update_high_qc(const quorum_certificate& high_qc); //check if update to our high qc is required

void leader_rotation_check(); //check if leader rotation is required

Expand Down Expand Up @@ -131,14 +189,12 @@ namespace eosio::hotstuff {
fc::sha256 _b_lock = NULL_PROPOSAL_ID;
fc::sha256 _b_exec = NULL_PROPOSAL_ID;
fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID;
eosio::chain::quorum_certificate _high_qc;
eosio::chain::quorum_certificate _current_qc;
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;
bool _log = true;
bool _errors = true;
name _id;

mutable std::atomic<uint64_t> _state_version = 1;
Expand Down
Loading

0 comments on commit 4ef68bd

Please sign in to comment.