mirror of
https://github.com/EvernodeXRPL/hpcore.git
synced 2026-04-29 15:37:59 +00:00
Added stage slice config to control stage time allocation. (#310)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
|
||||
35
src/conf.cpp
35
src/conf.cpp
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
31
src/conf.hpp
31
src/conf.hpp
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace consensus
|
||||
|
||||
int apply_consensed_patch_file_changes(const util::h32 &prop_patch_hash, const util::h32 ¤t_patch_hash);
|
||||
|
||||
void refresh_roundtime(const bool perform_detection);
|
||||
void refresh_time_config(const bool perform_detection);
|
||||
|
||||
} // namespace consensus
|
||||
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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__,
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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.
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
38
src/unl.cpp
38
src/unl.cpp
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user