From 81c9e98d7b76854a48207f716f04d33be0f3feb3 Mon Sep 17 00:00:00 2001 From: Roman Olearski Date: Fri, 25 Nov 2016 19:40:25 +0100 Subject: [PATCH] solution ...issues/#7 Allow vesting core tokens to vote and receive dividends --- libraries/chain/db_maint.cpp | 69 +++++++++++++++---- .../graphene/chain/vesting_balance_object.hpp | 21 +++++- 2 files changed, 76 insertions(+), 14 deletions(-) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 4bbd1b77..eccd40b9 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -727,14 +727,15 @@ void schedule_pending_dividend_balances(database& db, const asset_dividend_data_object& dividend_data, const fc::time_point_sec& current_head_block_time, const account_balance_index& balance_index, + const vesting_balance_index& vesting_index, const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index, const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index) { - dlog("Processing dividend payments for dividend holder asset type ${holder_asset} at time ${t}", + dlog("Processing dividend payments for dividend holder asset type ${holder_asset} at time ${t}", ("holder_asset", dividend_holder_asset_obj.symbol)("t", db.head_block_time())); auto current_distribution_account_balance_range = balance_index.indices().get().equal_range(boost::make_tuple(dividend_data.dividend_distribution_account)); - auto previous_distribution_account_balance_range = + auto previous_distribution_account_balance_range = distributed_dividend_balance_index.indices().get().equal_range(boost::make_tuple(dividend_holder_asset_obj.id)); // the current range is now all current balances for the distribution account, sorted by asset_type // the previous range is now all previous balances for this account, sorted by asset type @@ -744,7 +745,7 @@ void schedule_pending_dividend_balances(database& db, // get the list of accounts that hold nonzero balances of the dividend asset auto holder_balances_begin = balance_index.indices().get().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id)); - auto holder_balances_end = + auto holder_balances_end = balance_index.indices().get().upper_bound(boost::make_tuple(dividend_holder_asset_obj.id, share_type())); uint32_t holder_account_count = std::distance(holder_balances_begin, holder_balances_end); uint64_t distribution_base_fee = gpo.parameters.current_fees->get().distribution_base_fee; @@ -752,6 +753,20 @@ void schedule_pending_dividend_balances(database& db, // the fee, in BTS, for distributing each asset in the account uint64_t total_fee_per_asset_in_core = distribution_base_fee + holder_account_count * (uint64_t)distribution_fee_per_holder; + std::map vesting_amounts; + // get only once a collection of accounts that hold nonzero vesting balances of the dividend asset + auto vesting_balances_begin = + vesting_index.indices().get().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id)); + auto vesting_balances_end = + vesting_index.indices().get().upper_bound(boost::make_tuple(dividend_holder_asset_obj.id, share_type())); + for (const vesting_balance_object& vesting_balance_obj : boost::make_iterator_range(vesting_balances_begin, vesting_balances_end)) + { + vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount; + dlog("Vesting balance for account: ${owner}, amount: ${amount}", + ("owner", vesting_balance_obj.owner(db).name) + ("amount", vesting_balance_obj.balance.amount)); + } + auto current_distribution_account_balance_iter = current_distribution_account_balance_range.first; auto previous_distribution_account_balance_iter = previous_distribution_account_balance_range.first; dlog("Current balances in distribution account: ${current}, Previous balances: ${previous}", @@ -764,9 +779,12 @@ void schedule_pending_dividend_balances(database& db, share_type total_balance_of_dividend_asset; for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_balances_begin, holder_balances_end)) if (holder_balance_object.owner != dividend_data.dividend_distribution_account) + { total_balance_of_dividend_asset += holder_balance_object.balance; - - + auto itr = vesting_amounts.find(holder_balance_object.owner); + if (itr != vesting_amounts.end()) + total_balance_of_dividend_asset += itr->second; + } // loop through all of the assets currently or previously held in the distribution account while (current_distribution_account_balance_iter != current_distribution_account_balance_range.second || previous_distribution_account_balance_iter != previous_distribution_account_balance_range.second) @@ -892,13 +910,21 @@ void schedule_pending_dividend_balances(database& db, // credit each account with their portion, don't send any back to the dividend distribution account for (const account_balance_object& holder_balance_object : boost::make_iterator_range(holder_balances_begin, holder_balances_end)) - if (holder_balance_object.owner != dividend_data.dividend_distribution_account && - holder_balance_object.balance.value) + { + if (holder_balance_object.owner == dividend_data.dividend_distribution_account) continue; + + auto holder_balance = holder_balance_object.balance; + + auto itr = vesting_amounts.find(holder_balance_object.owner); + if (itr != vesting_amounts.end()) + holder_balance += itr->second; + + if (holder_balance.value) { - fc::uint128_t amount_to_credit(delta_balance.value); - amount_to_credit *= holder_balance_object.balance.value; + fc::uint128_t amount_to_credit(delta_balance.value); + amount_to_credit *= holder_balance.value; amount_to_credit /= total_balance_of_dividend_asset.value; - //wdump((delta_balance.value)(holder_balance_object.balance)(total_balance_of_dividend_asset)); + wdump((delta_balance.value)(holder_balance)(total_balance_of_dividend_asset)); share_type shares_to_credit((int64_t)amount_to_credit.to_uint64()); remaining_amount_to_distribute -= shares_to_credit; @@ -920,6 +946,7 @@ void schedule_pending_dividend_balances(database& db, pending_balance.pending_balance += shares_to_credit; }); } + } for (const auto& pending_payout : pending_payout_balance_index.indices()) dlog("Pending payout: ${account_name} -> ${amount}", @@ -928,7 +955,6 @@ void schedule_pending_dividend_balances(database& db, dlog("Remaining balance not paid out: ${amount}", ("amount", asset(remaining_amount_to_distribute, payout_asset_type))); - share_type distributed_amount = delta_balance - remaining_amount_to_distribute; if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second || previous_distribution_account_balance_iter->dividend_payout_asset_type != payout_asset_type) @@ -1017,6 +1043,7 @@ void process_dividend_assets(database& db) ilog("In process_dividend_assets time ${time}", ("time", db.head_block_time())); const account_balance_index& balance_index = db.get_index_type(); + const vesting_balance_index& vbalance_index = db.get_index_type(); const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index = db.get_index_type(); const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index = db.get_index_type(); @@ -1030,7 +1057,7 @@ void process_dividend_assets(database& db) fc::time_point_sec current_head_block_time = db.head_block_time(); schedule_pending_dividend_balances(db, dividend_holder_asset_obj, dividend_data, current_head_block_time, - balance_index, distributed_dividend_balance_index, pending_payout_balance_index); + balance_index, vbalance_index, distributed_dividend_balance_index, pending_payout_balance_index); if (dividend_data.options.next_payout_time && db.head_block_time() >= *dividend_data.options.next_payout_time) { @@ -1180,6 +1207,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g struct vote_tally_helper { database& d; const global_property_object& props; + std::map vesting_amounts; vote_tally_helper(database& d, const global_property_object& gpo) : d(d), props(gpo) @@ -1188,6 +1216,19 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g d._witness_count_histogram_buffer.resize(props.parameters.maximum_witness_count / 2 + 1); d._committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1); d._total_voting_stake = 0; + + const vesting_balance_index& vesting_index = d.get_index_type(); + auto vesting_balances_begin = + vesting_index.indices().get().lower_bound(boost::make_tuple(asset_id_type())); + auto vesting_balances_end = + vesting_index.indices().get().upper_bound(boost::make_tuple(asset_id_type(), share_type())); + for (const vesting_balance_object& vesting_balance_obj : boost::make_iterator_range(vesting_balances_begin, vesting_balances_end)) + { + vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount; + dlog("Vesting balance for account: ${owner}, amount: ${amount}", + ("owner", vesting_balance_obj.owner(d).name) + ("amount", vesting_balance_obj.balance.amount)); + } } void operator()(const account_object& stake_account) { @@ -1206,6 +1247,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g + (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value: 0) + d.get_balance(stake_account.get_id(), asset_id_type()).amount.value; + auto itr = vesting_amounts.find(stake_account.id); + if (itr != vesting_amounts.end()) + voting_stake += itr->second.value; + for( vote_id_type id : opinion_account.options.votes ) { uint32_t offset = id.instance(); diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index 210c6c58..49b3464c 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -31,8 +31,10 @@ #include #include +#include - +#define offset_d(i,f) (long(&(i)->f) - long(i)) +#define offset_s(t,f) offset_d((t*)1000, f) namespace graphene { namespace chain { using namespace graphene::db; @@ -171,13 +173,28 @@ namespace graphene { namespace chain { * @ingroup object_index */ struct by_account; + struct by_asset_balance; typedef multi_index_container< vesting_balance_object, indexed_by< ordered_unique< tag, member< object, object_id_type, &object::id > >, ordered_non_unique< tag, member - > + >, + ordered_unique< tag, + composite_key< + vesting_balance_object, + member_offset, + member_offset + //member + //member_offset + >, + composite_key_compare< + std::less< asset_id_type >, + std::greater< share_type > + //std::less< account_id_type > + > + > > > vesting_balance_multi_index_type; /**