blob: 3d1c7b617728acc6df561dc81f2e532701c9a5a9 (
plain) (
tree)
|
|
#ifndef _HOTSTUFF_CORE_H
#define _HOTSTUFF_CORE_H
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include "salticidae/util.h"
#include "salticidae/network.h"
#include "salticidae/msg.h"
#include "hotstuff/util.h"
#include "hotstuff/consensus.h"
#include "hotstuff/liveness.h"
namespace hotstuff {
using salticidae::MsgNetwork;
using salticidae::PeerNetwork;
using salticidae::ElapsedTime;
using salticidae::_1;
using salticidae::_2;
const double ent_waiting_timeout = 10;
const double double_inf = 1e10;
/** Network message format for HotStuff. */
struct MsgPropose {
static const opcode_t opcode = 0x0;
DataStream serialized;
Proposal proposal;
MsgPropose(const Proposal &);
/** Only move the data to serialized, do not parse immediately. */
MsgPropose(DataStream &&s): serialized(std::move(s)) {}
/** Parse the serialized data to blks now, with `hsc->storage`. */
void postponed_parse(HotStuffCore *hsc);
};
struct MsgVote {
static const opcode_t opcode = 0x1;
DataStream serialized;
Vote vote;
MsgVote(const Vote &);
MsgVote(DataStream &&s): serialized(std::move(s)) {}
void postponed_parse(HotStuffCore *hsc);
};
struct MsgReqBlock {
static const opcode_t opcode = 0x2;
DataStream serialized;
std::vector<uint256_t> blk_hashes;
MsgReqBlock() = default;
MsgReqBlock(const std::vector<uint256_t> &blk_hashes);
MsgReqBlock(DataStream &&s);
};
struct MsgRespBlock {
static const opcode_t opcode = 0x3;
DataStream serialized;
std::vector<block_t> blks;
MsgRespBlock(const std::vector<block_t> &blks);
MsgRespBlock(DataStream &&s): serialized(std::move(s)) {}
void postponed_parse(HotStuffCore *hsc);
};
using promise::promise_t;
class HotStuffBase;
template<EntityType ent_type>
class FetchContext: public promise_t {
Event timeout;
HotStuffBase *hs;
MsgReqBlock fetch_msg;
const uint256_t ent_hash;
std::unordered_set<NetAddr> replica_ids;
inline void timeout_cb(evutil_socket_t, short);
public:
FetchContext(const FetchContext &) = delete;
FetchContext &operator=(const FetchContext &) = delete;
FetchContext(FetchContext &&other);
FetchContext(const uint256_t &ent_hash, HotStuffBase *hs);
~FetchContext() {}
inline void send(const NetAddr &replica_id);
inline void reset_timeout();
inline void add_replica(const NetAddr &replica_id, bool fetch_now = true);
};
class BlockDeliveryContext: public promise_t {
public:
ElapsedTime elapsed;
BlockDeliveryContext &operator=(const BlockDeliveryContext &) = delete;
BlockDeliveryContext(const BlockDeliveryContext &other):
promise_t(static_cast<const promise_t &>(other)),
elapsed(other.elapsed) {}
BlockDeliveryContext(BlockDeliveryContext &&other):
promise_t(static_cast<const promise_t &>(other)),
elapsed(std::move(other.elapsed)) {}
template<typename Func>
BlockDeliveryContext(Func callback): promise_t(callback) {
elapsed.start();
}
};
/** HotStuff protocol (with network implementation). */
class HotStuffBase: public HotStuffCore {
using BlockFetchContext = FetchContext<ENT_TYPE_BLK>;
using CmdFetchContext = FetchContext<ENT_TYPE_CMD>;
using Conn = PeerNetwork<opcode_t>::Conn;
friend BlockFetchContext;
friend CmdFetchContext;
protected:
/** the binding address in replica network */
NetAddr listen_addr;
/** the block size */
size_t blk_size;
/** libevent handle */
EventContext eb;
VeriPool vpool;
private:
/** whether libevent handle is owned by itself */
bool eb_loop;
/** network stack */
PeerNetwork<opcode_t> pn;
#ifdef HOTSTUFF_BLK_PROFILE
BlockProfiler
|