SON193-SON200- SON Heartbeats and maintenance mode changes

This commit is contained in:
Personal 2019-12-10 21:59:01 +11:00
parent d03bfa81f7
commit 20e598276d
8 changed files with 90 additions and 2 deletions

View file

@ -307,6 +307,9 @@ struct get_impacted_account_visitor
void operator()( const son_delete_operation& op ){
_impacted.insert( op.owner_account );
}
void operator()( const son_heartbeat_operation& op ){
_impacted.insert( op.owner_account );
}
};
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )

View file

@ -294,6 +294,9 @@ struct get_impacted_account_visitor
void operator()( const son_delete_operation& op ) {
_impacted.insert( op.owner_account );
}
void operator()( const son_heartbeat_operation& op ) {
_impacted.insert( op.owner_account );
}
};
void operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )

View file

@ -139,7 +139,8 @@ namespace graphene { namespace chain {
sweeps_vesting_claim_operation,
son_create_operation,
son_update_operation,
son_delete_operation
son_delete_operation,
son_heartbeat_operation
> operation;
/// @} // operations group

View file

@ -47,6 +47,19 @@ namespace graphene { namespace chain {
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
struct son_heartbeat_operation : public base_operation
{
struct fee_parameters_type { uint64_t fee = 0; };
asset fee;
son_id_type son_id;
account_id_type owner_account;
time_point_sec ts;
account_id_type fee_payer()const { return owner_account; }
share_type calculate_fee(const fee_parameters_type& k)const { return 0; }
};
} } // namespace graphene::chain
FC_REFLECT(graphene::chain::son_create_operation::fee_parameters_type, (fee) )
@ -59,3 +72,6 @@ FC_REFLECT(graphene::chain::son_update_operation, (fee)(son_id)(owner_account)(n
FC_REFLECT(graphene::chain::son_delete_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_delete_operation, (fee)(son_id)(payer)(owner_account) )
FC_REFLECT(graphene::chain::son_heartbeat_operation::fee_parameters_type, (fee) )
FC_REFLECT(graphene::chain::son_heartbeat_operation, (fee)(son_id)(owner_account)(ts) )

View file

@ -31,4 +31,13 @@ public:
void_result do_apply(const son_delete_operation& o);
};
class son_heartbeat_evaluator : public evaluator<son_heartbeat_evaluator>
{
public:
typedef son_heartbeat_operation operation_type;
void_result do_evaluate(const son_heartbeat_operation& o);
object_id_type do_apply(const son_heartbeat_operation& o);
};
} } // namespace graphene::chain

View file

@ -10,7 +10,8 @@ namespace graphene { namespace chain {
{
inactive,
active,
in_maintenance
in_maintenance,
deregistered
};
/**
* @class son_statistics_object
@ -31,8 +32,12 @@ namespace graphene { namespace chain {
uint64_t txs_signed = 0;
// Total Downtime barring the current down time in seconds, used for stats to present to user
uint64_t total_downtime = 0;
// Current Interval Downtime since last maintenance
uint64_t current_interval_downtime = 0;
// Down timestamp, if son status is in_maintenance use this
fc::time_point_sec last_down_timestamp;
// Last Active heartbeat timestamp
fc::time_point_sec last_active_timestamp;
};
/**

View file

@ -148,6 +148,10 @@ struct proposal_operation_hardfork_visitor
FC_ASSERT( block_time >= HARDFORK_SON_TIME, "son_delete_operation not allowed yet!" );
}
void operator()(const son_heartbeat_operation &v) const {
FC_ASSERT( block_time >= HARDFORK_SON_TIME, "son_heartbeat_operation not allowed yet!" );
}
// loop and self visit in proposals
void operator()(const proposal_create_operation &v) const {
for (const op_wrapper &op : v.proposed_ops)

View file

@ -94,4 +94,51 @@ void_result delete_son_evaluator::do_apply(const son_delete_operation& op)
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
void_result son_heartbeat_evaluator::do_evaluate(const son_heartbeat_operation& op)
{ try {
FC_ASSERT(db().head_block_time() >= HARDFORK_SON_TIME, "Not allowed until SON HARDFORK"); // can be removed after HF date pass
FC_ASSERT(db().get(op.son_id).son_account == op.owner_account);
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() );
// 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");
// 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_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");
FC_ASSERT(op.ts <= max_ts, "Heartbeat ts is above the max threshold");
return void_result();
} FC_CAPTURE_AND_RETHROW( (op) ) }
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);
if(itr != idx.end())
{
if(itr->status == son_status::in_maintenance) {
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
{
sso.current_interval_downtime += op.ts.sec_since_epoch() - sso.last_down_timestamp.sec_since_epoch();
sso.last_active_timestamp = op.ts;
} );
db().modify(*itr, [&op](son_object &so) {
so.status = son_status::active;
});
} else if (itr->status == son_status::active) {
db().modify( itr->statistics( db() ), [&]( son_statistics_object& sso )
{
sso.last_active_timestamp = op.ts;
} );
}
}
return op.son_id;
} FC_CAPTURE_AND_RETHROW( (op) ) }
} } // namespace graphene::chain