#387 Allow changing number of SONs by voting, similar to witnesses
This commit is contained in:
parent
02d898d4dc
commit
1a196bfcc2
8 changed files with 64 additions and 25 deletions
|
|
@ -454,7 +454,7 @@ public:
|
||||||
std::vector<fc::uint160_t> &contained_transaction_message_ids) override {
|
std::vector<fc::uint160_t> &contained_transaction_message_ids) override {
|
||||||
|
|
||||||
// check point for the threads which may be cancled on application shutdown
|
// check point for the threads which may be cancled on application shutdown
|
||||||
if(!_running.load()) {
|
if (!_running.load()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,11 +62,14 @@ void verify_account_votes( const database& db, const account_options& options )
|
||||||
const auto& gpo = db.get_global_properties();
|
const auto& gpo = db.get_global_properties();
|
||||||
const auto& chain_params = gpo.parameters;
|
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,
|
FC_ASSERT( options.num_witness <= chain_params.maximum_witness_count,
|
||||||
"Voted for more witnesses than currently allowed (${c})", ("c", 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,
|
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) );
|
"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;
|
uint32_t max_vote_id = gpo.next_available_vote_id;
|
||||||
bool has_worker_votes = false;
|
bool has_worker_votes = false;
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,26 @@ void database::pay_sons()
|
||||||
const dynamic_global_property_object& dpo = get_dynamic_global_properties();
|
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
|
// 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()))) {
|
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<son_index>(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<std::reference_wrapper<const son_object>> sons = [this, &son_count]{
|
||||||
|
if(head_block_time() >= HARDFORK_SON3_TIME)
|
||||||
|
return sort_votable_objects<son_index>(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count));
|
||||||
|
else
|
||||||
|
return sort_votable_objects<son_index>(get_global_properties().parameters.maximum_son_count());
|
||||||
|
}();
|
||||||
// After SON2 HF
|
// After SON2 HF
|
||||||
uint64_t total_votes = 0;
|
uint64_t total_votes = 0;
|
||||||
for( const son_object& son : sons )
|
for( const son_object& son : sons )
|
||||||
|
|
@ -683,8 +702,12 @@ void database::update_active_sons()
|
||||||
}
|
}
|
||||||
|
|
||||||
const global_property_object& gpo = get_global_properties();
|
const global_property_object& gpo = get_global_properties();
|
||||||
const chain_parameters& cp = gpo.parameters;
|
const vector<std::reference_wrapper<const son_object>> sons = [this, &son_count]{
|
||||||
auto sons = sort_votable_objects<son_index>(cp.maximum_son_count());
|
if(head_block_time() >= HARDFORK_SON3_TIME)
|
||||||
|
return sort_votable_objects<son_index>(std::max(son_count*2+1, (size_t)get_chain_properties().immutable_parameters.min_son_count));
|
||||||
|
else
|
||||||
|
return sort_votable_objects<son_index>(get_global_properties().parameters.maximum_son_count());
|
||||||
|
}();
|
||||||
|
|
||||||
const auto& all_sons = get_index_type<son_index>().indices();
|
const auto& all_sons = get_index_type<son_index>().indices();
|
||||||
|
|
||||||
|
|
@ -2041,6 +2064,13 @@ void update_son_params(database& db)
|
||||||
gpo.parameters.extensions.value.maximum_son_count = 7;
|
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)
|
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
|
// same rationale as for witnesses
|
||||||
d._committee_count_histogram_buffer[offset] += voting_stake;
|
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);
|
d._son_count_histogram_buffer.size() - 1);
|
||||||
// votes for a number greater than maximum_son_count
|
// votes for a number greater than maximum_son_count
|
||||||
// are turned into votes for 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
|
// 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.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.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.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.son_account = p.parameters.extensions.value.son_account;
|
||||||
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
|
p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,11 @@ namespace graphene { namespace chain {
|
||||||
/// These are the fields which can be updated by the active authority.
|
/// These are the fields which can be updated by the active authority.
|
||||||
struct account_options
|
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-
|
/// 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
|
/// validated account activities. This field is here to prevent confusion if the active authority has zero or
|
||||||
/// multiple keys in it.
|
/// multiple keys in it.
|
||||||
|
|
@ -54,11 +59,11 @@ namespace graphene { namespace chain {
|
||||||
uint16_t num_committee = 0;
|
uint16_t num_committee = 0;
|
||||||
/// The number of active son members this account votes the blockchain should appoint
|
/// 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
|
/// 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
|
/// 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.
|
/// account's balance of core asset.
|
||||||
flat_set<vote_id_type> votes;
|
flat_set<vote_id_type> votes;
|
||||||
extensions_type extensions;
|
extension< ext > extensions;
|
||||||
|
|
||||||
/// Whether this account is voting
|
/// Whether this account is voting
|
||||||
inline bool is_voting() const
|
inline bool is_voting() const
|
||||||
|
|
@ -289,6 +294,7 @@ namespace graphene { namespace chain {
|
||||||
|
|
||||||
} } // graphene::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(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_TYPENAME( graphene::chain::account_whitelist_operation::account_listing)
|
||||||
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
|
FC_REFLECT_ENUM( graphene::chain::account_whitelist_operation::account_listing,
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ void account_options::validate() const
|
||||||
{
|
{
|
||||||
auto needed_witnesses = num_witness;
|
auto needed_witnesses = num_witness;
|
||||||
auto needed_committee = num_committee;
|
auto needed_committee = num_committee;
|
||||||
auto needed_sons = num_son;
|
auto needed_sons = num_son();
|
||||||
|
|
||||||
for( vote_id_type id : votes )
|
for( vote_id_type id : votes )
|
||||||
if( id.type() == vote_id_type::witness && needed_witnesses )
|
if( id.type() == vote_id_type::witness && needed_witnesses )
|
||||||
|
|
|
||||||
|
|
@ -2875,7 +2875,7 @@ public:
|
||||||
if (!votes_removed)
|
if (!votes_removed)
|
||||||
FC_THROW("Account ${account} is already not voting for SON ${son}", ("account", voting_account)("son", son));
|
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_operation account_update_op;
|
||||||
account_update_op.account = voting_account_object.id;
|
account_update_op.account = voting_account_object.id;
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,8 @@ BOOST_FIXTURE_TEST_CASE( select_top_fifteen_sons, cli_fixture )
|
||||||
global_property_object gpo;
|
global_property_object gpo;
|
||||||
|
|
||||||
gpo = con.wallet_api_ptr->get_global_properties();
|
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_type, string> sidechain_public_keys;
|
flat_map<sidechain_type, string> 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_TEST_MESSAGE("gpo: " << gpo.active_sons.size());
|
||||||
BOOST_CHECK(generate_maintenance_block());
|
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 ) {
|
} catch( fc::exception& e ) {
|
||||||
BOOST_TEST_MESSAGE("SON cli wallet tests exception");
|
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;
|
global_property_object gpo;
|
||||||
|
|
||||||
gpo = con.wallet_api_ptr->get_global_properties();
|
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_type, string> sidechain_public_keys;
|
flat_map<sidechain_type, string> sidechain_public_keys;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1040,16 +1040,13 @@ BOOST_FIXTURE_TEST_CASE( hardfork_son2_time, database_fixture )
|
||||||
|
|
||||||
generate_blocks(HARDFORK_SON3_TIME);
|
generate_blocks(HARDFORK_SON3_TIME);
|
||||||
// after this hardfork maximum son account should not reset the value
|
// after this hardfork maximum son account should not reset the value
|
||||||
// on 7 after maintenance interval anymore. So change the global parameters
|
// on 7 after maintenance interval anymore. It must be GRAPHENE_DEFAULT_MAX_SONS
|
||||||
// and check the value after maintenance interval
|
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maximum_son_count(), GRAPHENE_DEFAULT_MAX_SONS);
|
||||||
db.modify(db.get_global_properties(), [](global_property_object& p) {
|
|
||||||
p.parameters.extensions.value.maximum_son_count = 13;
|
|
||||||
});
|
|
||||||
|
|
||||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||||
generate_block();
|
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() }
|
} FC_LOG_AND_RETHROW() }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue