solution ...issues/#7 Allow vesting core tokens to vote and receive dividends

This commit is contained in:
Roman Olearski 2016-11-25 19:40:25 +01:00
parent f2c0157bb7
commit 81c9e98d7b
2 changed files with 76 additions and 14 deletions

View file

@ -727,14 +727,15 @@ void schedule_pending_dividend_balances(database& db,
const asset_dividend_data_object& dividend_data, const asset_dividend_data_object& dividend_data,
const fc::time_point_sec& current_head_block_time, const fc::time_point_sec& current_head_block_time,
const account_balance_index& balance_index, const account_balance_index& balance_index,
const vesting_balance_index& vesting_index,
const total_distributed_dividend_balance_object_index& distributed_dividend_balance_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) 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())); ("holder_asset", dividend_holder_asset_obj.symbol)("t", db.head_block_time()));
auto current_distribution_account_balance_range = auto current_distribution_account_balance_range =
balance_index.indices().get<by_account_asset>().equal_range(boost::make_tuple(dividend_data.dividend_distribution_account)); balance_index.indices().get<by_account_asset>().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<by_dividend_payout_asset>().equal_range(boost::make_tuple(dividend_holder_asset_obj.id)); distributed_dividend_balance_index.indices().get<by_dividend_payout_asset>().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 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 // 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 // get the list of accounts that hold nonzero balances of the dividend asset
auto holder_balances_begin = auto holder_balances_begin =
balance_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id)); balance_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id));
auto holder_balances_end = auto holder_balances_end =
balance_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(dividend_holder_asset_obj.id, share_type())); balance_index.indices().get<by_asset_balance>().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); uint32_t holder_account_count = std::distance(holder_balances_begin, holder_balances_end);
uint64_t distribution_base_fee = gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_base_fee; uint64_t distribution_base_fee = gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().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 // 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; uint64_t total_fee_per_asset_in_core = distribution_base_fee + holder_account_count * (uint64_t)distribution_fee_per_holder;
std::map<account_id_type, share_type> 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<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id));
auto vesting_balances_end =
vesting_index.indices().get<by_asset_balance>().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 current_distribution_account_balance_iter = current_distribution_account_balance_range.first;
auto previous_distribution_account_balance_iter = previous_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}", 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; 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)) 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) if (holder_balance_object.owner != dividend_data.dividend_distribution_account)
{
total_balance_of_dividend_asset += holder_balance_object.balance; 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 // 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 || while (current_distribution_account_balance_iter != current_distribution_account_balance_range.second ||
previous_distribution_account_balance_iter != previous_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 // 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)) 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); fc::uint128_t amount_to_credit(delta_balance.value);
amount_to_credit *= holder_balance_object.balance.value; amount_to_credit *= holder_balance.value;
amount_to_credit /= total_balance_of_dividend_asset.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()); share_type shares_to_credit((int64_t)amount_to_credit.to_uint64());
remaining_amount_to_distribute -= shares_to_credit; 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; pending_balance.pending_balance += shares_to_credit;
}); });
} }
}
for (const auto& pending_payout : pending_payout_balance_index.indices()) for (const auto& pending_payout : pending_payout_balance_index.indices())
dlog("Pending payout: ${account_name} -> ${amount}", dlog("Pending payout: ${account_name} -> ${amount}",
@ -928,7 +955,6 @@ void schedule_pending_dividend_balances(database& db,
dlog("Remaining balance not paid out: ${amount}", dlog("Remaining balance not paid out: ${amount}",
("amount", asset(remaining_amount_to_distribute, payout_asset_type))); ("amount", asset(remaining_amount_to_distribute, payout_asset_type)));
share_type distributed_amount = delta_balance - remaining_amount_to_distribute; share_type distributed_amount = delta_balance - remaining_amount_to_distribute;
if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second || if (previous_distribution_account_balance_iter == previous_distribution_account_balance_range.second ||
previous_distribution_account_balance_iter->dividend_payout_asset_type != payout_asset_type) 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())); ilog("In process_dividend_assets time ${time}", ("time", db.head_block_time()));
const account_balance_index& balance_index = db.get_index_type<account_balance_index>(); const account_balance_index& balance_index = db.get_index_type<account_balance_index>();
const vesting_balance_index& vbalance_index = db.get_index_type<vesting_balance_index>();
const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index = db.get_index_type<total_distributed_dividend_balance_object_index>(); const total_distributed_dividend_balance_object_index& distributed_dividend_balance_index = db.get_index_type<total_distributed_dividend_balance_object_index>();
const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index = db.get_index_type<pending_dividend_payout_balance_for_holder_object_index>(); const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index = db.get_index_type<pending_dividend_payout_balance_for_holder_object_index>();
@ -1030,7 +1057,7 @@ void process_dividend_assets(database& db)
fc::time_point_sec current_head_block_time = db.head_block_time(); 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, 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 && if (dividend_data.options.next_payout_time &&
db.head_block_time() >= *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 { struct vote_tally_helper {
database& d; database& d;
const global_property_object& props; const global_property_object& props;
std::map<account_id_type, share_type> vesting_amounts;
vote_tally_helper(database& d, const global_property_object& gpo) vote_tally_helper(database& d, const global_property_object& gpo)
: d(d), props(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._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._committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
d._total_voting_stake = 0; d._total_voting_stake = 0;
const vesting_balance_index& vesting_index = d.get_index_type<vesting_balance_index>();
auto vesting_balances_begin =
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(asset_id_type()));
auto vesting_balances_end =
vesting_index.indices().get<by_asset_balance>().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) { 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) + (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; + 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 ) for( vote_id_type id : opinion_account.options.votes )
{ {
uint32_t offset = id.instance(); uint32_t offset = id.instance();

View file

@ -31,8 +31,10 @@
#include <fc/uint128.hpp> #include <fc/uint128.hpp>
#include <algorithm> #include <algorithm>
#include <boost/multi_index/composite_key.hpp>
#define offset_d(i,f) (long(&(i)->f) - long(i))
#define offset_s(t,f) offset_d((t*)1000, f)
namespace graphene { namespace chain { namespace graphene { namespace chain {
using namespace graphene::db; using namespace graphene::db;
@ -171,13 +173,28 @@ namespace graphene { namespace chain {
* @ingroup object_index * @ingroup object_index
*/ */
struct by_account; struct by_account;
struct by_asset_balance;
typedef multi_index_container< typedef multi_index_container<
vesting_balance_object, vesting_balance_object,
indexed_by< indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >, ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
ordered_non_unique< tag<by_account>, ordered_non_unique< tag<by_account>,
member<vesting_balance_object, account_id_type, &vesting_balance_object::owner> member<vesting_balance_object, account_id_type, &vesting_balance_object::owner>
> >,
ordered_unique< tag<by_asset_balance>,
composite_key<
vesting_balance_object,
member_offset<vesting_balance_object, asset_id_type, (size_t) (offset_s(vesting_balance_object,balance) + offset_s(asset,asset_id))>,
member_offset<vesting_balance_object, share_type, (size_t) (offset_s(vesting_balance_object,balance) + offset_s(asset,amount))>
//member<vesting_balance_object, account_id_type, &vesting_balance_object::owner>
//member_offset<vesting_balance_object, account_id_type, (size_t) (offset_s(vesting_balance_object,owner))>
>,
composite_key_compare<
std::less< asset_id_type >,
std::greater< share_type >
//std::less< account_id_type >
>
>
> >
> vesting_balance_multi_index_type; > vesting_balance_multi_index_type;
/** /**