diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index d6324d7df..841f6747b 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -454,7 +454,7 @@ class application_impl : public net::node_delegate { std::vector &contained_transaction_message_ids) override { // check point for the threads which may be cancled on application shutdown - if(!_running.load()) { + if (!_running.load()) { return true; } diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index aa199c84f..3026c2f0d 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -62,11 +62,14 @@ void verify_account_votes( const database& db, const account_options& options ) const auto& gpo = db.get_global_properties(); const auto& chain_params = gpo.parameters; + FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." ); + FC_ASSERT( options.num_witness <= chain_params.maximum_witness_count, "Voted for more witnesses than currently allowed (${c})", ("c", chain_params.maximum_witness_count) ); FC_ASSERT( options.num_committee <= chain_params.maximum_committee_count, "Voted for more committee members than currently allowed (${c})", ("c", chain_params.maximum_committee_count) ); - FC_ASSERT( db.find_object(options.voting_account), "Invalid proxy account specified." ); + FC_ASSERT( options.num_son() <= chain_params.maximum_son_count(), + "Voted for more sons than currently allowed (${c})", ("c", chain_params.maximum_son_count()) ); uint32_t max_vote_id = gpo.next_available_vote_id; bool has_worker_votes = false; diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 0c6843d90..c3f826d11 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -182,7 +182,26 @@ 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()))) { - auto sons = sort_votable_objects(get_global_properties().parameters.maximum_son_count()); + assert( _son_count_histogram_buffer.size() > 0 ); + const share_type stake_target = (_total_voting_stake-_son_count_histogram_buffer[0]) / 2; + /// accounts that vote for 0 or 1 son do not get to express an opinion on + /// the number of sons to have (they abstain and are non-voting accounts) + share_type stake_tally = 0; + size_t son_count = 0; + if( stake_target > 0 ) + { + while( (son_count < _son_count_histogram_buffer.size() - 1) + && (stake_tally <= stake_target) ) + { + stake_tally += _son_count_histogram_buffer[++son_count]; + } + } + const vector> sons = [this, &son_count]{ + if(head_block_time() >= HARDFORK_SON3_TIME) + return sort_votable_objects(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)); + else + return sort_votable_objects(get_global_properties().parameters.maximum_son_count()); + }(); // After SON2 HF uint64_t total_votes = 0; for( const son_object& son : sons ) @@ -683,8 +702,12 @@ void database::update_active_sons() } const global_property_object& gpo = get_global_properties(); - const chain_parameters& cp = gpo.parameters; - auto sons = sort_votable_objects(cp.maximum_son_count()); + const vector> sons = [this, &son_count]{ + if(head_block_time() >= HARDFORK_SON3_TIME) + return sort_votable_objects(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count)); + else + return sort_votable_objects(get_global_properties().parameters.maximum_son_count()); + }(); const auto& all_sons = get_index_type().indices(); @@ -2041,6 +2064,13 @@ void update_son_params(database& db) gpo.parameters.extensions.value.maximum_son_count = 7; }); } + else + { + const auto& gpo = db.get_global_properties(); + db.modify( gpo, []( global_property_object& gpo ) { + gpo.parameters.extensions.value.maximum_son_count = GRAPHENE_DEFAULT_MAX_SONS; + }); + } } void database::perform_chain_maintenance(const signed_block& next_block, const global_property_object& global_props) @@ -2167,9 +2197,9 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // same rationale as for witnesses d._committee_count_histogram_buffer[offset] += voting_stake; } - if( opinion_account.options.num_son <= props.parameters.maximum_son_count() ) + if( opinion_account.options.num_son() <= props.parameters.maximum_son_count() ) { - uint16_t offset = std::min(size_t(opinion_account.options.num_son/2), + uint16_t offset = std::min(size_t(opinion_account.options.num_son()/2), d._son_count_histogram_buffer.size() - 1); // votes for a number greater than maximum_son_count // are turned into votes for maximum_son_count. @@ -2271,6 +2301,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g // the following parameters are not allowed to be changed. So take what is in global property p.pending_parameters->extensions.value.hive_asset = p.parameters.extensions.value.hive_asset; p.pending_parameters->extensions.value.hbd_asset = p.parameters.extensions.value.hbd_asset; + p.pending_parameters->extensions.value.maximum_son_count = p.parameters.extensions.value.maximum_son_count; p.pending_parameters->extensions.value.btc_asset = p.parameters.extensions.value.btc_asset; p.pending_parameters->extensions.value.son_account = p.parameters.extensions.value.son_account; p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start; diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp index 50ccb8aef..c6de2047c 100644 --- a/libraries/chain/include/graphene/chain/protocol/account.hpp +++ b/libraries/chain/include/graphene/chain/protocol/account.hpp @@ -37,6 +37,11 @@ namespace graphene { namespace chain { /// These are the fields which can be updated by the active authority. struct account_options { + struct ext + { + optional< uint16_t > num_son = 0; + }; + /// The memo key is the key this account will typically use to encrypt/sign transaction memos and other non- /// validated account activities. This field is here to prevent confusion if the active authority has zero or /// multiple keys in it. @@ -54,11 +59,11 @@ namespace graphene { namespace chain { uint16_t num_committee = 0; /// The number of active son members this account votes the blockchain should appoint /// Must not exceed the actual number of son members voted for in @ref votes - uint16_t num_son = 0; + uint16_t num_son() const { return extensions.value.num_son.valid() ? *extensions.value.num_son : 0; } /// This is the list of vote IDs this account votes for. The weight of these votes is determined by this /// account's balance of core asset. flat_set votes; - extensions_type extensions; + extension< ext > extensions; /// Whether this account is voting inline bool is_voting() const @@ -289,6 +294,7 @@ namespace graphene { namespace chain { } } // graphene::chain +FC_REFLECT(graphene::chain::account_options::ext, (num_son) ) FC_REFLECT(graphene::chain::account_options, (memo_key)(voting_account)(num_witness)(num_committee)(votes)(extensions)) // FC_REFLECT_TYPENAME( graphene::chain::account_whitelist_operation::account_listing) FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing, diff --git a/libraries/chain/protocol/account.cpp b/libraries/chain/protocol/account.cpp index 2405369a8..b980998cc 100644 --- a/libraries/chain/protocol/account.cpp +++ b/libraries/chain/protocol/account.cpp @@ -174,7 +174,7 @@ void account_options::validate() const { auto needed_witnesses = num_witness; auto needed_committee = num_committee; - auto needed_sons = num_son; + auto needed_sons = num_son(); for( vote_id_type id : votes ) if( id.type() == vote_id_type::witness && needed_witnesses ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index d2fac215f..35b9ab1c5 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -2158,8 +2158,8 @@ class wallet_api_impl return sign_transaction( tx, broadcast ); } FC_CAPTURE_AND_RETHROW( (owner_account)(url)(block_signing_key)(broadcast) ) } - signed_transaction activate_deregistered_son(const string & owner_account, - bool broadcast /* = false */) + signed_transaction activate_deregistered_son(const string & owner_account, + bool broadcast /* = false */) { try { son_object son = get_son(owner_account); @@ -2408,7 +2408,7 @@ class wallet_api_impl op.sidechain = sidechain; op.peerplays_uid = peerplays_uid; op.peerplays_transaction_id = peerplays_transaction_id; - op.peerplays_from = peerplays_from; + op.peerplays_from = peerplays_from; op.peerplays_asset = asset(asset_val.amount * asset_price.base.amount / asset_price.quote.amount); op.withdraw_sidechain = withdraw_sidechain; op.withdraw_address = withdraw_address; @@ -2875,7 +2875,7 @@ class wallet_api_impl if (!votes_removed) FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son)); } - voting_account_object.options.num_son = desired_number_of_sons; + voting_account_object.options.extensions.value.num_son = desired_number_of_sons; account_update_operation account_update_op; account_update_op.account = voting_account_object.id; @@ -5410,7 +5410,7 @@ signed_transaction wallet_api::sidechain_withdrawal_transaction(const string &so const string &withdraw_amount) { return my->sidechain_withdrawal_transaction(son_name_or_id, - block_num, + block_num, sidechain, peerplays_uid, peerplays_transaction_id, @@ -5540,7 +5540,7 @@ signed_transaction wallet_api::sidechain_deposit_transaction( const string &son const string &peerplays_from_name_or_id, const string &peerplays_to_name_or_id) { - return my->sidechain_deposit_transaction(son_name_or_id, + return my->sidechain_deposit_transaction(son_name_or_id, sidechain, transaction_id, operation_index, diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 491ec8f96..1f09de9f4 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -337,7 +337,8 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) global_property_object gpo; gpo = con.wallet_api_ptr->get_global_properties(); - unsigned int son_number = gpo.parameters.maximum_son_count(); + //! Set son number as 5 (as the begining son count) + unsigned int son_number = 5; flat_map sidechain_public_keys; @@ -400,7 +401,7 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture ) BOOST_TEST_MESSAGE("gpo: " << gpo.active_sons.size()); BOOST_CHECK(generate_maintenance_block()); - BOOST_CHECK(gpo.active_sons.size() == gpo.parameters.maximum_son_count()); + BOOST_CHECK(gpo.active_sons.size() == son_number); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); @@ -644,7 +645,8 @@ BOOST_FIXTURE_TEST_CASE( cli_list_active_sons, cli_fixture ) global_property_object gpo; gpo = con.wallet_api_ptr->get_global_properties(); - unsigned int son_number = gpo.parameters.maximum_son_count(); + //! Set son number as 5 (as the begining son count) + unsigned int son_number = 5; flat_map sidechain_public_keys; diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index a802aac58..4fb3a24d8 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -1040,16 +1040,13 @@ BOOST_FIXTURE_TEST_CASE( hardfork_son2_time, database_fixture ) generate_blocks(HARDFORK_SON3_TIME); // after this hardfork maximum son account should not reset the value - // on 7 after maintenance interval anymore. So change the global parameters - // and check the value after maintenance interval - db.modify(db.get_global_properties(), [](global_property_object& p) { - p.parameters.extensions.value.maximum_son_count = 13; - }); + // on 7 after maintenance interval anymore. It must be GRAPHENE_DEFAULT_MAX_SONS + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), GRAPHENE_DEFAULT_MAX_SONS); generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); generate_block(); - BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 13); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), 15); } FC_LOG_AND_RETHROW() }