Dynamic roundtime detection. (#244)

When consensus is unreliable detect roundtime based on roundtime reported by peers.
This commit is contained in:
Ravin Perera
2021-02-16 13:34:29 +05:30
committed by GitHub
parent 4c4e109233
commit 9f4499653a
19 changed files with 430 additions and 241 deletions

View File

@@ -148,9 +148,9 @@ namespace conf
cfg.contract.is_npl_public = false;
cfg.mesh.port = 22860;
cfg.mesh.msg_forwarding = false;
cfg.mesh.msg_forwarding = true;
cfg.mesh.idle_timeout = 120;
cfg.mesh.peer_discovery.enabled = false;
cfg.mesh.peer_discovery.enabled = true;
cfg.mesh.peer_discovery.interval = 30000;
cfg.user.port = 8080;
@@ -846,7 +846,7 @@ namespace conf
jdoc.insert_or_assign("unl", unl);
jdoc.insert_or_assign("bin_path", contract.bin_path);
jdoc.insert_or_assign("bin_args", contract.bin_args);
jdoc.insert_or_assign("roundtime", contract.roundtime);
jdoc.insert_or_assign("roundtime", contract.roundtime.load());
jdoc.insert_or_assign("consensus", contract.is_consensus_public ? PUBLIC : PRIVATE);
jdoc.insert_or_assign("npl", contract.is_npl_public ? PUBLIC : PRIVATE);

View File

@@ -97,16 +97,16 @@ namespace conf
struct contract_config
{
std::string id; // Contract guid.
bool execute = false; // Whether or not to execute the contract on the node.
bool log_output = false; // Whether to log stdout/err of the contract process.
std::string version; // Contract version string.
std::set<std::string> unl; // Unique node list (list of binary public keys)
std::string bin_path; // Full path to the contract binary
std::string bin_args; // CLI arguments to pass to the contract binary
uint16_t roundtime = 0; // Consensus round time in ms
bool is_consensus_public = false; // If true, consensus are broadcasted to non-unl nodes as well.
bool is_npl_public = false; // If true, npl messages are broadcasted to non-unl nodes as well.
std::string id; // Contract guid.
bool execute = false; // Whether or not to execute the contract on the node.
bool log_output = false; // Whether to log stdout/err of the contract process.
std::string version; // Contract version string.
std::set<std::string> unl; // Unique node list (list of binary public keys)
std::string bin_path; // Full path to the contract binary
std::string bin_args; // CLI arguments to pass to the contract binary
std::atomic<uint16_t> roundtime = 0; // Consensus round time in ms
bool is_consensus_public = false; // If true, consensus are broadcasted to non-unl nodes as well.
bool is_npl_public = false; // If true, npl messages are broadcasted to non-unl nodes as well.
appbill_config appbill;
round_limits_config round_limits;

View File

@@ -24,20 +24,16 @@ namespace consensus
constexpr size_t ROUND_NONCE_SIZE = 64;
constexpr const char *HPFS_SESSION_NAME = "ro_patch_file_to_hp";
// Max no. of time to get unreliable votes before we try heuristics to increase vote receiving reliability.
constexpr uint16_t MAX_UNRELIABLE_VOTES_ATTEMPTS = 5;
consensus_context ctx;
bool init_success = false;
std::atomic<bool> is_patch_update_pending = false; // Keep track whether the patch file is changed by the SC and is not yet applied to runtime.
int init()
{
// We allocate 1/4 of roundtime for each stage (0, 1, 2, 3).
ctx.stage_time = conf::cfg.contract.roundtime / 4;
ctx.stage_reset_wait_threshold = conf::cfg.contract.roundtime / 10;
// We use a time window boundry offset based on contract id to vary the window boundries between
// different contracts with same round time.
std::hash<std::string> str_hasher;
ctx.round_boundry_offset = str_hasher(conf::cfg.contract.id) % conf::cfg.contract.roundtime;
refresh_roundtime(false);
// Starting consensus processing thread.
ctx.consensus_thread = std::thread(run_consensus);
@@ -138,6 +134,20 @@ namespace consensus
vote_counter votes;
const int sync_status = check_sync_status(lcl, unl_count, votes);
if (sync_status == -2) // Unreliable votes.
{
ctx.unreliable_votes_attempts++;
if (ctx.unreliable_votes_attempts >= MAX_UNRELIABLE_VOTES_ATTEMPTS)
{
refresh_roundtime(true);
ctx.unreliable_votes_attempts = 0;
}
}
else
{
ctx.unreliable_votes_attempts = 0;
}
if (sync_status == 0)
{
// If we are in sync, vote and broadcast the winning votes to next stage.
@@ -257,6 +267,9 @@ namespace consensus
collected_proposals.splice(collected_proposals.end(), p2p::ctx.collected_msgs.proposals);
}
// Provide latest roundtime information to unl statistics.
unl::update_roundtime_stats(collected_proposals);
// Move collected propsals to candidate set of proposals.
// Add propsals of new nodes and replace proposals from old nodes to reflect current status of nodes.
for (const auto &proposal : collected_proposals)
@@ -1048,4 +1061,33 @@ namespace consensus
return 0;
}
/**
* Updates roundtime-based calculations with the latest roundtime value.
* @param perform_detection Whether or not to detect roundtime from latest network information.
*/
void refresh_roundtime(const bool perform_detection)
{
if (perform_detection)
{
LOG_DEBUG << "Detecting roundtime...";
const uint16_t majority_roundtime = unl::get_majority_roundtime();
if (majority_roundtime == 0 || conf::cfg.contract.roundtime == majority_roundtime)
return;
LOG_INFO << "New roundtime detected:" << majority_roundtime << " previous:" << conf::cfg.contract.roundtime;
conf::cfg.contract.roundtime = majority_roundtime;
}
// We allocate 1/4 of roundtime for each stage (0, 1, 2, 3).
ctx.stage_time = conf::cfg.contract.roundtime / 4;
ctx.stage_reset_wait_threshold = conf::cfg.contract.roundtime / 10;
// We use a time window boundry offset based on contract id to vary the window boundries between
// different contracts with same round time.
std::hash<std::string> str_hasher;
ctx.round_boundry_offset = str_hasher(conf::cfg.contract.id) % conf::cfg.contract.roundtime;
}
} // namespace consensus

View File

@@ -72,6 +72,7 @@ namespace consensus
uint16_t stage_time = 0; // Time allocated to a consensus stage.
uint16_t stage_reset_wait_threshold = 0; // Minimum stage wait time to reset the stage.
uint64_t round_boundry_offset = 0; // Time window boundry offset based on contract id.
uint16_t unreliable_votes_attempts = 0; // No. of times we failed to get reliable votes continously.
std::optional<sc::execution_context> contract_ctx;
std::mutex contract_ctx_mutex;
@@ -157,6 +158,8 @@ namespace consensus
int apply_consensed_patch_file_changes(const util::h32 &prop_patch_hash, const util::h32 &current_patch_hash);
void refresh_roundtime(const bool perform_detection);
} // namespace consensus
#endif

View File

@@ -46,7 +46,7 @@ namespace crypto
* @param private_key Private key bytes.
* @return Signature bytes.
*/
std::string sign(std::string_view msg, std::string_view private_key)
const std::string sign(std::string_view msg, std::string_view private_key)
{
//Generate the signature using libsodium.
@@ -93,7 +93,7 @@ namespace crypto
* @param data String to hash.
* @return The blake3 hash of the given string.
*/
std::string get_hash(std::string_view data)
const std::string get_hash(std::string_view data)
{
std::string hash;
hash.resize(BLAKE3_OUT_LEN);
@@ -110,12 +110,12 @@ namespace crypto
}
/**
* Generate blake3 hash for a given message.
* @param data unsigned char array pointer to hash data.
* @param data_length hash data length.
* @return The blake3 hash of the pointed buffer.
*/
std::string get_hash(const unsigned char *data, size_t data_length)
* Generate blake3 hash for a given message.
* @param data unsigned char array pointer to hash data.
* @param data_length hash data length.
* @return The blake3 hash of the pointed buffer.
*/
const std::string get_hash(const unsigned char *data, size_t data_length)
{
std::string hash;
hash.resize(BLAKE3_OUT_LEN);
@@ -134,7 +134,7 @@ namespace crypto
/**
* Generates blake3 hash for the given set of strings using stream hashing.
*/
std::string get_hash(std::string_view s1, std::string_view s2)
const std::string get_hash(std::string_view s1, std::string_view s2)
{
std::string hash;
hash.resize(BLAKE3_OUT_LEN);
@@ -156,7 +156,7 @@ namespace crypto
/**
* Generates blake3 hash for the given string view vector using stream hashing.
*/
std::string get_hash(const std::vector<std::string_view> &sw_vect)
const std::string get_hash(const std::vector<std::string_view> &sw_vect)
{
std::string hash;
hash.resize(BLAKE3_OUT_LEN);
@@ -178,7 +178,7 @@ namespace crypto
/**
* Generates blake3 hash for the given string set using stream hashing.
*/
std::string get_hash(const std::set<std::string> &sw_set)
const std::string get_hash(const std::set<std::string> &sw_set)
{
std::string hash;
hash.resize(BLAKE3_OUT_LEN);
@@ -197,7 +197,7 @@ namespace crypto
return hash;
}
std::string generate_uuid()
const std::string generate_uuid()
{
std::string rand_bytes;
random_bytes(rand_bytes, 16);

View File

@@ -17,23 +17,23 @@ namespace crypto
void generate_signing_keys(std::string &pubkey, std::string &seckey);
std::string sign(std::string_view msg, std::string_view seckey);
const std::string sign(std::string_view msg, std::string_view seckey);
int verify(std::string_view msg, std::string_view sig, std::string_view pubkey);
void random_bytes(std::string &result, const size_t len);
std::string get_hash(std::string_view data);
const std::string get_hash(std::string_view data);
std::string get_hash(const unsigned char *data, size_t data_length);
const std::string get_hash(const unsigned char *data, size_t data_length);
std::string get_hash(std::string_view s1, std::string_view s2);
const std::string get_hash(std::string_view s1, std::string_view s2);
std::string get_hash(const std::vector<std::string_view> &sw_vect);
const std::string get_hash(const std::vector<std::string_view> &sw_vect);
std::string get_hash(const std::set<std::string> &sw_set);
const std::string get_hash(const std::set<std::string> &sw_set);
std::string generate_uuid();
const std::string generate_uuid();
} // namespace crypto

View File

@@ -33,7 +33,6 @@ namespace hpfs
this->name = name;
this->fs_mount = fs_mount;
REQUEST_BATCH_TIMEOUT = hpfs::get_request_resubmit_timeout() * 0.9;
hpfs_serve_thread = std::thread(&hpfs_serve::hpfs_serve_loop, this);
init_success = true;
return 0;
@@ -57,7 +56,6 @@ namespace hpfs
LOG_INFO << "Hpfs " << name << " server started.";
// Indicates whether any requests were processed in the previous loop iteration.
bool prev_requests_processed = false;
@@ -72,6 +70,7 @@ namespace hpfs
prev_requests_processed = !hpfs_requests.empty();
const uint64_t time_start = util::get_epoch_milliseconds();
const std::string lcl = ledger::ctx.get_lcl();
const uint16_t request_batch_timeout = hpfs::get_request_resubmit_timeout() * 0.9;
if (hpfs_requests.empty())
continue;
@@ -86,7 +85,7 @@ namespace hpfs
// If we have spent too much time handling hpfs requests, abandon the entire batch
// because the requester would have stopped waiting for us.
const uint64_t time_now = util::get_epoch_milliseconds();
if ((time_now - time_start) > REQUEST_BATCH_TIMEOUT)
if ((time_now - time_start) > request_batch_timeout)
{
LOG_DEBUG << "Hpfs " << name << " serve batch timeout. Abandonding hpfs requests.";
break;

View File

@@ -11,8 +11,6 @@ namespace hpfs
class hpfs_serve
{
private:
uint16_t REQUEST_BATCH_TIMEOUT;
bool is_shutting_down = false;
bool init_success = false;
std::thread hpfs_serve_thread;

View File

@@ -37,7 +37,6 @@ namespace hpfs
this->name = name;
this->fs_mount = fs_mount;
REQUEST_RESUBMIT_TIMEOUT = hpfs::get_request_resubmit_timeout();
hpfs_sync_thread = std::thread(&hpfs_sync::hpfs_syncer_loop, this);
init_success = true;
return 0;
@@ -287,13 +286,16 @@ namespace hpfs
candidate_hpfs_responses.clear();
// No. of milliseconds to wait before resubmitting a request.
const uint16_t request_resubmit_timeout = hpfs::get_request_resubmit_timeout();
// Check for long-awaited responses and re-request them.
for (auto &[hash, request] : submitted_requests)
{
if (should_stop_request_loop(current_target_hash))
return 0;
if (request.waiting_time < REQUEST_RESUBMIT_TIMEOUT)
if (request.waiting_time < request_resubmit_timeout)
{
// Increment wait time.
request.waiting_time += REQUEST_LOOP_WAIT;

View File

@@ -48,8 +48,7 @@ namespace hpfs
{
private:
bool init_success = false;
uint16_t REQUEST_RESUBMIT_TIMEOUT; // No. of milliseconds to wait before resubmitting a request.
std::string name; // Name used for logging.
std::string name; // Name used for logging.
std::queue<sync_target> target_list; // The current target hashes we are syncing towards.

View File

@@ -6,6 +6,7 @@ namespace msg.fbuf.p2pmsg;
table Peer_Challenge_Message {
contract_id:string;
roundtime:uint16;
challenge:string;
}
@@ -52,6 +53,7 @@ table NonUnl_Proposal_Message {
table Proposal_Message { //Proposal type message schema
stage:uint8;
time:uint64;
roundtime:uint16;
nonce: [ubyte];
users:[ByteArray];
input_hashes:[ByteArray];

View File

@@ -81,7 +81,7 @@ struct Peer_List_Response_MessageBuilder;
struct Peer_Properties;
struct Peer_PropertiesBuilder;
enum Message : uint8_t {
enum Message {
Message_NONE = 0,
Message_Peer_Challenge_Response_Message = 1,
Message_Peer_Challenge_Message = 2,
@@ -206,7 +206,7 @@ template<> struct MessageTraits<msg::fbuf::p2pmsg::Available_Capacity_Announceme
bool VerifyMessage(flatbuffers::Verifier &verifier, const void *obj, Message type);
bool VerifyMessageVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
enum Ledger_Response_Error : uint8_t {
enum Ledger_Response_Error {
Ledger_Response_Error_None = 0,
Ledger_Response_Error_Invalid_Min_Ledger = 1,
Ledger_Response_Error_Req_Ledger_Not_Found = 2,
@@ -239,7 +239,7 @@ inline const char *EnumNameLedger_Response_Error(Ledger_Response_Error e) {
return EnumNamesLedger_Response_Error()[index];
}
enum Hpfs_Response : uint8_t {
enum Hpfs_Response {
Hpfs_Response_NONE = 0,
Hpfs_Response_File_HashMap_Response = 1,
Hpfs_Response_Block_Response = 2,
@@ -298,7 +298,8 @@ struct Peer_Challenge_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Tab
typedef Peer_Challenge_MessageBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_CONTRACT_ID = 4,
VT_CHALLENGE = 6
VT_ROUNDTIME = 6,
VT_CHALLENGE = 8
};
const flatbuffers::String *contract_id() const {
return GetPointer<const flatbuffers::String *>(VT_CONTRACT_ID);
@@ -306,6 +307,12 @@ struct Peer_Challenge_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Tab
flatbuffers::String *mutable_contract_id() {
return GetPointer<flatbuffers::String *>(VT_CONTRACT_ID);
}
uint16_t roundtime() const {
return GetField<uint16_t>(VT_ROUNDTIME, 0);
}
bool mutate_roundtime(uint16_t _roundtime) {
return SetField<uint16_t>(VT_ROUNDTIME, _roundtime, 0);
}
const flatbuffers::String *challenge() const {
return GetPointer<const flatbuffers::String *>(VT_CHALLENGE);
}
@@ -316,6 +323,7 @@ struct Peer_Challenge_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Tab
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_CONTRACT_ID) &&
verifier.VerifyString(contract_id()) &&
VerifyField<uint16_t>(verifier, VT_ROUNDTIME) &&
VerifyOffset(verifier, VT_CHALLENGE) &&
verifier.VerifyString(challenge()) &&
verifier.EndTable();
@@ -329,6 +337,9 @@ struct Peer_Challenge_MessageBuilder {
void add_contract_id(flatbuffers::Offset<flatbuffers::String> contract_id) {
fbb_.AddOffset(Peer_Challenge_Message::VT_CONTRACT_ID, contract_id);
}
void add_roundtime(uint16_t roundtime) {
fbb_.AddElement<uint16_t>(Peer_Challenge_Message::VT_ROUNDTIME, roundtime, 0);
}
void add_challenge(flatbuffers::Offset<flatbuffers::String> challenge) {
fbb_.AddOffset(Peer_Challenge_Message::VT_CHALLENGE, challenge);
}
@@ -336,6 +347,7 @@ struct Peer_Challenge_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Peer_Challenge_MessageBuilder &operator=(const Peer_Challenge_MessageBuilder &);
flatbuffers::Offset<Peer_Challenge_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Peer_Challenge_Message>(end);
@@ -346,22 +358,26 @@ struct Peer_Challenge_MessageBuilder {
inline flatbuffers::Offset<Peer_Challenge_Message> CreatePeer_Challenge_Message(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> contract_id = 0,
uint16_t roundtime = 0,
flatbuffers::Offset<flatbuffers::String> challenge = 0) {
Peer_Challenge_MessageBuilder builder_(_fbb);
builder_.add_challenge(challenge);
builder_.add_contract_id(contract_id);
builder_.add_roundtime(roundtime);
return builder_.Finish();
}
inline flatbuffers::Offset<Peer_Challenge_Message> CreatePeer_Challenge_MessageDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *contract_id = nullptr,
uint16_t roundtime = 0,
const char *challenge = nullptr) {
auto contract_id__ = contract_id ? _fbb.CreateString(contract_id) : 0;
auto challenge__ = challenge ? _fbb.CreateString(challenge) : 0;
return msg::fbuf::p2pmsg::CreatePeer_Challenge_Message(
_fbb,
contract_id__,
roundtime,
challenge__);
}
@@ -407,6 +423,7 @@ struct Peer_Challenge_Response_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Peer_Challenge_Response_MessageBuilder &operator=(const Peer_Challenge_Response_MessageBuilder &);
flatbuffers::Offset<Peer_Challenge_Response_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Peer_Challenge_Response_Message>(end);
@@ -489,6 +506,7 @@ struct UserInputBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
UserInputBuilder &operator=(const UserInputBuilder &);
flatbuffers::Offset<UserInput> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<UserInput>(end);
@@ -565,6 +583,7 @@ struct UserInputGroupBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
UserInputGroupBuilder &operator=(const UserInputGroupBuilder &);
flatbuffers::Offset<UserInputGroup> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<UserInputGroup>(end);
@@ -724,6 +743,7 @@ struct ContentBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
ContentBuilder &operator=(const ContentBuilder &);
flatbuffers::Offset<Content> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Content>(end);
@@ -772,6 +792,7 @@ struct NonUnl_Proposal_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
NonUnl_Proposal_MessageBuilder &operator=(const NonUnl_Proposal_MessageBuilder &);
flatbuffers::Offset<NonUnl_Proposal_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<NonUnl_Proposal_Message>(end);
@@ -801,13 +822,14 @@ struct Proposal_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_STAGE = 4,
VT_TIME = 6,
VT_NONCE = 8,
VT_USERS = 10,
VT_INPUT_HASHES = 12,
VT_OUTPUT_HASH = 14,
VT_OUTPUT_SIG = 16,
VT_STATE_HASH = 18,
VT_PATCH_HASH = 20
VT_ROUNDTIME = 8,
VT_NONCE = 10,
VT_USERS = 12,
VT_INPUT_HASHES = 14,
VT_OUTPUT_HASH = 16,
VT_OUTPUT_SIG = 18,
VT_STATE_HASH = 20,
VT_PATCH_HASH = 22
};
uint8_t stage() const {
return GetField<uint8_t>(VT_STAGE, 0);
@@ -821,6 +843,12 @@ struct Proposal_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool mutate_time(uint64_t _time) {
return SetField<uint64_t>(VT_TIME, _time, 0);
}
uint16_t roundtime() const {
return GetField<uint16_t>(VT_ROUNDTIME, 0);
}
bool mutate_roundtime(uint16_t _roundtime) {
return SetField<uint16_t>(VT_ROUNDTIME, _roundtime, 0);
}
const flatbuffers::Vector<uint8_t> *nonce() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_NONCE);
}
@@ -867,6 +895,7 @@ struct Proposal_Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return VerifyTableStart(verifier) &&
VerifyField<uint8_t>(verifier, VT_STAGE) &&
VerifyField<uint64_t>(verifier, VT_TIME) &&
VerifyField<uint16_t>(verifier, VT_ROUNDTIME) &&
VerifyOffset(verifier, VT_NONCE) &&
verifier.VerifyVector(nonce()) &&
VerifyOffset(verifier, VT_USERS) &&
@@ -897,6 +926,9 @@ struct Proposal_MessageBuilder {
void add_time(uint64_t time) {
fbb_.AddElement<uint64_t>(Proposal_Message::VT_TIME, time, 0);
}
void add_roundtime(uint16_t roundtime) {
fbb_.AddElement<uint16_t>(Proposal_Message::VT_ROUNDTIME, roundtime, 0);
}
void add_nonce(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> nonce) {
fbb_.AddOffset(Proposal_Message::VT_NONCE, nonce);
}
@@ -922,6 +954,7 @@ struct Proposal_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Proposal_MessageBuilder &operator=(const Proposal_MessageBuilder &);
flatbuffers::Offset<Proposal_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Proposal_Message>(end);
@@ -933,6 +966,7 @@ inline flatbuffers::Offset<Proposal_Message> CreateProposal_Message(
flatbuffers::FlatBufferBuilder &_fbb,
uint8_t stage = 0,
uint64_t time = 0,
uint16_t roundtime = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> nonce = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> users = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::ByteArray>>> input_hashes = 0,
@@ -949,6 +983,7 @@ inline flatbuffers::Offset<Proposal_Message> CreateProposal_Message(
builder_.add_input_hashes(input_hashes);
builder_.add_users(users);
builder_.add_nonce(nonce);
builder_.add_roundtime(roundtime);
builder_.add_stage(stage);
return builder_.Finish();
}
@@ -957,6 +992,7 @@ inline flatbuffers::Offset<Proposal_Message> CreateProposal_MessageDirect(
flatbuffers::FlatBufferBuilder &_fbb,
uint8_t stage = 0,
uint64_t time = 0,
uint16_t roundtime = 0,
const std::vector<uint8_t> *nonce = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *users = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::ByteArray>> *input_hashes = nullptr,
@@ -975,6 +1011,7 @@ inline flatbuffers::Offset<Proposal_Message> CreateProposal_MessageDirect(
_fbb,
stage,
time,
roundtime,
nonce__,
users__,
input_hashes__,
@@ -1014,6 +1051,7 @@ struct Npl_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Npl_MessageBuilder &operator=(const Npl_MessageBuilder &);
flatbuffers::Offset<Npl_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Npl_Message>(end);
@@ -1068,6 +1106,7 @@ struct History_Request_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
History_Request_MessageBuilder &operator=(const History_Request_MessageBuilder &);
flatbuffers::Offset<History_Request_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<History_Request_Message>(end);
@@ -1146,6 +1185,7 @@ struct History_Response_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
History_Response_MessageBuilder &operator=(const History_Response_MessageBuilder &);
flatbuffers::Offset<History_Response_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<History_Response_Message>(end);
@@ -1220,6 +1260,7 @@ struct HistoryLedgerBlockPairBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
HistoryLedgerBlockPairBuilder &operator=(const HistoryLedgerBlockPairBuilder &);
flatbuffers::Offset<HistoryLedgerBlockPair> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<HistoryLedgerBlockPair>(end);
@@ -1279,6 +1320,7 @@ struct HistoryLedgerBlockBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
HistoryLedgerBlockBuilder &operator=(const HistoryLedgerBlockBuilder &);
flatbuffers::Offset<HistoryLedgerBlock> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<HistoryLedgerBlock>(end);
@@ -1383,6 +1425,7 @@ struct Hpfs_Request_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Hpfs_Request_MessageBuilder &operator=(const Hpfs_Request_MessageBuilder &);
flatbuffers::Offset<Hpfs_Request_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Hpfs_Request_Message>(end);
@@ -1519,6 +1562,7 @@ struct Hpfs_Response_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Hpfs_Response_MessageBuilder &operator=(const Hpfs_Response_MessageBuilder &);
flatbuffers::Offset<Hpfs_Response_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Hpfs_Response_Message>(end);
@@ -1591,6 +1635,7 @@ struct Fs_Entry_ResponseBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Fs_Entry_ResponseBuilder &operator=(const Fs_Entry_ResponseBuilder &);
flatbuffers::Offset<Fs_Entry_Response> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Fs_Entry_Response>(end);
@@ -1656,6 +1701,7 @@ struct File_HashMap_ResponseBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
File_HashMap_ResponseBuilder &operator=(const File_HashMap_ResponseBuilder &);
flatbuffers::Offset<File_HashMap_Response> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<File_HashMap_Response>(end);
@@ -1725,6 +1771,7 @@ struct Block_ResponseBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Block_ResponseBuilder &operator=(const Block_ResponseBuilder &);
flatbuffers::Offset<Block_Response> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Block_Response>(end);
@@ -1806,6 +1853,7 @@ struct Hpfs_FS_Hash_EntryBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Hpfs_FS_Hash_EntryBuilder &operator=(const Hpfs_FS_Hash_EntryBuilder &);
flatbuffers::Offset<Hpfs_FS_Hash_Entry> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Hpfs_FS_Hash_Entry>(end);
@@ -1868,6 +1916,7 @@ struct Peer_Requirement_Announcement_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Peer_Requirement_Announcement_MessageBuilder &operator=(const Peer_Requirement_Announcement_MessageBuilder &);
flatbuffers::Offset<Peer_Requirement_Announcement_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Peer_Requirement_Announcement_Message>(end);
@@ -1923,6 +1972,7 @@ struct Available_Capacity_Announcement_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Available_Capacity_Announcement_MessageBuilder &operator=(const Available_Capacity_Announcement_MessageBuilder &);
flatbuffers::Offset<Available_Capacity_Announcement_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Available_Capacity_Announcement_Message>(end);
@@ -1956,6 +2006,7 @@ struct Peer_List_Request_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Peer_List_Request_MessageBuilder &operator=(const Peer_List_Request_MessageBuilder &);
flatbuffers::Offset<Peer_List_Request_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Peer_List_Request_Message>(end);
@@ -2000,6 +2051,7 @@ struct Peer_List_Response_MessageBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Peer_List_Response_MessageBuilder &operator=(const Peer_List_Response_MessageBuilder &);
flatbuffers::Offset<Peer_List_Response_Message> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Peer_List_Response_Message>(end);
@@ -2087,6 +2139,7 @@ struct Peer_PropertiesBuilder {
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
Peer_PropertiesBuilder &operator=(const Peer_PropertiesBuilder &);
flatbuffers::Offset<Peer_Properties> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<Peer_Properties>(end);

View File

@@ -20,30 +20,30 @@ namespace msg::fbuf::p2pmsg
constexpr size_t MAX_SIZE_FOR_TIME_CHECK = 1 * 1024 * 1024; // 1 MB
/**
* This section contains Flatbuffer message reading/writing helpers.
* These helpers are mainly used by peer_session_handler.
*
* All Flatbuffer peer messages are 'Container' messages. 'Container' message is a bucket
* which some common headers (version, singature etc..) and the message 'Content' (Proposal, NPL etc..).
*
* Therefore, when constructing peer messages, we have to first construct 'Content' message and then
* place the 'Content' inside a 'Conatiner. 'Content' and 'Container' messages are constructed using
* Flatbuffer builders.
*
* Reading is also 2 steps because of this. We have first interprit the 'Container' message from the
* received data and then interprit the 'Content' portion of it separately to read the actual content.
*/
* This section contains Flatbuffer message reading/writing helpers.
* These helpers are mainly used by peer_session_handler.
*
* All Flatbuffer peer messages are 'Container' messages. 'Container' message is a bucket
* which some common headers (version, singature etc..) and the message 'Content' (Proposal, NPL etc..).
*
* Therefore, when constructing peer messages, we have to first construct 'Content' message and then
* place the 'Content' inside a 'Conatiner. 'Content' and 'Container' messages are constructed using
* Flatbuffer builders.
*
* Reading is also 2 steps because of this. We have first interprit the 'Container' message from the
* received data and then interprit the 'Content' portion of it separately to read the actual content.
*/
//---Message validation helpers---/
/**
* Verifies Conatiner message structure and outputs faltbuffer Container pointer to access the given buffer.
*
* @param container_ref A pointer reference to assign the pointer to the Container object.
* @param container_buf The buffer containing the data that should be validated and interpreted
* via the container pointer.
* @return 0 on successful verification. -1 for failure.
*/
* Verifies Conatiner message structure and outputs faltbuffer Container pointer to access the given buffer.
*
* @param container_ref A pointer reference to assign the pointer to the Container object.
* @param container_buf The buffer containing the data that should be validated and interpreted
* via the container pointer.
* @return 0 on successful verification. -1 for failure.
*/
int validate_and_extract_container(const Container **container_ref, std::string_view container_buf)
{
//Accessing message buffer
@@ -123,14 +123,14 @@ namespace msg::fbuf::p2pmsg
}
/**
* Verifies the Content message structure and outputs faltbuffer Content pointer to access the given buffer.
*
* @param content_ref A pointer reference to assign the pointer to the Content object.
* @param content_ptr Pointer to the buffer containing the data that should validated and interpreted
* via the container pointer.
* @param content_size Data buffer size.
* @return 0 on successful verification. -1 for failure.
*/
* Verifies the Content message structure and outputs faltbuffer Content pointer to access the given buffer.
*
* @param content_ref A pointer reference to assign the pointer to the Content object.
* @param content_ptr Pointer to the buffer containing the data that should validated and interpreted
* via the container pointer.
* @param content_size Data buffer size.
* @return 0 on successful verification. -1 for failure.
*/
int validate_and_extract_content(const Content **content_ref, const uint8_t *content_ptr, const flatbuffers::uoffset_t content_size)
{
//Defining Flatbuffer verifier for message content verification.
@@ -151,22 +151,23 @@ namespace msg::fbuf::p2pmsg
//---Message reading helpers---/
/**
* Returns challenge from the peer challenge message.
* @param The Flatbuffer peer challenge message received from the peer.
* @return Peer challenge struct.
*/
* Returns challenge from the peer challenge message.
* @param The Flatbuffer peer challenge message received from the peer.
* @return Peer challenge struct.
*/
const p2p::peer_challenge get_peer_challenge_from_msg(const Peer_Challenge_Message &msg)
{
return {
std::string(flatbuff_str_to_sv(msg.contract_id())),
msg.roundtime(),
std::string(flatbuff_str_to_sv(msg.challenge()))};
}
/**
* Creates a peer challenge response struct from the given peer challenge response message.
* @param The Flatbuffer peer challenge response message received from the peer.
* @return A peer challenge response struct representing the message.
*/
* Creates a peer challenge response struct from the given peer challenge response message.
* @param The Flatbuffer peer challenge response message received from the peer.
* @return A peer challenge response struct representing the message.
*/
const p2p::peer_challenge_response create_peer_challenge_response_from_msg(const Peer_Challenge_Response_Message &msg, const flatbuffers::Vector<uint8_t> *pubkey)
{
p2p::peer_challenge_response pchalresp;
@@ -179,10 +180,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Creates a non-unl proposal stuct from the given non-unl proposal message.
* @param The Flatbuffer non-unl poporal received from the peer.
* @return A non-unl proposal struct representing the message.
*/
* Creates a non-unl proposal stuct from the given non-unl proposal message.
* @param The Flatbuffer non-unl poporal received from the peer.
* @return A non-unl proposal struct representing the message.
*/
const p2p::nonunl_proposal create_nonunl_proposal_from_msg(const NonUnl_Proposal_Message &msg, const uint64_t timestamp)
{
p2p::nonunl_proposal nup;
@@ -194,10 +195,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Creates a history response stuct from the given histrory response message.
* @param msg Flatbuffer History response message received from the peer.
* @return A History response struct representing the message.
*/
* Creates a history response stuct from the given histrory response message.
* @param msg Flatbuffer History response message received from the peer.
* @return A History response struct representing the message.
*/
const p2p::history_response create_history_response_from_msg(const History_Response_Message &msg)
{
p2p::history_response hr;
@@ -215,10 +216,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Creates a proposal stuct from the given proposal message.
* @param The Flatbuffer poposal received from the peer.
* @return A proposal struct representing the message.
*/
* Creates a proposal stuct from the given proposal message.
* @param The Flatbuffer poposal received from the peer.
* @return A proposal struct representing the message.
*/
const p2p::proposal create_proposal_from_msg(const Proposal_Message &msg, const flatbuffers::Vector<uint8_t> *pubkey, const uint64_t timestamp, const flatbuffers::Vector<uint8_t> *lcl)
{
p2p::proposal p;
@@ -227,6 +228,7 @@ namespace msg::fbuf::p2pmsg
p.sent_timestamp = timestamp;
p.recv_timestamp = util::get_epoch_milliseconds();
p.time = msg.time();
p.roundtime = msg.roundtime();
p.nonce = flatbuff_bytes_to_sv(msg.nonce());
p.stage = msg.stage();
p.lcl = flatbuff_bytes_to_sv(lcl);
@@ -249,10 +251,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Creates a history request struct from the given history request message.
* @param msg Flatbuffer History request message received from the peer.
* @return A History request struct representing the message.
*/
* Creates a history request struct from the given history request message.
* @param msg Flatbuffer History request message received from the peer.
* @return A History request struct representing the message.
*/
const p2p::history_request create_history_request_from_msg(const History_Request_Message &msg, const flatbuffers::Vector<uint8_t> *lcl)
{
p2p::history_request hr;
@@ -284,10 +286,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Creates a peer property list from the given peer list response message.
* @param msg Flatbuffer Peer List response message received from the peer.
* @return A Peer list representing the message.
*/
* Creates a peer property list from the given peer list response message.
* @param msg Flatbuffer Peer List response message received from the peer.
* @return A Peer list representing the message.
*/
const std::vector<conf::peer_properties> create_peer_list_response_from_msg(const Peer_List_Response_Message &msg)
{
return flatbuf_peer_propertieslist_to_peer_propertiesvector(msg.peer_list());
@@ -296,10 +298,10 @@ namespace msg::fbuf::p2pmsg
//---Message creation helpers---//
/**
* Create peer challenge message from the given challenge.
* @param container_builder Flatbuffer builder for the container message.
* @param challenge Challenge message needed to convert to flatbuffer message.
*/
* Create peer challenge message from the given challenge.
* @param container_builder Flatbuffer builder for the container message.
* @param challenge Challenge message needed to convert to flatbuffer message.
*/
void create_msg_from_peer_challenge(flatbuffers::FlatBufferBuilder &container_builder, std::string &challenge)
{
flatbuffers::FlatBufferBuilder builder(1024);
@@ -313,6 +315,7 @@ namespace msg::fbuf::p2pmsg
CreatePeer_Challenge_Message(
builder,
sv_to_flatbuff_str(builder, conf::cfg.contract.id),
conf::cfg.contract.roundtime,
sv_to_flatbuff_str(builder, challenge));
const flatbuffers::Offset<Content> message = CreateContent(builder, Message_Peer_Challenge_Message, peer_challenge_msg.Union());
@@ -323,10 +326,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create peer challenge response message from the given challenge.
* @param container_builder Flatbuffer builder for the container message.
* @param challenge Message which need to be signed and placed in the container message.
*/
* Create peer challenge response message from the given challenge.
* @param container_builder Flatbuffer builder for the container message.
* @param challenge Message which need to be signed and placed in the container message.
*/
void create_peer_challenge_response_from_challenge(flatbuffers::FlatBufferBuilder &container_builder, const std::string &challenge)
{
flatbuffers::FlatBufferBuilder builder(1024);
@@ -363,10 +366,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create proposal peer message from the given proposal struct.
* @param container_builder Flatbuffer builder for the container message.
* @param p The proposal struct to be placed in the container message.
*/
* Create proposal peer message from the given proposal struct.
* @param container_builder Flatbuffer builder for the container message.
* @param p The proposal struct to be placed in the container message.
*/
void create_msg_from_proposal(flatbuffers::FlatBufferBuilder &container_builder, const p2p::proposal &p)
{
// todo:get a average propsal message size and allocate content builder based on that.
@@ -377,6 +380,7 @@ namespace msg::fbuf::p2pmsg
builder,
p.stage,
p.time,
p.roundtime,
sv_to_flatbuff_bytes(builder, p.nonce),
stringlist_to_flatbuf_bytearrayvector(builder, p.users),
stringlist_to_flatbuf_bytearrayvector(builder, p.input_hashes),
@@ -394,11 +398,11 @@ namespace msg::fbuf::p2pmsg
}
/**
* Ctreat npl message from the given npl output srtuct.
* @param container_builder Flatbuffer builder for the container message.
* @param msg The message to be sent as NPL message.
* @param lcl Lcl value to be passed in the container message.
*/
* Ctreat npl message from the given npl output srtuct.
* @param container_builder Flatbuffer builder for the container message.
* @param msg The message to be sent as NPL message.
* @param lcl Lcl value to be passed in the container message.
*/
void create_msg_from_npl_output(flatbuffers::FlatBufferBuilder &container_builder, const std::string_view &msg, std::string_view lcl)
{
flatbuffers::FlatBufferBuilder builder(1024);
@@ -417,10 +421,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create history request message from the given history request struct.
* @param container_builder Flatbuffer builder for the container message.
* @param hr The History request struct to be placed in the container message.
*/
* Create history request message from the given history request struct.
* @param container_builder Flatbuffer builder for the container message.
* @param hr The History request struct to be placed in the container message.
*/
void create_msg_from_history_request(flatbuffers::FlatBufferBuilder &container_builder, const p2p::history_request &hr)
{
flatbuffers::FlatBufferBuilder builder(1024);
@@ -439,10 +443,10 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create history response message from the given history response struct.
* @param container_builder Flatbuffer builder for the container message.
* @param hr The History response struct to be placed in the container message.
*/
* Create history response message from the given history response struct.
* @param container_builder Flatbuffer builder for the container message.
* @param hr The History response struct to be placed in the container message.
*/
void create_msg_from_history_response(flatbuffers::FlatBufferBuilder &container_builder, const p2p::history_response &hr)
{
flatbuffers::FlatBufferBuilder builder(1024);
@@ -489,14 +493,14 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param path The path of the directory.
* @param mount_id The mount id of the relavent hpfs mount.
* @param hash_nodes File or directory entries with hashes in the given parent path.
* @param expected_hash The exptected hash of the requested path.
* @param lcl Lcl to be include in the container msg.
*/
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param path The path of the directory.
* @param mount_id The mount id of the relavent hpfs mount.
* @param hash_nodes File or directory entries with hashes in the given parent path.
* @param expected_hash The exptected hash of the requested path.
* @param lcl Lcl to be include in the container msg.
*/
void create_msg_from_fsentry_response(
flatbuffers::FlatBufferBuilder &container_builder, const std::string_view path, const uint32_t mount_id,
std::vector<hpfs::child_hash_node> &hash_nodes, util::h32 expected_hash, std::string_view lcl)
@@ -523,13 +527,13 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param path The path of the directory.
* @param mount_id The mount id of the relavent hpfs mount.
* @param hashmap Hashmap of the file
* @param lcl Lcl to be include in the container msg.
*/
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param path The path of the directory.
* @param mount_id The mount id of the relavent hpfs mount.
* @param hashmap Hashmap of the file
* @param lcl Lcl to be include in the container msg.
*/
void create_msg_from_filehashmap_response(
flatbuffers::FlatBufferBuilder &container_builder, std::string_view path, const uint32_t mount_id,
std::vector<util::h32> &hashmap, std::size_t file_length, util::h32 expected_hash, std::string_view lcl)
@@ -561,12 +565,12 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param block_resp Block response struct to place in the message.
* @param mount_id The mount id of the relavent hpfs mount.
* @param lcl Lcl to be include in the container message.
*/
* Create content response message from the given content response.
* @param container_builder Flatbuffer builder for the container message.
* @param block_resp Block response struct to place in the message.
* @param mount_id The mount id of the relavent hpfs mount.
* @param lcl Lcl to be include in the container message.
*/
void create_msg_from_block_response(flatbuffers::FlatBufferBuilder &container_builder, p2p::block_response &block_resp, const uint32_t mount_id, std::string_view lcl)
{
// todo:get a average propsal message size and allocate content builder based on that.
@@ -683,12 +687,12 @@ namespace msg::fbuf::p2pmsg
}
/**
* Creates a Flatbuffer container message from the given Content message.
* @param container_builder The Flatbuffer builder to which the final container message should be written to.
* @param content_builder The Flatbuffer builder containing the content message that should be placed
* inside the container message.
* @param sign Whether to sign the message content.
*/
* Creates a Flatbuffer container message from the given Content message.
* @param container_builder The Flatbuffer builder to which the final container message should be written to.
* @param content_builder The Flatbuffer builder containing the content message that should be placed
* inside the container message.
* @param sign Whether to sign the message content.
*/
void create_containermsg_from_content(
flatbuffers::FlatBufferBuilder &container_builder, const flatbuffers::FlatBufferBuilder &content_builder, std::string_view lcl, const bool sign)
{
@@ -854,11 +858,11 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create peer list message from the given vector of peer properties structs.
* @param container_builder Flatbuffer builder for the container message.
* @param peers The Vector of peer properties to be placed in the container message.
* @param skipping_peer Peer that does not need to be sent.
*/
* Create peer list message from the given vector of peer properties structs.
* @param container_builder Flatbuffer builder for the container message.
* @param peers The Vector of peer properties to be placed in the container message.
* @param skipping_peer Peer that does not need to be sent.
*/
const flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<Peer_Properties>>>
peer_propertiesvector_to_flatbuf_peer_propertieslist(flatbuffers::FlatBufferBuilder &builder, const std::vector<conf::peer_properties> &peers, const std::optional<conf::ip_port_prop> &skipping_ip_port)
{
@@ -879,9 +883,9 @@ namespace msg::fbuf::p2pmsg
}
/**
* Create vector of peer properties structs from the given peer list message.
* @param fbvec The peer list message to be convert to a list of peer properties structs.
*/
* Create vector of peer properties structs from the given peer list message.
* @param fbvec The peer list message to be convert to a list of peer properties structs.
*/
const std::vector<conf::peer_properties>
flatbuf_peer_propertieslist_to_peer_propertiesvector(const flatbuffers::Vector<flatbuffers::Offset<Peer_Properties>> *fbvec)
{

View File

@@ -23,10 +23,11 @@ namespace p2p
std::string pubkey;
uint64_t sent_timestamp = 0; // The timestamp of the sender when this proposal was sent.
uint64_t recv_timestamp = 0; // The timestamp when we received the proposal. (used for statistics)
uint64_t time = 0; // The time value that is voted on.
uint8_t stage = 0;
std::string nonce; // Random nonce that is used to reduce lcl predictability.
uint64_t recv_timestamp = 0; // The timestamp when we received the proposal. (used for network statistics)
uint64_t time = 0; // The descreet concensus time value that is voted on.
uint8_t stage = 0; // The round-stage that this proposal belongs to.
uint16_t roundtime = 0; // Roundtime of the proposer.
std::string nonce; // Random nonce that is used to reduce lcl predictability.
std::string lcl;
util::h32 state_hash; // Contract state hash.
util::h32 patch_hash; // Patch file hash.
@@ -56,6 +57,7 @@ namespace p2p
struct peer_challenge
{
std::string contract_id;
uint16_t roundtime = 0;
std::string challenge;
};
@@ -145,7 +147,7 @@ namespace p2p
// Holds all the messages until they are processed by consensus.
message_collection collected_msgs;
// Set of currently connected peer connections mapped by the pubkey of socket session.
// Set of currently connected peer connections mapped by the binary pubkey of socket session.
std::unordered_map<std::string, peer_comm_session *> peer_connections;
std::mutex peer_connections_mutex; // Mutex for peer connections access race conditions.
@@ -192,6 +194,7 @@ namespace p2p
int16_t get_available_capacity();
void update_unl_connections();
} // namespace p2p
#endif

View File

@@ -24,6 +24,7 @@ namespace p2p
std::optional<conf::ip_port_prop> known_ipport; // A known ip/port information that matches with our peer list configuration.
bool need_consensus_msg_forwarding = false; // Holds whether this node requires consensus message forwarding.
bool is_unl = false; // Whether this session's pubkey is in unl list.
uint16_t reported_roundtime = 0; // Initial roundtime reported by this peer on peer challenge.
};
} // namespace p2p

View File

@@ -109,6 +109,9 @@ namespace p2p
return -1;
}
// Remember the roundtime reported by this peer.
session.reported_roundtime = chall.roundtime;
// Sending the challenge response to the sender.
flatbuffers::FlatBufferBuilder fbuf(1024);
p2pmsg::create_peer_challenge_response_from_challenge(fbuf, chall.challenge);
@@ -153,13 +156,9 @@ namespace p2p
const p2pmsg::Peer_Requirement_Announcement_Message *announcement_msg = content->message_as_Peer_Requirement_Announcement_Message();
session.need_consensus_msg_forwarding = announcement_msg->need_consensus_msg_forwarding();
if (session.need_consensus_msg_forwarding)
{
LOG_DEBUG << "Consensus message forwaring is required for " << session.display_name();
}
else
{
LOG_DEBUG << "Consensus message forwaring is not required for " << session.display_name();
}
}
else if (content_message_type == p2pmsg::Message_Proposal_Message) // message is a proposal message
{

View File

@@ -9,10 +9,9 @@
*/
namespace unl
{
std::set<std::string> list; // List of binary pubkeys of UNL.
std::string json_list; // Stringified json array of UNL. (To be fed into the contract args)
std::map<std::string, uint16_t> list; // List of binary pubkeys of UNL and their latest reported roundtime.
std::string json_list; // Stringified json array of UNL. (To be fed into the contract args)
std::shared_mutex unl_mutex;
std::string hash;
/**
* Performs startup activitites related to unl list.
@@ -24,11 +23,8 @@ namespace unl
return -1;
std::unique_lock lock(unl_mutex);
list = conf::cfg.contract.unl;
// Update the own node's unl status.
conf::cfg.node.is_unl = (list.find(conf::cfg.node.public_key) != list.end());
update_json_list();
hash = calculate_hash(list);
update_unl_list(conf::cfg.contract.unl);
return 0;
}
@@ -38,13 +34,16 @@ namespace unl
return list.size();
}
std::set<std::string> get()
const std::set<std::string> get()
{
std::shared_lock lock(unl_mutex);
return list;
std::set<std::string> ret;
for (auto [pubkey, roundtime] : list)
ret.emplace(std::move(pubkey));
return ret;
}
std::string get_json()
const std::string get_json()
{
std::shared_lock lock(unl_mutex);
return json_list;
@@ -61,34 +60,6 @@ namespace unl
return list.find(bin_pubkey) != list.end();
}
void update_json_list()
{
std::ostringstream os;
os << "[";
for (auto pk = list.begin(); pk != list.end(); pk++)
{
if (pk != list.begin())
os << ","; // Trailing comma separator for previous element.
// Convert binary pubkey into hex.
os << "\"" << util::to_hex(*pk) << "\"";
}
os << "]";
json_list = os.str();
}
/**
* Calculate hash of the given set.
* @param unl_list UNL list.
* @return Returns the generated hash of the given list.
*/
std::string calculate_hash(const std::set<std::string> &new_list)
{
std::vector<std::string_view> unl_vector(new_list.begin(), new_list.end());
return crypto::get_hash(unl_vector);
}
/**
* Replace the unl list from the latest unl list from patch file.
*/
@@ -97,17 +68,7 @@ namespace unl
bool is_unl_list_changed = false;
{
std::unique_lock lock(unl_mutex);
const std::string updated_hash = calculate_hash(conf::cfg.contract.unl);
if (hash != updated_hash)
{
hash = updated_hash;
list = conf::cfg.contract.unl;
update_json_list();
// Update the own node's unl status.
conf::cfg.node.is_unl = (list.find(conf::cfg.node.public_key) != list.end());
is_unl_list_changed = true;
}
is_unl_list_changed = update_unl_list(conf::cfg.contract.unl);
}
// Update the is_unl flag of peer sessions.
@@ -115,8 +76,128 @@ namespace unl
if (is_unl_list_changed)
{
p2p::update_unl_connections();
usr::announce_unl_list(list);
usr::announce_unl_list(conf::cfg.contract.unl);
}
}
/**
* Updates unl pubkey-roundtime information using the specified list of proposals.
*/
void update_roundtime_stats(const std::list<p2p::proposal> &proposals)
{
std::unique_lock lock(unl_mutex);
for (const auto &p : proposals)
{
const auto itr = list.find(p.pubkey);
if (itr != list.end())
itr->second = p.roundtime;
}
}
/**
* Returns the majority roundtime reported among the unl.
*/
uint16_t get_majority_roundtime()
{
std::unique_lock lock(unl_mutex);
// Vote and find majority roundtime within the unl.
// Fill any 0 roundtimes with information from peer connections.
std::map<uint16_t, uint32_t> roundtime_votes;
{
std::scoped_lock<std::mutex> lock(p2p::ctx.peer_connections_mutex);
for (auto itr = list.begin(); itr != list.end(); itr++)
{
// If roundtime is 0, attempt to get from peer connection (if available).
if (itr->second == 0)
{
const auto peer_itr = p2p::ctx.peer_connections.find(itr->first);
if (peer_itr != p2p::ctx.peer_connections.end())
itr->second = peer_itr->second->reported_roundtime;
}
const uint16_t roundtime = itr->second;
if (roundtime > 0)
roundtime_votes[roundtime]++;
}
}
// Find the majority vote.
uint32_t highest_votes = 0;
uint16_t majority_roundtime = 0;
for (const auto [roundtime, num_votes] : roundtime_votes)
{
if (num_votes > highest_votes)
{
highest_votes = num_votes;
majority_roundtime = roundtime;
}
}
return majority_roundtime;
}
/**
* Updates the unl list using the provided new list.
* @return Whether or not any unl list changes were made.
*/
bool update_unl_list(const std::set<std::string> &new_list)
{
bool changes_made = false;
// Erase any pubkeys from current unl list that does not exist in new config.
for (auto itr = list.begin(); itr != list.end();)
{
if (conf::cfg.contract.unl.count(itr->first) == 0)
{
itr = list.erase(itr);
changes_made = true;
}
else
{
itr++;
}
}
// Add any pubkeys that are not in current unl list.
for (const std::string pubkey : conf::cfg.contract.unl)
{
if (list.count(pubkey) == 0)
{
list.emplace(pubkey, 0);
changes_made = true;
}
}
if (!changes_made)
return false;
// Update the prepared json list which will be fed into contract args.
json_list = prepare_json_list(new_list);
// Update the own node's unl status.
conf::cfg.node.is_unl = (list.count(conf::cfg.node.public_key) == 1);
return true; // Changes made.
}
const std::string prepare_json_list(const std::set<std::string> &new_list)
{
std::ostringstream os;
os << "[";
for (auto pk = new_list.begin(); pk != new_list.end(); pk++)
{
if (pk != new_list.begin())
os << ","; // Trailing comma separator for previous element.
// Convert binary pubkey into hex.
os << "\"" << util::to_hex(*pk) << "\"";
}
os << "]";
return os.str();
}
} // namespace unl

View File

@@ -12,13 +12,15 @@ namespace unl
{
size_t count();
std::set<std::string> get();
std::string get_json();
const std::set<std::string> get();
const std::string get_json();
bool exists(const std::string &bin_pubkey);
int init();
void update_json_list();
std::string calculate_hash(const std::set<std::string> &new_list);
void update_unl_changes_from_patch();
void update_roundtime_stats(const std::list<p2p::proposal> &proposals);
uint16_t get_majority_roundtime();
bool update_unl_list(const std::set<std::string> &new_list);
const std::string prepare_json_list(const std::set<std::string> &new_list);
} // namespace unl

View File

@@ -16,13 +16,14 @@ clusterloc=$(pwd)/hpcluster
n=$1
let pubport=8080+$n
# let peerport=22860+$n #Uncomment if peer port needs to be exposed to host.
let peerport=22860+$n
# Mount the node<id> contract directory into hpcore docker container and run.
# We specify --network=hpnet so all nodes will communicate via 'hpnet' docker virtual network.
# We specify --name for each node so it will be the virtual dns name for each node.
docker run --rm -t -i --network=hpnet --name=node${n} \
-p ${pubport}:${pubport} \
-p ${peerport}:${peerport} \
--device /dev/fuse --cap-add SYS_ADMIN --security-opt apparmor:unconfined \
--mount type=bind,source=${clusterloc}/node${n},target=/contract \
hpcore:latest run /contract