Config patch change detection. (#211)

* Applying patch file changes to hpcore runtime after patch file change detection.
* Removing unl sync functionality.
* Removing subjecting unl changeset to consensus.
This commit is contained in:
Savinda Senevirathne
2021-01-06 20:02:14 +05:30
committed by GitHub
parent c87ae6693d
commit bed8205ca8
22 changed files with 90 additions and 1033 deletions

View File

@@ -113,7 +113,6 @@ namespace consensus
const uint64_t lcl_seq_no = ledger::ctx.get_seq_no();
util::h32 state_hash = hpfs::ctx.get_hash(hpfs::HPFS_PARENT_COMPONENTS::STATE);
util::h32 patch_hash = hpfs::ctx.get_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH);
std::string unl_hash = unl::get_hash();
if (ctx.stage == 0)
{
@@ -122,7 +121,7 @@ namespace consensus
if (verify_and_populate_candidate_user_inputs(lcl_seq_no) == -1)
return -1;
const p2p::proposal p = create_stage0_proposal(lcl, state_hash, patch_hash, unl_hash);
const p2p::proposal p = create_stage0_proposal(lcl, state_hash, patch_hash);
broadcast_proposal(p);
ctx.stage = 1; // Transition to next stage.
@@ -133,12 +132,12 @@ namespace consensus
const size_t unl_count = unl::count();
vote_counter votes;
const int sync_status = check_sync_status(lcl, unl_hash, unl_count, votes);
const int sync_status = check_sync_status(lcl, unl_count, votes);
if (sync_status == 0)
{
// If we are in sync, vote and broadcast the winning votes to next stage.
const p2p::proposal p = create_stage123_proposal(votes, lcl, unl_count, state_hash, patch_hash, unl_hash);
const p2p::proposal p = create_stage123_proposal(votes, lcl, unl_count, state_hash, patch_hash);
broadcast_proposal(p);
// Upon successful consensus at stage 3, update the ledger and execute the contract using the consensus proposal.
@@ -167,9 +166,9 @@ namespace consensus
/**
* Checks whether we are in sync with the received votes.
* @return 0 if we are in sync. -1 on lcl, hpfs or unl desync. -2 if majority lcl unreliable.
* @return 0 if we are in sync. -1 on lcl or hpfs desync. -2 if majority lcl unreliable.
*/
int check_sync_status(std::string_view lcl, std::string_view unl_hash, const size_t unl_count, vote_counter &votes)
int check_sync_status(std::string_view lcl, const size_t unl_count, vote_counter &votes)
{
// Check if we're ahead/behind of consensus lcl.
bool is_lcl_desync = false;
@@ -200,19 +199,8 @@ namespace consensus
hpfs_sync::set_target(majority_state_hash, majority_patch_hash);
}
// Check unl hash with the majority unl hash.
bool is_unl_desync = false;
std::string majority_unl;
check_unl_votes(is_unl_desync, majority_unl, votes, unl_hash);
// Start unl sync if we are out-of-sync with majority unl.
if (is_unl_desync)
{
conf::change_role(conf::ROLE::OBSERVER);
unl::set_sync_target(majority_unl);
}
// Proceed further only if both lcl and state are in sync with majority.
if (!is_lcl_desync && !is_state_desync && !is_patch_desync && !is_unl_desync)
if (!is_lcl_desync && !is_state_desync && !is_patch_desync)
{
conf::change_role(conf::ROLE::VALIDATOR);
return 0;
@@ -232,7 +220,7 @@ namespace consensus
*/
void check_sync_completion()
{
if (conf::cfg.node.role == conf::ROLE::OBSERVER && !hpfs_sync::ctx.is_syncing && !ledger::sync_ctx.is_syncing && !unl::sync_ctx.is_syncing)
if (conf::cfg.node.role == conf::ROLE::OBSERVER && !hpfs_sync::ctx.is_syncing && !ledger::sync_ctx.is_syncing)
conf::change_role(conf::ROLE::VALIDATOR);
}
@@ -535,7 +523,7 @@ namespace consensus
return 0;
}
p2p::proposal create_stage0_proposal(std::string_view lcl, util::h32 state_hash, util::h32 patch_hash, std::string_view unl_hash)
p2p::proposal create_stage0_proposal(std::string_view lcl, util::h32 state_hash, util::h32 patch_hash)
{
// This is the proposal that stage 0 votes on.
// We report our own values in stage 0.
@@ -545,7 +533,6 @@ namespace consensus
p.lcl = lcl;
p.state_hash = state_hash;
p.patch_hash = patch_hash;
p.unl_hash = unl_hash;
crypto::random_bytes(p.nonce, ROUND_NONCE_SIZE);
// Populate the proposal with set of candidate user pubkeys.
@@ -559,13 +546,10 @@ namespace consensus
p.output_hash = ctx.user_outputs_hashtree.root_hash();
p.output_sig = ctx.user_outputs_our_sig;
// Populate the proposal with unl changeset.
p.unl_changeset = ctx.candidate_unl_changeset;
return p;
}
p2p::proposal create_stage123_proposal(vote_counter &votes, std::string_view lcl, const size_t unl_count, const util::h32 state_hash, const util::h32 patch_hash, std::string_view unl_hash)
p2p::proposal create_stage123_proposal(vote_counter &votes, std::string_view lcl, const size_t unl_count, const util::h32 state_hash, const util::h32 patch_hash)
{
// The proposal to be emited at the end of this stage.
p2p::proposal p;
@@ -574,13 +558,10 @@ namespace consensus
p.patch_hash = patch_hash;
// We always vote for our current lcl and state regardless of what other peers are saying.
// If there's a fork condition we will either request history and state from
// If there's a fork condition we will either request history and hpfs state from
// our peers or we will halt depending on level of consensus on the sides of the fork.
p.lcl = lcl;
// We always vote for our current unl hash.
p.unl_hash = unl_hash;
const uint64_t time_now = util::get_epoch_milliseconds();
// Vote for rest of the proposal fields by looking at candidate proposals.
@@ -605,16 +586,6 @@ namespace consensus
// Vote for contract output hash.
increment(votes.output_hash, cp.output_hash);
// Vote for unl additions. Only vote for the unl additions that are in our candidate_unl_changeset.
for (const std::string &pubkey : cp.unl_changeset.additions)
if (ctx.candidate_unl_changeset.additions.count(pubkey) > 0)
increment(votes.unl_additions, pubkey);
// Vote for unl removals. Only vote for the unl removals that are in our candidate_unl_changeset.
for (const std::string &pubkey : cp.unl_changeset.removals)
if (ctx.candidate_unl_changeset.removals.count(pubkey) > 0)
increment(votes.unl_removals, pubkey);
}
uint32_t required_votes = ceil(STAGE_THRESHOLDS[ctx.stage - 1] * unl_count);
@@ -634,19 +605,9 @@ namespace consensus
if (numvotes >= required_votes || (ctx.stage == 1 && numvotes > 0))
p.input_hashes.emplace(hash);
// For the unl changeset, reset required votes for majority votes.
// Reset required votes for majority votes.
required_votes = ceil(MAJORITY_THRESHOLD * unl_count);
// Add unl additions which have votes over majority threshold to proposal.
for (const auto &[pubkey, numvotes] : votes.unl_additions)
if (numvotes >= required_votes)
p.unl_changeset.additions.emplace(pubkey);
// Add unl removals which have votes over majority threshold to proposal.
for (const auto &[pubkey, numvotes] : votes.unl_removals)
if (numvotes >= required_votes)
p.unl_changeset.removals.emplace(pubkey);
// Add the output hash which has most votes over stage threshold to proposal.
uint32_t highest_output_vote = 0;
for (const auto &[hash, numvotes] : votes.output_hash)
@@ -820,33 +781,6 @@ namespace consensus
is_patch_desync = (hpfs::ctx.get_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH) != majority_patch_hash);
}
/**
* Check unl against the winning and canonical unl
* @param is_desync Is unl is in desync.
* @param majority_unl The majority unl.
* @param votes The voting table.
* @param unl_hash Hash of the current unl list.
*/
void check_unl_votes(bool &is_desync, std::string &majority_unl, vote_counter &votes, std::string_view unl_hash)
{
for (const auto &[pubkey, cp] : ctx.candidate_proposals)
{
increment(votes.unl, cp.unl_hash);
}
uint32_t winning_votes = 0;
for (const auto [unl, votes] : votes.unl)
{
if (votes > winning_votes)
{
winning_votes = votes;
majority_unl = unl;
}
}
is_desync = (unl_hash != majority_unl);
}
/**
* Update the ledger and execute the contract after consensus.
* @param cons_prop The proposal that reached consensus.
@@ -897,10 +831,6 @@ namespace consensus
}
}
// Update the unl with the unl changeset that subjected to the consensus.
unl::apply_changeset(cons_prop.unl_changeset.additions, cons_prop.unl_changeset.removals);
ctx.candidate_unl_changeset.clear();
// Send any output from the previous consensus round to locally connected users.
if (dispatch_user_outputs(cons_prop, new_lcl_seq_no, new_lcl) == -1)
return -1;
@@ -945,10 +875,6 @@ namespace consensus
ctx.user_outputs_our_sig = crypto::sign(ctx.user_outputs_hashtree.root_hash(), conf::cfg.node.private_key);
}
// Prepare the consensus candidate unl changeset that we have accumulated so far. (We receive them as control inputs)
// The candidate unl changeset will be included in the stage 0 proposal.
std::swap(ctx.candidate_unl_changeset, ctx.contract_ctx->args.unl_changeset);
{
std::scoped_lock lock(ctx.contract_ctx_mutex);
ctx.contract_ctx.reset();