Revert "GPOS protocol"
This commit is contained in:
parent
2c86caacc5
commit
67616417b7
14 changed files with 64 additions and 1373 deletions
|
|
@ -161,8 +161,6 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
|
|||
vector<tournament_object> get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, tournament_state state);
|
||||
vector<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
|
||||
|
||||
// gpos
|
||||
gpos_info get_gpos_info(const account_id_type account) const;
|
||||
|
||||
//private:
|
||||
template<typename T>
|
||||
|
|
@ -2023,55 +2021,6 @@ vector<tournament_id_type> database_api_impl::get_registered_tournaments(account
|
|||
return tournament_ids;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// GPOS methods //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
graphene::app::gpos_info database_api::get_gpos_info(const account_id_type account) const
|
||||
{
|
||||
return my->get_gpos_info(account);
|
||||
|
||||
}
|
||||
graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type account) const
|
||||
{
|
||||
gpos_info result;
|
||||
result.vesting_factor = _db.calculate_vesting_factor(account(_db));
|
||||
|
||||
const auto& dividend_data = asset_id_type()(_db).dividend_data(_db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(_db);
|
||||
result.award = _db.get_balance(dividend_distribution_account, asset_id_type()(_db));
|
||||
|
||||
share_type total_amount;
|
||||
auto balance_type = vesting_balance_type::gpos;
|
||||
#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX
|
||||
// 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(asset_id_type(), balance_type));
|
||||
auto vesting_balances_end =
|
||||
vesting_index.indices().get<by_asset_balance>().upper_bound(boost::make_tuple(asset_id_type(), balance_type, share_type()));
|
||||
|
||||
for (const vesting_balance_object& vesting_balance_obj : boost::make_iterator_range(vesting_balances_begin, vesting_balances_end))
|
||||
{
|
||||
total_amount += vesting_balance_obj.balance.amount;
|
||||
}
|
||||
#else
|
||||
const vesting_balance_index& vesting_index = _db.get_index_type<vesting_balance_index>();
|
||||
const auto& vesting_balances = vesting_index.indices().get<by_id>();
|
||||
for (const vesting_balance_object& vesting_balance_obj : vesting_balances)
|
||||
{
|
||||
if (vesting_balance_obj.balance.asset_id == asset_id_type() && vesting_balance_obj.balance_type == balance_type)
|
||||
{
|
||||
total_amount += vesting_balance_obj.balance.amount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
result.total_amount = total_amount;
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Private methods //
|
||||
|
|
|
|||
|
|
@ -114,12 +114,6 @@ struct market_trade
|
|||
double value;
|
||||
};
|
||||
|
||||
struct gpos_info {
|
||||
double vesting_factor;
|
||||
asset award;
|
||||
share_type total_amount;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The database_api class implements the RPC API for the chain database.
|
||||
*
|
||||
|
|
@ -651,17 +645,7 @@ class database_api
|
|||
*/
|
||||
vector<tournament_id_type> get_registered_tournaments(account_id_type account_filter, uint32_t limit) const;
|
||||
|
||||
//////////
|
||||
// GPOS //
|
||||
//////////
|
||||
/**
|
||||
* @return account and network GPOS information
|
||||
*/
|
||||
gpos_info get_gpos_info(const account_id_type account) const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
std::shared_ptr< database_api_impl > my;
|
||||
};
|
||||
|
||||
|
|
@ -672,8 +656,6 @@ FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) );
|
|||
FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) );
|
||||
FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) );
|
||||
FC_REFLECT( graphene::app::market_trade, (date)(price)(amount)(value) );
|
||||
FC_REFLECT( graphene::app::gpos_info, (vesting_factor)(award)(total_amount) );
|
||||
|
||||
|
||||
FC_API(graphene::app::database_api,
|
||||
// Objects
|
||||
|
|
@ -783,7 +765,4 @@ FC_API(graphene::app::database_api,
|
|||
(get_tournaments_by_state)
|
||||
(get_tournaments )
|
||||
(get_registered_tournaments)
|
||||
|
||||
// gpos
|
||||
(get_gpos_info)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -725,120 +725,6 @@ void deprecate_annual_members( database& db )
|
|||
return;
|
||||
}
|
||||
|
||||
double database::calculate_vesting_factor(const account_object& stake_account)
|
||||
{
|
||||
// get last time voted form stats
|
||||
const auto &stats = stake_account.statistics(*this);
|
||||
fc::time_point_sec last_date_voted = stats.last_vote_time;
|
||||
|
||||
// get global data related to gpos
|
||||
const auto &gpo = this->get_global_properties();
|
||||
const auto vesting_period = gpo.parameters.gpos_period();
|
||||
const auto vesting_subperiod = gpo.parameters.gpos_subperiod();
|
||||
const auto period_start = fc::time_point_sec(gpo.parameters.gpos_period_start());
|
||||
|
||||
// variables needed
|
||||
const fc::time_point_sec period_end = period_start + vesting_period;
|
||||
const auto number_of_subperiods = vesting_period / vesting_subperiod;
|
||||
const auto now = this->head_block_time();
|
||||
double vesting_factor;
|
||||
auto seconds_since_period_start = now.sec_since_epoch() - period_start.sec_since_epoch();
|
||||
|
||||
FC_ASSERT(period_start <= now && now <= period_end);
|
||||
|
||||
// get in what sub period we are
|
||||
uint32_t current_subperiod = 0;
|
||||
std::list<uint32_t> period_list(number_of_subperiods);
|
||||
std::iota(period_list.begin(), period_list.end(), 1);
|
||||
|
||||
std::for_each(period_list.begin(), period_list.end(),[&](uint32_t period) {
|
||||
if(seconds_since_period_start >= vesting_subperiod * (period - 1) &&
|
||||
seconds_since_period_start < vesting_subperiod * period)
|
||||
current_subperiod = period;
|
||||
});
|
||||
|
||||
if(current_subperiod == 0 || current_subperiod > number_of_subperiods) return 0;
|
||||
if(last_date_voted < period_start) return 0;
|
||||
|
||||
double numerator = number_of_subperiods;
|
||||
|
||||
if(current_subperiod > 1) {
|
||||
std::list<uint32_t> subperiod_list(current_subperiod - 1);
|
||||
std::iota(subperiod_list.begin(), subperiod_list.end(), 2);
|
||||
subperiod_list.reverse();
|
||||
|
||||
for(auto subperiod: subperiod_list)
|
||||
{
|
||||
numerator--;
|
||||
|
||||
auto last_period_start = period_start + fc::seconds(vesting_subperiod * (subperiod - 1));
|
||||
auto last_period_end = period_start + fc::seconds(vesting_subperiod * (subperiod));
|
||||
|
||||
if (last_date_voted > last_period_start && last_date_voted <= last_period_end) {
|
||||
numerator++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vesting_factor = numerator / number_of_subperiods;
|
||||
return vesting_factor;
|
||||
}
|
||||
|
||||
share_type credit_account(database& db, const account_id_type owner_id, const std::string owner_name,
|
||||
share_type remaining_amount_to_distribute,
|
||||
const share_type shares_to_credit, const asset_id_type payout_asset_type,
|
||||
const pending_dividend_payout_balance_for_holder_object_index& pending_payout_balance_index,
|
||||
const asset_id_type dividend_id) {
|
||||
|
||||
//wdump((delta_balance.value)(holder_balance)(total_balance_of_dividend_asset));
|
||||
if (shares_to_credit.value) {
|
||||
|
||||
remaining_amount_to_distribute -= shares_to_credit;
|
||||
|
||||
dlog("Crediting account ${account} with ${amount}",
|
||||
("account", owner_name)
|
||||
("amount", asset(shares_to_credit, payout_asset_type)));
|
||||
auto pending_payout_iter =
|
||||
pending_payout_balance_index.indices().get<by_dividend_payout_account>().find(
|
||||
boost::make_tuple(dividend_id, payout_asset_type,
|
||||
owner_id));
|
||||
if (pending_payout_iter ==
|
||||
pending_payout_balance_index.indices().get<by_dividend_payout_account>().end())
|
||||
db.create<pending_dividend_payout_balance_for_holder_object>(
|
||||
[&](pending_dividend_payout_balance_for_holder_object &obj) {
|
||||
obj.owner = owner_id;
|
||||
obj.dividend_holder_asset_type = dividend_id;
|
||||
obj.dividend_payout_asset_type = payout_asset_type;
|
||||
obj.pending_balance = shares_to_credit;
|
||||
});
|
||||
else
|
||||
db.modify(*pending_payout_iter,
|
||||
[&](pending_dividend_payout_balance_for_holder_object &pending_balance) {
|
||||
pending_balance.pending_balance += shares_to_credit;
|
||||
});
|
||||
}
|
||||
return remaining_amount_to_distribute;
|
||||
}
|
||||
|
||||
void rolling_period_start(database& db)
|
||||
{
|
||||
if(db.head_block_time() >= HARDFORK_GPOS_TIME)
|
||||
{
|
||||
auto gpo = db.get_global_properties();
|
||||
auto period_start = db.get_global_properties().parameters.gpos_period_start();
|
||||
auto vesting_period = db.get_global_properties().parameters.gpos_period();
|
||||
|
||||
auto now = db.head_block_time();
|
||||
if(now.sec_since_epoch() > (period_start + vesting_period))
|
||||
{
|
||||
// roll
|
||||
db.modify(db.get_global_properties(), [now](global_property_object& p) {
|
||||
p.parameters.extensions.value.gpos_period_start = now.sec_since_epoch();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Schedules payouts from a dividend distribution account to the current holders of the
|
||||
// dividend-paying asset. This takes any deposits made to the dividend distribution account
|
||||
// since the last time it was called, and distributes them to the current owners of the
|
||||
|
|
@ -868,41 +754,34 @@ void schedule_pending_dividend_balances(database& db,
|
|||
balance_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(dividend_holder_asset_obj.id));
|
||||
auto holder_balances_end =
|
||||
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);
|
||||
uint64_t distribution_base_fee = gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_base_fee;
|
||||
uint32_t distribution_fee_per_holder = gpo.parameters.current_fees->get<asset_dividend_distribution_operation>().distribution_fee_per_holder;
|
||||
// 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<account_id_type, share_type> vesting_amounts;
|
||||
|
||||
auto balance_type = vesting_balance_type::unspecified;
|
||||
if(db.head_block_time() >= HARDFORK_GPOS_TIME)
|
||||
balance_type = vesting_balance_type::gpos;
|
||||
|
||||
uint32_t holder_account_count = 0;
|
||||
#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX
|
||||
// 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, balance_type));
|
||||
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, balance_type, share_type()));
|
||||
|
||||
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;
|
||||
++holder_account_count;
|
||||
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
|
||||
("owner", vesting_balance_obj.owner(db).name)
|
||||
("amount", 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));
|
||||
}
|
||||
#else
|
||||
// get only once a collection of accounts that hold nonzero vesting balances of the dividend asset
|
||||
const auto& vesting_balances = vesting_index.indices().get<by_id>();
|
||||
for (const vesting_balance_object& vesting_balance_obj : vesting_balances)
|
||||
{
|
||||
if (vesting_balance_obj.balance.asset_id == dividend_holder_asset_obj.id && vesting_balance_obj.balance.amount &&
|
||||
vesting_balance_object.balance_type == balance_type)
|
||||
if (vesting_balance_obj.balance.asset_id == dividend_holder_asset_obj.id && vesting_balance_obj.balance.amount)
|
||||
{
|
||||
vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount;
|
||||
++gpos_holder_account_count;
|
||||
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
|
||||
("owner", vesting_balance_obj.owner(db).name)
|
||||
("amount", vesting_balance_obj.balance.amount));
|
||||
|
|
@ -910,11 +789,6 @@ void schedule_pending_dividend_balances(database& db,
|
|||
}
|
||||
#endif
|
||||
|
||||
if(db.head_block_time() < HARDFORK_GPOS_TIME)
|
||||
holder_account_count = std::distance(holder_balances_begin, holder_balances_end);
|
||||
// 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;
|
||||
|
||||
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}",
|
||||
|
|
@ -925,23 +799,14 @@ void schedule_pending_dividend_balances(database& db,
|
|||
// accounts other than the distribution account (it would be silly to distribute dividends back to
|
||||
// the distribution account)
|
||||
share_type total_balance_of_dividend_asset;
|
||||
if(db.head_block_time() >= HARDFORK_GPOS_TIME && dividend_holder_asset_obj.symbol == GRAPHENE_SYMBOL) { // only core
|
||||
for (const vesting_balance_object &holder_balance_object : boost::make_iterator_range(vesting_balances_begin,
|
||||
vesting_balances_end))
|
||||
if (holder_balance_object.owner != dividend_data.dividend_distribution_account) {
|
||||
total_balance_of_dividend_asset += holder_balance_object.balance.amount;
|
||||
}
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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)
|
||||
|
|
@ -1065,68 +930,46 @@ void schedule_pending_dividend_balances(database& db,
|
|||
("total", total_balance_of_dividend_asset));
|
||||
share_type remaining_amount_to_distribute = delta_balance;
|
||||
|
||||
if(db.head_block_time() >= HARDFORK_GPOS_TIME && dividend_holder_asset_obj.symbol == GRAPHENE_SYMBOL) { // core only
|
||||
// credit each account with their portion, don't send any back to the dividend distribution account
|
||||
for (const vesting_balance_object &holder_balance_object : boost::make_iterator_range(
|
||||
vesting_balances_begin, vesting_balances_end)) {
|
||||
if (holder_balance_object.owner == dividend_data.dividend_distribution_account) continue;
|
||||
// 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) continue;
|
||||
|
||||
auto vesting_factor = db.calculate_vesting_factor(holder_balance_object.owner(db));
|
||||
auto holder_balance = holder_balance_object.balance;
|
||||
|
||||
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;
|
||||
|
||||
fc::uint128_t amount_to_credit(delta_balance.value);
|
||||
amount_to_credit *= holder_balance.amount.value;
|
||||
amount_to_credit /= total_balance_of_dividend_asset.value;
|
||||
share_type full_shares_to_credit((int64_t) amount_to_credit.to_uint64());
|
||||
share_type shares_to_credit = (uint64_t) floor(full_shares_to_credit.value * vesting_factor);
|
||||
fc::uint128_t amount_to_credit(delta_balance.value);
|
||||
amount_to_credit *= holder_balance.value;
|
||||
amount_to_credit /= total_balance_of_dividend_asset.value;
|
||||
share_type shares_to_credit((int64_t)amount_to_credit.to_uint64());
|
||||
if (shares_to_credit.value)
|
||||
{
|
||||
wdump((delta_balance.value)(holder_balance)(total_balance_of_dividend_asset));
|
||||
|
||||
if (shares_to_credit < full_shares_to_credit) {
|
||||
// Todo: sending results of decay to committee account, need to change to specified account
|
||||
dlog("Crediting committee_account with ${amount}",
|
||||
("amount", asset(full_shares_to_credit - shares_to_credit, payout_asset_type)));
|
||||
db.adjust_balance(dividend_data.dividend_distribution_account,
|
||||
-(full_shares_to_credit - shares_to_credit));
|
||||
db.adjust_balance(account_id_type(0), full_shares_to_credit - shares_to_credit);
|
||||
}
|
||||
remaining_amount_to_distribute -= shares_to_credit;
|
||||
|
||||
remaining_amount_to_distribute = credit_account(db,
|
||||
holder_balance_object.owner,
|
||||
holder_balance_object.owner(db).name,
|
||||
remaining_amount_to_distribute,
|
||||
shares_to_credit,
|
||||
payout_asset_type,
|
||||
pending_payout_balance_index,
|
||||
dividend_holder_asset_obj.id);
|
||||
dlog("Crediting account ${account} with ${amount}",
|
||||
("account", holder_balance_object.owner(db).name)
|
||||
("amount", asset(shares_to_credit, payout_asset_type)));
|
||||
auto pending_payout_iter =
|
||||
pending_payout_balance_index.indices().get<by_dividend_payout_account>().find(boost::make_tuple(dividend_holder_asset_obj.id, payout_asset_type, holder_balance_object.owner));
|
||||
if (pending_payout_iter == pending_payout_balance_index.indices().get<by_dividend_payout_account>().end())
|
||||
db.create<pending_dividend_payout_balance_for_holder_object>( [&]( pending_dividend_payout_balance_for_holder_object& obj ){
|
||||
obj.owner = holder_balance_object.owner;
|
||||
obj.dividend_holder_asset_type = dividend_holder_asset_obj.id;
|
||||
obj.dividend_payout_asset_type = payout_asset_type;
|
||||
obj.pending_balance = shares_to_credit;
|
||||
});
|
||||
else
|
||||
db.modify(*pending_payout_iter, [&]( pending_dividend_payout_balance_for_holder_object& pending_balance ){
|
||||
pending_balance.pending_balance += shares_to_credit;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 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) 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;
|
||||
|
||||
fc::uint128_t amount_to_credit(delta_balance.value);
|
||||
amount_to_credit *= holder_balance.value;
|
||||
amount_to_credit /= total_balance_of_dividend_asset.value;
|
||||
share_type shares_to_credit((int64_t) amount_to_credit.to_uint64());
|
||||
|
||||
remaining_amount_to_distribute = credit_account(db,
|
||||
holder_balance_object.owner,
|
||||
holder_balance_object.owner(db).name,
|
||||
remaining_amount_to_distribute,
|
||||
shares_to_credit,
|
||||
payout_asset_type,
|
||||
pending_payout_balance_index,
|
||||
dividend_holder_asset_obj.id);
|
||||
}
|
||||
}
|
||||
for (const auto& pending_payout : pending_payout_balance_index.indices())
|
||||
if (pending_payout.pending_balance.value)
|
||||
dlog("Pending payout: ${account_name} -> ${amount}",
|
||||
|
|
@ -1386,8 +1229,6 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
|||
distribute_fba_balances(*this);
|
||||
create_buyback_orders(*this);
|
||||
|
||||
rolling_period_start(*this);
|
||||
|
||||
process_dividend_assets(*this);
|
||||
|
||||
struct vote_tally_helper {
|
||||
|
|
@ -1403,28 +1244,24 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
|||
d._committee_count_histogram_buffer.resize(props.parameters.maximum_committee_count / 2 + 1);
|
||||
d._total_voting_stake = 0;
|
||||
|
||||
auto balance_type = vesting_balance_type::unspecified;
|
||||
if(d.head_block_time() >= HARDFORK_GPOS_TIME)
|
||||
balance_type = vesting_balance_type::gpos;
|
||||
|
||||
const vesting_balance_index& vesting_index = d.get_index_type<vesting_balance_index>();
|
||||
#ifdef USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX
|
||||
auto vesting_balances_begin =
|
||||
vesting_index.indices().get<by_asset_balance>().lower_bound(boost::make_tuple(asset_id_type(), balance_type));
|
||||
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(), balance_type, share_type()));
|
||||
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));
|
||||
//dlog("Vesting balance for account: ${owner}, amount: ${amount}",
|
||||
// ("owner", vesting_balance_obj.owner(d).name)
|
||||
// ("amount", vesting_balance_obj.balance.amount));
|
||||
}
|
||||
#else
|
||||
const auto& vesting_balances = vesting_index.indices().get<by_id>();
|
||||
for (const vesting_balance_object& vesting_balance_obj : vesting_balances)
|
||||
{
|
||||
if (vesting_balance_obj.balance.asset_id == asset_id_type() && vesting_balance_obj.balance.amount && vesting_balance_obj.balance_type == balance_type)
|
||||
if (vesting_balance_obj.balance.asset_id == asset_id_type() && vesting_balance_obj.balance.amount)
|
||||
{
|
||||
vesting_amounts[vesting_balance_obj.owner] += vesting_balance_obj.balance.amount;
|
||||
dlog("Vesting balance for account: ${owner}, amount: ${amount}",
|
||||
|
|
@ -1452,27 +1289,13 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
|
|||
const account_object& opinion_account = *opinion_account_ptr;
|
||||
|
||||
const auto& stats = stake_account.statistics(d);
|
||||
uint64_t voting_stake = 0;
|
||||
uint64_t voting_stake = stats.total_core_in_orders.value
|
||||
+ (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;
|
||||
|
||||
if(d.head_block_time() >= HARDFORK_GPOS_TIME)
|
||||
{
|
||||
if (itr == vesting_amounts.end())
|
||||
return;
|
||||
|
||||
auto vesting_factor = d.calculate_vesting_factor(stake_account);
|
||||
voting_stake = (uint64_t)floor(voting_stake * vesting_factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
voting_stake += stats.total_core_in_orders.value
|
||||
+ (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;
|
||||
}
|
||||
|
||||
for( vote_id_type id : opinion_account.options.votes )
|
||||
{
|
||||
uint32_t offset = id.instance();
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
// GPOS HARDFORK Friday, March 15, 2019 11:57:28 PM
|
||||
#ifndef HARDFORK_GPOS_TIME
|
||||
#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1552694248 ))
|
||||
#endif
|
||||
|
|
@ -151,7 +151,7 @@
|
|||
#define GRAPHENE_RECENTLY_MISSED_COUNT_INCREMENT 4
|
||||
#define GRAPHENE_RECENTLY_MISSED_COUNT_DECREMENT 3
|
||||
|
||||
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.2"
|
||||
#define GRAPHENE_CURRENT_DB_VERSION "PPY2.1"
|
||||
|
||||
#define GRAPHENE_IRREVERSIBLE_THRESHOLD (70 * GRAPHENE_1_PERCENT)
|
||||
|
||||
|
|
@ -226,5 +226,3 @@
|
|||
#define TOURNAMENT_MAX_WHITELIST_LENGTH 1000
|
||||
#define TOURNAMENT_MAX_START_TIME_IN_FUTURE (60*60*24*7*4) // 1 month
|
||||
#define TOURNAMENT_MAX_START_DELAY (60*60*24*7) // 1 week
|
||||
#define GPOS_PERIOD (60*60*24*30*6) // 6 months
|
||||
#define GPOS_SUBPERIOD (60*60*24*30) // 1 month
|
||||
|
|
|
|||
|
|
@ -498,11 +498,8 @@ namespace graphene { namespace chain {
|
|||
void update_active_witnesses();
|
||||
void update_active_committee_members();
|
||||
void update_worker_votes();
|
||||
public:
|
||||
double calculate_vesting_factor(const account_object& stake_account);
|
||||
|
||||
|
||||
template<class... Types>
|
||||
template<class... Types>
|
||||
void perform_account_maintenance(std::tuple<Types...> helpers);
|
||||
///@}
|
||||
///@}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@
|
|||
#include <graphene/chain/protocol/types.hpp>
|
||||
#include <fc/smart_ref_fwd.hpp>
|
||||
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
namespace graphene { namespace chain { struct fee_schedule; } }
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
|
@ -39,10 +37,6 @@ namespace graphene { namespace chain {
|
|||
optional< uint16_t > betting_rake_fee_percentage;
|
||||
optional< flat_map<bet_multiplier_type, bet_multiplier_type> > permitted_betting_odds_increments;
|
||||
optional< uint16_t > live_betting_delay_time;
|
||||
/* gpos parameters */
|
||||
optional < uint32_t > gpos_period;
|
||||
optional < uint32_t > gpos_subperiod;
|
||||
optional < uint32_t > gpos_period_start;
|
||||
};
|
||||
|
||||
struct chain_parameters
|
||||
|
|
@ -112,15 +106,6 @@ namespace graphene { namespace chain {
|
|||
inline uint16_t live_betting_delay_time()const {
|
||||
return extensions.value.live_betting_delay_time.valid() ? *extensions.value.live_betting_delay_time : GRAPHENE_DEFAULT_LIVE_BETTING_DELAY_TIME;
|
||||
}
|
||||
inline uint32_t gpos_period()const {
|
||||
return extensions.value.gpos_period.valid() ? *extensions.value.gpos_period : GPOS_PERIOD; /// total seconds of current gpos period
|
||||
}
|
||||
inline uint32_t gpos_subperiod()const {
|
||||
return extensions.value.gpos_subperiod.valid() ? *extensions.value.gpos_subperiod : GPOS_SUBPERIOD; /// gpos_period % gpos_subperiod = 0
|
||||
}
|
||||
inline uint32_t gpos_period_start()const {
|
||||
return extensions.value.gpos_period_start.valid() ? *extensions.value.gpos_period_start : HARDFORK_GPOS_TIME.sec_since_epoch(); /// current period start date
|
||||
}
|
||||
};
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
@ -131,9 +116,6 @@ FC_REFLECT( graphene::chain::parameter_extension,
|
|||
(betting_rake_fee_percentage)
|
||||
(permitted_betting_odds_increments)
|
||||
(live_betting_delay_time)
|
||||
(gpos_period)
|
||||
(gpos_subperiod)
|
||||
(gpos_period_start)
|
||||
)
|
||||
|
||||
FC_REFLECT( graphene::chain::chain_parameters,
|
||||
|
|
|
|||
|
|
@ -24,9 +24,7 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
enum class vesting_balance_type { unspecified, gpos };
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
struct linear_vesting_policy_initializer
|
||||
{
|
||||
|
|
@ -74,7 +72,6 @@ namespace graphene { namespace chain {
|
|||
account_id_type owner; ///< Who is able to withdraw the balance
|
||||
asset amount;
|
||||
vesting_policy_initializer policy;
|
||||
vesting_balance_type balance_type;
|
||||
|
||||
account_id_type fee_payer()const { return creator; }
|
||||
void validate()const
|
||||
|
|
@ -115,11 +112,9 @@ namespace graphene { namespace chain {
|
|||
FC_REFLECT( graphene::chain::vesting_balance_create_operation::fee_parameters_type, (fee) )
|
||||
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type, (fee) )
|
||||
|
||||
FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy)(balance_type) )
|
||||
FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy) )
|
||||
FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount) )
|
||||
|
||||
FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) )
|
||||
FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer )
|
||||
|
||||
FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (unspecified)(gpos) )
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <graphene/chain/protocol/asset.hpp>
|
||||
#include <graphene/chain/protocol/vesting.hpp>
|
||||
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
|
|
@ -145,9 +143,6 @@ namespace graphene { namespace chain {
|
|||
/// The vesting policy stores details on when funds vest, and controls when they may be withdrawn
|
||||
vesting_policy policy;
|
||||
|
||||
/// We can have 2 types of vesting, gpos and all the rest
|
||||
vesting_balance_type balance_type = vesting_balance_type::unspecified;
|
||||
|
||||
vesting_balance_object() {}
|
||||
|
||||
///@brief Deposit amount into vesting balance, requiring it to vest before withdrawal
|
||||
|
|
@ -190,14 +185,12 @@ namespace graphene { namespace chain {
|
|||
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<vesting_balance_object, vesting_balance_type, &vesting_balance_object::balance_type>,
|
||||
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::less< vesting_balance_type >,
|
||||
std::greater< share_type >
|
||||
//std::less< account_id_type >
|
||||
>
|
||||
|
|
@ -231,5 +224,4 @@ FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::objec
|
|||
(owner)
|
||||
(balance)
|
||||
(policy)
|
||||
(balance_type)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -135,11 +135,6 @@ struct proposal_operation_hardfork_visitor
|
|||
FC_ASSERT( block_time >= HARDFORK_1000_TIME, "event_update_status_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const vesting_balance_create_operation &vbco) const {
|
||||
if(block_time < HARDFORK_GPOS_TIME)
|
||||
FC_ASSERT( vbco.balance_type == vesting_balance_type::unspecified, "balance_type in vesting create not allowed yet!" );
|
||||
}
|
||||
|
||||
// loop and self visit in proposals
|
||||
void operator()(const proposal_create_operation &v) const {
|
||||
for (const op_wrapper &op : v.proposed_ops)
|
||||
|
|
|
|||
|
|
@ -42,9 +42,6 @@ void_result vesting_balance_create_evaluator::do_evaluate( const vesting_balance
|
|||
FC_ASSERT( d.get_balance( creator_account.id, op.amount.asset_id ) >= op.amount );
|
||||
FC_ASSERT( !op.amount.asset_id(d).is_transfer_restricted() );
|
||||
|
||||
if(d.head_block_time() < HARDFORK_GPOS_TIME) // Todo: can be removed after gpos hf time pass
|
||||
FC_ASSERT( op.balance_type == vesting_balance_type::unspecified);
|
||||
|
||||
return void_result();
|
||||
} FC_CAPTURE_AND_RETHROW( (op) ) }
|
||||
|
||||
|
|
@ -95,20 +92,7 @@ object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance
|
|||
// If making changes to this logic, check if those changes should also be made there as well.
|
||||
obj.owner = op.owner;
|
||||
obj.balance = op.amount;
|
||||
if(op.balance_type == vesting_balance_type::gpos)
|
||||
{
|
||||
const auto &gpo = d.get_global_properties();
|
||||
// forcing gpos policy
|
||||
linear_vesting_policy p;
|
||||
p.begin_timestamp = now;
|
||||
p.vesting_cliff_seconds = gpo.parameters.gpos_subperiod();
|
||||
p.vesting_duration_seconds = gpo.parameters.gpos_subperiod();
|
||||
obj.policy = p;
|
||||
}
|
||||
else {
|
||||
op.policy.visit(init_policy_visitor(obj.policy, op.amount.amount, now));
|
||||
}
|
||||
obj.balance_type = op.balance_type;
|
||||
op.policy.visit( init_policy_visitor( obj.policy, op.amount.amount, now ) );
|
||||
} );
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1795,20 +1795,6 @@ class wallet_api
|
|||
rock_paper_scissors_gesture gesture,
|
||||
bool broadcast);
|
||||
|
||||
/** Create a vesting balance including gpos vesting balance after HARDFORK_GPOS_TIME
|
||||
* @param owner vesting balance owner and creator
|
||||
* @param amount amount to vest
|
||||
* @param asset_symbol the symbol of the asset to vest
|
||||
* @param is_gpos True if the balance is of gpos type
|
||||
* @param broadcast true if you wish to broadcast the transaction
|
||||
* @return the signed version of the transaction
|
||||
*/
|
||||
signed_transaction create_vesting_balance(string owner,
|
||||
string amount,
|
||||
string asset_symbol,
|
||||
bool is_gpos,
|
||||
bool broadcast);
|
||||
|
||||
void dbg_make_uia(string creator, string symbol);
|
||||
void dbg_make_mia(string creator, string symbol);
|
||||
void dbg_push_blocks( std::string src_filename, uint32_t count );
|
||||
|
|
@ -2045,7 +2031,6 @@ FC_API( graphene::wallet::wallet_api,
|
|||
(tournament_join)
|
||||
(tournament_leave)
|
||||
(rps_throw)
|
||||
(create_vesting_balance)
|
||||
(get_upcoming_tournaments)
|
||||
(get_tournaments)
|
||||
(get_tournaments_by_state)
|
||||
|
|
|
|||
|
|
@ -5756,37 +5756,6 @@ signed_transaction wallet_api::rps_throw(game_id_type game_id,
|
|||
return my->sign_transaction( tx, broadcast );
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_vesting_balance(string owner,
|
||||
string amount,
|
||||
string asset_symbol,
|
||||
bool is_gpos,
|
||||
bool broadcast)
|
||||
{
|
||||
FC_ASSERT( !is_locked() );
|
||||
|
||||
account_object owner_account = get_account(owner);
|
||||
account_id_type owner_id = owner_account.id;
|
||||
|
||||
fc::optional<asset_object> asset_obj = get_asset(asset_symbol);
|
||||
|
||||
auto type = vesting_balance_type::unspecified;
|
||||
if(is_gpos)
|
||||
type = vesting_balance_type::gpos;
|
||||
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = owner_id;
|
||||
op.owner = owner_id;
|
||||
op.amount = asset_obj->amount_from_string(amount);
|
||||
op.balance_type = type;
|
||||
|
||||
signed_transaction trx;
|
||||
trx.operations.push_back(op);
|
||||
my->set_operation_fees( trx, my->_remote_db->get_global_properties().parameters.current_fees );
|
||||
trx.validate();
|
||||
|
||||
return my->sign_transaction( trx, broadcast );
|
||||
}
|
||||
|
||||
// default ctor necessary for FC_REFLECT
|
||||
signed_block_with_info::signed_block_with_info()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,953 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 oxarbitrage and contributors.
|
||||
*
|
||||
* The MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
|
||||
#include <graphene/chain/balance_object.hpp>
|
||||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/committee_member_object.hpp>
|
||||
#include <graphene/chain/worker_object.hpp>
|
||||
|
||||
#include "../common/database_fixture.hpp"
|
||||
|
||||
#include <graphene/app/database_api.hpp>
|
||||
|
||||
using namespace graphene::chain;
|
||||
using namespace graphene::chain::test;
|
||||
|
||||
struct gpos_fixture: database_fixture
|
||||
{
|
||||
const worker_object& create_worker( const account_id_type owner, const share_type daily_pay,
|
||||
const fc::microseconds& duration ) {
|
||||
worker_create_operation op;
|
||||
op.owner = owner;
|
||||
op.daily_pay = daily_pay;
|
||||
op.initializer = vesting_balance_worker_initializer(1);
|
||||
op.work_begin_date = db.head_block_time();
|
||||
op.work_end_date = op.work_begin_date + duration;
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
trx.validate();
|
||||
processed_transaction ptx = db.push_transaction(trx, ~0);
|
||||
trx.clear();
|
||||
return db.get<worker_object>(ptx.operation_results[0].get<object_id_type>());
|
||||
}
|
||||
const vesting_balance_object& create_vesting(const account_id_type owner, const asset amount,
|
||||
const vesting_balance_type type)
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = owner;
|
||||
op.owner = owner;
|
||||
op.amount = amount;
|
||||
op.balance_type = type;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
return db.get<vesting_balance_object>(ptx.operation_results[0].get<object_id_type>());
|
||||
}
|
||||
|
||||
void update_payout_interval(std::string asset_name, fc::time_point start, uint32_t interval)
|
||||
{
|
||||
auto dividend_holder_asset_object = get_asset(asset_name);
|
||||
asset_update_dividend_operation op;
|
||||
op.issuer = dividend_holder_asset_object.issuer;
|
||||
op.asset_to_update = dividend_holder_asset_object.id;
|
||||
op.new_options.next_payout_time = start;
|
||||
op.new_options.payout_interval = interval;
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX(db, trx, ~0);
|
||||
trx.operations.clear();
|
||||
}
|
||||
|
||||
void update_gpos_global(uint32_t vesting_period, uint32_t vesting_subperiod, fc::time_point_sec period_start)
|
||||
{
|
||||
db.modify(db.get_global_properties(), [vesting_period, vesting_subperiod, period_start](global_property_object& p) {
|
||||
p.parameters.extensions.value.gpos_period = vesting_period;
|
||||
p.parameters.extensions.value.gpos_subperiod = vesting_subperiod;
|
||||
p.parameters.extensions.value.gpos_period_start = period_start.sec_since_epoch();
|
||||
});
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), vesting_period);
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), vesting_subperiod);
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), period_start.sec_since_epoch());
|
||||
}
|
||||
void vote_for(const account_id_type account_id, const vote_id_type vote_for, const fc::ecc::private_key& key)
|
||||
{
|
||||
account_update_operation op;
|
||||
op.account = account_id;
|
||||
op.new_options = account_id(db).options;
|
||||
op.new_options->votes.insert(vote_for);
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
trx.validate();
|
||||
sign(trx, key);
|
||||
PUSH_TX(db, trx);
|
||||
trx.clear();
|
||||
}
|
||||
void fill_reserve_pool(const account_id_type account_id, asset amount)
|
||||
{
|
||||
asset_reserve_operation op;
|
||||
op.payer = account_id;
|
||||
op.amount_to_reserve = amount;
|
||||
trx.operations.push_back(op);
|
||||
trx.validate();
|
||||
set_expiration(db, trx);
|
||||
PUSH_TX( db, trx, ~0 );
|
||||
trx.clear();
|
||||
}
|
||||
|
||||
void advance_x_maint(int periods)
|
||||
{
|
||||
for(int i=0; i<periods; i++)
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BOOST_FIXTURE_TEST_SUITE( gpos_tests, gpos_fixture )
|
||||
|
||||
BOOST_AUTO_TEST_CASE(gpos_vesting_type)
|
||||
{
|
||||
ACTORS((alice)(bob));
|
||||
try
|
||||
{
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
// send some asset to alice and bob
|
||||
transfer( committee_account, alice_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, bob_id, core.amount( 1000 ) );
|
||||
|
||||
generate_block();
|
||||
|
||||
// gpos balance creation is not allowed before HF
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = alice_id;
|
||||
op.owner = alice_id;
|
||||
op.amount = core.amount(100);
|
||||
op.balance_type = vesting_balance_type::gpos;
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
GRAPHENE_REQUIRE_THROW( PUSH_TX(db, trx, ~0), fc::exception );
|
||||
trx.clear();
|
||||
|
||||
// pass hardfork
|
||||
generate_blocks( HARDFORK_GPOS_TIME );
|
||||
generate_block();
|
||||
|
||||
// repeat operation
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
processed_transaction ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
|
||||
generate_block();
|
||||
|
||||
auto alice_vesting = db.get<vesting_balance_object>(ptx.operation_results[0].get<object_id_type>());
|
||||
|
||||
// check created vesting amount and policy
|
||||
BOOST_CHECK_EQUAL(alice_vesting.balance.amount.value, 100);
|
||||
BOOST_CHECK_EQUAL(alice_vesting.policy.get<linear_vesting_policy>().vesting_duration_seconds,
|
||||
db.get_global_properties().parameters.gpos_subperiod());
|
||||
BOOST_CHECK_EQUAL(alice_vesting.policy.get<linear_vesting_policy>().vesting_cliff_seconds,
|
||||
db.get_global_properties().parameters.gpos_subperiod());
|
||||
|
||||
// bob creates a gpos vesting with his custom policy
|
||||
{
|
||||
vesting_balance_create_operation op;
|
||||
op.creator = bob_id;
|
||||
op.owner = bob_id;
|
||||
op.amount = core.amount(200);
|
||||
op.balance_type = vesting_balance_type::gpos;
|
||||
op.policy = cdd_vesting_policy_initializer{ 60*60*24 };
|
||||
|
||||
trx.operations.push_back(op);
|
||||
set_expiration(db, trx);
|
||||
ptx = PUSH_TX(db, trx, ~0);
|
||||
trx.clear();
|
||||
}
|
||||
auto bob_vesting = db.get<vesting_balance_object>(ptx.operation_results[0].get<object_id_type>());
|
||||
|
||||
generate_block();
|
||||
|
||||
// policy is not the one defined by the user but default
|
||||
BOOST_CHECK_EQUAL(bob_vesting.balance.amount.value, 200);
|
||||
BOOST_CHECK_EQUAL(bob_vesting.policy.get<linear_vesting_policy>().vesting_duration_seconds,
|
||||
db.get_global_properties().parameters.gpos_subperiod());
|
||||
BOOST_CHECK_EQUAL(bob_vesting.policy.get<linear_vesting_policy>().vesting_cliff_seconds,
|
||||
db.get_global_properties().parameters.gpos_subperiod());
|
||||
|
||||
}
|
||||
catch (fc::exception& e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( dividends )
|
||||
{
|
||||
ACTORS((alice)(bob));
|
||||
try
|
||||
{
|
||||
// move to 1 week before hardfork
|
||||
generate_blocks( HARDFORK_GPOS_TIME - fc::days(7) );
|
||||
generate_block();
|
||||
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
// all core coins are in the committee_account
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 1000000000000000);
|
||||
|
||||
// transfer half of the total stake to alice so not all the dividends will go to the committee_account
|
||||
transfer( committee_account, alice_id, core.amount( 500000000000000 ) );
|
||||
generate_block();
|
||||
|
||||
// send some to bob
|
||||
transfer( committee_account, bob_id, core.amount( 1000 ) );
|
||||
generate_block();
|
||||
|
||||
// committee balance
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 499999999999000);
|
||||
|
||||
// alice balance
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 500000000000000);
|
||||
|
||||
// bob balance
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 1000);
|
||||
|
||||
// get core asset object
|
||||
const auto& dividend_holder_asset_object = get_asset(GRAPHENE_SYMBOL);
|
||||
|
||||
// by default core token pays dividends once per month
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 2592000); // 30 days
|
||||
|
||||
// update the payout interval for speed purposes of the test
|
||||
update_payout_interval(core.symbol, fc::time_point::now() + fc::minutes(1), 60 * 60 * 24); // 1 day
|
||||
|
||||
generate_block();
|
||||
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 86400); // 1 day now
|
||||
|
||||
// get the dividend distribution account
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
|
||||
// transfering some coins to distribution account.
|
||||
// simulating the blockchain haves some dividends to pay.
|
||||
transfer( committee_account, dividend_distribution_account.id, core.amount( 100 ) );
|
||||
generate_block();
|
||||
|
||||
// committee balance
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 499999999998900 );
|
||||
|
||||
// distribution account balance
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, core), 100);
|
||||
|
||||
// get when is the next payout time as we need to advance there
|
||||
auto next_payout_time = dividend_data.options.next_payout_time;
|
||||
|
||||
// advance to next payout
|
||||
generate_blocks(*next_payout_time);
|
||||
|
||||
// advance to next maint after payout time arrives
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// check balances now, dividends are paid "normally"
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 499999999998949 );
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 500000000000050 );
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 1000 );
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, core), 1);
|
||||
|
||||
// advance to hardfork
|
||||
generate_blocks( HARDFORK_GPOS_TIME );
|
||||
|
||||
// advance to next maint
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// send 99 to the distribution account so it will have 100 PPY again to share
|
||||
transfer( committee_account, dividend_distribution_account.id, core.amount( 99 ) );
|
||||
generate_block();
|
||||
|
||||
// get when is the next payout time as we need to advance there
|
||||
next_payout_time = dividend_data.options.next_payout_time;
|
||||
|
||||
// advance to next payout
|
||||
generate_blocks(*next_payout_time);
|
||||
|
||||
// advance to next maint
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// make sure no dividends were paid "normally"
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 499999999998850 );
|
||||
BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 500000000000050 );
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 1000 );
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, core), 100);
|
||||
|
||||
// create vesting balance
|
||||
create_vesting(bob_id, core.amount(100), vesting_balance_type::gpos);
|
||||
|
||||
// need to vote to get paid
|
||||
auto witness1 = witness_id_type(1)(db);
|
||||
vote_for(bob_id, witness1.vote_id, bob_private_key);
|
||||
|
||||
generate_block();
|
||||
|
||||
// check balances
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 900 );
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, core), 100);
|
||||
|
||||
// advance to next payout
|
||||
generate_blocks(*next_payout_time);
|
||||
|
||||
// advance to next maint
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// check balances, dividends paid to bob
|
||||
BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 1000 );
|
||||
BOOST_CHECK_EQUAL(get_balance(dividend_distribution_account, core), 0);
|
||||
}
|
||||
catch (fc::exception& e)
|
||||
{
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( voting )
|
||||
{
|
||||
ACTORS((alice)(bob));
|
||||
try {
|
||||
|
||||
// move to hardfork
|
||||
generate_blocks( HARDFORK_GPOS_TIME );
|
||||
generate_block();
|
||||
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
// send some asset to alice and bob
|
||||
transfer( committee_account, alice_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, bob_id, core.amount( 1000 ) );
|
||||
generate_block();
|
||||
|
||||
// default maintenance_interval is 1 day
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maintenance_interval, 86400);
|
||||
|
||||
// add some vesting to alice and bob
|
||||
create_vesting(alice_id, core.amount(100), vesting_balance_type::gpos);
|
||||
create_vesting(bob_id, core.amount(100), vesting_balance_type::gpos);
|
||||
generate_block();
|
||||
|
||||
// default gpos values
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), 15552000);
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), 2592000);
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), HARDFORK_GPOS_TIME.sec_since_epoch());
|
||||
|
||||
// update default gpos for test speed
|
||||
auto now = db.head_block_time();
|
||||
// 5184000 = 60x60x24x60 = 60 days
|
||||
// 864000 = 60x60x24x10 = 10 days
|
||||
update_gpos_global(5184000, 864000, now);
|
||||
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), 5184000);
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), 864000);
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch());
|
||||
// end global changes
|
||||
|
||||
generate_block();
|
||||
|
||||
// no votes for witness 1
|
||||
auto witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
|
||||
// no votes for witness 2
|
||||
auto witness2 = witness_id_type(2)(db);
|
||||
BOOST_CHECK_EQUAL(witness2.total_votes, 0);
|
||||
|
||||
// vote for witness1
|
||||
vote_for(alice_id, witness1.vote_id, alice_private_key);
|
||||
|
||||
// go to maint
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// vote is the same as amount in the first subperiod since voting
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 100);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// vote decay as time pass
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 83);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// decay more
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 66);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// more
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 50);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// more
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 33);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// more
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 16);
|
||||
|
||||
// we are still in gpos period 1
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch());
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// until 0
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
|
||||
// a new GPOS period is in but vote from user is before the start so his voting power is 0
|
||||
now = db.head_block_time();
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch());
|
||||
|
||||
generate_block();
|
||||
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
|
||||
// we are in the second GPOS period, at subperiod 2, lets vote here
|
||||
vote_for(bob_id, witness2.vote_id, bob_private_key);
|
||||
generate_block();
|
||||
|
||||
// go to maint
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
witness1 = witness_id_type(1)(db);
|
||||
witness2 = witness_id_type(2)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
BOOST_CHECK_EQUAL(witness2.total_votes, 100);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
witness1 = witness_id_type(1)(db);
|
||||
witness2 = witness_id_type(2)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
BOOST_CHECK_EQUAL(witness2.total_votes, 83);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
witness1 = witness_id_type(1)(db);
|
||||
witness2 = witness_id_type(2)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
BOOST_CHECK_EQUAL(witness2.total_votes, 66);
|
||||
|
||||
// alice votes again, now for witness 2, her vote worth 100 now
|
||||
vote_for(alice_id, witness2.vote_id, alice_private_key);
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
witness1 = witness_id_type(1)(db);
|
||||
witness2 = witness_id_type(2)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 100);
|
||||
BOOST_CHECK_EQUAL(witness2.total_votes, 166);
|
||||
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( rolling_period_start )
|
||||
{
|
||||
// period start rolls automatically after HF
|
||||
try {
|
||||
// advance to HF
|
||||
generate_blocks(HARDFORK_GPOS_TIME);
|
||||
generate_block();
|
||||
|
||||
// update default gpos global parameters to make this thing faster
|
||||
auto now = db.head_block_time();
|
||||
update_gpos_global(518400, 86400, now);
|
||||
|
||||
// moving outside period:
|
||||
while( db.head_block_time() <= now + fc::days(6) )
|
||||
{
|
||||
generate_block();
|
||||
}
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// rolling is here so getting the new now
|
||||
now = db.head_block_time();
|
||||
generate_block();
|
||||
|
||||
// period start rolled
|
||||
BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch());
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE( worker_dividends_voting )
|
||||
{
|
||||
try {
|
||||
// advance to HF
|
||||
generate_blocks(HARDFORK_GPOS_TIME);
|
||||
generate_block();
|
||||
|
||||
// update default gpos global parameters to 4 days
|
||||
auto now = db.head_block_time();
|
||||
update_gpos_global(345600, 86400, now);
|
||||
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
// get core asset object
|
||||
const auto& dividend_holder_asset_object = get_asset(GRAPHENE_SYMBOL);
|
||||
|
||||
// by default core token pays dividends once per month
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
BOOST_CHECK_EQUAL(*dividend_data.options.payout_interval, 2592000); // 30 days
|
||||
|
||||
// update the payout interval to 1 day for speed purposes of the test
|
||||
update_payout_interval(core.symbol, fc::time_point::now() + fc::minutes(1), 60 * 60 * 24); // 1 day
|
||||
|
||||
generate_block();
|
||||
|
||||
// get the dividend distribution account
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
|
||||
// transfering some coins to distribution account.
|
||||
transfer( committee_account, dividend_distribution_account.id, core.amount( 100 ) );
|
||||
generate_block();
|
||||
|
||||
ACTORS((nathan)(voter1)(voter2)(voter3));
|
||||
|
||||
transfer( committee_account, nathan_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, voter1_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, voter2_id, core.amount( 1000 ) );
|
||||
|
||||
generate_block();
|
||||
|
||||
upgrade_to_lifetime_member(nathan_id);
|
||||
|
||||
auto worker = create_worker(nathan_id, 10, fc::days(6));
|
||||
|
||||
// add some vesting to voter1
|
||||
create_vesting(voter1_id, core.amount(100), vesting_balance_type::gpos);
|
||||
|
||||
// add some vesting to voter2
|
||||
create_vesting(voter2_id, core.amount(100), vesting_balance_type::gpos);
|
||||
|
||||
generate_block();
|
||||
|
||||
// vote for worker
|
||||
vote_for(voter1_id, worker.vote_for, voter1_private_key);
|
||||
|
||||
// first maint pass, coefficient will be 1
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
worker = worker_id_type()(db);
|
||||
BOOST_CHECK_EQUAL(worker.total_votes_for, 100);
|
||||
|
||||
// here dividends are paid to voter1 and voter2
|
||||
// voter1 get paid full dividend share as coefficent is at 1 here
|
||||
BOOST_CHECK_EQUAL(get_balance(voter1_id(db), core), 950);
|
||||
|
||||
// voter2 didnt voted so he dont get paid
|
||||
BOOST_CHECK_EQUAL(get_balance(voter2_id(db), core), 900);
|
||||
|
||||
// send some asset to the reserve pool so the worker can get paid
|
||||
fill_reserve_pool(account_id_type(), asset(GRAPHENE_MAX_SHARE_SUPPLY/2));
|
||||
|
||||
BOOST_CHECK_EQUAL(worker_id_type()(db).worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(worker.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// worker is getting paid
|
||||
BOOST_CHECK_EQUAL(worker_id_type()(db).worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 10);
|
||||
BOOST_CHECK_EQUAL(worker.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 10);
|
||||
|
||||
// second maint pass, coefficient will be 0.75
|
||||
worker = worker_id_type()(db);
|
||||
BOOST_CHECK_EQUAL(worker.total_votes_for, 75);
|
||||
|
||||
// more decay
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
worker = worker_id_type()(db);
|
||||
BOOST_CHECK_EQUAL(worker.total_votes_for, 50);
|
||||
|
||||
transfer( committee_account, dividend_distribution_account.id, core.amount( 100 ) );
|
||||
generate_block();
|
||||
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 499999999996850);
|
||||
|
||||
// more decay
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
worker = worker_id_type()(db);
|
||||
BOOST_CHECK_EQUAL(worker.total_votes_for, 25);
|
||||
|
||||
// here voter1 get paid again but less money by vesting coefficient
|
||||
BOOST_CHECK_EQUAL(get_balance(voter1_id(db), core), 962);
|
||||
BOOST_CHECK_EQUAL(get_balance(voter2_id(db), core), 900);
|
||||
|
||||
// remaining dividends not paid by coeffcient are sent to committee account
|
||||
BOOST_CHECK_EQUAL(get_balance(committee_account(db), core), 499999999996938);
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( account_multiple_vesting )
|
||||
{
|
||||
try {
|
||||
// advance to HF
|
||||
generate_blocks(HARDFORK_GPOS_TIME);
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
|
||||
// update default gpos global parameters to 4 days
|
||||
auto now = db.head_block_time();
|
||||
update_gpos_global(345600, 86400, now);
|
||||
|
||||
ACTORS((sam)(patty));
|
||||
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
transfer( committee_account, sam_id, core.amount( 300 ) );
|
||||
transfer( committee_account, patty_id, core.amount( 100 ) );
|
||||
|
||||
// add some vesting to sam
|
||||
create_vesting(sam_id, core.amount(100), vesting_balance_type::gpos);
|
||||
|
||||
// have another balance with 200 more
|
||||
create_vesting(sam_id, core.amount(200), vesting_balance_type::gpos);
|
||||
|
||||
// patty also have vesting balance
|
||||
create_vesting(patty_id, core.amount(100), vesting_balance_type::gpos);
|
||||
|
||||
// get core asset object
|
||||
const auto& dividend_holder_asset_object = get_asset(GRAPHENE_SYMBOL);
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
|
||||
// update the payout interval
|
||||
update_payout_interval(core.symbol, fc::time_point::now() + fc::minutes(1), 60 * 60 * 24); // 1 day
|
||||
|
||||
// get the dividend distribution account
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
|
||||
// transfering some coins to distribution account.
|
||||
transfer( committee_account, dividend_distribution_account.id, core.amount( 100 ) );
|
||||
generate_block();
|
||||
|
||||
// vote for a votable object
|
||||
auto witness1 = witness_id_type(1)(db);
|
||||
vote_for(sam_id, witness1.vote_id, sam_private_key);
|
||||
vote_for(patty_id, witness1.vote_id, patty_private_key);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// amount in vested balanced will sum up as voting power
|
||||
witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 400);
|
||||
|
||||
// sam get paid dividends
|
||||
BOOST_CHECK_EQUAL(get_balance(sam_id(db), core), 75);
|
||||
|
||||
// patty also
|
||||
BOOST_CHECK_EQUAL(get_balance(patty_id(db), core), 25);
|
||||
|
||||
// total vote not decaying
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
witness1 = witness_id_type(1)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 300);
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/*
|
||||
BOOST_AUTO_TEST_CASE( competing_proposals )
|
||||
{
|
||||
try {
|
||||
// advance to HF
|
||||
generate_blocks(HARDFORK_GPOS_TIME);
|
||||
generate_block();
|
||||
set_expiration(db, trx);
|
||||
|
||||
ACTORS((voter1)(voter2)(worker1)(worker2));
|
||||
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
transfer( committee_account, worker1_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, worker2_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, voter1_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, voter2_id, core.amount( 1000 ) );
|
||||
|
||||
create_vesting(voter1_id, core.amount(200), vesting_balance_type::gpos);
|
||||
create_vesting(voter2_id, core.amount(300), vesting_balance_type::gpos);
|
||||
|
||||
generate_block();
|
||||
|
||||
auto now = db.head_block_time();
|
||||
update_gpos_global(518400, 86400, now);
|
||||
|
||||
update_payout_interval(core.symbol, fc::time_point::now() + fc::minutes(1), 60 * 60 * 24); // 1 day
|
||||
|
||||
upgrade_to_lifetime_member(worker1_id);
|
||||
upgrade_to_lifetime_member(worker2_id);
|
||||
|
||||
// create 2 competing proposals asking a lot of token
|
||||
// todo: maybe a refund worker here so we can test with smaller numbers
|
||||
auto w1 = create_worker(worker1_id, 100000000000, fc::days(10));
|
||||
auto w1_id_instance = w1.id.instance();
|
||||
auto w2 = create_worker(worker2_id, 100000000000, fc::days(10));
|
||||
auto w2_id_instance = w2.id.instance();
|
||||
|
||||
fill_reserve_pool(account_id_type(), asset(GRAPHENE_MAX_SHARE_SUPPLY/2));
|
||||
|
||||
// vote for the 2 workers
|
||||
vote_for(voter1_id, w1.vote_for, voter1_private_key);
|
||||
vote_for(voter2_id, w2.vote_for, voter2_private_key);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
w1 = worker_id_type(w1_id_instance)(db);
|
||||
w2 = worker_id_type(w2_id_instance)(db);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
// only w2 is getting paid as it haves more votes and money is only enough for 1
|
||||
BOOST_CHECK_EQUAL(w1.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(w2.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 100000000000);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
BOOST_CHECK_EQUAL(w1.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(w2.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 150000000000);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
w1 = worker_id_type(w1_id_instance)(db);
|
||||
w2 = worker_id_type(w2_id_instance)(db);
|
||||
|
||||
// as votes decay w1 is still getting paid as it always have more votes than w1
|
||||
BOOST_CHECK_EQUAL(w1.total_votes_for, 100);
|
||||
BOOST_CHECK_EQUAL(w2.total_votes_for, 150);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(w2.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 200000000000);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
w1 = worker_id_type(w1_id_instance)(db);
|
||||
w2 = worker_id_type(w2_id_instance)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1.total_votes_for, 66);
|
||||
BOOST_CHECK_EQUAL(w2.total_votes_for, 100);
|
||||
|
||||
// worker is sil getting paid as days pass
|
||||
BOOST_CHECK_EQUAL(w1.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(w2.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 250000000000);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
w1 = worker_id_type(w1_id_instance)(db);
|
||||
w2 = worker_id_type(w2_id_instance)(db);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1.total_votes_for, 33);
|
||||
BOOST_CHECK_EQUAL(w2.total_votes_for, 50);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(w2.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 300000000000);
|
||||
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
generate_block();
|
||||
|
||||
w1 = worker_id_type(w1_id_instance)(db);
|
||||
w2 = worker_id_type(w2_id_instance)(db);
|
||||
|
||||
// worker2 will not get paid anymore as it haves 0 votes
|
||||
BOOST_CHECK_EQUAL(w1.total_votes_for, 0);
|
||||
BOOST_CHECK_EQUAL(w2.total_votes_for, 0);
|
||||
|
||||
BOOST_CHECK_EQUAL(w1.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(w2.worker.get<vesting_balance_worker_type>().balance(db).balance.amount.value, 300000000000);
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
*/
|
||||
BOOST_AUTO_TEST_CASE( proxy_voting )
|
||||
{
|
||||
try {
|
||||
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( no_proposal )
|
||||
{
|
||||
try {
|
||||
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
BOOST_AUTO_TEST_CASE( database_api )
|
||||
{
|
||||
ACTORS((alice)(bob));
|
||||
try {
|
||||
|
||||
// move to hardfork
|
||||
generate_blocks( HARDFORK_GPOS_TIME );
|
||||
generate_block();
|
||||
|
||||
// database api
|
||||
graphene::app::database_api db_api(db);
|
||||
|
||||
const auto& core = asset_id_type()(db);
|
||||
|
||||
// send some asset to alice and bob
|
||||
transfer( committee_account, alice_id, core.amount( 1000 ) );
|
||||
transfer( committee_account, bob_id, core.amount( 1000 ) );
|
||||
generate_block();
|
||||
|
||||
// add some vesting to alice and bob
|
||||
create_vesting(alice_id, core.amount(100), vesting_balance_type::gpos);
|
||||
generate_block();
|
||||
|
||||
// total balance is 100 rest of data at 0
|
||||
auto gpos_info = db_api.get_gpos_info(alice_id);
|
||||
BOOST_CHECK_EQUAL(gpos_info.vesting_factor, 0);
|
||||
BOOST_CHECK_EQUAL(gpos_info.award.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(gpos_info.total_amount.value, 100);
|
||||
|
||||
create_vesting(bob_id, core.amount(100), vesting_balance_type::gpos);
|
||||
generate_block();
|
||||
|
||||
// total gpos balance is now 200
|
||||
gpos_info = db_api.get_gpos_info(alice_id);
|
||||
BOOST_CHECK_EQUAL(gpos_info.total_amount.value, 200);
|
||||
|
||||
// update default gpos and dividend interval to 10 days
|
||||
auto now = db.head_block_time();
|
||||
update_gpos_global(5184000, 864000, now); // 10 days subperiods
|
||||
update_payout_interval(core.symbol, fc::time_point::now() + fc::minutes(1), 60 * 60 * 24 * 10); // 10 days
|
||||
|
||||
generate_block();
|
||||
|
||||
// no votes for witness 1
|
||||
auto witness1 = witness_id_type(1)(db);
|
||||
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
|
||||
|
||||
// no votes for witness 2
|
||||
auto witness2 = witness_id_type(2)(db);
|
||||
BOOST_CHECK_EQUAL(witness2.total_votes, 0);
|
||||
|
||||
// transfering some coins to distribution account.
|
||||
const auto& dividend_holder_asset_object = get_asset(GRAPHENE_SYMBOL);
|
||||
const auto& dividend_data = dividend_holder_asset_object.dividend_data(db);
|
||||
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(db);
|
||||
transfer( committee_account, dividend_distribution_account.id, core.amount( 100 ) );
|
||||
generate_block();
|
||||
|
||||
// award balance is now 100
|
||||
gpos_info = db_api.get_gpos_info(alice_id);
|
||||
BOOST_CHECK_EQUAL(gpos_info.vesting_factor, 0);
|
||||
BOOST_CHECK_EQUAL(gpos_info.award.amount.value, 100);
|
||||
BOOST_CHECK_EQUAL(gpos_info.total_amount.value, 200);
|
||||
|
||||
// vote for witness1
|
||||
vote_for(alice_id, witness1.vote_id, alice_private_key);
|
||||
vote_for(bob_id, witness1.vote_id, bob_private_key);
|
||||
|
||||
// go to maint
|
||||
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
|
||||
|
||||
// payment for alice and bob is done, distribution account is back in 0
|
||||
gpos_info = db_api.get_gpos_info(alice_id);
|
||||
BOOST_CHECK_EQUAL(gpos_info.vesting_factor, 1);
|
||||
BOOST_CHECK_EQUAL(gpos_info.award.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(gpos_info.total_amount.value, 200);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// alice vesting coeffcient decay
|
||||
gpos_info = db_api.get_gpos_info(alice_id);
|
||||
BOOST_CHECK_EQUAL(gpos_info.vesting_factor, 0.83333333333333337);
|
||||
BOOST_CHECK_EQUAL(gpos_info.award.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(gpos_info.total_amount.value, 200);
|
||||
|
||||
advance_x_maint(10);
|
||||
|
||||
// vesting factor for alice decaying more
|
||||
gpos_info = db_api.get_gpos_info(alice_id);
|
||||
BOOST_CHECK_EQUAL(gpos_info.vesting_factor, 0.66666666666666663);
|
||||
BOOST_CHECK_EQUAL(gpos_info.award.amount.value, 0);
|
||||
BOOST_CHECK_EQUAL(gpos_info.total_amount.value, 200);
|
||||
}
|
||||
catch (fc::exception &e) {
|
||||
edump((e.to_detail_string()));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
Loading…
Reference in a new issue