aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2019-04-07 16:10:23 -0400
committerDeterminant <ted.sybil@gmail.com>2019-04-07 16:10:23 -0400
commit2757995cb91dd02ebd6ede693cc6c02c4e359afe (patch)
treed5d3acfe2bae5907c2d949358acfc9659604495b
parent49225da30a16a81f5e07c499af88c95da68b45b1 (diff)
clean up consensus code
-rw-r--r--include/hotstuff/consensus.h53
-rw-r--r--include/hotstuff/liveness.h36
m---------salticidae0
-rw-r--r--src/consensus.cpp75
-rw-r--r--src/hotstuff.cpp13
5 files changed, 78 insertions, 99 deletions
diff --git a/include/hotstuff/consensus.h b/include/hotstuff/consensus.h
index 5f781c5..a59c02f 100644
--- a/include/hotstuff/consensus.h
+++ b/include/hotstuff/consensus.h
@@ -38,7 +38,7 @@ class HotStuffCore {
block_t b0; /** the genesis block */
/* === state variables === */
/** block containing the QC for the highest block having one */
- block_t bqc;
+ std::pair<block_t, quorum_cert_bt> hqc;
block_t bexec; /**< last executed block */
uint32_t vheight; /**< height of the block last voted for */
/* === auxilliary variables === */
@@ -49,16 +49,16 @@ class HotStuffCore {
std::unordered_map<block_t, promise_t> qc_waiting;
promise_t propose_waiting;
promise_t receive_proposal_waiting;
- promise_t bqc_update_waiting;
+ promise_t hqc_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 update(const block_t &nblk);
+ void update_hqc(const block_t &_hqc, const quorum_cert_bt &qc);
+ void on_hqc_update();
void on_qc_finish(const block_t &blk);
void on_propose_(const Proposal &prop);
void on_receive_proposal_(const Proposal &prop);
@@ -152,12 +152,12 @@ class HotStuffCore {
promise_t async_wait_proposal();
/** Get a promise resolved when a new proposal is received. */
promise_t async_wait_receive_proposal();
- /** Get a promise resolved when bqc is updated. */
- promise_t async_bqc_update();
+ /** Get a promise resolved when hqc is updated. */
+ promise_t async_hqc_update();
/* Other useful functions */
const block_t &get_genesis() { return b0; }
- const block_t &get_bqc() { return bqc; }
+ const block_t &get_hqc() { return hqc.first; }
const ReplicaConfig &get_config() { return config; }
ReplicaID get_id() const { return id; }
const std::set<block_t, BlockHeightCmp> get_tails() const { return tails; }
@@ -168,34 +168,27 @@ class HotStuffCore {
/** Abstraction for proposal messages. */
struct Proposal: public Serializable {
ReplicaID proposer;
- /** hash for the block containing the highest QC */
- uint256_t bqc_hash;
/** block being proposed */
block_t blk;
-
/** handle of the core object to allow polymorphism. The user should use
* a pointer to the object of the class derived from HotStuffCore */
HotStuffCore *hsc;
Proposal(): blk(nullptr), hsc(nullptr) {}
Proposal(ReplicaID proposer,
- const uint256_t &bqc_hash,
const block_t &blk,
HotStuffCore *hsc):
proposer(proposer),
- bqc_hash(bqc_hash),
blk(blk), hsc(hsc) {}
void serialize(DataStream &s) const override {
s << proposer
- << bqc_hash
<< *blk;
}
void unserialize(DataStream &s) override {
assert(hsc != nullptr);
- s >> proposer
- >> bqc_hash;
+ s >> proposer;
Block _blk;
_blk.unserialize(s, hsc);
blk = hsc->storage->add_blk(std::move(_blk), hsc->get_config());
@@ -205,7 +198,6 @@ struct Proposal: public Serializable {
DataStream s;
s << "<proposal "
<< "rid=" << std::to_string(proposer) << " "
- << "bqc=" << get_hex10(bqc_hash) << " "
<< "blk=" << get_hex10(blk->get_hash()) << ">";
return std::move(s);
}
@@ -214,11 +206,9 @@ struct Proposal: public Serializable {
/** Abstraction for vote messages. */
struct Vote: public Serializable {
ReplicaID voter;
- /** hash for the block containing the highest QC */
- uint256_t bqc_hash;
/** block being voted */
uint256_t blk_hash;
- /** proof of validity for the vote (nullptr for a negative vote) */
+ /** proof of validity for the vote */
part_cert_bt cert;
/** handle of the core object to allow polymorphism */
@@ -226,18 +216,15 @@ struct Vote: public Serializable {
Vote(): cert(nullptr), hsc(nullptr) {}
Vote(ReplicaID voter,
- const uint256_t &bqc_hash,
const uint256_t &blk_hash,
part_cert_bt &&cert,
HotStuffCore *hsc):
voter(voter),
- bqc_hash(bqc_hash),
blk_hash(blk_hash),
cert(std::move(cert)), hsc(hsc) {}
Vote(const Vote &other):
voter(other.voter),
- bqc_hash(other.bqc_hash),
blk_hash(other.blk_hash),
cert(other.cert ? other.cert->clone() : nullptr),
hsc(other.hsc) {}
@@ -245,23 +232,13 @@ struct Vote: public Serializable {
Vote(Vote &&other) = default;
void serialize(DataStream &s) const override {
- s << voter
- << bqc_hash
- << blk_hash;
- if (cert == nullptr)
- s << (uint8_t)0;
- else
- s << (uint8_t)1 << *cert;
+ s << voter << blk_hash << *cert;
}
void unserialize(DataStream &s) override {
assert(hsc != nullptr);
- uint8_t has_cert;
- s >> voter
- >> bqc_hash
- >> blk_hash
- >> has_cert;
- cert = has_cert ? hsc->parse_part_cert(s) : nullptr;
+ s >> voter >> blk_hash;
+ cert = hsc->parse_part_cert(s);
}
bool verify() const {
@@ -281,9 +258,7 @@ struct Vote: public Serializable {
DataStream s;
s << "<vote "
<< "rid=" << std::to_string(voter) << " "
- << "bqc=" << get_hex10(bqc_hash) << " "
- << "blk=" << get_hex10(blk_hash) << " "
- << "cert=" << (cert ? "yes" : "no") << ">";
+ << "blk=" << get_hex10(blk_hash) << ">";
return std::move(s);
}
};
diff --git a/include/hotstuff/liveness.h b/include/hotstuff/liveness.h
index 903ac83..6d3c3cf 100644
--- a/include/hotstuff/liveness.h
+++ b/include/hotstuff/liveness.h
@@ -60,42 +60,42 @@ using pacemaker_bt = BoxObj<PaceMaker>;
* direct parent, while including other tail blocks (up to parent_limit) as
* uncles/aunts. */
class PMAllParents: public virtual PaceMaker {
- block_t bqc_tail;
+ block_t hqc_tail;
const int32_t parent_limit; /**< maximum number of parents */
- void reg_bqc_update() {
- hsc->async_bqc_update().then([this](const block_t &bqc) {
- const auto &pref = bqc->get_qc_ref();
+ void reg_hqc_update() {
+ hsc->async_hqc_update().then([this](const block_t &hqc) {
+ const auto &pref = hqc;
for (const auto &blk: hsc->get_tails())
{
block_t b;
for (b = blk;
b->get_height() > pref->get_height();
b = b->get_parents()[0]);
- if (b == pref && blk->get_height() > bqc_tail->get_height())
- bqc_tail = blk;
+ if (b == pref && blk->get_height() > hqc_tail->get_height())
+ hqc_tail = blk;
}
- reg_bqc_update();
+ reg_hqc_update();
});
}
void reg_proposal() {
hsc->async_wait_proposal().then([this](const Proposal &prop) {
- bqc_tail = prop.blk;
+ hqc_tail = prop.blk;
reg_proposal();
});
}
void reg_receive_proposal() {
hsc->async_wait_receive_proposal().then([this](const Proposal &prop) {
- const auto &pref = hsc->get_bqc()->get_qc_ref();
+ const auto &pref = hsc->get_hqc();
const auto &blk = prop.blk;
block_t b;
for (b = blk;
b->get_height() > pref->get_height();
b = b->get_parents()[0]);
- if (b == pref && blk->get_height() > bqc_tail->get_height())
- bqc_tail = blk;
+ if (b == pref && blk->get_height() > hqc_tail->get_height())
+ hqc_tail = blk;
reg_receive_proposal();
});
}
@@ -103,15 +103,15 @@ class PMAllParents: public virtual PaceMaker {
public:
PMAllParents(int32_t parent_limit): parent_limit(parent_limit) {}
void init() {
- bqc_tail = hsc->get_genesis();
- reg_bqc_update();
+ hqc_tail = hsc->get_genesis();
+ reg_hqc_update();
reg_proposal();
reg_receive_proposal();
}
std::vector<block_t> get_parents() override {
const auto &tails = hsc->get_tails();
- std::vector<block_t> parents{bqc_tail};
+ std::vector<block_t> parents{hqc_tail};
auto nparents = tails.size();
if (parent_limit > 0)
nparents = std::min(nparents, (size_t)parent_limit);
@@ -119,7 +119,7 @@ class PMAllParents: public virtual PaceMaker {
/* add the rest of tails as "uncles/aunts" */
for (const auto &blk: tails)
{
- if (blk != bqc_tail)
+ if (blk != hqc_tail)
{
parents.push_back(blk);
if (!--nparents) break;
@@ -386,7 +386,7 @@ class PMStickyProposer: virtual public PaceMaker {
HOTSTUFF_LOG_PROTO("got block %s from %d", std::string(*prop.blk).c_str(), _proposer);
p.reject();
(p = hsc->async_qc_finish(prop.blk)).then([this, blk=prop.blk, _proposer]() {
- if (hsc->get_bqc()->get_qc_ref() == blk)
+ if (hsc->get_hqc() == blk)
to_follower(_proposer);
});
reg_cp_receive_proposal();
@@ -423,7 +423,7 @@ class PMStickyProposer: virtual public PaceMaker {
to_candidate();
});
reg_cp_receive_proposal();
- proposer_propose(Proposal(-1, uint256_t(), hsc->get_genesis(), nullptr));
+ proposer_propose(Proposal(-1, hsc->get_genesis(), nullptr));
}
void to_candidate() {
@@ -675,7 +675,7 @@ class PMRoundRobinProposer: virtual public PaceMaker {
/* proposer unable to get a QC in time */
to_candidate();
});
- proposer_propose(Proposal(-1, uint256_t(), hsc->get_genesis(), nullptr));
+ proposer_propose(Proposal(-1, hsc->get_genesis(), nullptr));
}
void to_candidate() {
diff --git a/salticidae b/salticidae
-Subproject 07d197a2d049aedb77536edeb3b20e51cc8c958
+Subproject 8a0d8fbaf59be7acc536b2a753caa27aa1fbae2
diff --git a/src/consensus.cpp b/src/consensus.cpp
index 8b6e977..b57e258 100644
--- a/src/consensus.cpp
+++ b/src/consensus.cpp
@@ -33,16 +33,14 @@ namespace hotstuff {
HotStuffCore::HotStuffCore(ReplicaID id,
privkey_bt &&priv_key):
b0(new Block(true, 1)),
- bqc(b0),
bexec(b0),
vheight(0),
priv_key(std::move(priv_key)),
- tails{bqc},
+ tails{b0},
neg_vote(false),
id(id),
storage(new EntityStorage()) {
storage->add_blk(b0);
- b0->qc_ref = b0;
}
void HotStuffCore::sanity_check_delivered(const block_t &blk) {
@@ -84,8 +82,20 @@ bool HotStuffCore::on_deliver_blk(const block_t &blk) {
return true;
}
-void HotStuffCore::check_commit(const block_t &_blk) {
- const block_t &blk = _blk->qc_ref;
+void HotStuffCore::update_hqc(const block_t &_hqc, const quorum_cert_bt &qc) {
+ if (_hqc->height > hqc.first->height)
+ {
+ hqc = std::make_pair(_hqc, qc->clone());
+ on_hqc_update();
+ }
+}
+
+void HotStuffCore::update(const block_t &nblk) {
+ const block_t &blk = nblk->qc_ref;
+ if (blk == nullptr)
+ throw std::runtime_error("empty qc_ref");
+ update_hqc(blk, nblk->qc);
+ /* check for commit */
if (blk->qc_ref == nullptr) return;
/* decided blk could possible be incomplete due to pruning */
if (blk->decision) return;
@@ -117,18 +127,6 @@ void HotStuffCore::check_commit(const block_t &_blk) {
bexec = p;
}
-bool HotStuffCore::update(const uint256_t &bqc_hash) {
- block_t _bqc = get_delivered_blk(bqc_hash);
- if (_bqc->qc_ref == nullptr) return false;
- check_commit(_bqc);
- if (_bqc->qc_ref->height > bqc->qc_ref->height)
- {
- bqc = _bqc;
- on_bqc_update();
- }
- return true;
-}
-
void HotStuffCore::on_propose(const std::vector<uint256_t> &cmds,
const std::vector<block_t> &parents,
bytearray_t &&extra) {
@@ -139,7 +137,7 @@ void HotStuffCore::on_propose(const std::vector<uint256_t> &cmds,
quorum_cert_bt qc = nullptr;
block_t qc_ref = nullptr;
/* a block can optionally carray a QC */
- if (p != b0 && p->voted.size() >= config.nmajority)
+ if (p->voted.size() >= config.nmajority)
{
qc = p->self_qc->clone();
qc_ref = p;
@@ -155,15 +153,15 @@ void HotStuffCore::on_propose(const std::vector<uint256_t> &cmds,
const uint256_t bnew_hash = bnew->get_hash();
bnew->self_qc = create_quorum_cert(bnew_hash);
on_deliver_blk(bnew);
- update(bnew_hash);
- Proposal prop(id, bqc->get_hash(), bnew, nullptr);
+ update(bnew);
+ Proposal prop(id, bnew, nullptr);
LOG_PROTO("propose %s", std::string(*bnew).c_str());
/* self-vote */
if (bnew->height <= vheight)
throw std::runtime_error("new block should be higher than vheight");
vheight = bnew->height;
on_receive_vote(
- Vote(id, bqc->get_hash(), bnew_hash,
+ Vote(id, bnew_hash,
create_part_cert(*priv_key, bnew_hash), this));
on_propose_(prop);
/* boradcast to other replicas */
@@ -171,14 +169,14 @@ void HotStuffCore::on_propose(const std::vector<uint256_t> &cmds,
}
void HotStuffCore::on_receive_proposal(const Proposal &prop) {
- if (!update(prop.bqc_hash)) return;
LOG_PROTO("got %s", std::string(prop).c_str());
block_t bnew = prop.blk;
sanity_check_delivered(bnew);
+ update(bnew);
bool opinion = false;
if (bnew->height > vheight)
{
- block_t pref = bqc->qc_ref;
+ block_t pref = hqc.first;
block_t b;
for (b = bnew;
b->height > pref->height;
@@ -195,14 +193,11 @@ void HotStuffCore::on_receive_proposal(const Proposal &prop) {
on_receive_proposal_(prop);
if (opinion && !neg_vote)
do_vote(prop.proposer,
- Vote(id,
- bqc->get_hash(),
- bnew->get_hash(),
+ Vote(id, bnew->get_hash(),
create_part_cert(*priv_key, bnew->get_hash()), this));
}
void HotStuffCore::on_receive_vote(const Vote &vote) {
- if (!update(vote.bqc_hash)) return;
LOG_PROTO("got %s", std::string(vote).c_str());
LOG_PROTO("now state: %s", std::string(*this).c_str());
block_t blk = get_delivered_blk(vote.blk_hash);
@@ -225,10 +220,18 @@ void HotStuffCore::on_receive_vote(const Vote &vote) {
{
qc->compute();
on_qc_finish(blk);
+ update_hqc(blk, qc);
}
}
/*** end HotStuff protocol logic ***/
-void HotStuffCore::on_init(uint32_t nfaulty) { config.nmajority = 2 * nfaulty + 1; }
+void HotStuffCore::on_init(uint32_t nfaulty) {
+ config.nmajority = 2 * nfaulty + 1;
+ b0->qc = create_quorum_cert(b0->get_hash());
+ b0->qc->compute();
+ b0->self_qc = b0->qc->clone();
+ b0->qc_ref = b0;
+ hqc = std::make_pair(b0, b0->qc->clone());
+}
void HotStuffCore::prune(uint32_t staleness) {
block_t start;
@@ -292,9 +295,9 @@ promise_t HotStuffCore::async_wait_receive_proposal() {
});
}
-promise_t HotStuffCore::async_bqc_update() {
- return bqc_update_waiting.then([this]() {
- return bqc;
+promise_t HotStuffCore::async_hqc_update() {
+ return hqc_update_waiting.then([this]() {
+ return hqc.first;
});
}
@@ -310,17 +313,17 @@ void HotStuffCore::on_receive_proposal_(const Proposal &prop) {
t.resolve(prop);
}
-void HotStuffCore::on_bqc_update() {
- auto t = std::move(bqc_update_waiting);
- bqc_update_waiting = promise_t();
+void HotStuffCore::on_hqc_update() {
+ auto t = std::move(hqc_update_waiting);
+ hqc_update_waiting = promise_t();
t.resolve();
}
HotStuffCore::operator std::string () const {
DataStream s;
s << "<hotstuff "
- << "bqc=" << get_hex10(bqc->get_hash()) << " "
- << "bqc.rheight=" << std::to_string(bqc->qc_ref->height) << " "
+ << "hqc=" << get_hex10(hqc.first->get_hash()) << " "
+ << "hqc.height=" << std::to_string(hqc.first->height) << " "
<< "bexec=" << get_hex10(bexec->get_hash()) << " "
<< "vheight=" << std::to_string(vheight) << " "
<< "tails=" << std::to_string(tails.size()) << ">";
diff --git a/src/hotstuff.cpp b/src/hotstuff.cpp
index 4a84927..9b36fa2 100644
--- a/src/hotstuff.cpp
+++ b/src/hotstuff.cpp
@@ -223,7 +223,8 @@ promise_t HotStuffBase::async_deliver_blk(const uint256_t &blk_hash,
/* the parents should be delivered */
for (const auto &phash: blk->get_parent_hashes())
pms.push_back(async_deliver_blk(phash, replica_id));
- pms.push_back(blk->verify(get_config(), vpool));
+ if (blk != get_genesis())
+ pms.push_back(blk->verify(get_config(), vpool));
promise::all(pms).then([this, blk]() {
on_deliver_blk(blk);
});
@@ -238,8 +239,7 @@ void HotStuffBase::propose_handler(MsgPropose &&msg, const Net::conn_t &conn) {
block_t blk = prop.blk;
if (!blk) return;
promise::all(std::vector<promise_t>{
- async_deliver_blk(prop.bqc_hash, peer),
- async_deliver_blk(blk->get_hash(), peer),
+ async_deliver_blk(blk->get_hash(), peer)
}).then([this, prop = std::move(prop)]() {
on_receive_proposal(prop);
});
@@ -251,11 +251,10 @@ void HotStuffBase::vote_handler(MsgVote &&msg, const Net::conn_t &conn) {
//auto &vote = msg.vote;
RcObj<Vote> v(new Vote(std::move(msg.vote)));
promise::all(std::vector<promise_t>{
- async_deliver_blk(v->bqc_hash, peer),
async_deliver_blk(v->blk_hash, peer),
v->verify(vpool),
}).then([this, v=std::move(v)](const promise::values_t values) {
- if (!promise::any_cast<bool>(values[2]))
+ if (!promise::any_cast<bool>(values[1]))
LOG_WARN("invalid vote from %d", v->voter);
else
on_receive_vote(*v);
@@ -415,7 +414,9 @@ void HotStuffBase::do_decide(Finality &&fin) {
HotStuffBase::~HotStuffBase() {}
-void HotStuffBase::start(std::vector<std::pair<NetAddr, pubkey_bt>> &&replicas, bool ec_loop) {
+void HotStuffBase::start(
+ std::vector<std::pair<NetAddr, pubkey_bt>> &&replicas,
+ bool ec_loop) {
for (size_t i = 0; i < replicas.size(); i++)
{
auto &addr = replicas[i].first;