diff --git a/src/consensus.cpp b/src/consensus.cpp index 0af574aa..4250898e 100644 --- a/src/consensus.cpp +++ b/src/consensus.cpp @@ -25,9 +25,11 @@ namespace consensus constexpr float STAGE_THRESHOLDS[] = {0.5, 0.65, 0.8}; // Voting thresholds for stage 1,2,3 constexpr float MAJORITY_THRESHOLD = 0.8; constexpr size_t ROUND_NONCE_SIZE = 64; + constexpr const char *HPFS_SESSION_NAME = "ro_patch_file_to_hp"; consensus_context ctx; bool init_success = false; + std::atomic 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() { @@ -141,7 +143,7 @@ namespace consensus broadcast_proposal(p); // Upon successful consensus at stage 3, update the ledger and execute the contract using the consensus proposal. - if (ctx.stage == 3 && update_ledger_and_execute_contract(p, lcl, state_hash) == -1) + if (ctx.stage == 3 && update_ledger_and_execute_contract(p, lcl, state_hash, patch_hash) == -1) LOG_ERROR << "Error occured in Stage 3 consensus execution."; } @@ -192,6 +194,11 @@ namespace consensus check_patch_votes(is_patch_desync, majority_patch_hash, votes); check_state_votes(is_state_desync, majority_state_hash, votes); + // Stop any patch file updates triggered from the sc. The sync is triggered because the changes + // done by the contract is not meeting consensus. + if (is_patch_desync) + is_patch_update_pending = false; + // Start hpfs sync if we are out-of-sync with majority hpfs state. if (is_state_desync || is_patch_desync) { @@ -784,8 +791,10 @@ namespace consensus /** * Update the ledger and execute the contract after consensus. * @param cons_prop The proposal that reached consensus. + * @param new_state_hash The state hash. + * @param patch_hash The patch hash. */ - int update_ledger_and_execute_contract(const p2p::proposal &cons_prop, std::string &new_lcl, util::h32 &new_state_hash) + int update_ledger_and_execute_contract(const p2p::proposal &cons_prop, std::string &new_lcl, util::h32 &new_state_hash, const util::h32 &patch_hash) { // Map to temporarily store the raw inputs along with the hash. std::unordered_map raw_inputs; @@ -819,6 +828,10 @@ namespace consensus LOG_INFO << "****Ledger created**** (lcl:" << new_lcl.substr(0, 15) << " state:" << cons_prop.state_hash << " patch:" << cons_prop.patch_hash << ")"; + // Apply consensed patch file changes to the hpcore runtime and hp.cfg. + if (apply_consensed_patch_file_changes(cons_prop.patch_hash, patch_hash) == -1) + return -1; + // After the current ledger seq no is updated, we remove any newly expired inputs from candidate set. { auto itr = ctx.candidate_user_inputs.begin(); @@ -1019,4 +1032,37 @@ namespace consensus counter.try_emplace(candidate, 1); } + /** + * Apply patch file changes after verification from consensus. + * @param prop_patch_hash Hash of patch file which reached consensus. + * @param current_patch_hash Hash of the current patch file. + * @return 0 on success. -1 on failure. + */ + int apply_consensed_patch_file_changes(const util::h32 &prop_patch_hash, const util::h32 ¤t_patch_hash) + { + // Check whether is there any patch changes to be applied which reached consensus. + if (is_patch_update_pending && current_patch_hash == prop_patch_hash) + { + if (hpfs::start_ro_session(HPFS_SESSION_NAME, false) != -1) + { + // 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."; + hpfs::stop_ro_session(HPFS_SESSION_NAME); + return -1; + } + else + { + unl::update_unl_changes_from_patch(); + is_patch_update_pending = false; + } + } + + if (hpfs::stop_ro_session(HPFS_SESSION_NAME) == -1) + return -1; + } + return 0; + } + } // namespace consensus diff --git a/src/consensus.hpp b/src/consensus.hpp index ec96b211..68a45f57 100644 --- a/src/consensus.hpp +++ b/src/consensus.hpp @@ -95,6 +95,7 @@ namespace consensus std::map state_hash; std::map patch_hash; }; + extern std::atomic is_patch_update_pending; // Keep track whether the patch file is changed by the SC and is not yet applied to runtime. int init(); @@ -129,7 +130,7 @@ namespace consensus bool check_lcl_votes(bool &is_desync, std::string &majority_lcl, vote_counter &votes, std::string_view lcl, const size_t unl_count); void check_state_votes(bool &is_state_desync, util::h32 &majority_state_hash, vote_counter &votes); - + void check_patch_votes(bool &is_patch_desync, util::h32 &majority_patch_hash, vote_counter &votes); void timewait_stage(const bool reset, const uint64_t time); @@ -138,7 +139,7 @@ namespace consensus uint64_t get_stage_time_resolution(const uint64_t time); - int update_ledger_and_execute_contract(const p2p::proposal &proposal, std::string &new_lcl, util::h32 &new_state_hash); + int update_ledger_and_execute_contract(const p2p::proposal &cons_prop, std::string &new_lcl, util::h32 &new_state_hash, const util::h32 &patch_hash); int dispatch_user_outputs(const p2p::proposal &cons_prop, const uint64_t lcl_seq_no, std::string_view lcl); @@ -153,6 +154,8 @@ namespace consensus bool push_control_message(const std::string &control_msg); + int apply_consensed_patch_file_changes(const util::h32 &prop_patch_hash, const util::h32 ¤t_patch_hash); + } // namespace consensus #endif diff --git a/src/sc.cpp b/src/sc.cpp index eeeffa1c..11edc536 100644 --- a/src/sc.cpp +++ b/src/sc.cpp @@ -180,6 +180,7 @@ namespace sc util::h32 patch_hash; const int patch_hash_result = hpfs::get_hash(patch_hash, ctx.args.hpfs_session_name, hpfs::PATCH_FILE_PATH); + if (patch_hash_result == -1) { hpfs::release_rw_session(); @@ -187,17 +188,10 @@ namespace sc } else if (patch_hash_result == 1 && patch_hash != hpfs::ctx.get_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH)) { - // Appling new patch file changes to hpcore runtime. - if (conf::apply_patch_config(ctx.args.hpfs_session_name) == -1) - { - LOG_ERROR << "Appling patch file after contract execution failed"; - } - else - { - // Update global hash tracker with the new patch file hash. - hpfs::ctx.set_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH, patch_hash); - unl::update_unl_changes_from_patch(); - } + // Update global hash tracker with the new patch file hash. + hpfs::ctx.set_hash(hpfs::HPFS_PARENT_COMPONENTS::PATCH, patch_hash); + // Denote that the patch file was updated by the SC. + consensus::is_patch_update_pending = true; } return hpfs::release_rw_session();