From 0d1c41557d54029ef2d49862d9a6a441cdd4ddec Mon Sep 17 00:00:00 2001
From: pbattu123
Date: Tue, 22 Oct 2019 10:39:45 -0300
Subject: [PATCH 1/6] changes to allow user to vote in each sub-period
---
libraries/app/database_api.cpp | 2 +
.../app/include/graphene/app/database_api.hpp | 5 ++-
libraries/chain/account_evaluator.cpp | 4 +-
libraries/chain/db_maint.cpp | 38 +++++++++++++++----
.../chain/include/graphene/chain/database.hpp | 1 +
libraries/wallet/wallet.cpp | 9 ++++-
6 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp
index e3e82790..e27da19b 100644
--- a/libraries/app/database_api.cpp
+++ b/libraries/app/database_api.cpp
@@ -2039,6 +2039,8 @@ graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type
{
gpos_info result;
result.vesting_factor = _db.calculate_vesting_factor(account(_db));
+ result.current_subperiod = _db.get_gpos_current_subperiod();
+ result.last_voted_time = account(_db).statistics(_db).last_vote_time;
const auto& dividend_data = asset_id_type()(_db).dividend_data(_db);
const account_object& dividend_distribution_account = dividend_data.dividend_distribution_account(_db);
diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp
index 3fac4b5f..7d9ffde8 100644
--- a/libraries/app/include/graphene/app/database_api.hpp
+++ b/libraries/app/include/graphene/app/database_api.hpp
@@ -118,6 +118,9 @@ struct gpos_info {
double vesting_factor;
asset award;
share_type total_amount;
+ uint32_t current_subperiod;
+ fc::time_point_sec last_voted_time;
+
};
/**
@@ -672,7 +675,7 @@ 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_REFLECT( graphene::app::gpos_info, (vesting_factor)(award)(total_amount)(current_subperiod)(last_voted_time) );
FC_API(graphene::app::database_api,
diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp
index 2d117f52..b29c169c 100644
--- a/libraries/chain/account_evaluator.cpp
+++ b/libraries/chain/account_evaluator.cpp
@@ -284,8 +284,8 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
{
d.modify( acnt->statistics( d ), [&]( account_statistics_object& aso )
{
- if((o.new_options->votes != acnt->options.votes ||
- o.new_options->voting_account != acnt->options.voting_account))
+ //if((o.new_options->votes != acnt->options.votes ||
+ // o.new_options->voting_account != acnt->options.voting_account))
aso.last_vote_time = d.head_block_time();
} );
}
diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp
index 81fce8f9..ade8c160 100644
--- a/libraries/chain/db_maint.cpp
+++ b/libraries/chain/db_maint.cpp
@@ -725,13 +725,8 @@ void deprecate_annual_members( database& db )
return;
}
-double database::calculate_vesting_factor(const account_object& stake_account)
+uint32_t database::get_gpos_current_subperiod()
{
- // 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();
@@ -741,7 +736,6 @@ double database::calculate_vesting_factor(const account_object& stake_account)
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);
@@ -757,6 +751,28 @@ double database::calculate_vesting_factor(const account_object& stake_account)
current_subperiod = period;
});
+ return current_subperiod;
+}
+
+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 auto number_of_subperiods = vesting_period / vesting_subperiod;
+ double vesting_factor;
+
+ // get in what sub period we are
+ uint32_t current_subperiod = get_gpos_current_subperiod();
+
if(current_subperiod == 0 || current_subperiod > number_of_subperiods) return 0;
if(last_date_voted < period_start) return 0;
@@ -1389,7 +1405,7 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
rolling_period_start(*this);
process_dividend_assets(*this);
-
+
struct vote_tally_helper {
database& d;
const global_property_object& props;
@@ -1558,6 +1574,12 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g
p.pending_parameters->extensions.value.permitted_betting_odds_increments = p.parameters.extensions.value.permitted_betting_odds_increments;
if( !p.pending_parameters->extensions.value.live_betting_delay_time.valid() )
p.pending_parameters->extensions.value.live_betting_delay_time = p.parameters.extensions.value.live_betting_delay_time;
+ if( !p.pending_parameters->extensions.value.gpos_period.valid() )
+ p.pending_parameters->extensions.value.gpos_period = p.parameters.extensions.value.gpos_period;
+ if( !p.pending_parameters->extensions.value.gpos_subperiod.valid() )
+ p.pending_parameters->extensions.value.gpos_subperiod = p.parameters.extensions.value.gpos_subperiod;
+ if( !p.pending_parameters->extensions.value.gpos_vesting_lockin_period.valid() )
+ p.pending_parameters->extensions.value.gpos_vesting_lockin_period = p.parameters.extensions.value.gpos_vesting_lockin_period;
p.parameters = std::move(*p.pending_parameters);
p.pending_parameters.reset();
}
diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp
index 179fb2df..a181fe58 100644
--- a/libraries/chain/include/graphene/chain/database.hpp
+++ b/libraries/chain/include/graphene/chain/database.hpp
@@ -500,6 +500,7 @@ namespace graphene { namespace chain {
void update_worker_votes();
public:
double calculate_vesting_factor(const account_object& stake_account);
+ uint32_t get_gpos_current_subperiod();
template
diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp
index b6aa2cbf..5b867c47 100644
--- a/libraries/wallet/wallet.cpp
+++ b/libraries/wallet/wallet.cpp
@@ -2125,13 +2125,20 @@ public:
account_object voting_account_object = get_account(voting_account);
account_id_type witness_owner_account_id = get_account_id(witness);
+
fc::optional witness_obj = _remote_db->get_witness_by_account(witness_owner_account_id);
if (!witness_obj)
FC_THROW("Account ${witness} is not registered as a witness", ("witness", witness));
if (approve)
{
+ account_id_type stake_account = get_account_id(voting_account);
+ const auto gpos_info = _remote_db->get_gpos_info(stake_account);
+ const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod();
+ const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start());
+ const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod;
+
auto insert_result = voting_account_object.options.votes.insert(witness_obj->vote_id);
- if (!insert_result.second)
+ if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time))
FC_THROW("Account ${account} was already voting for witness ${witness}", ("account", voting_account)("witness", witness));
}
else
From 48d0d88ff048e203a82bb9e2f6e736fe785e4ca0 Mon Sep 17 00:00:00 2001
From: pbattu123
Date: Wed, 23 Oct 2019 18:33:17 -0300
Subject: [PATCH 2/6] changes to update last voting time
---
.../app/include/graphene/app/database_api.hpp | 3 +--
libraries/chain/account_evaluator.cpp | 6 +++--
.../graphene/chain/protocol/account.hpp | 1 +
libraries/wallet/wallet.cpp | 24 ++++++++++++++++---
4 files changed, 27 insertions(+), 7 deletions(-)
diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp
index 7d9ffde8..843d6af5 100644
--- a/libraries/app/include/graphene/app/database_api.hpp
+++ b/libraries/app/include/graphene/app/database_api.hpp
@@ -119,8 +119,7 @@ struct gpos_info {
asset award;
share_type total_amount;
uint32_t current_subperiod;
- fc::time_point_sec last_voted_time;
-
+ fc::time_point_sec last_voted_time;
};
/**
diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp
index b29c169c..3185c456 100644
--- a/libraries/chain/account_evaluator.cpp
+++ b/libraries/chain/account_evaluator.cpp
@@ -284,8 +284,10 @@ void_result account_update_evaluator::do_apply( const account_update_operation&
{
d.modify( acnt->statistics( d ), [&]( account_statistics_object& aso )
{
- //if((o.new_options->votes != acnt->options.votes ||
- // o.new_options->voting_account != acnt->options.voting_account))
+ fc::optional< bool > flag = o.extensions.value.update_last_voting_time;
+ if((o.new_options->votes != acnt->options.votes ||
+ o.new_options->voting_account != acnt->options.voting_account) ||
+ flag)
aso.last_vote_time = d.head_block_time();
} );
}
diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp
index 6d13a4d3..a0e43ad0 100644
--- a/libraries/chain/include/graphene/chain/protocol/account.hpp
+++ b/libraries/chain/include/graphene/chain/protocol/account.hpp
@@ -140,6 +140,7 @@ namespace graphene { namespace chain {
optional< void_t > null_ext;
optional< special_authority > owner_special_authority;
optional< special_authority > active_special_authority;
+ optional< bool > update_last_voting_time = false;
};
struct fee_parameters_type
diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp
index 5b867c47..5bc53bdc 100644
--- a/libraries/wallet/wallet.cpp
+++ b/libraries/wallet/wallet.cpp
@@ -2087,11 +2087,22 @@ public:
fc::optional committee_member_obj = _remote_db->get_committee_member_by_account(committee_member_owner_account_id);
if (!committee_member_obj)
FC_THROW("Account ${committee_member} is not registered as a committee_member", ("committee_member", committee_member));
+
+ bool update_vote_time = false;
+
if (approve)
{
+ account_id_type stake_account = get_account_id(voting_account);
+ const auto gpos_info = _remote_db->get_gpos_info(stake_account);
+ const auto vesting_subperiod = _remote_db->get_global_properties().parameters.gpos_subperiod();
+ const auto gpos_start_time = fc::time_point_sec(_remote_db->get_global_properties().parameters.gpos_period_start());
+ const auto subperiod_start_time = gpos_start_time.sec_since_epoch() + (gpos_info.current_subperiod - 1) * vesting_subperiod;
+
auto insert_result = voting_account_object.options.votes.insert(committee_member_obj->vote_id);
- if (!insert_result.second)
- FC_THROW("Account ${account} was already voting for committee_member ${committee_member}", ("account", voting_account)("committee_member", committee_member));
+ if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time))
+ FC_THROW("Account ${account} was already voting for committee_member ${committee_member} in the current GPOS sub-period", ("account", voting_account)("committee_member", committee_member));
+ else
+ update_vote_time = true; //Allow user to vote in each sub-period(Update voting time, which is reference in calculating VF)
}
else
{
@@ -2102,6 +2113,7 @@ public:
account_update_operation account_update_op;
account_update_op.account = voting_account_object.id;
account_update_op.new_options = voting_account_object.options;
+ account_update_op.extensions.value.update_last_voting_time = update_vote_time;
signed_transaction tx;
tx.operations.push_back( account_update_op );
@@ -2129,6 +2141,8 @@ public:
fc::optional witness_obj = _remote_db->get_witness_by_account(witness_owner_account_id);
if (!witness_obj)
FC_THROW("Account ${witness} is not registered as a witness", ("witness", witness));
+
+ bool update_vote_time = false;
if (approve)
{
account_id_type stake_account = get_account_id(voting_account);
@@ -2139,7 +2153,9 @@ public:
auto insert_result = voting_account_object.options.votes.insert(witness_obj->vote_id);
if (!insert_result.second && (gpos_info.last_voted_time.sec_since_epoch() >= subperiod_start_time))
- FC_THROW("Account ${account} was already voting for witness ${witness}", ("account", voting_account)("witness", witness));
+ FC_THROW("Account ${account} was already voting for witness ${witness} in the current GPOS sub-period", ("account", voting_account)("witness", witness));
+ else
+ update_vote_time = true; //Allow user to vote in each sub-period(Update voting time, which is reference in calculating VF)
}
else
{
@@ -2147,9 +2163,11 @@ public:
if (!votes_removed)
FC_THROW("Account ${account} is already not voting for witness ${witness}", ("account", voting_account)("witness", witness));
}
+
account_update_operation account_update_op;
account_update_op.account = voting_account_object.id;
account_update_op.new_options = voting_account_object.options;
+ account_update_op.extensions.value.update_last_voting_time = update_vote_time;
signed_transaction tx;
tx.operations.push_back( account_update_op );
From d6da2963dcb2267ce7a924a6a876f56180b1b71f Mon Sep 17 00:00:00 2001
From: pbattu123
Date: Wed, 23 Oct 2019 22:15:26 -0300
Subject: [PATCH 3/6] resolve merge conflict
---
libraries/chain/db_maint.cpp | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp
index 7eab5cf8..aee9d451 100644
--- a/libraries/chain/db_maint.cpp
+++ b/libraries/chain/db_maint.cpp
@@ -728,12 +728,6 @@ void deprecate_annual_members( database& db )
uint32_t database::get_gpos_current_subperiod()
{
fc::time_point_sec last_date_voted;
- // get last time voted form account stats
- // check last_vote_time of proxy voting account if proxy is set
- if (stake_account.options.voting_account == GRAPHENE_PROXY_TO_SELF_ACCOUNT)
- last_date_voted = stake_account.statistics(*this).last_vote_time;
- else
- last_date_voted = stake_account.options.voting_account(*this).statistics(*this).last_vote_time;
const auto &gpo = this->get_global_properties();
const auto vesting_period = gpo.parameters.gpos_period();
@@ -764,9 +758,13 @@ uint32_t database::get_gpos_current_subperiod()
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;
+ fc::time_point_sec last_date_voted;
+ // get last time voted form account stats
+ // check last_vote_time of proxy voting account if proxy is set
+ if (stake_account.options.voting_account == GRAPHENE_PROXY_TO_SELF_ACCOUNT)
+ last_date_voted = stake_account.statistics(*this).last_vote_time;
+ else
+ last_date_voted = stake_account.options.voting_account(*this).statistics(*this).last_vote_time;
// get global data related to gpos
const auto &gpo = this->get_global_properties();
From cf3b54ece47773c4daa407b9ed51128fb2800a3a Mon Sep 17 00:00:00 2001
From: pbattu123
Date: Wed, 23 Oct 2019 23:13:23 -0300
Subject: [PATCH 4/6] unit test changes and also separated GPOS test suite
---
tests/CMakeLists.txt | 4 +
tests/gpos/gpos_tests.cpp | 1093 +++++++++++++++++++++++++++++++++++++
2 files changed, 1097 insertions(+)
create mode 100644 tests/gpos/gpos_tests.cpp
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 57a451aa..55f369f4 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -13,6 +13,10 @@ if(MSVC)
set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
endif(MSVC)
+file(GLOB GPOS_TESTS "gpos/*.cpp")
+add_executable( gpos_test ${GPOS_TESTS} ${COMMON_SOURCES} )
+target_link_libraries( gpos_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
+
file(GLOB PERFORMANCE_TESTS "performance/*.cpp")
add_executable( performance_test ${PERFORMANCE_TESTS} ${COMMON_SOURCES} )
target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
diff --git a/tests/gpos/gpos_tests.cpp b/tests/gpos/gpos_tests.cpp
new file mode 100644
index 00000000..335230d7
--- /dev/null
+++ b/tests/gpos/gpos_tests.cpp
@@ -0,0 +1,1093 @@
+/*
+ * 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
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "../common/database_fixture.hpp"
+
+#include
+
+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(ptx.operation_results[0].get());
+ }
+ 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(ptx.operation_results[0].get());
+ }
+
+ 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(ptx.operation_results[0].get());
+
+ // check created vesting amount and policy
+ BOOST_CHECK_EQUAL(alice_vesting.balance.amount.value, 100);
+ BOOST_CHECK_EQUAL(alice_vesting.policy.get().vesting_duration_seconds,
+ db.get_global_properties().parameters.gpos_subperiod());
+ BOOST_CHECK_EQUAL(alice_vesting.policy.get().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(ptx.operation_results[0].get());
+
+ 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().vesting_duration_seconds,
+ db.get_global_properties().parameters.gpos_subperiod());
+ BOOST_CHECK_EQUAL(bob_vesting.policy.get().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, HARDFORK_GPOS_TIME - fc::days(7) + 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);
+ vote_for(bob_id, witness2.vote_id, bob_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);
+ witness2 = witness_id_type(2)(db);
+ BOOST_CHECK_EQUAL(witness1.total_votes, 100);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
+ advance_x_maint(10);
+
+ auto now1 = db.head_block_time();
+ //vote bob tot witness2 in each subperiod and verify votes
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ // go to maint
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // vote decay as time pass
+ witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+
+ BOOST_CHECK_EQUAL(witness1.total_votes, 83);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
+ advance_x_maint(10);
+ now1 = db.head_block_time();
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
+ witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+ BOOST_CHECK_EQUAL(witness1.total_votes, 66);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
+ advance_x_maint(10);
+ now1 = db.head_block_time();
+ // more
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
+ witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+ BOOST_CHECK_EQUAL(witness1.total_votes, 50);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
+ advance_x_maint(10);
+ now1 = db.head_block_time();
+ // more
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
+ witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+
+ BOOST_CHECK_EQUAL(witness1.total_votes, 33);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
+ advance_x_maint(10);
+ now1 = db.head_block_time();
+
+ // more
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
+ witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+ BOOST_CHECK_EQUAL(witness1.total_votes, 16);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
+ // 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(5);
+ // 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);
+ witness2 = witness_id_type(2)(db);
+ BOOST_CHECK_EQUAL(witness1.total_votes, 0);
+ BOOST_CHECK_EQUAL(witness2.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);
+
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_block();
+
+ 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);
+
+ // 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, 183);
+
+ }
+ 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, HARDFORK_GPOS_TIME + 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().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(worker.worker.get().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().balance(db).balance.amount.value, 10);
+ BOOST_CHECK_EQUAL(worker.worker.get().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, HARDFORK_GPOS_TIME + 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().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(w2.worker.get().balance(db).balance.amount.value, 100000000000);
+
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ generate_block();
+
+ BOOST_CHECK_EQUAL(w1.worker.get().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
+ BOOST_CHECK_EQUAL(w2.worker.get().balance(db).balance.amount.value, 300000000000);
+ }
+ catch (fc::exception &e) {
+ edump((e.to_detail_string()));
+ throw;
+ }
+}
+*/
+BOOST_AUTO_TEST_CASE( proxy_voting )
+{
+ 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();
+
+ gpos_info = db_api.get_gpos_info(bob_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, 200);
+
+ auto now = db.head_block_time();
+ update_gpos_global(518400, 86400, now);
+
+ BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), 518400);
+ BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), 86400);
+ BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch());
+
+ // alice assign bob as voting account
+ graphene::chain::account_update_operation op;
+ op.account = alice_id;
+ op.new_options = alice_id(db).options;
+ op.new_options->voting_account = bob_id;
+ trx.operations.push_back(op);
+ set_expiration(db, trx);
+ trx.validate();
+ sign(trx, alice_private_key);
+ PUSH_TX( db, trx, ~0 );
+ trx.clear();
+
+ generate_block();
+
+ // vote for witness1
+ auto witness1 = witness_id_type(1)(db);
+ vote_for(bob_id, witness1.vote_id, bob_private_key);
+
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+
+ // check vesting factor of current subperiod
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 1);
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 1);
+
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ generate_block();
+
+ // GPOS 2nd subperiod started.
+ // vesting factor decay
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.83333333333333337);
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.83333333333333337);
+
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ generate_block();
+
+ // GPOS 3rd subperiod started
+ // vesting factor decay
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.66666666666666663);
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.66666666666666663);
+
+ // vote for witness2
+ auto witness2 = witness_id_type(2)(db);
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+
+ // vesting factor should be 1 for both alice and bob for the current subperiod
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 1);
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 1);
+
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ generate_block();
+
+ // vesting factor decay
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.83333333333333337);
+ BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.83333333333333337);
+ }
+ 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, HARDFORK_GPOS_TIME + 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()
+
+//#define BOOST_TEST_MODULE "C++ Unit Tests for Graphene Blockchain Database"
+#include
+#include
+#include
+
+boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
+ std::srand(time(NULL));
+ std::cout << "Random number generator seeded to " << time(NULL) << std::endl;
+
+ // betting operations don't take effect until HARDFORK 1000
+ GRAPHENE_TESTING_GENESIS_TIMESTAMP = HARDFORK_1000_TIME.sec_since_epoch() + 2;
+
+ return nullptr;
+}
From f7d7f043cefbc6adfa9fb2ff485323a9c47d9281 Mon Sep 17 00:00:00 2001
From: pbattu123
Date: Wed, 23 Oct 2019 23:18:44 -0300
Subject: [PATCH 5/6] delete unused variables
---
tests/gpos/gpos_tests.cpp | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/tests/gpos/gpos_tests.cpp b/tests/gpos/gpos_tests.cpp
index 335230d7..bfb0e5d3 100644
--- a/tests/gpos/gpos_tests.cpp
+++ b/tests/gpos/gpos_tests.cpp
@@ -403,7 +403,6 @@ BOOST_AUTO_TEST_CASE( voting )
advance_x_maint(10);
- auto now1 = db.head_block_time();
//vote bob tot witness2 in each subperiod and verify votes
vote_for(bob_id, witness2.vote_id, bob_private_key);
// go to maint
@@ -416,7 +415,6 @@ BOOST_AUTO_TEST_CASE( voting )
BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
- now1 = db.head_block_time();
vote_for(bob_id, witness2.vote_id, bob_private_key);
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
// decay more
@@ -426,7 +424,7 @@ BOOST_AUTO_TEST_CASE( voting )
BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
- now1 = db.head_block_time();
+
// more
vote_for(bob_id, witness2.vote_id, bob_private_key);
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
@@ -437,7 +435,7 @@ BOOST_AUTO_TEST_CASE( voting )
BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
- now1 = db.head_block_time();
+
// more
vote_for(bob_id, witness2.vote_id, bob_private_key);
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
@@ -449,8 +447,7 @@ BOOST_AUTO_TEST_CASE( voting )
BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
- now1 = db.head_block_time();
-
+
// more
vote_for(bob_id, witness2.vote_id, bob_private_key);
generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
From 22e5dfa502da136290fb480d774437b49b0ab44f Mon Sep 17 00:00:00 2001
From: pbattu123
Date: Thu, 24 Oct 2019 15:31:49 -0300
Subject: [PATCH 6/6] deleted GPOS specific test suite and updated gpos tests
---
tests/CMakeLists.txt | 4 -
tests/gpos/gpos_tests.cpp | 1090 ------------------------------------
tests/tests/gpos_tests.cpp | 55 +-
3 files changed, 42 insertions(+), 1107 deletions(-)
delete mode 100644 tests/gpos/gpos_tests.cpp
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 55f369f4..57a451aa 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -13,10 +13,6 @@ if(MSVC)
set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" )
endif(MSVC)
-file(GLOB GPOS_TESTS "gpos/*.cpp")
-add_executable( gpos_test ${GPOS_TESTS} ${COMMON_SOURCES} )
-target_link_libraries( gpos_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
-
file(GLOB PERFORMANCE_TESTS "performance/*.cpp")
add_executable( performance_test ${PERFORMANCE_TESTS} ${COMMON_SOURCES} )
target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} )
diff --git a/tests/gpos/gpos_tests.cpp b/tests/gpos/gpos_tests.cpp
deleted file mode 100644
index bfb0e5d3..00000000
--- a/tests/gpos/gpos_tests.cpp
+++ /dev/null
@@ -1,1090 +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
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "../common/database_fixture.hpp"
-
-#include
-
-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(ptx.operation_results[0].get());
- }
- 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(ptx.operation_results[0].get());
- }
-
- 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(ptx.operation_results[0].get());
-
- // check created vesting amount and policy
- BOOST_CHECK_EQUAL(alice_vesting.balance.amount.value, 100);
- BOOST_CHECK_EQUAL(alice_vesting.policy.get().vesting_duration_seconds,
- db.get_global_properties().parameters.gpos_subperiod());
- BOOST_CHECK_EQUAL(alice_vesting.policy.get().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(ptx.operation_results[0].get());
-
- 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().vesting_duration_seconds,
- db.get_global_properties().parameters.gpos_subperiod());
- BOOST_CHECK_EQUAL(bob_vesting.policy.get().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, HARDFORK_GPOS_TIME - fc::days(7) + 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);
- vote_for(bob_id, witness2.vote_id, bob_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);
- witness2 = witness_id_type(2)(db);
- BOOST_CHECK_EQUAL(witness1.total_votes, 100);
- BOOST_CHECK_EQUAL(witness2.total_votes, 100);
-
- advance_x_maint(10);
-
- //vote bob tot witness2 in each subperiod and verify votes
- vote_for(bob_id, witness2.vote_id, bob_private_key);
- // go to maint
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- // vote decay as time pass
- witness1 = witness_id_type(1)(db);
- witness2 = witness_id_type(2)(db);
-
- BOOST_CHECK_EQUAL(witness1.total_votes, 83);
- BOOST_CHECK_EQUAL(witness2.total_votes, 100);
-
- advance_x_maint(10);
- vote_for(bob_id, witness2.vote_id, bob_private_key);
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- // decay more
- witness1 = witness_id_type(1)(db);
- witness2 = witness_id_type(2)(db);
- BOOST_CHECK_EQUAL(witness1.total_votes, 66);
- BOOST_CHECK_EQUAL(witness2.total_votes, 100);
-
- advance_x_maint(10);
-
- // more
- vote_for(bob_id, witness2.vote_id, bob_private_key);
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- // decay more
- witness1 = witness_id_type(1)(db);
- witness2 = witness_id_type(2)(db);
- BOOST_CHECK_EQUAL(witness1.total_votes, 50);
- BOOST_CHECK_EQUAL(witness2.total_votes, 100);
-
- advance_x_maint(10);
-
- // more
- vote_for(bob_id, witness2.vote_id, bob_private_key);
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- // decay more
- witness1 = witness_id_type(1)(db);
- witness2 = witness_id_type(2)(db);
-
- BOOST_CHECK_EQUAL(witness1.total_votes, 33);
- BOOST_CHECK_EQUAL(witness2.total_votes, 100);
-
- advance_x_maint(10);
-
- // more
- vote_for(bob_id, witness2.vote_id, bob_private_key);
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- // decay more
- witness1 = witness_id_type(1)(db);
- witness2 = witness_id_type(2)(db);
- BOOST_CHECK_EQUAL(witness1.total_votes, 16);
- BOOST_CHECK_EQUAL(witness2.total_votes, 100);
-
- // 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(5);
- // 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);
- witness2 = witness_id_type(2)(db);
- BOOST_CHECK_EQUAL(witness1.total_votes, 0);
- BOOST_CHECK_EQUAL(witness2.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);
-
- vote_for(bob_id, witness2.vote_id, bob_private_key);
- generate_block();
-
- 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);
-
- // 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, 183);
-
- }
- 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, HARDFORK_GPOS_TIME + 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().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(worker.worker.get().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().balance(db).balance.amount.value, 10);
- BOOST_CHECK_EQUAL(worker.worker.get().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, HARDFORK_GPOS_TIME + 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().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(w2.worker.get().balance(db).balance.amount.value, 100000000000);
-
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- generate_block();
-
- BOOST_CHECK_EQUAL(w1.worker.get().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(w2.worker.get().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().balance(db).balance.amount.value, 0);
- BOOST_CHECK_EQUAL(w2.worker.get().balance(db).balance.amount.value, 300000000000);
- }
- catch (fc::exception &e) {
- edump((e.to_detail_string()));
- throw;
- }
-}
-*/
-BOOST_AUTO_TEST_CASE( proxy_voting )
-{
- 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();
-
- gpos_info = db_api.get_gpos_info(bob_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, 200);
-
- auto now = db.head_block_time();
- update_gpos_global(518400, 86400, now);
-
- BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), 518400);
- BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), 86400);
- BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), now.sec_since_epoch());
-
- // alice assign bob as voting account
- graphene::chain::account_update_operation op;
- op.account = alice_id;
- op.new_options = alice_id(db).options;
- op.new_options->voting_account = bob_id;
- trx.operations.push_back(op);
- set_expiration(db, trx);
- trx.validate();
- sign(trx, alice_private_key);
- PUSH_TX( db, trx, ~0 );
- trx.clear();
-
- generate_block();
-
- // vote for witness1
- auto witness1 = witness_id_type(1)(db);
- vote_for(bob_id, witness1.vote_id, bob_private_key);
-
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
-
- // check vesting factor of current subperiod
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 1);
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 1);
-
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- generate_block();
-
- // GPOS 2nd subperiod started.
- // vesting factor decay
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.83333333333333337);
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.83333333333333337);
-
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- generate_block();
-
- // GPOS 3rd subperiod started
- // vesting factor decay
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.66666666666666663);
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.66666666666666663);
-
- // vote for witness2
- auto witness2 = witness_id_type(2)(db);
- vote_for(bob_id, witness2.vote_id, bob_private_key);
-
- // vesting factor should be 1 for both alice and bob for the current subperiod
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 1);
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 1);
-
- generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
- generate_block();
-
- // vesting factor decay
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(alice_id).vesting_factor, 0.83333333333333337);
- BOOST_CHECK_EQUAL(db_api.get_gpos_info(bob_id).vesting_factor, 0.83333333333333337);
- }
- 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, HARDFORK_GPOS_TIME + 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()
-
-//#define BOOST_TEST_MODULE "C++ Unit Tests for Graphene Blockchain Database"
-#include
-#include
-#include
-
-boost::unit_test::test_suite* init_unit_test_suite(int argc, char* argv[]) {
- std::srand(time(NULL));
- std::cout << "Random number generator seeded to " << time(NULL) << std::endl;
-
- // betting operations don't take effect until HARDFORK 1000
- GRAPHENE_TESTING_GENESIS_TIMESTAMP = HARDFORK_1000_TIME.sec_since_epoch() + 2;
-
- return nullptr;
-}
diff --git a/tests/tests/gpos_tests.cpp b/tests/tests/gpos_tests.cpp
index 5b089685..3366a84b 100644
--- a/tests/tests/gpos_tests.cpp
+++ b/tests/tests/gpos_tests.cpp
@@ -390,53 +390,77 @@ BOOST_AUTO_TEST_CASE( voting )
// vote for witness1
vote_for(alice_id, witness1.vote_id, alice_private_key);
+ vote_for(bob_id, witness2.vote_id, bob_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);
+ witness2 = witness_id_type(2)(db);
BOOST_CHECK_EQUAL(witness1.total_votes, 100);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
+ //vote bob tot witness2 in each subperiod and verify votes
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ // go to maint
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
// vote decay as time pass
witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+
BOOST_CHECK_EQUAL(witness1.total_votes, 83);
-
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
+
advance_x_maint(10);
-
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
// decay more
witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
BOOST_CHECK_EQUAL(witness1.total_votes, 66);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
-
+
// more
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
BOOST_CHECK_EQUAL(witness1.total_votes, 50);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
-
+
// more
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
+
BOOST_CHECK_EQUAL(witness1.total_votes, 33);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
advance_x_maint(10);
-
+
// more
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_blocks(db.get_dynamic_global_properties().next_maintenance_time);
+ // decay more
witness1 = witness_id_type(1)(db);
+ witness2 = witness_id_type(2)(db);
BOOST_CHECK_EQUAL(witness1.total_votes, 16);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 100);
// 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);
-
+ advance_x_maint(5);
// 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());
@@ -444,7 +468,9 @@ BOOST_AUTO_TEST_CASE( voting )
generate_block();
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, 0);
// we are in the second GPOS period, at subperiod 2, lets vote here
vote_for(bob_id, witness2.vote_id, bob_private_key);
@@ -467,13 +493,16 @@ BOOST_AUTO_TEST_CASE( voting )
BOOST_CHECK_EQUAL(witness1.total_votes, 0);
BOOST_CHECK_EQUAL(witness2.total_votes, 83);
+ vote_for(bob_id, witness2.vote_id, bob_private_key);
+ generate_block();
+
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);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 83);
// alice votes again, now for witness 2, her vote worth 100 now
vote_for(alice_id, witness2.vote_id, alice_private_key);
@@ -483,7 +512,7 @@ BOOST_AUTO_TEST_CASE( voting )
witness2 = witness_id_type(2)(db);
BOOST_CHECK_EQUAL(witness1.total_votes, 100);
- BOOST_CHECK_EQUAL(witness2.total_votes, 166);
+ BOOST_CHECK_EQUAL(witness2.total_votes, 183);
}
catch (fc::exception &e) {