From 8cf869cf9e6c22d6dff366b0dde172cf618a8f7f Mon Sep 17 00:00:00 2001 From: Ravin Perera <33562092+ravinsp@users.noreply.github.com> Date: Fri, 17 Jan 2020 11:04:45 +0530 Subject: [PATCH] Observer mode fix (#78) * Fixed observer mode consensus issues. * Added startup_mode to fix mode change check. --- src/conf.cpp | 46 +++++++++++++++++++++++----------------------- src/conf.hpp | 8 ++++---- src/cons/cons.cpp | 26 ++++++++++++++------------ src/main.cpp | 2 +- 4 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/conf.cpp b/src/conf.cpp index 6461c012..0a37737a 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -14,8 +14,8 @@ contract_ctx ctx; // Global configuration struct exposed to the application. contract_config cfg; -const static char *MODE_OBSERVING = "observing"; -const static char *MODE_PROPOSING = "proposing"; +const static char *MODE_OBSERVER = "observer"; +const static char *MODE_PROPOSER = "proposer"; /** * Loads and initializes the contract config for execution. Must be called once during application startup. @@ -31,16 +31,13 @@ int init() if (validate_contract_dir_paths() != 0 || load_config() != 0 || validate_config() != 0) return -1; - if (cfg.mode == OPERATING_MODE::PROPOSING) - { - // Append self peer to peer list. - const std::string portstr = std::to_string(cfg.peerport); - const std::string peerid = "0.0.0.0:" + portstr; - cfg.peers.emplace(std::move(peerid), std::make_pair("0.0.0.0", portstr)); + // Append self peer to peer list. + const std::string portstr = std::to_string(cfg.peerport); + const std::string peerid = "0.0.0.0:" + portstr; + cfg.peers.emplace(std::move(peerid), std::make_pair("0.0.0.0", portstr)); - // Append self pubkey to unl list. - cfg.unl.emplace(cfg.pubkey); - } + // Append self pubkey to unl list. + cfg.unl.emplace(cfg.pubkey); return 0; } @@ -91,7 +88,7 @@ int create_contract() crypto::generate_signing_keys(cfg.pubkey, cfg.seckey); binpair_to_hex(); - cfg.mode = OPERATING_MODE::PROPOSING; + cfg.startup_mode = OPERATING_MODE::PROPOSER; cfg.listenip = "0.0.0.0"; cfg.peerport = 22860; cfg.roundtime = 1000; @@ -202,15 +199,16 @@ int load_config() // Load up the values into the struct. - if (d["mode"] == MODE_OBSERVING) - cfg.mode = OPERATING_MODE::OBSERVING; - else if (d["mode"] == MODE_PROPOSING) - cfg.mode = OPERATING_MODE::PROPOSING; + if (d["mode"] == MODE_OBSERVER) + cfg.startup_mode = OPERATING_MODE::OBSERVER; + else if (d["mode"] == MODE_PROPOSER) + cfg.startup_mode = OPERATING_MODE::PROPOSER; else { - std::cout << "Invalid mode. 'observing' or 'proposing' expected.\n"; + std::cout << "Invalid mode. 'observer' or 'proposer' expected.\n"; return -1; } + cfg.current_mode = cfg.startup_mode; cfg.pubkeyhex = d["pubkeyhex"].GetString(); cfg.seckeyhex = d["seckeyhex"].GetString(); @@ -221,18 +219,16 @@ int load_config() cfg.appbill = d["appbill"].GetString(); cfg.appbillargs = d["appbillargs"].GetString(); - // Populate runtime contract execution args. if (!cfg.binargs.empty()) boost::split(cfg.runtime_binexec_args, cfg.binargs, boost::is_any_of(" ")); - cfg.runtime_binexec_args.insert(cfg.runtime_binexec_args.begin(), ( cfg.binary[0] == '/' ? cfg.binary : util::realpath( ctx.contract_dir + "/bin/" + cfg.binary ) ) ); + cfg.runtime_binexec_args.insert(cfg.runtime_binexec_args.begin(), (cfg.binary[0] == '/' ? cfg.binary : util::realpath(ctx.contract_dir + "/bin/" + cfg.binary))); - // Populate runtime app bill args. if (!cfg.appbillargs.empty()) boost::split(cfg.runtime_appbill_args, cfg.appbillargs, boost::is_any_of(" ")); - cfg.runtime_appbill_args.insert(cfg.runtime_appbill_args.begin(), ( cfg.appbill[0] == '/' ? cfg.appbill : util::realpath( ctx.contract_dir + "/bin/" + cfg.appbill ) ) ); + cfg.runtime_appbill_args.insert(cfg.runtime_appbill_args.begin(), (cfg.appbill[0] == '/' ? cfg.appbill : util::realpath(ctx.contract_dir + "/bin/" + cfg.appbill))); // Uncomment for docker-based execution. // std::string volumearg; @@ -314,7 +310,7 @@ int save_config() d.SetObject(); rapidjson::Document::AllocatorType &allocator = d.GetAllocator(); d.AddMember("version", rapidjson::StringRef(util::HP_VERSION), allocator); - d.AddMember("mode", rapidjson::StringRef(cfg.mode == OPERATING_MODE::OBSERVING ? MODE_OBSERVING : MODE_PROPOSING), + d.AddMember("mode", rapidjson::StringRef(cfg.startup_mode == OPERATING_MODE::OBSERVER ? MODE_OBSERVER : MODE_PROPOSER), allocator); d.AddMember("pubkeyhex", rapidjson::StringRef(cfg.pubkeyhex.data()), allocator); @@ -611,7 +607,11 @@ int is_schema_valid(const rapidjson::Document &d) void change_operating_mode(const OPERATING_MODE mode) { - cfg.mode = mode; + // Do not allow to change the mode if the node was started as an observer. + if (cfg.startup_mode == OPERATING_MODE::OBSERVER) + return; + + cfg.current_mode = mode; } } // namespace conf diff --git a/src/conf.hpp b/src/conf.hpp index 4b164b54..1e90ea72 100644 --- a/src/conf.hpp +++ b/src/conf.hpp @@ -16,8 +16,8 @@ typedef std::pair ip_port_pair; // The operating mode of the contract node. enum OPERATING_MODE { - OBSERVING = 0, // Observer mode. Only emits NUPs. Does not participate in voting. - PROPOSING = 1 // Consensus participant mode. + OBSERVER = 0, // Observer mode. Only emits NUPs. Does not participate in voting. + PROPOSER = 1 // Consensus participant mode. }; // Holds contextual information about the currently loaded contract. @@ -47,11 +47,11 @@ struct contract_config std::string seckey; // Contract secret key bytes std::vector runtime_binexec_args; // Contract binary execution args used during runtime. std::vector runtime_appbill_args; // Appbill execution args used during runtime. - + OPERATING_MODE current_mode; // Current operating mode of the contract (Observer/Proposer) // Config elements which are loaded from the config file. - OPERATING_MODE mode; // Operating mode of the contract (Observing/Proposing). + OPERATING_MODE startup_mode; // Configured startup operating mode of the contract (Observer/Proposer). std::string pubkeyhex; // Contract hex public key std::string seckeyhex; // Contract hex secret key std::string binary; // Full path to the contract binary diff --git a/src/cons/cons.cpp b/src/cons/cons.cpp index 43804667..7193e44f 100644 --- a/src/cons/cons.cpp +++ b/src/cons/cons.cpp @@ -132,6 +132,7 @@ void consensus() // In stage 0 we create a novel proposal and broadcast it. const p2p::proposal stg_prop = create_stage0_proposal(); + broadcast_proposal(stg_prop); } else // Stage 1, 2, 3 @@ -205,8 +206,8 @@ void consensus() } else { - //Node is in sync with current lcl ->switch to proposing mode. - conf::change_operating_mode(conf::OPERATING_MODE::PROPOSING); + //Node is in sync with current lcl ->switch to proposer mode. + conf::change_operating_mode(conf::OPERATING_MODE::PROPOSER); } if (ctx.stage == 1 || (ctx.stage == 3 && ctx.is_state_syncing)) @@ -216,6 +217,7 @@ void consensus() { // In stage 1, 2, 3 we vote for incoming proposals and promote winning votes based on thresholds. const p2p::proposal stg_prop = create_stage123_proposal(votes); + broadcast_proposal(stg_prop); if (ctx.stage == 3) @@ -586,8 +588,8 @@ p2p::proposal create_stage123_proposal(vote_counter &votes) */ void broadcast_proposal(const p2p::proposal &p) { - // In observing mode, we do not send out any proposals. - if (conf::cfg.mode == conf::OPERATING_MODE::OBSERVING) + // In observer mode, we do not send out any proposals. + if (conf::cfg.current_mode == conf::OPERATING_MODE::OBSERVER) return; p2p::peer_outbound_message msg(std::make_shared(1024)); @@ -658,11 +660,11 @@ void check_lcl_votes(bool &is_desync, bool &should_request_history, std::string if (total_lcl_votes < (MAJORITY_THRESHOLD * conf::cfg.unl.size())) { - LOG_DBG << "Not enough peers proposing to perform consensus votes:" << std::to_string(total_lcl_votes) << " needed:" << std::to_string(MAJORITY_THRESHOLD * conf::cfg.unl.size()); + LOG_DBG << "Not enough peers proposer to perform consensus votes:" << std::to_string(total_lcl_votes) << " needed:" << std::to_string(MAJORITY_THRESHOLD * conf::cfg.unl.size()); is_desync = true; - //Not enough nodes are propsing. So Node is switching to Proposing if it's in observing mode. - conf::change_operating_mode(conf::OPERATING_MODE::PROPOSING); + //Not enough nodes are propsing. So Node is switching to Proposer if it's in observer mode. + conf::change_operating_mode(conf::OPERATING_MODE::PROPOSER); return; } @@ -685,8 +687,8 @@ void check_lcl_votes(bool &is_desync, bool &should_request_history, std::string LOG_DBG << "We are not on the consensus ledger, requesting history from a random peer"; is_desync = true; - //Node is in not sync with current lcl ->switch to observing mode. - conf::change_operating_mode(conf::OPERATING_MODE::OBSERVING); + //Node is not in sync with current lcl ->switch to observer mode. + conf::change_operating_mode(conf::OPERATING_MODE::OBSERVER); should_request_history = true; return; @@ -896,8 +898,8 @@ void check_state(vote_counter &votes) { if (ctx.state_sync_lcl != ctx.lcl) { - // Change the mode to passive and not sending out proposals till the state is synced - conf::change_operating_mode(conf::OPERATING_MODE::OBSERVING); + // Switch to observer mode to avoid sending out proposals till the state is synced + conf::change_operating_mode(conf::OPERATING_MODE::OBSERVER); const hasher::B2H majority_state_hash = *reinterpret_cast(majority_state.c_str()); LOG_INFO << "Starting state sync. Curr state:" << *reinterpret_cast(ctx.curr_hash_state.c_str()) << " majority:" << majority_state_hash; @@ -914,7 +916,7 @@ void check_state(vote_counter &votes) ctx.is_state_syncing = false; ctx.state_sync_lcl.clear(); - conf::change_operating_mode(conf::OPERATING_MODE::PROPOSING); + conf::change_operating_mode(conf::OPERATING_MODE::PROPOSER); } } diff --git a/src/main.cpp b/src/main.cpp index 949cb7a1..90878572 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -181,7 +181,7 @@ int main(int argc, char **argv) hplog::init(); LOG_INFO << "Operating mode: " - << (conf::cfg.mode == conf::OPERATING_MODE::OBSERVING ? "Observing" : "Proposing"); + << (conf::cfg.startup_mode == conf::OPERATING_MODE::OBSERVER ? "Observer" : "Proposer"); statefs::init(conf::ctx.state_hist_dir);