diff --git a/libraries/chain/son_evaluator.cpp b/libraries/chain/son_evaluator.cpp index 619d2e22..fc4802d2 100644 --- a/libraries/chain/son_evaluator.cpp +++ b/libraries/chain/son_evaluator.cpp @@ -123,6 +123,22 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& auto itr = idx.find(op.son_id); if(itr != idx.end()) { + const global_property_object& gpo = db().get_global_properties(); + vector active_son_ids; + active_son_ids.reserve(gpo.active_sons.size()); + std::transform(gpo.active_sons.begin(), gpo.active_sons.end(), + std::inserter(active_son_ids, active_son_ids.end()), + [](const son_info& swi) { + return swi.son_id; + }); + + auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id); + bool is_son_active = true; + + if(it_son == active_son_ids.end()) { + is_son_active = false; + } + if(itr->status == son_status::in_maintenance) { db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) { @@ -130,8 +146,12 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& sso.last_active_timestamp = op.ts; } ); - db().modify(*itr, [&op](son_object &so) { - so.status = son_status::active; + db().modify(*itr, [&is_son_active](son_object &so) { + if(is_son_active) { + so.status = son_status::active; + } else { + so.status = son_status::inactive; + } }); } else if (itr->status == son_status::active) { db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso ) diff --git a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp index e78c78c5..2874605b 100644 --- a/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp +++ b/libraries/plugins/peerplays_sidechain/peerplays_sidechain_plugin.cpp @@ -186,6 +186,10 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() { chain::database& d = plugin.database(); chain::son_id_type son_id = *(_sons.begin()); + const auto& idx = d.get_index_type().indices().get(); + auto son_obj = idx.find( son_id ); + if(son_obj == idx.end()) + return; const chain::global_property_object& gpo = d.get_global_properties(); vector active_son_ids; active_son_ids.reserve(gpo.active_sons.size()); @@ -196,11 +200,9 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() }); auto it = std::find(active_son_ids.begin(), active_son_ids.end(), son_id); - if(it != active_son_ids.end()) { + if(it != active_son_ids.end() || son_obj->status == chain::son_status::in_maintenance) { ilog("peerplays_sidechain_plugin: sending heartbeat"); chain::son_heartbeat_operation op; - const auto& idx = d.get_index_type().indices().get(); - auto son_obj = idx.find( son_id ); op.owner_account = son_obj->son_account; op.son_id = son_id; op.ts = fc::time_point::now() + fc::seconds(0); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index ad8cf0bd..f6037084 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -723,7 +723,40 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) { generate_block(); trx.clear(); BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch()); - downtime = op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch(); + downtime += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch(); + BOOST_CHECK( obj->status == son_status::inactive); + BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts); + } + + // Modify SON's status to in_maintenance + db.modify( *obj, [&]( son_object& _s) + { + _s.status = son_status::in_maintenance; + }); + + // SON is selected as one of the active SONs + db.modify( db.get_global_properties(), [&]( global_property_object& _gpo ) + { + son_info son_inf; + son_inf.son_id = son_id_type(0); + _gpo.active_sons.push_back(son_inf); + }); + + { + generate_block(); + // Send Heartbeat for an in_maintenance SON + son_heartbeat_operation op; + op.owner_account = alice_id; + op.son_id = son_id_type(0); + op.ts = (db.head_block_time()+fc::seconds(2*db.block_interval())); + + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX( db, trx, ~0); + generate_block(); + trx.clear(); + BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime, downtime + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch()); + downtime += op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch(); BOOST_CHECK( obj->status == son_status::active); BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts); }