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 );