From 011d3a51a556ba2c9f18cfa38e1ceb648f30fbbe Mon Sep 17 00:00:00 2001 From: satyakoneru Date: Tue, 22 Oct 2019 10:32:50 +0000 Subject: [PATCH] SON126 - Witness Proposals to deregister SONs --- libraries/chain/db_block.cpp | 20 ++++++ libraries/chain/db_getter.cpp | 67 ++++++++++++++++++- libraries/chain/db_init.cpp | 2 + .../chain/include/graphene/chain/config.hpp | 3 +- .../chain/include/graphene/chain/database.hpp | 4 ++ .../graphene/chain/proposal_evaluator.hpp | 15 +++++ .../include/graphene/chain/protocol/son.hpp | 3 +- .../include/graphene/chain/protocol/types.hpp | 5 ++ .../include/graphene/chain/son_object.hpp | 13 ++++ .../graphene/chain/son_proposal_object.hpp | 41 ++++++++++++ libraries/chain/proposal_evaluator.cpp | 16 +++++ libraries/wallet/wallet.cpp | 1 + tests/tests/son_operations_tests.cpp | 2 + 13 files changed, 189 insertions(+), 3 deletions(-) create mode 100644 libraries/chain/include/graphene/chain/son_proposal_object.hpp diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 1ad84fa0..8ee2e023 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -426,6 +426,26 @@ signed_block database::_generate_block( _pending_tx_session.reset(); _pending_tx_session = _undo_db.start_undo_session(); + if( head_block_time() > HARDFORK_SON_TIME ) + { + std::set sons_to_be_dereg = get_sons_to_be_deregistered(); + if(sons_to_be_dereg.size() > 0) + { + std::set sons_being_dereg = get_sons_being_deregistered(); + for( auto& son : sons_to_be_dereg) + { + if(sons_being_dereg.find(son) == sons_being_dereg.end()) + { + auto op = create_son_deregister_proposal(son, witness_obj); + if(op.valid()) + { + _pending_tx.insert( _pending_tx.begin(), create_signed_transaction( block_signing_private_key, *op ) ); + } + } + } + } + } + uint64_t postponed_tx_count = 0; // pop pending state (reset to head block state) for( const processed_transaction& tx : _pending_tx ) diff --git a/libraries/chain/db_getter.cpp b/libraries/chain/db_getter.cpp index aa50b551..8e4130d0 100644 --- a/libraries/chain/db_getter.cpp +++ b/libraries/chain/db_getter.cpp @@ -27,7 +27,8 @@ #include #include #include - +#include +#include #include #include @@ -141,4 +142,68 @@ const std::vector database::get_winner_numbers( asset_id_type for_asse return result; } +std::set database::get_sons_being_deregistered() +{ + std::set ret; + const auto& son_proposal_idx = get_index_type().indices().get< by_id >(); + + for( auto& son_proposal : son_proposal_idx ) + { + if(son_proposal.proposal_type == son_proposal_type::son_deregister_proposal) + { + ret.insert(son_proposal.son_id); + } + } + return ret; +} + +std::set database::get_sons_to_be_deregistered() +{ + std::set ret; + const auto& son_idx = get_index_type().indices().get< by_id >(); + + for( auto& son : son_idx ) + { + if(son.status == son_status::in_maintenance) + { + 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 + // is needed for release of funds from the PW + if(head_block_time() - stats.last_down_timestamp >= fc::hours(SON_DEREGISTER_TIME)) + { + ret.insert(son.id); + } + } + } + return ret; +} + +fc::optional database::create_son_deregister_proposal(const son_id_type& son_id, const witness_object& current_witness ) +{ + son_delete_operation son_dereg_op; + son_dereg_op.payer = current_witness.witness_account; + + proposal_create_operation proposal_op; + proposal_op.fee_paying_account = current_witness.witness_account; + proposal_op.proposed_ops.push_back( op_wrapper( son_dereg_op ) ); + uint32_t lifetime = ( get_global_properties().parameters.block_interval * get_global_properties().active_witnesses.size() ) * 3; + proposal_op.expiration_time = time_point_sec( head_block_time().sec_since_epoch() + lifetime ); + return proposal_op; +} + +signed_transaction database::create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op ) +{ + signed_transaction processed_trx; + auto dyn_props = get_dynamic_global_properties(); + processed_trx.set_reference_block( dyn_props.head_block_id ); + processed_trx.set_expiration( head_block_time() + get_global_properties().parameters.maximum_time_until_expiration ); + processed_trx.operations.push_back( op ); + current_fee_schedule().set_fee( processed_trx.operations.back() ); + + processed_trx.sign( signing_private_key, get_chain_id() ); + + return processed_trx; +} + } } diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 445e3adc..7dc986a4 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -288,6 +289,7 @@ void database::initialize_indexes() tournament_details_idx->add_secondary_index(); add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); //Implementation object indexes add_index< primary_index >(); diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index cf02b968..37b0885d 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -233,7 +233,8 @@ #define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week #define MIN_SON_MEMBER_COUNT 15 #define SON_VESTING_AMOUNT (50*GRAPHENE_BLOCKCHAIN_PRECISION) // 50 PPY -#define SON_VESTING_PERIOD (60*60*24*30) // 2 days +#define SON_VESTING_PERIOD (60*60*24*2) // 2 days +#define SON_DEREGISTER_TIME (12) // 12 Hours #define MIN_SON_PAY_DAILY_MAX (GRAPHENE_BLOCKCHAIN_PRECISION * int64_t(200)) #define SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE (2*GRAPHENE_1_PERCENT) #define SWEEPS_DEFAULT_DISTRIBUTION_ASSET (graphene::chain::asset_id_type(0)) diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 5f34eeaa..b5a46022 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -279,6 +279,10 @@ namespace graphene { namespace chain { const std::vector get_winner_numbers( asset_id_type for_asset, uint32_t count_members, uint8_t count_winners ) const; std::vector get_seeds( asset_id_type for_asset, uint8_t count_winners )const; uint64_t get_random_bits( uint64_t bound ); + std::set get_sons_being_deregistered(); + std::set get_sons_to_be_deregistered(); + fc::optional create_son_deregister_proposal(const son_id_type& son_id, const witness_object& current_witness ); + signed_transaction create_signed_transaction( const fc::ecc::private_key& signing_private_key, const operation& op ); time_point_sec head_block_time()const; uint32_t head_block_num()const; diff --git a/libraries/chain/include/graphene/chain/proposal_evaluator.hpp b/libraries/chain/include/graphene/chain/proposal_evaluator.hpp index bf6fc547..a7b76471 100644 --- a/libraries/chain/include/graphene/chain/proposal_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/proposal_evaluator.hpp @@ -30,6 +30,21 @@ namespace graphene { namespace chain { + class son_hardfork_visitor + { + public: + typedef void result_type; + database& db; + proposal_id_type prop_id; + + son_hardfork_visitor( database& _db, const proposal_id_type& _prop_id ) : db( _db ), prop_id( _prop_id ) {} + + template + void operator()( const T &v ) const {} + + void operator()( const son_delete_operation &v ); + }; + class proposal_create_evaluator : public evaluator { public: diff --git a/libraries/chain/include/graphene/chain/protocol/son.hpp b/libraries/chain/include/graphene/chain/protocol/son.hpp index efea3ef7..7b7796fc 100644 --- a/libraries/chain/include/graphene/chain/protocol/son.hpp +++ b/libraries/chain/include/graphene/chain/protocol/son.hpp @@ -40,9 +40,10 @@ namespace graphene { namespace chain { asset fee; son_id_type son_id; + account_id_type payer; account_id_type owner_account; - account_id_type fee_payer()const { return owner_account; } + account_id_type fee_payer()const { return payer; } share_type calculate_fee(const fee_parameters_type& k)const { return 0; } }; diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index c1e592f8..bcdd1a83 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -146,6 +146,7 @@ namespace graphene { namespace chain { betting_market_object_type, bet_object_type, son_object_type, + son_proposal_object_type, OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types }; @@ -207,6 +208,7 @@ namespace graphene { namespace chain { class betting_market_object; class bet_object; class son_object; + class son_proposal_object; typedef object_id< protocol_ids, account_object_type, account_object> account_id_type; typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type; @@ -234,6 +236,7 @@ namespace graphene { namespace chain { typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type; typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type; typedef object_id< protocol_ids, son_object_type, son_object> son_id_type; + typedef object_id< protocol_ids, son_proposal_object_type, son_proposal_object> son_proposal_id_type; // implementation types class global_property_object; @@ -417,6 +420,7 @@ FC_REFLECT_ENUM( graphene::chain::object_type, (betting_market_object_type) (bet_object_type) (son_object_type) + (son_proposal_object_type) (OBJECT_TYPE_COUNT) ) FC_REFLECT_ENUM( graphene::chain::impl_object_type, @@ -488,6 +492,7 @@ FC_REFLECT_TYPENAME( graphene::chain::betting_market_position_id_type ) FC_REFLECT_TYPENAME( graphene::chain::global_betting_statistics_id_type ) FC_REFLECT_TYPENAME( graphene::chain::tournament_details_id_type ) FC_REFLECT_TYPENAME( graphene::chain::son_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::son_proposal_id_type ) FC_REFLECT( graphene::chain::void_t, ) diff --git a/libraries/chain/include/graphene/chain/son_object.hpp b/libraries/chain/include/graphene/chain/son_object.hpp index dc5d3285..77316a4d 100644 --- a/libraries/chain/include/graphene/chain/son_object.hpp +++ b/libraries/chain/include/graphene/chain/son_object.hpp @@ -6,6 +6,12 @@ namespace graphene { namespace chain { using namespace graphene::db; + enum class son_status + { + inactive, + active, + in_maintenance + }; /** * @class son_statistics_object * @ingroup object @@ -23,6 +29,10 @@ namespace graphene { namespace chain { son_id_type owner; // Transactions signed since the last son payouts 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; + // Down timestamp, if son status is in_maintenance use this + fc::time_point_sec last_down_timestamp; }; /** @@ -44,6 +54,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; void pay_son_fee(share_type pay, database& db); }; @@ -76,6 +87,8 @@ namespace graphene { namespace chain { using son_stats_index = generic_index; } } // graphene::chain +FC_REFLECT_ENUM(graphene::chain::son_status, (inactive)(active)(in_maintenance) ) + FC_REFLECT_DERIVED( graphene::chain::son_object, (graphene::db::object), (son_account)(vote_id)(total_votes)(url)(deposit)(signing_key)(pay_vb) ) diff --git a/libraries/chain/include/graphene/chain/son_proposal_object.hpp b/libraries/chain/include/graphene/chain/son_proposal_object.hpp new file mode 100644 index 00000000..344ed2e3 --- /dev/null +++ b/libraries/chain/include/graphene/chain/son_proposal_object.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +namespace graphene { namespace chain { + +enum class son_proposal_type +{ + son_deregister_proposal +}; + +class son_proposal_object : public abstract_object +{ + public: + static const uint8_t space_id = protocol_ids; + static const uint8_t type_id = son_proposal_object_type; + + son_proposal_id_type get_id()const { return id; } + + proposal_id_type proposal_id; + son_id_type son_id; + son_proposal_type proposal_type; +}; + +//struct by_proposal; +//struct by_type; +using son_proposal_multi_index_container = multi_index_container< + son_proposal_object, + indexed_by< + ordered_unique< tag< by_id >, member< object, object_id_type, &object::id > > + > +>; +using son_proposal_index = generic_index; + +} } // graphene::chain + +FC_REFLECT_ENUM(graphene::chain::son_proposal_type, (son_deregister_proposal) ) + +FC_REFLECT_DERIVED( graphene::chain::son_proposal_object, (graphene::chain::object), (proposal_id)(son_id)(proposal_type) ) \ No newline at end of file diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index 245e1a53..d377e0d8 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -154,6 +155,15 @@ struct proposal_operation_hardfork_visitor } }; +void son_hardfork_visitor::operator()( const son_delete_operation &v ) +{ + db.create([&]( son_proposal_object& son_prop ) { + son_prop.proposal_type = son_proposal_type::son_deregister_proposal; + son_prop.proposal_id = prop_id; + son_prop.son_id = v.son_id; + }); +} + void_result proposal_create_evaluator::do_evaluate(const proposal_create_operation& o) { try { const database& d = db(); @@ -232,6 +242,12 @@ object_id_type proposal_create_evaluator::do_apply(const proposal_create_operati std::inserter(proposal.required_active_approvals, proposal.required_active_approvals.begin())); }); + son_hardfork_visitor son_vtor(d, proposal.id); + for(auto& op: o.proposed_ops) + { + op.op.visit(son_vtor); + } + return proposal.id; } FC_CAPTURE_AND_RETHROW( (o) ) } diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 4b4bbcf8..ef419d1a 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1918,6 +1918,7 @@ public: son_delete_operation son_delete_op; son_delete_op.son_id = son.id; son_delete_op.owner_account = son.son_account; + son_delete_op.payer = son.son_account; signed_transaction tx; tx.operations.push_back( son_delete_op ); diff --git a/tests/tests/son_operations_tests.cpp b/tests/tests/son_operations_tests.cpp index 8d5ae3f2..3ec78fc3 100644 --- a/tests/tests/son_operations_tests.cpp +++ b/tests/tests/son_operations_tests.cpp @@ -142,6 +142,7 @@ try { son_delete_operation op; op.owner_account = alice_id; op.son_id = son_id_type(0); + op.payer = alice_id; trx.operations.push_back(op); sign(trx, alice_private_key); @@ -205,6 +206,7 @@ try { son_delete_operation op; op.owner_account = bob_id; op.son_id = son_id_type(0); + op.payer = bob_id; trx.operations.push_back(op); sign(trx, bob_private_key);