From a58eb6fae81bb7588b9c89ee9ec1af50926a35ff Mon Sep 17 00:00:00 2001 From: Alfredo Date: Tue, 5 Mar 2019 17:48:47 -0300 Subject: [PATCH] add get_gpos_info database api call --- libraries/app/database_api.cpp | 51 ++++++++ .../app/include/graphene/app/database_api.hpp | 23 +++- libraries/chain/db_maint.cpp | 12 +- libraries/chain/hardfork.d/GPOS.hf | 4 +- .../chain/include/graphene/chain/database.hpp | 5 +- tests/tests/gpos_tests.cpp | 121 +++++++++++++++++- 6 files changed, 201 insertions(+), 15 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d3af2f29..3f95a8c1 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -161,6 +161,8 @@ class database_api_impl : public std::enable_shared_from_this vector get_tournaments_by_state(tournament_id_type stop, unsigned limit, tournament_id_type start, tournament_state state); vector 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 @@ -2021,6 +2023,55 @@ vector 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().lower_bound(boost::make_tuple(asset_id_type(), balance_type)); + auto vesting_balances_end = + vesting_index.indices().get().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(); + const auto& vesting_balances = vesting_index.indices().get(); + 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 // diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 7b0943e4..3fac4b5f 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -114,6 +114,12 @@ 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. * @@ -645,7 +651,17 @@ class database_api */ vector get_registered_tournaments(account_id_type account_filter, uint32_t limit) const; - private: + ////////// + // GPOS // + ////////// + /** + * @return account and network GPOS information + */ + gpos_info get_gpos_info(const account_id_type account) const; + + + +private: std::shared_ptr< database_api_impl > my; }; @@ -656,6 +672,8 @@ 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 @@ -765,4 +783,7 @@ FC_API(graphene::app::database_api, (get_tournaments_by_state) (get_tournaments ) (get_registered_tournaments) + + // gpos + (get_gpos_info) ) diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 57cb421f..06e15a19 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -725,14 +725,14 @@ void deprecate_annual_members( database& db ) return; } -double calculate_vesting_factor(const database& d, const account_object& stake_account) +double database::calculate_vesting_factor(const account_object& stake_account) { // get last time voted form stats - const auto &stats = stake_account.statistics(d); + 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 = d.get_global_properties(); + 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()); @@ -740,7 +740,7 @@ double calculate_vesting_factor(const database& d, const account_object& stake_a // 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 = d.head_block_time(); + const auto now = this->head_block_time(); double vesting_factor; auto seconds_since_period_start = now.sec_since_epoch() - period_start.sec_since_epoch(); @@ -1071,7 +1071,7 @@ void schedule_pending_dividend_balances(database& db, vesting_balances_begin, vesting_balances_end)) { if (holder_balance_object.owner == dividend_data.dividend_distribution_account) continue; - auto vesting_factor = calculate_vesting_factor(db, holder_balance_object.owner(db)); + auto vesting_factor = db.calculate_vesting_factor(holder_balance_object.owner(db)); auto holder_balance = holder_balance_object.balance; @@ -1463,7 +1463,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g if (itr == vesting_amounts.end()) return; - auto vesting_factor = calculate_vesting_factor(d, stake_account); + auto vesting_factor = d.calculate_vesting_factor(stake_account); voting_stake = (uint64_t)floor(voting_stake * vesting_factor); } else diff --git a/libraries/chain/hardfork.d/GPOS.hf b/libraries/chain/hardfork.d/GPOS.hf index ad914bec..f175ef2c 100644 --- a/libraries/chain/hardfork.d/GPOS.hf +++ b/libraries/chain/hardfork.d/GPOS.hf @@ -1,4 +1,4 @@ -// GPOS HARDFORK Friday, February 15, 2019 5:08:21 PM +// GPOS HARDFORK Friday, March 15, 2019 11:57:28 PM #ifndef HARDFORK_GPOS_TIME -#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1550250501 )) +#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1552694248 )) #endif \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index af50a94b..179fb2df 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -498,8 +498,11 @@ 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 + + template void perform_account_maintenance(std::tuple helpers); ///@} ///@} diff --git a/tests/tests/gpos_tests.cpp b/tests/tests/gpos_tests.cpp index cf133473..eb53c9c4 100644 --- a/tests/tests/gpos_tests.cpp +++ b/tests/tests/gpos_tests.cpp @@ -32,6 +32,8 @@ #include "../common/database_fixture.hpp" +#include + using namespace graphene::chain; using namespace graphene::chain::test; @@ -340,6 +342,7 @@ BOOST_AUTO_TEST_CASE( voting ) { ACTORS((alice)(bob)); try { + // move to hardfork generate_blocks( HARDFORK_GPOS_TIME ); generate_block(); @@ -638,16 +641,15 @@ BOOST_AUTO_TEST_CASE( worker_dividends_voting ) BOOST_AUTO_TEST_CASE( account_multiple_vesting ) { try { - - // update default gpos global parameters to 4 days - auto now = db.head_block_time(); - update_gpos_global(345600, 86400, now); - // 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); @@ -839,4 +841,113 @@ BOOST_AUTO_TEST_CASE( proxy_voting ) } } +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()