2019-10-09 20:24:36 +00:00
# include <graphene/chain/son_evaluator.hpp>
# include <graphene/chain/database.hpp>
# include <graphene/chain/son_object.hpp>
2019-10-23 16:46:04 +00:00
# include <graphene/chain/witness_object.hpp>
2019-10-09 20:24:36 +00:00
# include <graphene/chain/hardfork.hpp>
2019-10-16 00:55:48 +00:00
# include <graphene/chain/vesting_balance_object.hpp>
2019-10-09 20:24:36 +00:00
namespace graphene { namespace chain {
void_result create_son_evaluator : : do_evaluate ( const son_create_operation & op )
{ try {
FC_ASSERT ( db ( ) . head_block_time ( ) > = HARDFORK_SON_TIME , " Not allowed until SON HARDFORK " ) ;
FC_ASSERT ( db ( ) . get ( op . owner_account ) . is_lifetime_member ( ) , " Only Lifetime members may register a SON. " ) ;
2019-10-18 03:27:13 +00:00
FC_ASSERT ( op . deposit ( db ( ) ) . policy . which ( ) = = vesting_policy : : tag < dormant_vesting_policy > : : value ,
" Deposit balance must have dormant vesting policy " ) ;
return void_result ( ) ;
2019-10-09 20:24:36 +00:00
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
object_id_type create_son_evaluator : : do_apply ( const son_create_operation & op )
{ try {
vote_id_type vote_id ;
db ( ) . modify ( db ( ) . get_global_properties ( ) , [ & vote_id ] ( global_property_object & p ) {
vote_id = get_next_vote_id ( p , vote_id_type : : son ) ;
} ) ;
const auto & new_son_object = db ( ) . create < son_object > ( [ & ] ( son_object & obj ) {
obj . son_account = op . owner_account ;
obj . vote_id = vote_id ;
obj . url = op . url ;
obj . deposit = op . deposit ;
obj . signing_key = op . signing_key ;
2019-12-23 18:20:26 +00:00
obj . sidechain_public_keys = op . sidechain_public_keys ;
2019-10-09 20:24:36 +00:00
obj . pay_vb = op . pay_vb ;
2019-10-17 14:46:48 +00:00
obj . statistics = db ( ) . create < son_statistics_object > ( [ & ] ( son_statistics_object & s ) { s . owner = obj . id ; } ) . id ;
2019-10-09 20:24:36 +00:00
} ) ;
return new_son_object . id ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
void_result update_son_evaluator : : do_evaluate ( const son_update_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 ( ) ) ;
return void_result ( ) ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
object_id_type update_son_evaluator : : do_apply ( const son_update_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 ( ) )
{
db ( ) . modify ( * itr , [ & op ] ( son_object & so ) {
if ( op . new_url . valid ( ) ) so . url = * op . new_url ;
if ( op . new_deposit . valid ( ) ) so . deposit = * op . new_deposit ;
if ( op . new_signing_key . valid ( ) ) so . signing_key = * op . new_signing_key ;
2019-12-23 18:20:26 +00:00
if ( op . new_sidechain_public_keys . valid ( ) ) so . sidechain_public_keys = * op . new_sidechain_public_keys ;
2019-10-09 20:24:36 +00:00
if ( op . new_pay_vb . valid ( ) ) so . pay_vb = * op . new_pay_vb ;
} ) ;
}
return op . son_id ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
void_result delete_son_evaluator : : do_evaluate ( const son_delete_operation & op )
{ try {
FC_ASSERT ( db ( ) . head_block_time ( ) > = HARDFORK_SON_TIME , " Not allowed until SON_HARDFORK " ) ; // can be removed after HF date pass
2020-02-27 20:51:04 +00:00
// Either owner can remove or consensus son account
2020-03-25 09:21:09 +00:00
FC_ASSERT ( op . payer = = db ( ) . get ( op . son_id ) . son_account | | ( db ( ) . is_son_dereg_valid ( op . son_id ) & & op . payer = = db ( ) . get_global_properties ( ) . parameters . son_account ( ) ) ) ;
2019-10-09 20:24:36 +00:00
const auto & idx = db ( ) . get_index_type < son_index > ( ) . indices ( ) . get < by_id > ( ) ;
FC_ASSERT ( idx . find ( op . son_id ) ! = idx . end ( ) ) ;
return void_result ( ) ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
void_result delete_son_evaluator : : do_apply ( const son_delete_operation & op )
{ try {
const auto & idx = db ( ) . get_index_type < son_index > ( ) . indices ( ) . get < by_id > ( ) ;
2020-04-04 03:47:50 +00:00
const auto & ss_idx = db ( ) . get_index_type < son_stats_index > ( ) . indices ( ) . get < by_id > ( ) ;
2019-10-16 00:55:48 +00:00
auto son = idx . find ( op . son_id ) ;
if ( son ! = idx . end ( ) ) {
vesting_balance_object deposit = son - > deposit ( db ( ) ) ;
2019-10-18 03:01:40 +00:00
linear_vesting_policy new_vesting_policy ;
2019-10-16 00:55:48 +00:00
new_vesting_policy . begin_timestamp = db ( ) . head_block_time ( ) ;
new_vesting_policy . vesting_cliff_seconds = db ( ) . get_global_properties ( ) . parameters . son_vesting_period ( ) ;
2019-12-08 06:43:05 +00:00
new_vesting_policy . begin_balance = deposit . balance . amount ;
2019-10-16 00:55:48 +00:00
db ( ) . modify ( son - > deposit ( db ( ) ) , [ & new_vesting_policy ] ( vesting_balance_object & vbo ) {
vbo . policy = new_vesting_policy ;
} ) ;
2020-04-04 03:47:50 +00:00
auto stats_obj = ss_idx . find ( son - > statistics ) ;
if ( stats_obj ! = ss_idx . end ( ) )
db ( ) . remove ( * stats_obj ) ;
2019-10-16 00:55:48 +00:00
db ( ) . remove ( * son ) ;
}
2019-10-09 20:24:36 +00:00
return void_result ( ) ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
2019-12-12 13:06:38 +00:00
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
const auto & idx = db ( ) . get_index_type < son_index > ( ) . indices ( ) . get < by_id > ( ) ;
auto itr = idx . find ( op . son_id ) ;
2020-03-14 00:08:45 +00:00
FC_ASSERT ( itr ! = idx . end ( ) ) ;
FC_ASSERT ( itr - > son_account = = op . owner_account ) ;
2019-12-12 13:06:38 +00:00
auto stats = itr - > statistics ( db ( ) ) ;
// Inactive SONs need not send heartbeats
2020-02-07 05:49:16 +00:00
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 " ) ;
2019-12-12 13:06:38 +00:00
// 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
2020-02-07 05:49:16 +00:00
fc : : time_point_sec max_ts = db ( ) . head_block_time ( ) + fc : : seconds ( 5 * db ( ) . block_interval ( ) ) ;
2019-12-12 13:06:38 +00:00
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 ( ) )
{
2020-01-17 20:28:13 +00:00
const global_property_object & gpo = db ( ) . get_global_properties ( ) ;
vector < son_id_type > 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 ;
}
2019-12-12 13:06:38 +00:00
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 ;
} ) ;
2020-01-17 20:28:13 +00:00
db ( ) . modify ( * itr , [ & is_son_active ] ( son_object & so ) {
if ( is_son_active ) {
so . status = son_status : : active ;
} else {
so . status = son_status : : inactive ;
}
2019-12-12 13:06:38 +00:00
} ) ;
2020-02-07 05:49:16 +00:00
} else if ( ( itr - > status = = son_status : : active ) | | ( itr - > status = = son_status : : request_maintenance ) ) {
2019-12-12 13:06:38 +00:00
db ( ) . modify ( itr - > statistics ( db ( ) ) , [ & ] ( son_statistics_object & sso )
{
sso . last_active_timestamp = op . ts ;
} ) ;
}
}
return op . son_id ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
2020-01-06 12:59:35 +00:00
void_result son_report_down_evaluator : : do_evaluate ( const son_report_down_operation & op )
{ try {
2020-02-03 13:14:39 +00:00
FC_ASSERT ( db ( ) . head_block_time ( ) > = HARDFORK_SON_TIME , " Not allowed until SON HARDFORK " ) ; // can be removed after HF date pass
2020-03-25 09:21:09 +00:00
FC_ASSERT ( op . payer = = db ( ) . get_global_properties ( ) . parameters . son_account ( ) , " SON paying account must be set as payer. " ) ;
2020-01-06 12:59:35 +00:00
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 ( ) ) ;
2020-02-07 05:49:16 +00:00
FC_ASSERT ( itr - > status = = son_status : : active | | itr - > status = = son_status : : request_maintenance , " Inactive/Deregistered/in_maintenance SONs cannot be reported on as down " ) ;
2020-01-06 12:59:35 +00:00
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 ) ) }
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 ) ;
if ( itr ! = idx . end ( ) )
{
2020-02-07 05:49:16 +00:00
if ( ( itr - > status = = son_status : : active ) | | ( itr - > status = = son_status : : request_maintenance ) ) {
2020-01-06 12:59:35 +00:00
db ( ) . modify ( itr - > statistics ( db ( ) ) , [ & ] ( son_statistics_object & sso )
{
sso . last_down_timestamp = op . down_ts ;
} ) ;
db ( ) . modify ( * itr , [ & op ] ( son_object & so ) {
so . status = son_status : : in_maintenance ;
} ) ;
}
}
return op . son_id ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
2020-01-17 20:30:45 +00:00
void_result son_maintenance_evaluator : : do_evaluate ( const son_maintenance_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 > ( ) ;
auto itr = idx . find ( op . son_id ) ;
FC_ASSERT ( itr ! = idx . end ( ) ) ;
2020-02-07 05:49:16 +00:00
// Inactive SONs can't go to maintenance, toggle between active and request_maintenance states
2020-03-06 11:49:26 +00:00
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 " ) ;
} else {
FC_ASSERT ( false , " Invalid maintenance operation " ) ;
}
2020-01-17 20:30:45 +00:00
return void_result ( ) ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
object_id_type son_maintenance_evaluator : : do_apply ( const son_maintenance_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 ( ) )
{
2020-03-06 11:49:26 +00:00
if ( itr - > status = = son_status : : active & & op . request_type = = son_maintenance_request_type : : request_maintenance ) {
2020-01-17 20:30:45 +00:00
db ( ) . modify ( * itr , [ ] ( son_object & so ) {
2020-02-07 05:49:16 +00:00
so . status = son_status : : request_maintenance ;
} ) ;
2020-03-06 11:49:26 +00:00
} else if ( itr - > status = = son_status : : request_maintenance & & op . request_type = = son_maintenance_request_type : : cancel_request_maintenance ) {
2020-02-07 05:49:16 +00:00
db ( ) . modify ( * itr , [ ] ( son_object & so ) {
so . status = son_status : : active ;
2020-01-17 20:30:45 +00:00
} ) ;
}
}
return op . son_id ;
} FC_CAPTURE_AND_RETHROW ( ( op ) ) }
2019-10-09 20:24:36 +00:00
} } // namespace graphene::chain