#ifndef _HP_CONS_ #define _HP_CONS_ #include "pchheader.hpp" #include "util/util.hpp" #include "util/buffer_store.hpp" #include "util/merkle_hash_tree.hpp" #include "./sc/sc.hpp" #include "p2p/p2p.hpp" #include "usr/user_input.hpp" #include "util/h32.hpp" namespace consensus { /** * Represents a contract input that takes part in consensus. */ struct candidate_user_input { const std::string userpubkey; const uint64_t maxledgerseqno = 0; const util::buffer_view input; candidate_user_input(const std::string userpubkey, const util::buffer_view input, const uint64_t maxledgerseqno) : userpubkey(std::move(userpubkey)), input(input), maxledgerseqno(maxledgerseqno) { } }; /** * Represents a contract-generated user output that takes part in consensus. */ struct generated_user_output { const std::string userpubkey; std::list outputs; generated_user_output(const std::string userpubkey, const std::list outputs) : userpubkey(std::move(userpubkey)), outputs(std::move(outputs)) { } }; /** * This is used to store consensus information */ struct consensus_context { // The map of proposals that are being collected as consensus stages are progressing. // peer public key is the key. // todo: having a queue of proposals against peer pubkey. std::unordered_map candidate_proposals; // Set of user pubkeys that is said to be connected to the cluster. This will be cleared in each round. std::set candidate_users; // Map of candidate user inputs with input hash as map key. Inputs will stay here until they // achieve consensus or expire (due to maxledgerseqno). Input hash is globally unique among inputs // from all users. We will use this map to feed inputs into the contract once consensus is achieved. std::map candidate_user_inputs; // Map of outputs generated by the contract with output hash as the map key. Outputs will stay // here until the end of the current consensus round. Output hash is globally unique among outputs for // all users. We will use this map to distribute outputs back to connected users once consensus is achieved. std::map generated_user_outputs; util::merkle_hash_tree user_outputs_hashtree; std::string user_outputs_our_sig; std::vector> user_outputs_unl_sig; uint8_t stage = 1; uint64_t round_start_time = 0; uint16_t stage_time = 0; // Time allocated to a consensus stage. uint16_t stage_reset_wait_threshold = 0; // Minimum stage wait time to reset the stage. uint64_t round_boundry_offset = 0; // Time window boundry offset based on contract id. uint16_t unreliable_votes_attempts = 0; // No. of times we failed to get reliable votes continously. std::optional contract_ctx; std::mutex contract_ctx_mutex; bool is_shutting_down = false; std::thread consensus_thread; consensus_context() : user_outputs_hashtree(16) { } }; struct vote_counter { std::map time; std::map nonce; std::map lcl; std::map users; std::map inputs; std::map output_hash; 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(); void deinit(); void wait(); void run_consensus(); int consensus(); int check_sync_status(std::string_view lcl, const size_t unl_count, vote_counter &votes); void check_sync_completion(); void revise_candidate_proposals(); bool wait_and_proceed_stage(); void broadcast_nonunl_proposal(); bool push_npl_message(p2p::npl_message &npl_message); int verify_and_populate_candidate_user_inputs(const uint64_t lcl_seq_no); p2p::proposal create_stage0_proposal(std::string_view lcl, util::h32 state_hash, util::h32 patch_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); void broadcast_proposal(const p2p::proposal &p); 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); uint64_t get_ledger_time_resolution(const uint64_t time); uint64_t get_stage_time_resolution(const uint64_t time); 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); int feed_user_inputs_to_contract_bufmap(sc::contract_bufmap_t &bufmap, const p2p::proposal &cons_prop); void extract_user_outputs_from_contract_bufmap(sc::contract_bufmap_t &bufmap); template void increment(std::map &counter, const T &candidate); int get_initial_state_hash(util::h32 &hash); 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); void refresh_roundtime(const bool perform_detection); } // namespace consensus #endif