Added stage slice config to control stage time allocation. (#310)

This commit is contained in:
Ravin Perera
2021-05-19 16:59:01 +05:30
committed by GitHub
parent 94b29b9e05
commit 45492f7c7f
15 changed files with 148 additions and 110 deletions

View File

@@ -155,6 +155,7 @@ struct hp_config
char *bin_path;
char *bin_args;
uint32_t roundtime;
uint32_t stage_slice;
char *consensus;
char *npl;
uint16_t max_input_ledger_offset;
@@ -504,9 +505,12 @@ int hp_update_config(const struct hp_config *config)
if (!config->bin_path || strlen(config->bin_path) == 0)
__HP_UPDATE_CONFIG_ERROR("Binary path cannot be empty.");
if (config->roundtime <= 0)
__HP_UPDATE_CONFIG_ERROR("Round time must be higher than 0.");
if (config->roundtime <= 0 || config->roundtime > 3600000)
__HP_UPDATE_CONFIG_ERROR("Round time must be between 1 and 3600000ms inclusive.");
if (config->stage_slice <= 0 || config->stage_slice > 33)
__HP_UPDATE_CONFIG_ERROR("Stage slice must be between 1 and 33 percent inclusive");
if (config->max_input_ledger_offset < 0)
__HP_UPDATE_CONFIG_ERROR("Invalid max input ledger offset.");
@@ -646,18 +650,23 @@ int __hp_write_to_patch_file(const int fd, const struct hp_config *config)
// Top-level field values.
const char *json_string = " \"bin_path\": \"%s\",\n \"bin_args\": \"%s\",\n \"roundtime\": %s,\n"
const char *json_string = " \"bin_path\": \"%s\",\n \"bin_args\": \"%s\",\n \"roundtime\": %s,\n \"stage_slice\": %s,\n"
" \"consensus\": \"%s\",\n \"npl\": \"%s\",\n \"max_input_ledger_offset\": %s,\n";
char roundtime_str[16];
sprintf(roundtime_str, "%d", config->roundtime);
char stage_slice_str[16];
sprintf(stage_slice_str, "%d", config->stage_slice);
char max_input_ledger_offset_str[16];
sprintf(max_input_ledger_offset_str, "%d", config->max_input_ledger_offset);
const size_t json_string_len = 128 + strlen(config->bin_path) + strlen(config->bin_args) + strlen(roundtime_str) + strlen(config->consensus) + strlen(config->npl) + strlen(max_input_ledger_offset_str);
const size_t json_string_len = 149 + strlen(config->bin_path) + strlen(config->bin_args) +
strlen(roundtime_str) + strlen(stage_slice_str) +
strlen(config->consensus) + strlen(config->npl) + strlen(max_input_ledger_offset_str);
char json_buf[json_string_len];
sprintf(json_buf, json_string, config->bin_path, config->bin_args, roundtime_str, config->consensus, config->npl, max_input_ledger_offset_str);
sprintf(json_buf, json_string, config->bin_path, config->bin_args, roundtime_str, stage_slice_str, config->consensus, config->npl, max_input_ledger_offset_str);
iov_vec[2].iov_base = json_buf;
iov_vec[2].iov_len = json_string_len;
@@ -753,6 +762,11 @@ void __hp_populate_patch_from_json_object(struct hp_config *config, const struct
const struct json_number_s *value = (struct json_number_s *)elem->value->payload;
config->roundtime = strtol(value->number, NULL, 0);
}
else if (strcmp(k->string, "stage_slice") == 0)
{
const struct json_number_s *value = (struct json_number_s *)elem->value->payload;
config->stage_slice = strtol(value->number, NULL, 0);
}
else if (strcmp(k->string, "max_input_ledger_offset") == 0)
{
const struct json_number_s *value = (struct json_number_s *)elem->value->payload;

View File

@@ -147,8 +147,10 @@ class PatchConfig {
}
if (!config.bin_path || !config.bin_path.length)
throw "Binary path cannot be empty.";
if (config.roundtime <= 0)
throw "Round time must be higher than zero."
if (config.roundtime < 1 && config.roundtime > 3600000)
throw "Round time must be between 1 and 3600000ms inclusive.";
if (config.stage_slice < 1 || config.stage_slice > 33)
throw "Stage slice must be between 1 and 33 percent inclusive.";
if (config.consensus != "public" && config.consensus != "private")
throw "Invalid consensus flag configured in patch file. Valid values: public|private";
if (config.npl != "public" && config.npl != "private")

View File

@@ -20,6 +20,8 @@ namespace conf
ROLE startup_role;
constexpr int FILE_PERMS = 0644;
constexpr uint32_t MAX_ROUND_TIME = 3600000;
constexpr uint32_t MAX_STAGE_SLICE = 33;
constexpr const char *ROLE_OBSERVER = "observer";
constexpr const char *ROLE_VALIDATOR = "validator";
@@ -164,6 +166,7 @@ namespace conf
cfg.contract.unl.emplace(cfg.node.public_key);
cfg.contract.bin_path = "<your contract binary here>";
cfg.contract.roundtime = 1000;
cfg.contract.stage_slice = 25;
cfg.contract.is_consensus_public = false;
cfg.contract.is_npl_public = false;
cfg.contract.max_input_ledger_offset = 10;
@@ -644,13 +647,14 @@ namespace conf
// Other required fields.
bool fields_invalid = false;
fields_invalid |= cfg.contract.roundtime == 0 && std::cerr << "Invalid value for roundtime\n";
fields_invalid |= cfg.contract.roundtime == 0 && std::cerr << "Invalid value for roundtime.\n";
fields_invalid |= cfg.contract.stage_slice == 0 && std::cerr << "Invalid value for stage slice.\n";
fields_invalid |= cfg.contract.unl.empty() && std::cerr << "Invalid value for unl. Unl list cannot be empty.\n";
fields_invalid |= cfg.contract.id.empty() && std::cerr << "Invalid value for contract id.\n";
fields_invalid |= cfg.mesh.port == 0 && std::cerr << "Invalid value for mesh port\n";
fields_invalid |= cfg.user.port == 0 && std::cerr << "Invalid value for user port\n";
fields_invalid |= cfg.log.log_level.empty() && std::cerr << "Invalid value for loglevel\n";
fields_invalid |= cfg.log.loggers.empty() && std::cerr << "Invalid value for loggers\n";
fields_invalid |= cfg.mesh.port == 0 && std::cerr << "Invalid value for mesh port.\n";
fields_invalid |= cfg.user.port == 0 && std::cerr << "Invalid value for user port.\n";
fields_invalid |= cfg.log.log_level.empty() && std::cerr << "Invalid value for loglevel.\n";
fields_invalid |= cfg.log.loggers.empty() && std::cerr << "Invalid value for loggers.\n";
if (fields_invalid)
{
@@ -777,10 +781,13 @@ namespace conf
/**
* Prints the config json parsing field missing error.
*/
void print_missing_field_error(std::string_view jpath, const std::exception &e)
void print_missing_field_error(std::string_view jpath, const std::exception &e, const bool is_patch_config)
{
// Extract field name from jsoncons exception message.
std::cerr << "Config validation error: " << e.what() << " in '" << jpath << "' section at " << ctx.config_file << std::endl;
if (is_patch_config)
LOG_ERROR << "Config validation error: " << e.what() << " in '" << jpath << "' section in patch config";
else
std::cerr << "Config validation error: " << e.what() << " in '" << jpath << "' section at " << ctx.config_file << std::endl;
}
/**
@@ -942,6 +949,7 @@ namespace conf
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.load());
jdoc.insert_or_assign("stage_slice", contract.stage_slice.load());
jdoc.insert_or_assign("consensus", contract.is_consensus_public ? PUBLIC : PRIVATE);
jdoc.insert_or_assign("npl", contract.is_npl_public ? PUBLIC : PRIVATE);
jdoc.insert_or_assign("max_input_ledger_offset", contract.max_input_ledger_offset);
@@ -1016,9 +1024,16 @@ namespace conf
contract.bin_args = jdoc["bin_args"].as<std::string>();
contract.roundtime = jdoc["roundtime"].as<uint32_t>();
if (contract.roundtime == 0)
if (contract.roundtime < 1 || contract.roundtime > MAX_ROUND_TIME)
{
std::cerr << "Round time cannot be zero.\n";
std::cerr << "Round time must be between 1 and " << MAX_ROUND_TIME << "ms inclusive.\n";
return -1;
}
contract.stage_slice = jdoc["stage_slice"].as<uint32_t>();
if (contract.stage_slice < 1 || contract.stage_slice > MAX_STAGE_SLICE)
{
std::cerr << "Stage slice must be between 1 and " << MAX_STAGE_SLICE << " percent inclusive.\n";
return -1;
}
@@ -1051,7 +1066,7 @@ namespace conf
}
catch (const std::exception &e)
{
print_missing_field_error(jpath, e);
print_missing_field_error(jpath, e, is_patch_config);
return -1;
}

View File

@@ -11,6 +11,8 @@ namespace conf
{
constexpr size_t CONCURRENT_READ_REQUEST_MAX_LIMIT = 32;
#define CURRENT_TIME_CONFIG ((conf::cfg.contract.roundtime * 100) + conf::cfg.contract.stage_slice)
// Struct to represent ip and port of the peer.
struct peer_ip_port
{
@@ -94,17 +96,18 @@ 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
std::atomic<uint32_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.
uint16_t max_input_ledger_offset; // Maximum ledger sequence number offset that can be specified in the input.
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<uint32_t> roundtime = 0; // Consensus round time in ms (max: 3,600,000).
std::atomic<uint32_t> stage_slice = 0; // Percentage slice of round time that stages 0,1,2 get (max: 33).
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.
uint16_t max_input_ledger_offset; // Maximum ledger sequence number offset that can be specified in the input.
appbill_config appbill;
round_limits_config round_limits;
@@ -197,8 +200,8 @@ namespace conf
struct log_config
{
std::string log_level; // Log severity level (dbg, inf, wrn, wrr)
LOG_SEVERITY log_level_type; // Log severity level enum (debug, info, warn, error)
std::string log_level; // Log severity level (dbg, inf, wrn, wrr)
LOG_SEVERITY log_level_type; // Log severity level enum (debug, info, warn, error)
std::unordered_set<std::string> loggers; // List of enabled loggers (console, file)
size_t max_mbytes_per_file = 0; // Max MB size of a single log file.
size_t max_file_count = 0; // Max no. of log files to keep.
@@ -247,7 +250,7 @@ namespace conf
LOG_SEVERITY get_loglevel_type(std::string_view severity);
void print_missing_field_error(std::string_view jpath, const std::exception &e);
void print_missing_field_error(std::string_view jpath, const std::exception &e, const bool is_patch_config = false);
int populate_patch_config();

View File

@@ -34,7 +34,7 @@ namespace consensus
int init()
{
refresh_roundtime(false);
refresh_time_config(false);
// Starting consensus processing thread.
ctx.consensus_thread = std::thread(run_consensus);
@@ -149,7 +149,7 @@ namespace consensus
ctx.unreliable_votes_attempts++;
if (ctx.unreliable_votes_attempts >= MAX_UNRELIABLE_VOTES_ATTEMPTS)
{
refresh_roundtime(true);
refresh_time_config(true);
ctx.unreliable_votes_attempts = 0;
}
}
@@ -378,7 +378,7 @@ namespace consensus
}
// Provide latest roundtime information to unl statistics.
unl::update_roundtime_stats(collected_proposals);
unl::update_time_config_stats(collected_proposals);
// Move collected propsals to candidate set of proposals.
for (const auto &p : collected_proposals)
@@ -571,15 +571,15 @@ namespace consensus
// If a node doesn't have enough time (eg. due to network delay) to recieve/send reliable stage proposals for next stage,
// it will join in next round. Otherwise it will continue particapating in this round.
if (to_wait < ctx.stage_reset_wait_threshold) //todo: self claculating/adjusting network delay
if (stage_start < now || to_wait < ctx.stage_reset_wait_threshold) //todo: self claculating/adjusting network delay
{
LOG_DEBUG << "Missed stage " << std::to_string(ctx.stage) << " window. Resetting to stage 0.";
ctx.stage = 1;
ctx.stage = 0;
return false;
}
else
{
LOG_DEBUG << "Waiting " << std::to_string(to_wait) << "ms for stage " << std::to_string(ctx.stage);
LOG_DEBUG << "Waiting " << to_wait << "ms for stage " << std::to_string(ctx.stage);
util::sleep(to_wait);
return true;
}
@@ -773,6 +773,7 @@ namespace consensus
p.patch_hash = patch_hash;
p.last_primary_shard_id = last_primary_shard_id;
p.last_raw_shard_id = last_raw_shard_id;
p.time_config = CURRENT_TIME_CONFIG;
crypto::random_bytes(p.nonce, ROUND_NONCE_SIZE);
// Populate the proposal with set of candidate user pubkeys.
@@ -802,6 +803,7 @@ namespace consensus
p.patch_hash = patch_hash;
p.last_primary_shard_id = last_primary_shard_id;
p.last_raw_shard_id = last_raw_shard_id;
p.time_config = CURRENT_TIME_CONFIG;
p.output_hash.resize(BLAKE3_OUT_LEN); // Default empty hash.
const uint64_t time_now = util::get_epoch_milliseconds();
@@ -1253,7 +1255,7 @@ namespace consensus
// Appling new patch file changes to hpcore runtime.
if (conf::apply_patch_config(HPFS_SESSION_NAME) == -1)
{
LOG_ERROR << "Appling patch file changes after consensus failed.";
LOG_ERROR << "Applying patch file changes after consensus failed.";
sc::contract_fs.stop_ro_session(HPFS_SESSION_NAME);
return -1;
}
@@ -1261,7 +1263,7 @@ namespace consensus
{
unl::update_unl_changes_from_patch();
// Refresh values in consensus context to match newly synced roundtime from patch file.
refresh_roundtime(false);
refresh_time_config(false);
is_patch_update_pending = false;
}
}
@@ -1273,26 +1275,28 @@ namespace consensus
}
/**
* Updates roundtime-based calculations with the latest roundtime value.
* @param perform_detection Whether or not to detect roundtime from latest network information.
* Updates roundtime-based calculations with the latest time config value.
* @param perform_detection Whether or not to detect time config from latest network information.
*/
void refresh_roundtime(const bool perform_detection)
void refresh_time_config(const bool perform_detection)
{
if (perform_detection)
{
LOG_DEBUG << "Detecting roundtime...";
const uint32_t majority_roundtime = unl::get_majority_roundtime();
LOG_DEBUG << "Detecting time config...";
const uint32_t majority_time_config = unl::get_majority_time_config();
if (majority_roundtime == 0 || conf::cfg.contract.roundtime == majority_roundtime)
if (majority_time_config == 0 || CURRENT_TIME_CONFIG == majority_time_config)
return;
LOG_INFO << "New roundtime detected:" << majority_roundtime << " previous:" << conf::cfg.contract.roundtime;
LOG_INFO << "New time config detected:" << majority_time_config << " previous:" << CURRENT_TIME_CONFIG;
conf::cfg.contract.roundtime = majority_roundtime;
// Time config is a single value derived from roundtime*100 + stage_slice. Here we derive back the original components.
conf::cfg.contract.roundtime = (majority_time_config / 100);
conf::cfg.contract.stage_slice = majority_time_config - (conf::cfg.contract.roundtime * 100);
}
// We allocate 1/4 of roundtime for each stage (0, 1, 2, 3).
ctx.stage_time = conf::cfg.contract.roundtime / 4;
// We allocate configured stage slice for stages 0, 1, 2. Stage 3 gets the entire remaining time from the round window.
ctx.stage_time = conf::cfg.contract.roundtime * conf::cfg.contract.stage_slice / 100;
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

View File

@@ -214,7 +214,7 @@ 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);
void refresh_time_config(const bool perform_detection);
} // namespace consensus

View File

@@ -27,7 +27,7 @@ table P2PMsg {
table PeerChallengeMsg {
contract_id:string;
roundtime:uint32;
time_config:uint32; // Contains unified value derived from (roundtime*100 + stage_slice)
is_full_history:bool;
challenge:[ubyte];
}
@@ -58,7 +58,7 @@ table ProposalMsg {
sig:[ubyte]; // Signature of the field data.
stage:uint8;
time:uint64;
roundtime:uint32;
time_config:uint32; // Contains unified value derived from (roundtime*100 + stage_slice)
nonce: [ubyte];
users:[ByteArray];
input_hashes:[ByteArray];

View File

@@ -70,7 +70,7 @@ namespace msg::fbuf::p2pmsg
flatbuf_hasher hasher;
hasher.add(msg.stage());
hasher.add(msg.time());
hasher.add(msg.roundtime());
hasher.add(msg.time_config());
hasher.add(msg.nonce());
hasher.add(msg.users());
hasher.add(msg.input_hashes());
@@ -110,7 +110,7 @@ namespace msg::fbuf::p2pmsg
const auto &msg = *mi.p2p_msg->content_as_PeerChallengeMsg();
return {
std::string(flatbuf_str_to_sv(msg.contract_id())),
msg.roundtime(),
msg.time_config(),
msg.is_full_history(),
std::string(flatbuf_bytes_to_sv(msg.challenge()))};
}
@@ -133,7 +133,7 @@ namespace msg::fbuf::p2pmsg
p.sent_timestamp = mi.originated_on;
p.recv_timestamp = util::get_epoch_milliseconds();
p.time = msg.time();
p.roundtime = msg.roundtime();
p.time_config = msg.time_config();
p.nonce = flatbuf_bytes_to_sv(msg.nonce());
p.stage = msg.stage();
p.state_hash = flatbuf_bytes_to_sv(msg.state_hash());
@@ -319,7 +319,7 @@ namespace msg::fbuf::p2pmsg
flatbuf_hasher hasher;
hasher.add(p.stage);
hasher.add(p.time);
hasher.add(p.roundtime);
hasher.add(p.time_config);
hasher.add(p.nonce);
hasher.add(p.users);
hasher.add(p.input_ordered_hashes);
@@ -361,7 +361,7 @@ namespace msg::fbuf::p2pmsg
const auto msg = CreatePeerChallengeMsg(
builder,
sv_to_flatbuf_str(builder, conf::cfg.contract.id),
conf::cfg.contract.roundtime,
CURRENT_TIME_CONFIG,
conf::cfg.node.history == conf::HISTORY::FULL,
sv_to_flatbuf_bytes(builder, challenge));
create_p2p_msg(builder, P2PMsgContent_PeerChallengeMsg, msg.Union());
@@ -396,7 +396,7 @@ namespace msg::fbuf::p2pmsg
sv_to_flatbuf_bytes(builder, generate_proposal_signature(p)),
p.stage,
p.time,
p.roundtime,
p.time_config,
sv_to_flatbuf_bytes(builder, p.nonce),
stringlist_to_flatbuf_bytearrayvector(builder, p.users),
stringlist_to_flatbuf_bytearrayvector(builder, p.input_ordered_hashes),

View File

@@ -543,7 +543,7 @@ struct PeerChallengeMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef PeerChallengeMsgBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_CONTRACT_ID = 4,
VT_ROUNDTIME = 6,
VT_TIME_CONFIG = 6,
VT_IS_FULL_HISTORY = 8,
VT_CHALLENGE = 10
};
@@ -553,11 +553,11 @@ struct PeerChallengeMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
flatbuffers::String *mutable_contract_id() {
return GetPointer<flatbuffers::String *>(VT_CONTRACT_ID);
}
uint32_t roundtime() const {
return GetField<uint32_t>(VT_ROUNDTIME, 0);
uint32_t time_config() const {
return GetField<uint32_t>(VT_TIME_CONFIG, 0);
}
bool mutate_roundtime(uint32_t _roundtime) {
return SetField<uint32_t>(VT_ROUNDTIME, _roundtime, 0);
bool mutate_time_config(uint32_t _time_config) {
return SetField<uint32_t>(VT_TIME_CONFIG, _time_config, 0);
}
bool is_full_history() const {
return GetField<uint8_t>(VT_IS_FULL_HISTORY, 0) != 0;
@@ -575,7 +575,7 @@ struct PeerChallengeMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
return VerifyTableStart(verifier) &&
VerifyOffset(verifier, VT_CONTRACT_ID) &&
verifier.VerifyString(contract_id()) &&
VerifyField<uint32_t>(verifier, VT_ROUNDTIME) &&
VerifyField<uint32_t>(verifier, VT_TIME_CONFIG) &&
VerifyField<uint8_t>(verifier, VT_IS_FULL_HISTORY) &&
VerifyOffset(verifier, VT_CHALLENGE) &&
verifier.VerifyVector(challenge()) &&
@@ -590,8 +590,8 @@ struct PeerChallengeMsgBuilder {
void add_contract_id(flatbuffers::Offset<flatbuffers::String> contract_id) {
fbb_.AddOffset(PeerChallengeMsg::VT_CONTRACT_ID, contract_id);
}
void add_roundtime(uint32_t roundtime) {
fbb_.AddElement<uint32_t>(PeerChallengeMsg::VT_ROUNDTIME, roundtime, 0);
void add_time_config(uint32_t time_config) {
fbb_.AddElement<uint32_t>(PeerChallengeMsg::VT_TIME_CONFIG, time_config, 0);
}
void add_is_full_history(bool is_full_history) {
fbb_.AddElement<uint8_t>(PeerChallengeMsg::VT_IS_FULL_HISTORY, static_cast<uint8_t>(is_full_history), 0);
@@ -614,12 +614,12 @@ struct PeerChallengeMsgBuilder {
inline flatbuffers::Offset<PeerChallengeMsg> CreatePeerChallengeMsg(
flatbuffers::FlatBufferBuilder &_fbb,
flatbuffers::Offset<flatbuffers::String> contract_id = 0,
uint32_t roundtime = 0,
uint32_t time_config = 0,
bool is_full_history = false,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> challenge = 0) {
PeerChallengeMsgBuilder builder_(_fbb);
builder_.add_challenge(challenge);
builder_.add_roundtime(roundtime);
builder_.add_time_config(time_config);
builder_.add_contract_id(contract_id);
builder_.add_is_full_history(is_full_history);
return builder_.Finish();
@@ -628,7 +628,7 @@ inline flatbuffers::Offset<PeerChallengeMsg> CreatePeerChallengeMsg(
inline flatbuffers::Offset<PeerChallengeMsg> CreatePeerChallengeMsgDirect(
flatbuffers::FlatBufferBuilder &_fbb,
const char *contract_id = nullptr,
uint32_t roundtime = 0,
uint32_t time_config = 0,
bool is_full_history = false,
const std::vector<uint8_t> *challenge = nullptr) {
auto contract_id__ = contract_id ? _fbb.CreateString(contract_id) : 0;
@@ -636,7 +636,7 @@ inline flatbuffers::Offset<PeerChallengeMsg> CreatePeerChallengeMsgDirect(
return msg::fbuf::p2pmsg::CreatePeerChallengeMsg(
_fbb,
contract_id__,
roundtime,
time_config,
is_full_history,
challenge__);
}
@@ -953,7 +953,7 @@ struct ProposalMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_SIG = 6,
VT_STAGE = 8,
VT_TIME = 10,
VT_ROUNDTIME = 12,
VT_TIME_CONFIG = 12,
VT_NONCE = 14,
VT_USERS = 16,
VT_INPUT_HASHES = 18,
@@ -988,11 +988,11 @@ struct ProposalMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool mutate_time(uint64_t _time) {
return SetField<uint64_t>(VT_TIME, _time, 0);
}
uint32_t roundtime() const {
return GetField<uint32_t>(VT_ROUNDTIME, 0);
uint32_t time_config() const {
return GetField<uint32_t>(VT_TIME_CONFIG, 0);
}
bool mutate_roundtime(uint32_t _roundtime) {
return SetField<uint32_t>(VT_ROUNDTIME, _roundtime, 0);
bool mutate_time_config(uint32_t _time_config) {
return SetField<uint32_t>(VT_TIME_CONFIG, _time_config, 0);
}
const flatbuffers::Vector<uint8_t> *nonce() const {
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_NONCE);
@@ -1056,7 +1056,7 @@ struct ProposalMsg FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
verifier.VerifyVector(sig()) &&
VerifyField<uint8_t>(verifier, VT_STAGE) &&
VerifyField<uint64_t>(verifier, VT_TIME) &&
VerifyField<uint32_t>(verifier, VT_ROUNDTIME) &&
VerifyField<uint32_t>(verifier, VT_TIME_CONFIG) &&
VerifyOffset(verifier, VT_NONCE) &&
verifier.VerifyVector(nonce()) &&
VerifyOffset(verifier, VT_USERS) &&
@@ -1097,8 +1097,8 @@ struct ProposalMsgBuilder {
void add_time(uint64_t time) {
fbb_.AddElement<uint64_t>(ProposalMsg::VT_TIME, time, 0);
}
void add_roundtime(uint32_t roundtime) {
fbb_.AddElement<uint32_t>(ProposalMsg::VT_ROUNDTIME, roundtime, 0);
void add_time_config(uint32_t time_config) {
fbb_.AddElement<uint32_t>(ProposalMsg::VT_TIME_CONFIG, time_config, 0);
}
void add_nonce(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> nonce) {
fbb_.AddOffset(ProposalMsg::VT_NONCE, nonce);
@@ -1145,7 +1145,7 @@ inline flatbuffers::Offset<ProposalMsg> CreateProposalMsg(
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> sig = 0,
uint8_t stage = 0,
uint64_t time = 0,
uint32_t roundtime = 0,
uint32_t time_config = 0,
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> nonce = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::p2pmsg::ByteArray>>> users = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<msg::fbuf::p2pmsg::ByteArray>>> input_hashes = 0,
@@ -1166,7 +1166,7 @@ inline flatbuffers::Offset<ProposalMsg> CreateProposalMsg(
builder_.add_input_hashes(input_hashes);
builder_.add_users(users);
builder_.add_nonce(nonce);
builder_.add_roundtime(roundtime);
builder_.add_time_config(time_config);
builder_.add_sig(sig);
builder_.add_pubkey(pubkey);
builder_.add_stage(stage);
@@ -1179,7 +1179,7 @@ inline flatbuffers::Offset<ProposalMsg> CreateProposalMsgDirect(
const std::vector<uint8_t> *sig = nullptr,
uint8_t stage = 0,
uint64_t time = 0,
uint32_t roundtime = 0,
uint32_t time_config = 0,
const std::vector<uint8_t> *nonce = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::p2pmsg::ByteArray>> *users = nullptr,
const std::vector<flatbuffers::Offset<msg::fbuf::p2pmsg::ByteArray>> *input_hashes = nullptr,
@@ -1204,7 +1204,7 @@ inline flatbuffers::Offset<ProposalMsg> CreateProposalMsgDirect(
sig__,
stage,
time,
roundtime,
time_config,
nonce__,
users__,
input_hashes__,

View File

@@ -72,7 +72,7 @@ namespace p2p
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.
uint32_t roundtime = 0; // Roundtime of the proposer.
uint32_t time_config = 0; // Time config of the proposer.
std::string nonce; // Random nonce that is used to reduce lcl predictability.
sequence_hash last_primary_shard_id;
sequence_hash last_raw_shard_id;
@@ -92,7 +92,7 @@ namespace p2p
struct peer_challenge
{
std::string contract_id;
uint32_t roundtime = 0;
uint32_t time_config = 0; // Contains unified value derived from (roundtime*100 + stage_slice)
bool is_full_history = false;
std::string challenge;
};

View File

@@ -25,7 +25,7 @@ namespace p2p
std::optional<conf::peer_ip_port> 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.
uint32_t reported_roundtime = 0; // Initial roundtime reported by this peer on peer challenge.
uint32_t reported_time_config = 0; // Initial time config reported by this peer on peer challenge.
bool is_full_history; // Stores whether the connection is to a full history node or not.
};

View File

@@ -122,8 +122,8 @@ namespace p2p
return -1;
}
// Remember the roundtime reported by this peer.
session.reported_roundtime = chall.roundtime;
// Remember the time config reported by this peer.
session.reported_time_config = chall.time_config;
// Whether this node is a full history node or not.
session.is_full_history = chall.is_full_history;

View File

@@ -20,7 +20,7 @@ namespace sc
else
{
unl::update_unl_changes_from_patch();
consensus::refresh_roundtime(false);
consensus::refresh_time_config(false);
// Update global hash tracker with the new patch file hash.
fs_mount->set_parent_hash(synced_target.vpath, synced_target.hash);

View File

@@ -9,7 +9,7 @@
*/
namespace unl
{
std::map<std::string, uint32_t> list; // List of binary pubkeys of UNL and their latest reported roundtime.
std::map<std::string, uint32_t> list; // List of binary pubkeys of UNL and their latest reported time configs.
std::string json_list; // Stringified json array of UNL. (To be fed into the contract args)
std::shared_mutex unl_mutex;
@@ -38,7 +38,7 @@ namespace unl
{
std::shared_lock lock(unl_mutex);
std::set<std::string> ret;
for (auto [pubkey, roundtime] : list)
for (auto [pubkey, time_config] : list)
ret.emplace(std::move(pubkey));
return ret;
}
@@ -81,9 +81,9 @@ namespace unl
}
/**
* Updates unl pubkey-roundtime information using the specified list of proposals.
* Updates unl pubkey-->time config information using the specified list of proposals.
*/
void update_roundtime_stats(const std::list<p2p::proposal> &proposals)
void update_time_config_stats(const std::list<p2p::proposal> &proposals)
{
std::unique_lock lock(unl_mutex);
@@ -91,53 +91,53 @@ namespace unl
{
const auto itr = list.find(p.pubkey);
if (itr != list.end())
itr->second = p.roundtime;
itr->second = p.time_config;
}
}
/**
* Returns the majority roundtime reported among the unl.
* Returns the majority time config reported among the unl.
*/
uint32_t get_majority_roundtime()
uint32_t get_majority_time_config()
{
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<uint32_t, uint32_t> roundtime_votes;
// Vote and find majority time config within the unl using values extracted from incoming proposals.
// Fill any 0 time configs with information from peer connections.
std::map<uint32_t, uint32_t> time_config_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 time config 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;
itr->second = peer_itr->second->reported_time_config;
}
const uint32_t roundtime = itr->second;
if (roundtime > 0)
roundtime_votes[roundtime]++;
const uint32_t time_config = itr->second;
if (time_config > 0)
time_config_votes[time_config]++;
}
}
// Find the majority vote.
uint32_t highest_votes = 0;
uint32_t majority_roundtime = 0;
for (const auto [roundtime, num_votes] : roundtime_votes)
uint32_t majority_time_config = 0;
for (const auto [time_config, num_votes] : time_config_votes)
{
if (num_votes > highest_votes)
{
highest_votes = num_votes;
majority_roundtime = roundtime;
majority_time_config = time_config;
}
}
return majority_roundtime;
return majority_time_config;
}
/**

View File

@@ -17,8 +17,8 @@ namespace unl
bool exists(const std::string &bin_pubkey);
int init();
void update_unl_changes_from_patch();
void update_roundtime_stats(const std::list<p2p::proposal> &proposals);
uint32_t get_majority_roundtime();
void update_time_config_stats(const std::list<p2p::proposal> &proposals);
uint32_t get_majority_time_config();
bool update_unl_list(const std::set<std::string> &new_list);
const std::string prepare_json_list(const std::set<std::string> &new_list);