/**
* Copyright 2018 VMware
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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::ArcObj<Block>;
class Command: public Serializable {
friend HotStuffCore;
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<uint256_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<uint256_t> &cmds,
quorum_cert_bt &&qc,
bytearray_t &&extra,
uint32_t height