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

@@ -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