diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 44038b97..cda41654 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,8 +8,9 @@ include: stages: - build - test + - dockerize -build: +build-mainnet: stage: build script: - rm -rf .git/modules/docs .git/modules/libraries/fc ./docs ./libraries/fc @@ -29,10 +30,10 @@ build: tags: - builder -test: +test-mainnet: stage: test dependencies: - - build + - build-mainnet script: - ./build/libraries/fc/tests/all_tests - ./build/tests/betting_test --log_level=message @@ -41,16 +42,20 @@ test: tags: - builder -dockerize: - stage: build +dockerize-mainnet: + stage: dockerize + dependencies: + - test-mainnet variables: - IMAGE: $CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA + IMAGE: $CI_REGISTRY_IMAGE/mainnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA before_script: - docker info - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - - docker build -t $IMAGE . + - docker build --no-cache -t $IMAGE . - docker push $IMAGE + after_script: + - docker rmi $IMAGE tags: - builder when: @@ -97,3 +102,24 @@ test-testnet: manual timeout: 1h + +dockerize-testnet: + stage: dockerize + dependencies: + - test-testnet + variables: + IMAGE: $CI_REGISTRY_IMAGE/testnet/$CI_COMMIT_REF_SLUG:$CI_COMMIT_SHA + before_script: + - docker info + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + script: + - docker build --no-cache -t $IMAGE . + - docker push $IMAGE + after_script: + - docker rmi $IMAGE + tags: + - builder + when: + manual + timeout: + 3h diff --git a/Dockerfile b/Dockerfile index e90e5380..7a76c136 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,7 +23,6 @@ RUN \ libbz2-dev \ libcurl4-openssl-dev \ libncurses-dev \ - libreadline-dev \ libsnappy-dev \ libssl-dev \ libtool \ diff --git a/Dockerfile.18.04 b/Dockerfile.18.04 index 5e928263..d3fa1d75 100644 --- a/Dockerfile.18.04 +++ b/Dockerfile.18.04 @@ -21,7 +21,6 @@ RUN \ libbz2-dev \ libcurl4-openssl-dev \ libncurses-dev \ - libreadline-dev \ libsnappy-dev \ libssl-dev \ libtool \ diff --git a/README.md b/README.md index 12949dd5..a8d98021 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Following dependencies are needed for a clean install of Ubuntu 20.04: sudo apt-get install \ apt-utils autoconf bash build-essential ca-certificates clang-format cmake \ dnsutils doxygen expect git graphviz libboost-all-dev libbz2-dev \ - libcurl4-openssl-dev libncurses-dev libreadline-dev libsnappy-dev \ + libcurl4-openssl-dev libncurses-dev libsnappy-dev \ libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \ openssh-server pkg-config perl python3 python3-jinja2 sudo \ systemd-coredump wget @@ -74,11 +74,12 @@ sudo make install # this can install the executable files under /usr/local Following dependencies are needed for a clean install of Ubuntu 18.04: ``` sudo apt-get install \ - apt-utils autoconf bash build-essential ca-certificates dnsutils doxygen \ - expect git graphviz libbz2-dev libcurl4-openssl-dev libncurses-dev \ - libreadline-dev libsnappy-dev libssl-dev libtool libzip-dev locales \ - lsb-release mc nano net-tools ntp openssh-server pkg-config perl \ - python3 python3-jinja2 sudo systemd-coredump wget + apt-utils autoconf bash build-essential ca-certificates clang-format \ + dnsutils doxygen expect git graphviz libbz2-dev \ + libcurl4-openssl-dev libncurses-dev libsnappy-dev \ + libssl-dev libtool libzip-dev locales lsb-release mc nano net-tools ntp \ + openssh-server pkg-config perl python3 python3-jinja2 sudo \ + systemd-coredump wget ``` Install Boost libraries from source diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 56878eaf..afae81a7 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -107,6 +108,7 @@ public: fc::optional _lock_file; bool _is_block_producer = false; bool _force_validate = false; + std::atomic_bool _running{true}; void reset_p2p_node(const fc::path &data_dir) { try { @@ -115,67 +117,29 @@ public: _p2p_network->load_configuration(data_dir / "p2p"); _p2p_network->set_node_delegate(this); + vector all_seeds; + if (_options->count("seed-node")) { auto seeds = _options->at("seed-node").as>(); - for (const string &endpoint_string : seeds) { - try { - std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); - for (const fc::ip::endpoint &endpoint : endpoints) { - ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); - _p2p_network->add_node(endpoint); - _p2p_network->connect_to_endpoint(endpoint); - } - } catch (const fc::exception &e) { - wlog("caught exception ${e} while adding seed node ${endpoint}", - ("e", e.to_detail_string())("endpoint", endpoint_string)); - } - } + all_seeds.insert(all_seeds.end(), seeds.begin(), seeds.end()); } if (_options->count("seed-nodes")) { auto seeds_str = _options->at("seed-nodes").as(); auto seeds = fc::json::from_string(seeds_str).as>(2); - for (const string &endpoint_string : seeds) { - try { - std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); - for (const fc::ip::endpoint &endpoint : endpoints) { - ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); - _p2p_network->add_node(endpoint); - } - } catch (const fc::exception &e) { - wlog("caught exception ${e} while adding seed node ${endpoint}", - ("e", e.to_detail_string())("endpoint", endpoint_string)); - } - } - } else { - // t.me/peerplays #seednodes - vector seeds = { -#ifdef BUILD_PEERPLAYS_TESTNET + all_seeds.insert(all_seeds.end(), seeds.begin(), seeds.end()); + } -#else - "51.222.110.110:9777", - "95.216.90.243:9777", - "96.46.48.98:19777", - "96.46.48.98:29777", - "96.46.48.98:39777", - "96.46.48.98:49777", - "96.46.48.98:59777", - "seed.i9networks.net.br:9777", - "witness.serverpit.com:9777" -#endif - }; - - for (const string &endpoint_string : seeds) { - try { - std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); - for (const fc::ip::endpoint &endpoint : endpoints) { - ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); - _p2p_network->add_node(endpoint); - } - } catch (const fc::exception &e) { - wlog("caught exception ${e} while adding seed node ${endpoint}", - ("e", e.to_detail_string())("endpoint", endpoint_string)); + for (const string &endpoint_string : all_seeds) { + try { + std::vector endpoints = resolve_string_to_ip_endpoints(endpoint_string); + for (const fc::ip::endpoint &endpoint : endpoints) { + ilog("Adding seed node ${endpoint}", ("endpoint", endpoint)); + _p2p_network->add_node(endpoint); } + } catch (const fc::exception &e) { + wlog("caught exception ${e} while adding seed node ${endpoint}", + ("e", e.to_detail_string())("endpoint", endpoint_string)); } } @@ -450,6 +414,12 @@ public: */ virtual bool handle_block(const graphene::net::block_message &blk_msg, bool sync_mode, std::vector &contained_transaction_message_ids) override { + + // check point for the threads which may be cancled on application shutdown + if (!_running.load()) { + return true; + } + try { auto latency = fc::time_point::now() - blk_msg.block.timestamp; FC_ASSERT((latency.count() / 1000) > -5000, "Rejecting block with timestamp in the future"); @@ -864,9 +834,24 @@ application::~application() { void application::set_program_options(boost::program_options::options_description &cli, boost::program_options::options_description &cfg) const { + + std::vector seed_nodes = { +#ifdef BUILD_PEERPLAYS_TESTNET +#else + "51.222.110.110:9777", + "95.216.90.243:9777", + "ca.peerplays.info:9777", + "de.peerplays.xyz:9777", + "pl.peerplays.org:9777", + "seed.i9networks.net.br:9777", + "witness.serverpit.com:9777" +#endif + }; + std::string seed_nodes_str = fc::json::to_string(seed_nodes); + cfg.add_options()("p2p-endpoint", bpo::value()->default_value("0.0.0.0:9777"), "Endpoint for P2P node to listen on"); cfg.add_options()("seed-node,s", bpo::value>()->composing(), "P2P nodes to connect to on startup (may specify multiple times)"); - cfg.add_options()("seed-nodes", bpo::value()->composing(), "JSON array of P2P nodes to connect to on startup"); + cfg.add_options()("seed-nodes", bpo::value()->composing()->default_value(seed_nodes_str), "JSON array of P2P nodes to connect to on startup"); cfg.add_options()("checkpoint,c", bpo::value>()->composing(), "Pairs of [BLOCK_NUM,BLOCK_ID] that should be enforced as checkpoints."); cfg.add_options()("rpc-endpoint", bpo::value()->default_value("127.0.0.1:8090"), "Endpoint for websocket RPC to listen on"); cfg.add_options()("rpc-tls-endpoint", bpo::value()->implicit_value("127.0.0.1:8089"), "Endpoint for TLS websocket RPC to listen on"); @@ -1012,6 +997,7 @@ void application::shutdown_plugins() { return; } void application::shutdown() { + my->_running.store(false); if (my->_p2p_network) my->_p2p_network->close(); if (my->_chain_db) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index a9ea9774..1095bbeb 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -29,12 +29,15 @@ #include #include +#include + #include #include #include #include +#include #include #include #include @@ -90,6 +93,7 @@ public: processed_transaction get_transaction(uint32_t block_num, uint32_t trx_in_block) const; // Globals + version_info get_version_info() const; chain_property_object get_chain_properties() const; global_property_object get_global_properties() const; fc::variant_object get_config() const; @@ -563,6 +567,27 @@ processed_transaction database_api_impl::get_transaction(uint32_t block_num, uin // // ////////////////////////////////////////////////////////////////////// +version_info database_api::get_version_info() const { + return my->get_version_info(); +} + +version_info database_api_impl::get_version_info() const { + + std::string witness_version(graphene::utilities::git_revision_description); + const size_t pos = witness_version.find('/'); + if (pos != std::string::npos && witness_version.size() > pos) + witness_version = witness_version.substr(pos + 1); + + version_info vi; + vi.version = witness_version; + vi.git_revision = graphene::utilities::git_revision_sha; + vi.built = std::string(__DATE__) + " at " + std::string(__TIME__); + vi.openssl = OPENSSL_VERSION_TEXT; + vi.boost = boost::replace_all_copy(std::string(BOOST_LIB_VERSION), "_", "."); + + return vi; +} + chain_property_object database_api::get_chain_properties() const { return my->get_chain_properties(); } diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 93a2b88c..679d8a4c 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -130,6 +130,14 @@ struct gpos_info { share_type account_vested_balance; }; +struct version_info { + string version; + string git_revision; + string built; + string openssl; + string boost; +}; + /** * @brief The database_api class implements the RPC API for the chain database. * @@ -218,6 +226,11 @@ public: // Globals // ///////////// + /** + * @brief Retrieve the @ref version_info associated with the witness node + */ + version_info get_version_info() const; + /** * @brief Retrieve the @ref chain_property_object associated with the chain */ @@ -1040,6 +1053,7 @@ FC_REFLECT(graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highe FC_REFLECT(graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume)); FC_REFLECT(graphene::app::market_trade, (date)(price)(amount)(value)); FC_REFLECT(graphene::app::gpos_info, (vesting_factor)(award)(total_amount)(current_subperiod)(last_voted_time)(allowed_withdraw_amount)(account_vested_balance)); +FC_REFLECT(graphene::app::version_info, (version)(git_revision)(built)(openssl)(boost)); FC_API(graphene::app::database_api, // Objects @@ -1060,6 +1074,7 @@ FC_API(graphene::app::database_api, (get_recent_transaction_by_id) // Globals + (get_version_info) (get_chain_properties) (get_global_properties) (get_config) diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index aa199c84..3026c2f0 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -62,11 +62,14 @@ void verify_account_votes( const database& db, const account_options& options ) const auto& gpo = db.get_global_properties(); const auto& chain_params = gpo.parameters; + FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." ); + FC_ASSERT( options.num_witness <= chain_params.maximum_witness_count, "Voted for more witnesses than currently allowed (${c})", ("c", chain_params.maximum_witness_count) ); FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count, "Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) ); - FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." ); + FC_ASSERT( options.num_son() <= chain_params.maximum_son_count(), + "Voted for more sons than currently allowed (${c})", ("c", chain_params.maximum_son_count()) ); uint32_t max_vote_id = gpo.next_available_vote_id; bool has_worker_votes = false; diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 6c58e58b..c475813b 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -433,7 +433,12 @@ processed_transaction database::push_proposal(const proposal_object& proposal) { for( size_t i=old_applied_ops_size,n=_applied_ops.size(); iresult = result; else { diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 56ac6fd0..c3f826d1 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -182,7 +182,26 @@ void database::pay_sons() const dynamic_global_property_object& dpo = get_dynamic_global_properties(); // Current requirement is that we have to pay every 24 hours, so the following check if( dpo.son_budget.value > 0 && ((now - dpo.last_son_payout_time) >= fc::seconds(get_global_properties().parameters.son_pay_time()))) { - auto sons = sort_votable_objects(get_global_properties().parameters.maximum_son_count()); + assert( _son_count_histogram_buffer.size() > 0 ); + const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2; + /// accounts that vote for 0 or 1 son do not get to express an opinion on + /// the number of sons to have (they abstain and are non-voting accounts) + share_type stake_tally = 0; + size_t son_count = 0; + if( stake_target > 0 ) + { + while( (son_count < _son_count_histogram_buffer.size() - 1) + && (stake_tally <= stake_target) ) + { + stake_tally += _son_count_histogram_buffer[++son_count]; + } + } + const vector> sons = [this, &son_count]{ + if(head_block_time() >= HARDFORK_SON3_TIME) + return sort_votable_objects(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)); + else + return sort_votable_objects(get_global_properties().parameters.maximum_son_count()); + }(); // After SON2 HF uint64_t total_votes = 0; for( const son_object& son : sons ) @@ -660,6 +679,10 @@ void database::update_active_committee_members() void database::update_active_sons() { try { + if (head_block_time() < HARDFORK_SON_TIME) { + return; + } + assert( _son_count_histogram_buffer.size() > 0 ); share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2; @@ -679,8 +702,12 @@ void database::update_active_sons() } const global_property_object& gpo = get_global_properties(); - const chain_parameters& cp = gpo.parameters; - auto sons = sort_votable_objects(cp.maximum_son_count()); + const vector> sons = [this, &son_count]{ + if(head_block_time() >= HARDFORK_SON3_TIME) + return sort_votable_objects(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)); + else + return sort_votable_objects(get_global_properties().parameters.maximum_son_count()); + }(); const auto& all_sons = get_index_type().indices(); @@ -759,11 +786,7 @@ void database::update_active_sons() } } - if (son_sets_equal) { - ilog( "Active SONs set NOT CHANGED" ); - } else { - ilog( "Active SONs set CHANGED" ); - + if (!son_sets_equal) { update_son_wallet(new_active_sons); update_son_statuses(cur_active_sons, new_active_sons); } @@ -2041,6 +2064,13 @@ void update_son_params(database& db) gpo.parameters.extensions.value.maximum_son_count = 7; }); } + else + { + const auto& gpo = db.get_global_properties(); + db.modify( gpo, []( global_property_object& gpo ) { + gpo.parameters.extensions.value.maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; + }); + } } void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) @@ -2167,9 +2197,9 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // same rationale as for witnesses d._committee_count_histogram_buffer[offset] += voting_stake; } - if( opinion_account.options.num_son <= props.parameters.maximum_son_count() ) + if( opinion_account.options.num_son() <= props.parameters.maximum_son_count() ) { - uint16_t offset = std::min(size_t(opinion_account.options.num_son/2), + uint16_t offset = std::min(size_t(opinion_account.options.num_son()/2), d._son_count_histogram_buffer.size() - 1); // votes for a number greater than maximum_son_count // are turned into votes for maximum_son_count. @@ -2271,6 +2301,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // the following parameters are not allowed to be changed. So take what is in global property p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; + p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count; p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset; p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account; p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start; diff --git a/libraries/chain/hardfork.d/SON3.hf b/libraries/chain/hardfork.d/SON3.hf index 36347c09..d9556e30 100644 --- a/libraries/chain/hardfork.d/SON3.hf +++ b/libraries/chain/hardfork.d/SON3.hf @@ -1,7 +1,7 @@ #ifndef HARDFORK_SON3_TIME #ifdef BUILD_PEERPLAYS_TESTNET -#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-05-31T00:00:00")) +#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00")) #else -#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-05-31T00:00:00")) +#define HARDFORK_SON3_TIME (fc::time_point_sec::from_iso_string("2022-07-16T00:00:00")) #endif #endif diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 0f95a6e3..53bdec08 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -131,6 +131,7 @@ namespace graphene { namespace chain { }} FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object), + (random) (head_block_number) (head_block_id) (time) diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp index 50ccb8ae..c6de2047 100644 --- a/libraries/chain/include/graphene/chain/protocol/account.hpp +++ b/libraries/chain/include/graphene/chain/protocol/account.hpp @@ -37,6 +37,11 @@ namespace graphene { namespace chain { /// These are the fields which can be updated by the active authority. struct account_options { + struct ext + { + optional< uint16_t > num_son = 0; + }; + /// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non- /// validated account activities. This field is here to prevent confusion if the active authority has zero or /// multiple keys in it. @@ -54,11 +59,11 @@ namespace graphene { namespace chain { uint16_t num_committee = 0; /// The number of active son members this account votes the blockchain should appoint /// Must not exceed the actual number of son members voted for in @ref votes - uint16_t num_son = 0; + uint16_t num_son() const { return extensions.value.num_son.valid() ? *extensions.value.num_son : 0; } /// This is the list of vote IDs this account votes for. The weight of these votes is determined by this /// account's balance of core asset. flat_set votes; - extensions_type extensions; + extension< ext > extensions; /// Whether this account is voting inline bool is_voting() const @@ -289,6 +294,7 @@ namespace graphene { namespace chain { } } // graphene::chain +FC_REFLECT(graphene::chain::account_options::ext, (num_son) ) FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions)) // FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing) FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing, diff --git a/libraries/chain/protocol/account.cpp b/libraries/chain/protocol/account.cpp index 2405369a..b980998c 100644 --- a/libraries/chain/protocol/account.cpp +++ b/libraries/chain/protocol/account.cpp @@ -174,7 +174,7 @@ void account_options::validate() const { auto needed_witnesses = num_witness; auto needed_committee = num_committee; - auto needed_sons = num_son; + auto needed_sons = num_son(); for( vote_id_type id : votes ) if( id.type() == vote_id_type::witness && needed_witnesses ) diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index d0524d00..c6bef00f 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -92,6 +92,7 @@ #define DEFAULT_LOGGER "p2p" #define P2P_IN_DEDICATED_THREAD 1 +#define DISABLE_WITNESS_HF_CHECK 1 #define INVOCATION_COUNTER(name) \ static unsigned total_ ## name ## _counter = 0; \ @@ -894,7 +895,7 @@ namespace graphene { namespace net { namespace detail { void node_impl::p2p_network_connect_loop() { VERIFY_CORRECT_THREAD(); - while (!_p2p_network_connect_loop_done.canceled()) + while (!_p2p_network_connect_loop_done.canceled() && !_node_is_shutting_down) { try { @@ -1338,7 +1339,7 @@ namespace graphene { namespace net { namespace detail { // reconnect with the rest of the network, or it might just futher isolate us. { // As usual, the first step is to walk through all our peers and figure out which - // peers need action (disconnecting, sending keepalives, etc), then we walk through + // peers need action (disconnecting, sending keepalives, etc), then we walk through // those lists yielding at our leisure later. ASSERT_TASK_NOT_PREEMPTED(); @@ -1900,8 +1901,15 @@ namespace graphene { namespace net { namespace detail { originating_peer->last_known_fork_block_number = user_data["last_known_fork_block_number"].as(1); if (user_data.contains("last_known_hardfork_time")){ originating_peer->last_known_hardfork_time = fc::time_point_sec(user_data["last_known_hardfork_time"].as(1)); + }else{ + // this state is invalid when node which wants to connect doesn't provide + // last hardfork time. We are setting to 0 which will disconnect the node + // on hello message + originating_peer->last_known_hardfork_time = fc::time_point_sec(0); + if(DISABLE_WITNESS_HF_CHECK) { + originating_peer->last_known_hardfork_time = _delegate->get_last_known_hardfork_time(); + } } - } void node_impl::on_hello_message( peer_connection* originating_peer, const hello_message& hello_message_received ) @@ -2023,7 +2031,8 @@ namespace graphene { namespace net { namespace detail { // indetify if peer's are not compatible due the hardforks if ( originating_peer->last_known_hardfork_time < _delegate->get_last_known_hardfork_time()) { - if (_delegate->get_block_time(_delegate->get_head_block_id()).sec_since_epoch() >= _delegate->get_last_known_hardfork_time().sec_since_epoch()) + if ((_delegate->get_block_time(_delegate->get_head_block_id()).sec_since_epoch() >= _delegate->get_last_known_hardfork_time().sec_since_epoch()) + || originating_peer->last_known_hardfork_time.sec_since_epoch() == 0) { std::ostringstream rejection_message; rejection_message << "Your client is outdated -- you can only understand blocks up to #" << originating_peer->last_known_hardfork_time.to_iso_string() << ", but I'm already on block #" << _delegate->get_block_time(_delegate->get_head_block_id()).to_iso_string(); @@ -4042,6 +4051,8 @@ namespace graphene { namespace net { namespace detail { { VERIFY_CORRECT_THREAD(); + _node_is_shutting_down = true; + try { _potential_peer_db.close(); diff --git a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp index 9c067e0e..6fd1fcfa 100644 --- a/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp +++ b/libraries/plugins/peerplays_sidechain/include/graphene/peerplays_sidechain/sidechain_net_handler_bitcoin.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -90,7 +91,9 @@ private: class zmq_listener { public: zmq_listener(std::string _ip, uint32_t _zmq); + virtual ~zmq_listener(); + void start(); boost::signals2::signal event_received; private: @@ -102,6 +105,9 @@ private: zmq::context_t ctx; zmq::socket_t socket; + + std::atomic_bool stopped; + std::thread thr; }; // ============================================================================= diff --git a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp index a9e59307..6203ff79 100644 --- a/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp +++ b/libraries/plugins/peerplays_sidechain/sidechain_net_handler_bitcoin.cpp @@ -1,7 +1,6 @@ #include #include -#include #include #include @@ -1060,8 +1059,31 @@ zmq_listener::zmq_listener(std::string _ip, uint32_t _zmq) : ip(_ip), zmq_port(_zmq), ctx(1), - socket(ctx, ZMQ_SUB) { - std::thread(&zmq_listener::handle_zmq, this).detach(); + socket(ctx, ZMQ_SUB), + stopped(false) { +} + +void zmq_listener::start() { + int linger = 0; + auto rc = zmq_setsockopt(socket, ZMQ_SUBSCRIBE, "hashblock", 9); + FC_ASSERT(0 == rc); + rc = zmq_setsockopt(socket, ZMQ_LINGER, &linger, sizeof(linger)); + FC_ASSERT(0 == rc); + int timeout = 100; //millisec + rc = zmq_setsockopt(socket, ZMQ_RCVTIMEO, &timeout, sizeof(timeout)); + //socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 ); + //socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 ); + //socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 ); + socket.connect("tcp://" + ip + ":" + std::to_string(zmq_port)); + + thr = std::thread(&zmq_listener::handle_zmq, this); + + ilog("zmq_listener thread started"); +} + +zmq_listener::~zmq_listener() { + stopped = true; + thr.join(); } std::vector zmq_listener::receive_multipart() { @@ -1078,26 +1100,25 @@ std::vector zmq_listener::receive_multipart() { } void zmq_listener::handle_zmq() { - int linger = 0; - auto rc = zmq_setsockopt(socket, ZMQ_SUBSCRIBE, "hashblock", 9); - FC_ASSERT(0 == rc); - rc = zmq_setsockopt(socket, ZMQ_LINGER, &linger, sizeof(linger)); - FC_ASSERT(0 == rc); - //socket.setsockopt( ZMQ_SUBSCRIBE, "hashtx", 6 ); - //socket.setsockopt( ZMQ_SUBSCRIBE, "rawblock", 8 ); - //socket.setsockopt( ZMQ_SUBSCRIBE, "rawtx", 5 ); - socket.connect("tcp://" + ip + ":" + std::to_string(zmq_port)); - - while (true) { + while (false == stopped) { try { - auto msg = receive_multipart(); - const auto header = std::string(static_cast(msg[0].data()), msg[0].size()); - const auto block_hash = boost::algorithm::hex(std::string(static_cast(msg[1].data()), msg[1].size())); - event_received(block_hash); + std::vector msg; + auto res = zmq::recv_multipart(socket, std::back_inserter(msg)); + if (res.has_value()) { + if (3 != *res) { + elog("zmq::recv_multipart returned: ${res}", ("res", *res)); + throw zmq::error_t(); + } + const auto header = std::string(static_cast(msg[0].data()), msg[0].size()); + const auto block_hash = boost::algorithm::hex(std::string(static_cast(msg[1].data()), msg[1].size())); + event_received(block_hash); + } } catch (zmq::error_t &e) { elog("handle_zmq recv_multipart exception ${str}", ("str", e.what())); } } + + ilog("zmq_listener thread finished"); } // ============================================================================= @@ -1173,6 +1194,7 @@ sidechain_net_handler_bitcoin::sidechain_net_handler_bitcoin(peerplays_sidechain ilog("Bitcoin major version is: '${version}'", ("version", bitcoin_major_version)); listener = std::unique_ptr(new zmq_listener(ip, zmq_port)); + listener->start(); listener->event_received.connect([this](const std::string &event_data) { std::thread(&sidechain_net_handler_bitcoin::handle_event, this, event_data).detach(); }); diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index d2fac215..35b9ab1c 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2158,8 +2158,8 @@ public: return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (owner_account)(url)(block_signing_key)(broadcast) ) } - signed_transaction activate_deregistered_son(const string & owner_account, - bool broadcast /* = false */) + signed_transaction activate_deregistered_son(const string & owner_account, + bool broadcast /* = false */) { try { son_object son = get_son(owner_account); @@ -2408,7 +2408,7 @@ public: op.sidechain = sidechain; op.peerplays_uid = peerplays_uid; op.peerplays_transaction_id = peerplays_transaction_id; - op.peerplays_from = peerplays_from; + op.peerplays_from = peerplays_from; op.peerplays_asset = asset(asset_val.amount * asset_price.base.amount / asset_price.quote.amount); op.withdraw_sidechain = withdraw_sidechain; op.withdraw_address = withdraw_address; @@ -2875,7 +2875,7 @@ public: if (!votes_removed) FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son)); } - voting_account_object.options.num_son = desired_number_of_sons; + voting_account_object.options.extensions.value.num_son = desired_number_of_sons; account_update_operation account_update_op; account_update_op.account = voting_account_object.id; @@ -5410,7 +5410,7 @@ signed_transaction wallet_api::sidechain_withdrawal_transaction(const string &so const string &withdraw_amount) { return my->sidechain_withdrawal_transaction(son_name_or_id, - block_num, + block_num, sidechain, peerplays_uid, peerplays_transaction_id, @@ -5540,7 +5540,7 @@ signed_transaction wallet_api::sidechain_deposit_transaction( const string &son const string &peerplays_from_name_or_id, const string &peerplays_to_name_or_id) { - return my->sidechain_deposit_transaction(son_name_or_id, + return my->sidechain_deposit_transaction(son_name_or_id, sidechain, transaction_id, operation_index, diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index af5086b2..c5eea447 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -79,18 +79,12 @@ int main(int argc, char** argv) { node->set_program_options(cli, cfg); cfg_options.add(cfg); - cfg_options.add_options() - ("plugins", bpo::value()->default_value("witness account_history market_history accounts_list affiliate_stats bookie"), - "Space-separated list of plugins to activate"); - auto witness_plug = node->register_plugin(); auto debug_witness_plug = node->register_plugin(); auto history_plug = node->register_plugin(); auto elasticsearch_plug = node->register_plugin(); auto es_objects_plug = node->register_plugin(); auto market_history_plug = node->register_plugin(); - //auto generate_genesis_plug = node->register_plugin(); - //auto generate_uia_sharedrop_genesis_plug = node->register_plugin(); auto list_plug = node->register_plugin(); auto affiliate_stats_plug = node->register_plugin(); auto bookie_plug = node->register_plugin(); diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 491ec8f9..1f09de9f 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -337,7 +337,8 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) global_property_object gpo; gpo = con.wallet_api_ptr->get_global_properties(); - unsigned int son_number = gpo.parameters.maximum_son_count(); + //! Set son number as 5 (as the begining son count) + unsigned int son_number = 5; flat_map sidechain_public_keys; @@ -400,7 +401,7 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); BOOST_CHECK(generate_maintenance_block()); - BOOST_CHECK(gpo.active_sons.size() == gpo.parameters.maximum_son_count()); + BOOST_CHECK(gpo.active_sons.size() == son_number); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -644,7 +645,8 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) global_property_object gpo; gpo = con.wallet_api_ptr->get_global_properties(); - unsigned int son_number = gpo.parameters.maximum_son_count(); + //! Set son number as 5 (as the begining son count) + unsigned int son_number = 5; flat_map sidechain_public_keys; diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index a802aac5..4fb3a24d 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -1040,16 +1040,13 @@ BOOST_FIXTURE_TEST_CASE( hardfork_son2_time, database_fixture ) generate_blocks(HARDFORK_SON3_TIME); // after this hardfork maximum son account should not reset the value - // on 7 after maintenance interval anymore. So change the global parameters - // and check the value after maintenance interval - db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.extensions.value.maximum_son_count = 13; - }); + // on 7 after maintenance interval anymore. It must be GRAPHENE_DEFAULT_MAX_SONS + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), GRAPHENE_DEFAULT_MAX_SONS); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 13); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 15); } FC_LOG_AND_RETHROW() }