#308 - son_status as map

This commit is contained in:
Vlad Dobromyslov 2022-03-30 15:31:41 +03:00
parent 32d67b2c30
commit 467522f7d8
8 changed files with 200 additions and 82 deletions

View file

@ -222,11 +222,18 @@ std::set<son_id_type> database::get_sons_to_be_deregistered()
for( auto& son : son_idx )
{
if(son.status == son_status::in_maintenance)
bool need_to_be_deregistered = true;
for(const auto& status : son.statuses)
{
if(status.second != son_status::in_maintenance)
need_to_be_deregistered = false;
}
if(need_to_be_deregistered)
{
auto stats = son.statistics(*this);
// TODO : We need to add a function that returns if we can deregister SON
// i.e. with introduction of PW code, we have to make a decision if the SON
// TODO : We need to add a function that returns if we can deregister SON
// i.e. with introduction of PW code, we have to make a decision if the SON
// is needed for release of funds from the PW
if(head_block_time() - stats.last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time()))
{
@ -289,7 +296,14 @@ bool database::is_son_dereg_valid( son_id_type son_id )
return false;
}
return (son->status == son_status::in_maintenance &&
bool status_in_maintenance = true;
for(const auto& status : son->statuses)
{
if(status.second != son_status::in_maintenance)
status_in_maintenance = false;
}
return (status_in_maintenance &&
(head_block_time() - son->statistics(*this).last_down_timestamp >= fc::seconds(get_global_properties().parameters.son_deregister_time())));
}

View file

@ -84,7 +84,7 @@ vector<std::reference_wrapper<const son_object>> database::sort_votable_objects<
std::vector<std::reference_wrapper<const son_object>> refs;
for( auto& son : all_sons )
{
if(son.has_valid_config(head_block_time()) && son.status != son_status::deregistered)
if(son.has_valid_config(head_block_time()) && son.statuses.at(sidechain) != son_status::deregistered)
{
refs.push_back(std::cref(son));
}
@ -186,6 +186,7 @@ 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()))) {
//! Fixme - sort_votable_objects only for bitcoin
auto sons = sort_votable_objects<son_index>(sidechain_type::bitcoin, get_global_properties().parameters.maximum_son_count());
// After SON2 HF
uint64_t total_votes = 0;
@ -353,9 +354,9 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_in
if (son == idx.end()) // SON is deleted already
continue;
// keep maintenance status for nodes becoming inactive
if (son->status == son_status::active) {
if (son->statuses.at(sidechain) == son_status::active) {
modify(*son, [&](son_object &obj) {
obj.status = son_status::inactive;
obj.statuses.at(sidechain) = son_status::inactive;
});
}
}
@ -373,9 +374,9 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_in
auto son = idx.find(sid);
FC_ASSERT(son != idx.end(), "Invalid SON in active list, id={sonid}.", ("sonid", sid));
// keep maintenance status for new nodes
if (son->status == son_status::inactive) {
if (son->statuses.at(sidechain) == son_status::inactive) {
modify(*son, [&](son_object &obj) {
obj.status = son_status::active;
obj.statuses.at(sidechain) = son_status::active;
});
}
}
@ -385,7 +386,7 @@ void database::update_son_statuses( const flat_map<sidechain_type, vector<son_in
auto son = idx.find(new_sons[i]);
if (son == idx.end()) // SON is deleted already
continue;
ilog("${s}, status = ${ss}, total_votes = ${sv}", ("s", new_sons[i])("ss", son->status)("sv", son->total_votes));
ilog("${s}, status = ${ss}, total_votes = ${sv}", ("s", new_sons[i])("ss", son->statuses.at(sidechain))("sv", son->total_votes));
}
if (sons_to_remove.size() > 0) {
@ -723,19 +724,29 @@ void database::update_active_sons()
auto& local_vote_buffer_ref = _vote_tally_buffer;
for( const son_object& son : all_sons )
{
if(son.status == son_status::request_maintenance)
bool status_in_maintenance = true;
for(const auto& status: son.statuses)
{
auto& stats = son.statistics(*this);
modify( stats, [&]( son_statistics_object& _s){
_s.last_down_timestamp = head_block_time();
});
if(status.second != son_status::in_maintenance)
status_in_maintenance = false;
}
if(status_in_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 ){
for(const auto& sidechain_vote_id : obj.sidechain_vote_ids ){
obj.total_votes[sidechain_vote_id.first] = local_vote_buffer_ref[sidechain_vote_id.second];
}
if(obj.status == son_status::request_maintenance)
obj.status = son_status::in_maintenance;
for(auto& status: obj.statuses)
{
if (status.second == son_status::request_maintenance)
status.second = son_status::in_maintenance;
}
});
}

View file

@ -513,6 +513,7 @@ namespace graphene { namespace chain {
template<class Index>
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
//! Fixme return map here
template<class Index>
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(sidechain_type sidechain, size_t count)const;

View file

@ -35,11 +35,11 @@ namespace graphene { namespace chain {
// Transactions signed since the last son payouts
flat_map<sidechain_type, uint64_t> txs_signed;
// Total Voted Active time i.e. duration selected as part of voted active SONs
flat_map<sidechain_type, uint64_t> total_voted_time;
flat_map<sidechain_type, uint64_t> total_voted_time; //! Fixme - check if we need map of sidechain_type here
// Total Downtime barring the current down time in seconds, used for stats to present to user
flat_map<sidechain_type, uint64_t> total_downtime;
flat_map<sidechain_type, uint64_t> total_downtime; //! Fixme - check if we need map of sidechain_type here
// Current Interval Downtime since last maintenance
flat_map<sidechain_type, uint64_t> current_interval_downtime;
flat_map<sidechain_type, uint64_t> current_interval_downtime; //! Fixme - check if we need map of sidechain_type here
// Down timestamp, if son status is in_maintenance use this
fc::time_point_sec last_down_timestamp;
// Last Active heartbeat timestamp
@ -71,7 +71,7 @@ namespace graphene { namespace chain {
public_key_type signing_key;
vesting_balance_id_type pay_vb;
son_statistics_id_type statistics;
son_status status = son_status::inactive; //! Fixme -> as map of sidechain_type
flat_map<sidechain_type, son_status> statuses;
flat_map<sidechain_type, string> sidechain_public_keys;
void pay_son_fee(share_type pay, database& db);
@ -132,7 +132,7 @@ FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object),
(signing_key)
(pay_vb)
(statistics)
(status)
(statuses)
(sidechain_public_keys)
)

View file

@ -97,7 +97,8 @@ object_id_type update_son_evaluator::do_apply(const son_update_operation& op)
if(op.new_signing_key.valid()) so.signing_key = *op.new_signing_key;
if(op.new_sidechain_public_keys.valid()) so.sidechain_public_keys = *op.new_sidechain_public_keys;
if(op.new_pay_vb.valid()) so.pay_vb = *op.new_pay_vb;
if(so.status == son_status::deregistered) so.status = son_status::inactive;
for(auto& status : so.statuses)
if(status.second == son_status::deregistered) status.second = son_status::inactive;
});
}
return op.son_id;
@ -130,7 +131,8 @@ void_result deregister_son_evaluator::do_apply(const son_deregister_operation& o
});
db().modify(*son, [&op](son_object &so) {
so.status = son_status::deregistered;
for(auto& status : so.statuses)
status.second = son_status::deregistered;
});
auto stats_obj = ss_idx.find(son->statistics);
@ -147,12 +149,18 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
{ try {
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
auto itr = idx.find(op.son_id);
const auto itr = idx.find(op.son_id);
FC_ASSERT( itr != idx.end() );
FC_ASSERT(itr->son_account == op.owner_account);
auto stats = itr->statistics( db() );
// 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");
bool status_need_to_send_heartbeats = false;
for(const auto& status : itr->statuses)
{
if( (status.second == son_status::active) || (status.second == son_status::in_maintenance) || (status.second == son_status::request_maintenance) )
status_need_to_send_heartbeats = true;
}
FC_ASSERT(status_need_to_send_heartbeats, "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
@ -167,7 +175,7 @@ void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation&
object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation& op)
{ try {
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
auto itr = idx.find(op.son_id);
const auto itr = idx.find(op.son_id);
if(itr != idx.end())
{
const global_property_object& gpo = db().get_global_properties();
@ -184,27 +192,27 @@ object_id_type son_heartbeat_evaluator::do_apply(const son_heartbeat_operation&
return swi.son_id;
});
auto it_son = std::find(active_son_ids.begin(), active_son_ids.end(), op.son_id);
const 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) {
if (itr->statuses.at(sidechain) == son_status::in_maintenance) {
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
sso.current_interval_downtime[sidechain] += op.ts.sec_since_epoch() - sso.last_down_timestamp.sec_since_epoch();
sso.last_active_timestamp = op.ts;
});
db().modify(*itr, [&is_son_active](son_object &so) {
db().modify(*itr, [&is_son_active, &sidechain](son_object &so) {
if (is_son_active) {
so.status = son_status::active;
so.statuses[sidechain] = son_status::active;
} else {
so.status = son_status::inactive;
so.statuses[sidechain] = son_status::inactive;
}
});
} else if ((itr->status == son_status::active) || (itr->status == son_status::request_maintenance)) {
} else if ((itr->statuses.at(sidechain) == son_status::active) || (itr->statuses.at(sidechain) == son_status::request_maintenance)) {
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
sso.last_active_timestamp = op.ts;
});
@ -220,9 +228,15 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati
FC_ASSERT(op.payer == db().get_global_properties().parameters.son_account(), "SON paying account must be set as payer.");
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
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 || itr->status == son_status::request_maintenance, "Inactive/Deregistered/in_maintenance SONs cannot be reported on as down");
const auto itr = idx.find(op.son_id);
const auto stats = itr->statistics( db() );
bool status_need_to_report_down = false;
for(const auto& status : itr->statuses)
{
if( (status.second == son_status::active) || (status.second == son_status::request_maintenance) )
status_need_to_report_down = true;
}
FC_ASSERT(status_need_to_report_down, "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) ) }
@ -230,19 +244,28 @@ void_result son_report_down_evaluator::do_evaluate(const son_report_down_operati
object_id_type son_report_down_evaluator::do_apply(const son_report_down_operation& op)
{ try {
const auto& idx = db().get_index_type<son_index>().indices().get<by_id>();
auto itr = idx.find(op.son_id);
const auto itr = idx.find(op.son_id);
if(itr != idx.end())
{
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;
});
bool status_report_down = true;
db().modify(*itr, [&op](son_object &so) {
so.status = son_status::in_maintenance;
});
}
for( const auto& status : itr->statuses ) {
const auto& sidechain = status.first;
if ((status.second == son_status::active) || (status.second == son_status::request_maintenance)) {
db().modify(*itr, [&sidechain](son_object &so) {
so.statuses[sidechain] = son_status::in_maintenance;
});
}
else
status_report_down = false;
}
if(status_report_down) {
db().modify(itr->statistics(db()), [&](son_statistics_object &sso) {
sso.last_down_timestamp = op.down_ts;
});
}
}
return op.son_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
@ -256,9 +279,19 @@ void_result son_maintenance_evaluator::do_evaluate(const son_maintenance_operati
FC_ASSERT( itr != idx.end() );
// Inactive SONs can't go to maintenance, toggle between active and request_maintenance states
if(op.request_type == son_maintenance_request_type::request_maintenance) {
FC_ASSERT(itr->status == son_status::active, "Inactive SONs can't request for maintenance");
} else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
FC_ASSERT(itr->status == son_status::request_maintenance, "Only maintenance requested SONs can cancel the request");
bool status_active = false;
for(const auto& status : itr->statuses) {
if( (status.second == son_status::active) )
status_active = true;
}
FC_ASSERT(status_active, "Inactive SONs can't request for maintenance");
} else if(op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
bool status_request_maintenance = false;
for(const auto& status : itr->statuses) {
if( (status.second == son_status::request_maintenance) )
status_request_maintenance = true;
}
FC_ASSERT(status_request_maintenance, "Only maintenance requested SONs can cancel the request");
} else {
FC_ASSERT(false, "Invalid maintenance operation");
}
@ -271,15 +304,33 @@ object_id_type son_maintenance_evaluator::do_apply(const son_maintenance_operati
auto itr = idx.find(op.son_id);
if(itr != idx.end())
{
if(itr->status == son_status::active && op.request_type == son_maintenance_request_type::request_maintenance) {
db().modify(*itr, [](son_object &so) {
so.status = son_status::request_maintenance;
});
} else if(itr->status == son_status::request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
db().modify(*itr, [](son_object &so) {
so.status = son_status::active;
});
}
bool status_active = false;
for(const auto& status : itr->statuses) {
if( (status.second == son_status::active) )
status_active = true;
}
if(status_active && op.request_type == son_maintenance_request_type::request_maintenance) {
db().modify(*itr, [](son_object &so) {
for(auto& status : so.statuses) {
status.second = son_status::request_maintenance;
}
});
}
else
{
bool status_request_maintenance = false;
for(const auto& status : itr->statuses) {
if( (status.second == son_status::request_maintenance) )
status_request_maintenance = true;
}
if(status_request_maintenance && op.request_type == son_maintenance_request_type::cancel_request_maintenance) {
db().modify(*itr, [](son_object &so) {
for(auto& status : so.statuses) {
status.second = son_status::active;
}
});
}
}
}
return op.son_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }

View file

@ -338,7 +338,13 @@ bool peerplays_sidechain_plugin_impl::is_son_deregistered(son_id_type son_id) {
if (son_obj == idx.end())
return true;
if (son_obj->status == chain::son_status::deregistered) {
bool status_deregistered = true;
for(const auto& status : son_obj->statuses) {
if( (status.second != son_status::deregistered) )
status_deregistered = false;
}
if (status_deregistered) {
return true;
}
@ -364,8 +370,13 @@ bool peerplays_sidechain_plugin_impl::is_son_down_op_valid(const chain::operatio
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 = gpo.parameters.son_down_time();
if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) &&
((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
bool status_son_down_op_valid = true;
for(const auto& status : son_obj->statuses) {
if( (status.second != son_status::active) && (status.second != son_status::request_maintenance) )
status_son_down_op_valid = false;
}
if ((status_son_down_op_valid) && ((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
return true;
}
return false;
@ -400,7 +411,14 @@ void peerplays_sidechain_plugin_impl::heartbeat_loop() {
chain::database &d = plugin.database();
for (son_id_type son_id : sons) {
if (is_active_son(son_id) || get_son_object(son_id).status == chain::son_status::in_maintenance) {
const auto& son_obj = get_son_object(son_id);
bool status_in_maintenance= false;
for(const auto& status : son_obj.statuses) {
if( (status.second == son_status::in_maintenance) )
status_in_maintenance = true;
}
if (is_active_son(son_id) || status_in_maintenance) {
ilog("Sending heartbeat for SON ${son}", ("son", son_id));
chain::son_heartbeat_operation op;
@ -626,8 +644,13 @@ 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 = gpo.parameters.son_down_time();
if (((son_obj->status == chain::son_status::active) || (son_obj->status == chain::son_status::request_maintenance)) &&
((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
bool status_son_down_valid = true;
for(const auto& status : son_obj->statuses) {
if( (status.second != son_status::active) && (status.second != son_status::request_maintenance) )
status_son_down_valid = false;
}
if ((status_son_down_valid) && ((fc::time_point::now() - last_active_ts) > fc::seconds(down_threshold))) {
ilog("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(plugin.get_private_key(get_son_object(my_son_id).signing_key), op);

View file

@ -858,7 +858,8 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
BOOST_CHECK(generate_maintenance_block());
son_object son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.status == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
// put SON in maintenance mode
con.wallet_api_ptr->request_son_maintenance(name, true);
@ -866,7 +867,8 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
// check SON is in request_maintenance
son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.status == son_status::request_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::request_maintenance);
// restore SON activity
con.wallet_api_ptr->cancel_request_son_maintenance(name, true);
@ -874,7 +876,8 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
// check SON is active
son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.status == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
// put SON in maintenance mode
con.wallet_api_ptr->request_son_maintenance(name, true);
@ -882,14 +885,16 @@ BOOST_AUTO_TEST_CASE( maintenance_test )
// check SON is in request_maintenance
son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.status == son_status::request_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == 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);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::in_maintenance);
} catch( fc::exception& e ) {
@ -1006,7 +1011,8 @@ BOOST_AUTO_TEST_CASE( sidechain_withdraw_transaction_test )
BOOST_CHECK(generate_maintenance_block());
son_object son_obj = con.wallet_api_ptr->get_son(name);
BOOST_CHECK(son_obj.status == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK(son_obj.statuses.at(sidechain_type::hive) == son_status::active);
// create son account
std::string account_name("peerplaystest");

View file

@ -193,7 +193,8 @@ try {
// Modify SON's status to active
db.modify( *obj, [&]( son_object& _s)
{
_s.status = son_status::in_maintenance;
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
_s.statuses[sidechain_type::hive] = son_status::in_maintenance;
});
db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
@ -218,7 +219,8 @@ try {
generate_block();
BOOST_REQUIRE( idx.size() == 1 );
BOOST_REQUIRE( obj->status == son_status::deregistered );
BOOST_REQUIRE( obj->statuses.at(sidechain_type::bitcoin) == son_status::deregistered );
BOOST_REQUIRE( obj->statuses.at(sidechain_type::hive) == son_status::deregistered );
BOOST_REQUIRE( son_stats_obj->deregistered_timestamp == now );
deposit_vesting = db.get<vesting_balance_object>(vesting_balance_id_type(0));
@ -604,7 +606,8 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
// Modify SON's status to active
db.modify( *obj, [&]( son_object& _s)
{
_s.status = son_status::active;
_s.statuses[sidechain_type::bitcoin] = son_status::active;
_s.statuses[sidechain_type::hive] = son_status::active;
});
db.modify( *son_stats_obj, [&]( son_statistics_object& _s)
@ -626,7 +629,8 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
PUSH_TX( db, trx, ~0);
generate_block();
trx.clear();
BOOST_CHECK( obj->status == son_status::request_maintenance);
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::request_maintenance);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::request_maintenance);
}
{
@ -643,13 +647,15 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
PUSH_TX( db, trx, ~0);
generate_block();
trx.clear();
BOOST_CHECK( obj->status == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
}
// Modify SON's status to in_maintenance
db.modify( *obj, [&]( son_object& _s)
{
_s.status = son_status::in_maintenance;
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
_s.statuses[sidechain_type::hive] = son_status::in_maintenance;
});
uint64_t downtime = 0;
@ -671,14 +677,16 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch());
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), 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( obj->statuses.at(sidechain_type::bitcoin) == son_status::inactive);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == 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;
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
_s.statuses[sidechain_type::bitcoin] = son_status::in_maintenance;
});
// SON is selected as one of the active SONs
@ -707,7 +715,8 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), downtime + op.ts.sec_since_epoch() - son_stats_obj->last_down_timestamp.sec_since_epoch());
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), 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( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts);
}
@ -727,7 +736,8 @@ BOOST_AUTO_TEST_CASE( son_heartbeat_test ) {
trx.clear();
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::bitcoin), downtime);
BOOST_REQUIRE_EQUAL(son_stats_obj->current_interval_downtime.at(sidechain_type::hive), downtime);
BOOST_CHECK( obj->status == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
BOOST_CHECK( son_stats_obj->last_active_timestamp == op.ts);
}
} FC_LOG_AND_RETHROW()
@ -753,7 +763,8 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
auto son_stats_obj = sidx.find( obj->statistics );
BOOST_REQUIRE( son_stats_obj != sidx.end() );
BOOST_CHECK( obj->status == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::active);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::active);
{
// Check that transaction fails if down_ts < last_active_timestamp
@ -805,7 +816,8 @@ BOOST_AUTO_TEST_CASE( son_report_down_test ) {
generate_block();
trx.clear();
BOOST_CHECK( obj->status == son_status::in_maintenance);
BOOST_CHECK( obj->statuses.at(sidechain_type::bitcoin) == son_status::in_maintenance);
BOOST_CHECK( obj->statuses.at(sidechain_type::hive) == son_status::in_maintenance);
BOOST_CHECK( son_stats_obj->last_down_timestamp == op.down_ts);
}