#ifndef _HOTSTUFF_ENT_H
#define _HOTSTUFF_ENT_H
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <cstddef>
#include <ios>
#include "salticidae/netaddr.h"
#include "salticidae/ref.h"
#include "hotstuff/type.h"
#include "hotstuff/util.h"
#include "hotstuff/crypto.h"
namespace hotstuff {
enum EntityType {
ENT_TYPE_CMD = 0x0,
ENT_TYPE_BLK = 0x1
};
struct ReplicaInfo {
ReplicaID id;
salticidae::NetAddr addr;
pubkey_bt pubkey;
ReplicaInfo(ReplicaID id,
const salticidae::NetAddr &addr,
pubkey_bt &&pubkey):
id(id), addr(addr), pubkey(std::move(pubkey)) {}
ReplicaInfo(const ReplicaInfo &other):
id(other.id), addr(other.addr),
pubkey(other.pubkey->clone()) {}
ReplicaInfo(ReplicaInfo &&other):
id(other.id), addr(other.addr),
pubkey(std::move(other.pubkey)) {}
};
class ReplicaConfig {
std::unordered_map<ReplicaID, ReplicaInfo> replica_map;
public:
size_t nreplicas;
size_t nmajority;
ReplicaConfig(): nreplicas(0), nmajority(0) {}
void add_replica(ReplicaID rid, const ReplicaInfo &info) {
replica_map.insert(std::make_pair(rid, info));
nreplicas++;
}
const ReplicaInfo &get_info(ReplicaID rid) const {
auto it = replica_map.find(rid);
if (it == replica_map.end())
throw HotStuffError("rid %s not found",
get_hex(rid).c_str());
return it->second;
}
const PubKey &get_pubkey(ReplicaID rid) const {
return *(get_info(rid).pubkey);
}
const salticidae::NetAddr &get_addr(ReplicaID rid) const {
return get_info(rid).addr;
}
};
class Block;
class HotStuffCore;
using block_t = salticidae::RcObj<Block>;
using block_weak_t = salticidae::WeakObj<Block>;
class Command: public Serializable {
friend HotStuffCore;
block_weak_t container;
public:
virtual ~Command() = default;
virtual const uint256_t &get_hash() const = 0;
virtual bool verify() const = 0;
virtual operator std::string () const {
DataStream s;
s << "<cmd id=" << get_hex10(get_hash()) << ">";
return std::move(s);
}
};
using command_t = RcObj<Command>;
template<typename Hashable>
inline static std::vector<uint256_t>
get_hashes(const std::vector<Hashable> &plist) {
std::vector<uint256_t> hashes;
for (const auto &p: plist)
hashes.push_back(p->get_hash());
return std::move(hashes);
}
class Block {
friend HotStuffCore;
std::vector<uint256_t> parent_hashes;
std::vector<command_t> cmds;
quorum_cert_bt qc;
bytearray_t extra;
/* the following fields can be derived from above */
uint256_t hash;
std::vector<block_t> parents;
block_t qc_ref;
quorum_cert_bt self_qc;
uint32_t height;
bool delivered;
int8_t decision;
std::unordered_set<ReplicaID> voted;
public:
Block():
qc(nullptr),
qc_ref(nullptr),
self_qc(nullptr), height(0),
delivered(false), decision(0) {}
Block(bool delivered, int8_t decision):
qc(nullptr),
hash(salticidae::get_hash(*this)),
qc_ref(nullptr),
self_qc(nullptr), height(0),
delivered(delivered), decision(decision) {}
Block(const std::vector<block_t> &parents,
const std::vector<command_t> &cmds,
quorum_cert_bt &&qc,
bytearray_t &&extra,
uint32_t height,
const block_t &qc_ref,
quorum_cert_bt &&self_qc,
int8_t decision = 0):
parent_hashes(get_hashes(parents)),
cmds(cmds),
qc(std::move(qc)),
extra(std::move(extra)),
hash(salticidae::get_hash(*this)),
parents(parents),
qc_ref(qc_ref),
self_qc(std::move(self_qc)),
height(height),
delivered(0),
decision(decision) {}
void serialize(DataStream &s) const;
void unserialize(DataStream &s, HotStuffCore *hsc);
const std::vector<command_t> &get_cmds() const {
return cmds;
}
const std::vector<block_t> &get_parents() const {
return parents;
}
const std::vector<uint256_t> &get_parent_hashes() const {
return parent_hashes;
}
const uint256_t &get_hash() const { return hash; }
bool verify(const ReplicaConfig &config) const {
if (qc && !qc->verify(config)) return false;
for (auto cmd: cmds)
if (!cmd->