From daf7ac5da808afb2b497b4df6b6ad579317c5817 Mon Sep 17 00:00:00 2001 From: satyakoneru Date: Fri, 7 Feb 2020 16:49:16 +1100 Subject: [PATCH] SON214 - Request maintenance wallet commands (#280) --- libraries/chain/db_maint.cpp | 14 +++++++++++-- .../include/graphene/chain/son_object.hpp | 3 ++- libraries/chain/son_evaluator.cpp | 20 +++++++++++-------- .../peerplays_sidechain_plugin.cpp | 3 ++- .../wallet/include/graphene/wallet/wallet.hpp | 2 ++ libraries/wallet/wallet.cpp | 3 +-- tests/cli/son.cpp | 20 +++++++++++++++++-- tests/tests/son_operations_tests.cpp | 8 +++++++- 8 files changed, 56 insertions(+), 17 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 935e520e..157e28c0 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -414,10 +414,20 @@ void database::update_active_sons() const auto& all_sons = get_index_type().indices(); + auto& local_vote_buffer_ref = _vote_tally_buffer; for( const son_object& son : all_sons ) { - modify( son, [&]( son_object& obj ){ - obj.total_votes = _vote_tally_buffer[son.vote_id]; + if(son.status == son_status::request_maintenance) + { + auto& stats = son.statistics(*this); + modify( stats, [&]( son_statistics_object& _s){ + _s.last_down_timestamp = head_block_time(); + }); + } + modify( son, [local_vote_buffer_ref]( son_object& obj ){ + obj.total_votes = local_vote_buffer_ref[obj.vote_id]; + if(obj.status == son_status::request_maintenance) + obj.status = son_status::in_maintenance; }); } diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index 5ce45242..7a73a312 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -11,6 +11,7 @@ namespace graphene { namespace chain { { inactive, active, + request_maintenance, in_maintenance, deregistered }; @@ -94,7 +95,7 @@ namespace graphene { namespace chain { using son_stats_index = generic_index; } } // graphene::chain -FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(in_maintenance)(deregistered) ) +FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(request_maintenance)(in_maintenance)(deregistered) ) FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object), (son_account)(vote_id)(total_votes)(url)(deposit)(signing_key)(pay_vb)(statistics)(status)(sidechain_public_keys) ) diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 79660921..bcdda1ba 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -105,11 +105,11 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation& auto itr = idx.find(op.son_id); auto stats = itr->statistics( db() ); // Inactive SONs need not send heartbeats - FC_ASSERT(itr->status == son_status::active || itr->status == son_status::in_maintenance, "Inactive SONs need not send heartbeats"); + FC_ASSERT((itr->status == son_status::active) || (itr->status == son_status::in_maintenance) || (itr->status == son_status::request_maintenance), "Inactive SONs need not send heartbeats"); // Account for network delays fc::time_point_sec min_ts = db().head_block_time() - fc::seconds(5 * db().block_interval()); // Account for server ntp sync difference - fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(2 * db().block_interval()); + fc::time_point_sec max_ts = db().head_block_time() + fc::seconds(5 * db().block_interval()); FC_ASSERT(op.ts > stats.last_active_timestamp, "Heartbeat sent without waiting minimum time"); FC_ASSERT(op.ts > stats.last_down_timestamp, "Heartbeat sent is invalid can't be <= last down timestamp"); FC_ASSERT(op.ts >= min_ts, "Heartbeat ts is behind the min threshold"); @@ -153,7 +153,7 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& so.status = son_status::inactive; } }); - } else if (itr->status == son_status::active) { + } else if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) { db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) { sso.last_active_timestamp = op.ts; @@ -171,7 +171,7 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati FC_ASSERT( idx.find(op.son_id) != idx.end() ); auto itr = idx.find(op.son_id); auto stats = itr->statistics( db() ); - FC_ASSERT(itr->status == son_status::active, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down"); + FC_ASSERT(itr->status == son_status::active || itr->status == son_status::request_maintenance, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down"); FC_ASSERT(op.down_ts >= stats.last_active_timestamp, "down_ts should be greater than last_active_timestamp"); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -182,7 +182,7 @@ object_id_type son_report_down_evaluator::do_apply(const son_report_down_operati auto itr = idx.find(op.son_id); if(itr != idx.end()) { - if (itr->status == son_status::active) { + if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) { db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) { sso.last_down_timestamp = op.down_ts; @@ -203,8 +203,8 @@ void_result son_maintenance_evaluator::do_evaluate(const son_maintenance_operati const auto& idx = db().get_index_type().indices().get(); auto itr = idx.find(op.son_id); FC_ASSERT( itr != idx.end() ); - // Inactive SONs can't go to maintenance - FC_ASSERT(itr->status == son_status::active || itr->status == son_status::in_maintenance, "Inactive SONs can't go to maintenance"); + // Inactive SONs can't go to maintenance, toggle between active and request_maintenance states + FC_ASSERT(itr->status == son_status::active || itr->status == son_status::request_maintenance, "Inactive SONs can't go to maintenance"); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -216,7 +216,11 @@ object_id_type son_maintenance_evaluator::do_apply(const son_maintenance_operati { if(itr->status == son_status::active) { db().modify(*itr, [](son_object &so) { - so.status = son_status::in_maintenance; + so.status = son_status::request_maintenance; + }); + } else if(itr->status == son_status::request_maintenance) { + db().modify(*itr, [](son_object &so) { + so.status = son_status::active; }); } } diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index 6f7a0d77..0c05756a 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -317,7 +317,8 @@ void peerplays_sidechain_plugin_impl::create_son_down_proposals() fc::time_point_sec last_maintenance_time = dgpo.next_maintenance_time - gpo.parameters.maintenance_interval; fc::time_point_sec last_active_ts = ((stats.last_active_timestamp > last_maintenance_time) ? stats.last_active_timestamp : last_maintenance_time); int64_t down_threshold = 2*180000000; - if(son_obj->status == chain::son_status::active && (fc::time_point::now() - last_active_ts) > fc::microseconds(down_threshold)) { + if(((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) && + ((fc::time_point::now() - last_active_ts) > fc::microseconds(down_threshold))) { ilog("peerplays_sidechain_plugin: sending son down proposal for ${t} from ${s}",("t",std::string(object_id_type(son_obj->id)))("s",std::string(object_id_type(my_son_id)))); chain::proposal_create_operation op = create_son_down_proposal(son_inf.son_id, last_active_ts); chain::signed_transaction trx = d.create_signed_transaction(_private_keys.begin()->second, op); diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 3d470703..bfe9ab35 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2241,6 +2241,8 @@ FC_API( graphene::wallet::wallet_api, (delete_son) (list_sons) (list_active_sons) + (start_son_maintenance) + (stop_son_maintenance) (get_active_son_wallet) (get_son_wallet_by_time_point) (get_son_wallets) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 8e438ec4..194254be 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1964,10 +1964,9 @@ public: { try { son_object son = get_son(owner_account); - son_heartbeat_operation op; + son_maintenance_operation op; op.owner_account = son.son_account; op.son_id = son.id; - op.ts = _remote_db->get_dynamic_global_properties().time; // or fc::time_point_sec(fc::time_point::now()) ??? signed_transaction tx; tx.operations.push_back( op ); diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 5f8ad78a..d71ac4c8 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -699,9 +699,9 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) con.wallet_api_ptr->start_son_maintenance(name, true); BOOST_CHECK(generate_block()); - // check SON is in maintenance + // check SON is in request_maintenance son_obj = con.wallet_api_ptr->get_son(name); - BOOST_CHECK(son_obj.status == son_status::in_maintenance); + BOOST_CHECK(son_obj.status == son_status::request_maintenance); // restore SON activity con.wallet_api_ptr->stop_son_maintenance(name, true); @@ -711,6 +711,22 @@ BOOST_AUTO_TEST_CASE( maintenance_test ) son_obj = con.wallet_api_ptr->get_son(name); BOOST_CHECK(son_obj.status == son_status::active); + // put SON in maintenance mode + con.wallet_api_ptr->start_son_maintenance(name, true); + BOOST_CHECK(generate_block()); + + // check SON is in request_maintenance + son_obj = con.wallet_api_ptr->get_son(name); + BOOST_CHECK(son_obj.status == son_status::request_maintenance); + + // process maintenance + BOOST_CHECK(generate_maintenance_block()); + + // check SON is in maintenance + son_obj = con.wallet_api_ptr->get_son(name); + BOOST_CHECK(son_obj.status == son_status::in_maintenance); + + } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); edump((e.to_detail_string())); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 329b1629..c283f21e 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -735,9 +735,15 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { PUSH_TX( db, trx, ~0); generate_block(); trx.clear(); - BOOST_CHECK( obj->status == son_status::in_maintenance); + BOOST_CHECK( obj->status == son_status::request_maintenance); } + // Modify SON's status to in_maintenance + db.modify( *obj, [&]( son_object& _s) + { + _s.status = son_status::in_maintenance; + }); + uint64_t downtime = 0; {