blob: e8f97655de53a203a3ed96fbf5eb351eb504ee44 (
plain) (
tree)
|
|
#ifndef _HOTSTUFF_CONSENSUS_H
#define _HOTSTUFF_CONSENSUS_H
#include <cassert>
#include <set>
#include <unordered_map>
#include "hotstuff/promise.hpp"
#include "hotstuff/type.h"
#include "hotstuff/entity.h"
#include "hotstuff/crypto.h"
namespace hotstuff {
struct Proposal;
struct Vote;
struct Finality;
/** Abstraction for HotStuff protocol state machine (without network implementation). */
class HotStuffCore {
block_t b0; /** the genesis block */
/* === state variables === */
/** block containing the QC for the highest block having one */
block_t bqc;
block_t bexec; /**< last executed block */
uint32_t vheight; /**< height of the block last voted for */
/* === auxilliary variables === */
privkey_bt priv_key; /**< private key for signing votes */
std::set<block_t, BlockHeightCmp> tails; /**< set of tail blocks */
ReplicaConfig config; /**< replica configuration */
/* === async event queues === */
std::unordered_map<block_t, promise_t> qc_waiting;
promise_t propose_waiting;
promise_t receive_proposal_waiting;
promise_t bqc_update_waiting;
/* == feature switches == */
/** always vote negatively, useful for some PaceMakers */
bool neg_vote;
block_t get_delivered_blk(const uint256_t &blk_hash);
void sanity_check_delivered(const block_t &blk);
void check_commit(const block_t &_bqc);
bool update(const uint256_t &bqc_hash);
void on_bqc_update();
void on_qc_finish(const block_t &blk);
void on_propose_(const Proposal &prop);
void on_receive_proposal_(const Proposal &prop);
protected:
ReplicaID id; /**< identity of the replica itself */
public:
BoxObj<EntityStorage> storage;
HotStuffCore(ReplicaID id, privkey_bt &&priv_key);
virtual ~HotStuffCore() {
b0->qc_ref = nullptr;
}
/* Inputs of the state machine triggered by external events, should called
* by the class user, with proper invariants. */
/** Call to initialize the protocol, should be called once before all other
* functions. */
void on_init(uint32_t nfaulty) { config.nmajority = 2 * nfaulty + 1; }
/* TODO: better name for "delivery" ? */
/** Call to inform the state machine that a block is ready to be handled.
* A block is only delivered if itself is fetched, the block for the
* contained qc is fetched and all parents are delivered. The user should
* always ensure this invariant. The invalid blocks will be dropped by this
* function.
* @return true if valid */
bool on_deliver_blk(const block_t &blk);
/** Call upon the delivery of a proposal message.
* The block mentioned in the message should be already delivered. */
void on_receive_proposal(const Proposal &prop);
/** Call upon the delivery of a vote message.
* The block mentioned in the message should be already delivered. */
void on_receive_vote(const Vote &vote);
/** Call to submit new commands to be decided (executed). "Parents" must
* contain at least one block, and the first block is the actual parent,
* while the others are uncles/aunts */
void on_propose(const std::vector<uint256_t> &cmds,
const std::vector<block_t> &parents,
bytearray_t &&extra = bytearray_t());
/* Functions required to construct concrete instances for abstract classes.
* */
/* Outputs of the state machine triggering external events. The virtual
* functions should be implemented by the user to specify the behavior upon
* the events. */
protected:
/** Called by HotStuffCore upon the decision being made for cmd. */
virtual void do_decide(Finality &&fin) = 0;
/** Called by HotStuffCore upon broadcasting a new proposal.
* The user should send the proposal message to all replicas except for
* itself. */
virtual void do_broadcast_proposal(const Proposal &prop) = 0;
/** Called upon sending out a new vote to the next proposer. The user
* should send the vote message to a *good* proposer to have good liveness,
* while safety is always guaranteed by HotStuffCore. */
virtual void do_vote(ReplicaID last_proposer, const Vote &vote) = 0;
/* The user plugs in the detailed instances for those
* polymorphic data types. */
public:
/** Create a partial certificate that proves the vote for a block. */
virtual part_cert_bt create_part_cert(const PrivKey &priv_key, const uint256_t &blk_hash) = 0;
/** Create a partial certificate from its seralized form. */
virtual part_cert_bt parse_part_cert(DataStream &s) = 0;
/** Create a quorum certificate that proves 2f+1 votes for a block. */
virtual quorum_cert_bt create_quorum_cert(const uint256_t &blk_hash) = 0;
/** Create a quorum certificate from its serialized form. */
virtual
|