diff --git a/libraries/api/chain_api_properties.cpp b/libraries/api/chain_api_properties.cpp index dc3cd95d53..19b9ea704b 100644 --- a/libraries/api/chain_api_properties.cpp +++ b/libraries/api/chain_api_properties.cpp @@ -19,10 +19,10 @@ namespace golos { namespace api { max_referral_interest_rate = src.max_referral_interest_rate; max_referral_term_sec = src.max_referral_term_sec; max_referral_break_fee = src.max_referral_break_fee; - comments_capacity_100 = src.comments_capacity_100; - comment_consumption = src.comment_consumption; - voting_capacity_100 = src.voting_capacity_100; - voting_consumption = src.voting_consumption; + comments_window = src.comments_window; + comments_per_window = src.comments_per_window; + votes_window = src.votes_window; + votes_per_window = src.votes_per_window; } } diff --git a/libraries/api/include/golos/api/chain_api_properties.hpp b/libraries/api/include/golos/api/chain_api_properties.hpp index d2f918a47f..8f0c01a832 100644 --- a/libraries/api/include/golos/api/chain_api_properties.hpp +++ b/libraries/api/include/golos/api/chain_api_properties.hpp @@ -25,10 +25,10 @@ namespace golos { namespace api { fc::optional max_referral_term_sec; fc::optional max_referral_break_fee; - fc::optional comments_capacity_100; - fc::optional comment_consumption; - fc::optional voting_capacity_100; - fc::optional voting_consumption; + fc::optional comments_window; + fc::optional comments_per_window; + fc::optional votes_window; + fc::optional votes_per_window; }; } } // golos::api @@ -39,4 +39,4 @@ FC_REFLECT( (create_account_min_golos_fee)(create_account_min_delegation) (create_account_delegation_time)(min_delegation) (max_referral_interest_rate)(max_referral_term_sec)(max_referral_break_fee) - (comments_capacity_100)(comment_consumption)(voting_capacity_100)(voting_consumption)) + (comments_window)(comments_per_window)(votes_window)(votes_per_window)) diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index e3058906fd..96e946407a 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -1888,6 +1888,17 @@ namespace golos { namespace chain { median_props.*param = active[active.size() / 2]->props.*param; }; + auto calc_median_battery = [&](auto&& window, auto&& items, auto&& sort_by) { + std::nth_element( + active.begin(), active.begin() + active.size() / 2, active.end(), + [&](const auto* a, const auto* b) { + return a->props.*sort_by < b->props.*sort_by; + } + ); + median_props.*window = active[active.size() / 2]->props.*window; + median_props.*items = active[active.size() / 2]->props.*items; + }; + calc_median(&chain_properties_17::account_creation_fee); calc_median(&chain_properties_17::maximum_block_size); calc_median(&chain_properties_17::sbd_interest_rate); @@ -1898,10 +1909,10 @@ namespace golos { namespace chain { calc_median(&chain_properties_19::max_referral_interest_rate); calc_median(&chain_properties_19::max_referral_term_sec); calc_median(&chain_properties_19::max_referral_break_fee); - calc_median(&chain_properties_19::comments_capacity_100); - calc_median(&chain_properties_19::comment_consumption); - calc_median(&chain_properties_19::voting_capacity_100); - calc_median(&chain_properties_19::voting_consumption); + calc_median_battery(&chain_properties_19::comments_window, + &chain_properties_19::comments_per_window, &chain_properties_19::comments_window); + calc_median_battery(&chain_properties_19::votes_window, + &chain_properties_19::votes_per_window, &chain_properties_19::votes_window); modify(wso, [&](witness_schedule_object &_wso) { _wso.median_props = median_props; diff --git a/libraries/chain/include/golos/chain/account_object.hpp b/libraries/chain/include/golos/chain/account_object.hpp index 5a3d813087..bf229259fc 100644 --- a/libraries/chain/include/golos/chain/account_object.hpp +++ b/libraries/chain/include/golos/chain/account_object.hpp @@ -50,8 +50,8 @@ class account_object bool can_vote = true; uint16_t voting_power = STEEMIT_100_PERCENT; ///< current voting power of this account, it falls after every vote - uint16_t comments_capacity = STEEMIT_COMMENTS_CAPACITY_100; - uint16_t voting_capacity = STEEMIT_VOTING_CAPACITY_100; + uint16_t comments_capacity = STEEMIT_COMMENTS_WINDOW; + uint16_t voting_capacity = STEEMIT_VOTES_WINDOW; time_point_sec last_vote_time; ///< used to increase the voting power of this account the longer it goes without voting. asset balance = asset(0, STEEM_SYMBOL); ///< total liquid shares held by this account diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index be1ed29d68..3dac09af92 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -572,22 +572,28 @@ namespace golos { namespace chain { }); } - int64_t elapsed_seconds = (now - auth.last_post).to_seconds(); - int64_t regenerated_capacity = std::min(int64_t(mprops.comments_capacity_100), int64_t(elapsed_seconds)); - int64_t current_capacity = std::min(int64_t(auth.comments_capacity + regenerated_capacity), - int64_t(mprops.comments_capacity_100)); + auto elapsed_seconds = (now - auth.last_post).to_seconds(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_19__533)) { + auto consumption = mprops.comments_window / mprops.comments_per_window; + + auto regenerated_capacity = std::min(mprops.comments_window, uint16_t(elapsed_seconds)); + auto current_capacity = std::min(uint16_t(auth.comments_capacity + regenerated_capacity), mprops.comments_window); + if (o.parent_author == STEEMIT_ROOT_POST_PARENT) { GOLOS_CHECK_BANDWIDTH(now, band->last_bandwidth_update + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, bandwidth_exception::post_bandwidth, "You may only post once every 5 minutes."); } else { - GOLOS_CHECK_BANDWIDTH(current_capacity, mprops.comment_consumption, + GOLOS_CHECK_BANDWIDTH(current_capacity, consumption, bandwidth_exception::comment_bandwidth, - "You may only comment " + std::to_string(mprops.comments_capacity_100 / mprops.comment_consumption) - + " times in " + std::to_string(mprops.comments_capacity_100) + " seconds."); + "You may only comment " + std::to_string(mprops.comments_per_window) + + " times in " + std::to_string(mprops.comments_window) + " seconds."); } + + db().modify(auth, [&](account_object &a) { + a.comments_capacity = uint16_t(current_capacity - consumption); + }); } else if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__176)) { if (o.parent_author == STEEMIT_ROOT_POST_PARENT) GOLOS_CHECK_BANDWIDTH(now, band->last_bandwidth_update + STEEMIT_MIN_ROOT_COMMENT_INTERVAL, @@ -641,11 +647,11 @@ namespace golos { namespace chain { db().modify(auth, [&](account_object &a) { a.last_post = now; - a.post_count++; if (o.parent_author != STEEMIT_ROOT_POST_PARENT) { a.comment_count++; + } else { + a.post_count++; } - a.comments_capacity = uint16_t(current_capacity - mprops.comment_consumption); }); _db.create([&](comment_object &com) { @@ -1229,15 +1235,22 @@ namespace golos { namespace chain { const auto& comment_vote_idx = _db.get_index().indices().get(); auto itr = comment_vote_idx.find(std::make_tuple(comment.id, voter.id)); - int64_t elapsed_seconds = (_db.head_block_time() - voter.last_vote_time).to_seconds(); - int64_t regenerated_capacity = std::min(int64_t(mprops.voting_capacity_100), int64_t(elapsed_seconds)); - int64_t current_capacity = std::min(int64_t(voter.voting_capacity + regenerated_capacity), int64_t(mprops.voting_capacity_100)); + auto elapsed_seconds = (_db.head_block_time() - voter.last_vote_time).to_seconds(); if (_db.has_hardfork(STEEMIT_HARDFORK_0_19__533)) { - GOLOS_CHECK_BANDWIDTH(current_capacity, mprops.voting_consumption, + auto consumption = mprops.comments_window / mprops.comments_per_window; + + auto regenerated_capacity = std::min(mprops.votes_window, uint16_t(elapsed_seconds)); + auto current_capacity = std::min(uint16_t(voter.voting_capacity + regenerated_capacity), mprops.comments_window); + + GOLOS_CHECK_BANDWIDTH(current_capacity, consumption, bandwidth_exception::vote_bandwidth, - "Can only vote " + std::to_string(mprops.voting_capacity_100 / mprops.voting_consumption) - + " times in " + std::to_string(mprops.voting_capacity_100) + " seconds."); + "Can only vote " + std::to_string(mprops.votes_per_window) + + " times in " + std::to_string(mprops.votes_window) + " seconds."); + + _db.modify(voter, [&](account_object &a) { + a.voting_capacity = uint16_t(current_capacity - consumption); + }); } else { GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), voter.last_vote_time + STEEMIT_MIN_VOTE_INTERVAL_SEC-1, bandwidth_exception::vote_bandwidth, "Can only vote once every 3 seconds."); @@ -1306,7 +1319,6 @@ namespace golos { namespace chain { _db.modify(voter, [&](account_object &a) { a.voting_power = current_power - used_power; a.last_vote_time = _db.head_block_time(); - a.voting_capacity = uint16_t(current_capacity - mprops.voting_consumption); }); /// if the current net_rshares is less than 0, the post is getting 0 rewards so it is not factored into total rshares^2 @@ -1595,7 +1607,6 @@ namespace golos { namespace chain { _db.adjust_rshares2(comment, old_rshares, new_rshares); } - } FC_CAPTURE_AND_RETHROW((o)) } diff --git a/libraries/protocol/include/golos/protocol/config.hpp b/libraries/protocol/include/golos/protocol/config.hpp index 2bfe4f00bb..2d7af39f25 100644 --- a/libraries/protocol/include/golos/protocol/config.hpp +++ b/libraries/protocol/include/golos/protocol/config.hpp @@ -80,10 +80,10 @@ #define STEEMIT_POST_MAX_BANDWIDTH (4*STEEMIT_100_PERCENT) // 2 posts per 1 days, average 1 every 12 hours #define STEEMIT_POST_WEIGHT_CONSTANT (uint64_t(STEEMIT_POST_MAX_BANDWIDTH) * STEEMIT_POST_MAX_BANDWIDTH) -#define STEEMIT_COMMENTS_CAPACITY_100 200 -#define STEEMIT_COMMENT_CONSUMPTION 20 -#define STEEMIT_VOTING_CAPACITY_100 30 -#define STEEMIT_VOTING_CONSUMPTION 10 +#define STEEMIT_COMMENTS_WINDOW 200 +#define STEEMIT_COMMENTS_PER_WINDOW 10 +#define STEEMIT_VOTES_WINDOW 30 // For testnet +#define STEEMIT_VOTES_PER_WINDOW 3 #define STEEMIT_MAX_ACCOUNT_WITNESS_VOTES 30 @@ -300,10 +300,10 @@ #define STEEMIT_POST_MAX_BANDWIDTH (4*STEEMIT_100_PERCENT) // 2 posts per 1 days, average 1 every 12 hours #define STEEMIT_POST_WEIGHT_CONSTANT (uint64_t(STEEMIT_POST_MAX_BANDWIDTH) * STEEMIT_POST_MAX_BANDWIDTH) -#define STEEMIT_COMMENTS_CAPACITY_100 200 -#define STEEMIT_COMMENT_CONSUMPTION 20 -#define STEEMIT_VOTING_CAPACITY_100 15 -#define STEEMIT_VOTING_CONSUMPTION 3 +#define STEEMIT_COMMENTS_WINDOW 200 +#define STEEMIT_COMMENTS_PER_WINDOW 10 +#define STEEMIT_VOTES_WINDOW 15 +#define STEEMIT_VOTES_PER_WINDOW 5 #define STEEMIT_MAX_ACCOUNT_WITNESS_VOTES 30 diff --git a/libraries/protocol/include/golos/protocol/steem_operations.hpp b/libraries/protocol/include/golos/protocol/steem_operations.hpp index 59db631f1d..920ce0e438 100644 --- a/libraries/protocol/include/golos/protocol/steem_operations.hpp +++ b/libraries/protocol/include/golos/protocol/steem_operations.hpp @@ -518,24 +518,24 @@ namespace golos { namespace protocol { asset max_referral_break_fee = GOLOS_DEFAULT_REFERRAL_BREAK_FEE; /** - * Total bandwidth battery capacity for comments + * Time window for commenting by account */ - uint16_t comments_capacity_100 = STEEMIT_COMMENTS_CAPACITY_100; + uint16_t comments_window = STEEMIT_COMMENTS_WINDOW; /** - * Consumption of bandwidth battery by each comment + * Maximum count of comments per one window by account */ - uint16_t comment_consumption = STEEMIT_COMMENT_CONSUMPTION; + uint16_t comments_per_window = STEEMIT_COMMENTS_PER_WINDOW; /** - * Total bandwidth battery capacity for votes + * Time window for voting by account */ - uint16_t voting_capacity_100 = STEEMIT_VOTING_CAPACITY_100; + uint16_t votes_window = STEEMIT_VOTES_WINDOW; /** - * Consumption of bandwidth battery by each vote + * Maximum count of votes per one window by account */ - uint16_t voting_consumption = STEEMIT_VOTING_CONSUMPTION; + uint16_t votes_per_window = STEEMIT_VOTES_PER_WINDOW; void validate() const; @@ -1199,7 +1199,7 @@ FC_REFLECT_DERIVED( FC_REFLECT_DERIVED( (golos::protocol::chain_properties_19), ((golos::protocol::chain_properties_18)), (max_referral_interest_rate)(max_referral_term_sec)(max_referral_break_fee) - (comments_capacity_100)(comment_consumption)(voting_capacity_100)(voting_consumption)) + (comments_window)(comments_per_window)(votes_window)(votes_per_window)) FC_REFLECT_TYPENAME((golos::protocol::versioned_chain_properties)) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index 3c9b04acb4..5bddf56fcd 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -231,6 +231,10 @@ namespace golos { namespace protocol { GOLOS_CHECK_VALUE_LE(max_referral_interest_rate, GOLOS_MAX_REFERRAL_INTEREST_RATE); GOLOS_CHECK_VALUE_LE(max_referral_term_sec, GOLOS_MAX_REFERRAL_TERM_SEC); GOLOS_CHECK_VALUE_LEGE(max_referral_break_fee.amount, 0, GOLOS_MAX_REFERRAL_BREAK_FEE.amount); + GOLOS_CHECK_VALUE_GE(comments_window, 1); + GOLOS_CHECK_VALUE_GE(comments_per_window, 1); + GOLOS_CHECK_VALUE_GE(votes_window, 1); + GOLOS_CHECK_VALUE_GE(votes_per_window, 1); } void witness_update_operation::validate() const { diff --git a/libraries/wallet/include/golos/wallet/wallet.hpp b/libraries/wallet/include/golos/wallet/wallet.hpp index 6000fc12b0..04ba4f170e 100644 --- a/libraries/wallet/include/golos/wallet/wallet.hpp +++ b/libraries/wallet/include/golos/wallet/wallet.hpp @@ -49,10 +49,10 @@ namespace golos { namespace wallet { fc::optional max_referral_term_sec; fc::optional max_referral_break_fee; - fc::optional comments_capacity_100; - fc::optional comment_consumption; - fc::optional voting_capacity_100; - fc::optional voting_consumption; + fc::optional comments_window; + fc::optional comments_per_window; + fc::optional votes_window; + fc::optional votes_per_window; }; struct optional_private_box_query { @@ -1499,7 +1499,7 @@ FC_REFLECT((golos::wallet::optional_chain_props), (create_account_min_golos_fee)(create_account_min_delegation) (create_account_delegation_time)(min_delegation) (max_referral_interest_rate)(max_referral_term_sec)(max_referral_break_fee) - (comments_capacity_100)(comment_consumption)(voting_capacity_100)(voting_consumption)) + (comments_window)(comments_per_window)(votes_window)(votes_per_window)) FC_REFLECT( (golos::wallet::message_body), diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index c003a7d8d8..4a9c682dba 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -330,10 +330,10 @@ namespace golos { namespace wallet { result["max_referral_interest_rate"] = median_props.max_referral_interest_rate; result["max_referral_term_sec"] = median_props.max_referral_term_sec; result["max_referral_break_fee"] = median_props.max_referral_break_fee; - result["comments_capacity_100"] = median_props.comments_capacity_100; - result["comment_consumption"] = median_props.comment_consumption; - result["voting_capacity_100"] = median_props.voting_capacity_100; - result["voting_consumption"] = median_props.voting_consumption; + result["comments_window"] = median_props.comments_window; + result["comments_per_window"] = median_props.comments_per_window; + result["votes_window"] = median_props.votes_window; + result["votes_per_window"] = median_props.votes_per_window; } return result; @@ -2198,10 +2198,10 @@ fc::ecc::private_key wallet_api::derive_private_key(const std::string& prefix_st SET_PROP(max_referral_interest_rate); SET_PROP(max_referral_term_sec); SET_PROP(max_referral_break_fee); - SET_PROP(comments_capacity_100); - SET_PROP(comment_consumption); - SET_PROP(voting_capacity_100); - SET_PROP(voting_consumption); + SET_PROP(comments_window); + SET_PROP(comments_per_window); + SET_PROP(votes_window); + SET_PROP(votes_per_window); #undef SET_PROP op.owner = witness_account_name;