Skip to content
This repository has been archived by the owner on Oct 4, 2019. It is now read-only.

Commit

Permalink
New limits algorithm for comments and votes #533 #825
Browse files Browse the repository at this point in the history
  • Loading branch information
maslenitsa93 committed Sep 18, 2018
1 parent 0d44ab9 commit c092dcb
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 10 deletions.
4 changes: 4 additions & 0 deletions libraries/api/chain_api_properties.cpp
Expand Up @@ -19,6 +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_window = src.comments_window;
comments_per_window = src.comments_per_window;
votes_window = src.votes_window;
votes_per_window = src.votes_per_window;
}
}

Expand Down
8 changes: 7 additions & 1 deletion libraries/api/include/golos/api/chain_api_properties.hpp
Expand Up @@ -24,6 +24,11 @@ namespace golos { namespace api {
fc::optional<uint16_t> max_referral_interest_rate;
fc::optional<uint32_t> max_referral_term_sec;
fc::optional<asset> max_referral_break_fee;

fc::optional<uint16_t> comments_window;
fc::optional<uint16_t> comments_per_window;
fc::optional<uint16_t> votes_window;
fc::optional<uint16_t> votes_per_window;
};

} } // golos::api
Expand All @@ -33,4 +38,5 @@ FC_REFLECT(
(account_creation_fee)(maximum_block_size)(sbd_interest_rate)
(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))
(max_referral_interest_rate)(max_referral_term_sec)(max_referral_break_fee)
(comments_window)(comments_per_window)(votes_window)(votes_per_window))
21 changes: 19 additions & 2 deletions libraries/chain/database.cpp
Expand Up @@ -1878,14 +1878,29 @@ namespace golos { namespace chain {

chain_properties_19 median_props;

auto median = active.size() / 2;

auto calc_median = [&](auto&& param) {
std::nth_element(
active.begin(), active.begin() + active.size() / 2, active.end(),
active.begin(), active.begin() + median, active.end(),
[&](const auto* a, const auto* b) {
return a->props.*param < b->props.*param;
}
);
median_props.*param = active[active.size() / 2]->props.*param;
median_props.*param = active[median]->props.*param;
};

auto calc_median_battery = [&](auto&& window, auto&& items) {
std::nth_element(
active.begin(), active.begin() + median, active.end(),
[&](const auto* a, const auto* b) {
auto a_consumption = a->props.*window / a->props.*items;
auto b_consumption = b->props.*window / b->props.*items;
return std::tie(a_consumption, a->props.*items) < std::tie(b_consumption, b->props.*items);
}
);
median_props.*window = active[median]->props.*window;
median_props.*items = active[median]->props.*items;
};

calc_median(&chain_properties_17::account_creation_fee);
Expand All @@ -1898,6 +1913,8 @@ 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_battery(&chain_properties_19::comments_window, &chain_properties_19::comments_per_window);
calc_median_battery(&chain_properties_19::votes_window, &chain_properties_19::votes_per_window);

modify(wso, [&](witness_schedule_object &_wso) {
_wso.median_props = median_props;
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/hardfork.d/0_19.hf
@@ -1,5 +1,6 @@
#ifndef STEEMIT_HARDFORK_0_19
#define STEEMIT_HARDFORK_0_19 19
#define STEEMIT_HARDFORK_0_19__533 (STEEMIT_HARDFORK_0_19) // Leaky algorithm for comment and vote bandwidth

#ifdef STEEMIT_BUILD_TESTNET
#define STEEMIT_HARDFORK_0_19_TIME 1534755600 // 20 aug 2018 12:00:00 MSK
Expand Down
2 changes: 2 additions & 0 deletions libraries/chain/include/golos/chain/account_object.hpp
Expand Up @@ -50,6 +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_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
Expand Down
55 changes: 50 additions & 5 deletions libraries/chain/steem_evaluator.cpp
Expand Up @@ -527,6 +527,8 @@ namespace golos { namespace chain {
logic_exception::cannot_update_comment_because_nothing_changed,
"Cannot update comment because nothing appears to be changing.");

const auto& mprops = _db.get_witness_schedule_object().median_props;

const auto &by_permlink_idx = _db.get_index<comment_index>().indices().get<by_permlink>();
auto itr = by_permlink_idx.find(boost::make_tuple(o.author, o.permlink));

Expand Down Expand Up @@ -570,7 +572,29 @@ namespace golos { namespace chain {
});
}

if (_db.has_hardfork(STEEMIT_HARDFORK_0_12__176)) {
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(uint32_t(mprops.comments_window), uint32_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, consumption,
bandwidth_exception::comment_bandwidth,
"You may only comment ${comments_per_window} times in ${comments_window} seconds.",
("comments_per_window", mprops.comments_per_window)("comments_window", mprops.comments_window));
}

db().modify(auth, [&](account_object &a) {
a.comments_capacity = 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,
bandwidth_exception::post_bandwidth,
Expand Down Expand Up @@ -623,7 +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++;
}
});

_db.create<comment_object>([&](comment_object &com) {
Expand Down Expand Up @@ -1169,6 +1197,8 @@ namespace golos { namespace chain {
const auto& comment = _db.get_comment(o.author, o.permlink);
const auto& voter = _db.get_account(o.voter);

const auto& mprops = _db.get_witness_schedule_object().median_props;

GOLOS_CHECK_LOGIC(!(voter.owner_challenged || voter.active_challenged),
logic_exception::account_is_currently_challenged,
"Account \"${account}\" is currently challenged", ("account", voter.name));
Expand Down Expand Up @@ -1205,10 +1235,26 @@ namespace golos { namespace chain {
const auto& comment_vote_idx = _db.get_index<comment_vote_index>().indices().get<by_comment_voter>();
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();
auto elapsed_seconds = (_db.head_block_time() - voter.last_vote_time).to_seconds();

if (_db.has_hardfork(STEEMIT_HARDFORK_0_19__533)) {
auto consumption = mprops.votes_window / mprops.votes_per_window;

auto regenerated_capacity = std::min(uint32_t(mprops.votes_window), uint32_t(elapsed_seconds));
auto current_capacity = std::min(uint16_t(voter.voting_capacity + regenerated_capacity), mprops.votes_window);

GOLOS_CHECK_BANDWIDTH(current_capacity, consumption,
bandwidth_exception::vote_bandwidth,
"Can only vote ${votes_per_window} times in ${votes_window} seconds.",
("votes_per_window", mprops.votes_per_window)("votes_window", mprops.votes_window));

GOLOS_CHECK_BANDWIDTH(_db.head_block_time(), voter.last_vote_time + STEEMIT_MIN_VOTE_INTERVAL_SEC-1,
_db.modify(voter, [&](account_object &a) {
a.voting_capacity = 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.");
}

int64_t regenerated_power =
(STEEMIT_100_PERCENT * elapsed_seconds) /
Expand Down Expand Up @@ -1561,7 +1607,6 @@ namespace golos { namespace chain {

_db.adjust_rshares2(comment, old_rshares, new_rshares);
}

} FC_CAPTURE_AND_RETHROW((o))
}

Expand Down
10 changes: 10 additions & 0 deletions libraries/protocol/include/golos/protocol/config.hpp
Expand Up @@ -80,6 +80,11 @@
#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_WINDOW 200
#define STEEMIT_COMMENTS_PER_WINDOW 10
#define STEEMIT_VOTES_WINDOW 200 // For testnet
#define STEEMIT_VOTES_PER_WINDOW 10

#define STEEMIT_MAX_ACCOUNT_WITNESS_VOTES 30

#define STEEMIT_100_PERCENT 10000
Expand Down Expand Up @@ -295,6 +300,11 @@
#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_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

#define STEEMIT_100_PERCENT 10000
Expand Down
23 changes: 22 additions & 1 deletion libraries/protocol/include/golos/protocol/steem_operations.hpp
Expand Up @@ -517,6 +517,26 @@ namespace golos { namespace protocol {
*/
asset max_referral_break_fee = GOLOS_DEFAULT_REFERRAL_BREAK_FEE;

/**
* Time window for commenting by account
*/
uint16_t comments_window = STEEMIT_COMMENTS_WINDOW;

/**
* Maximum count of comments per one window by account
*/
uint16_t comments_per_window = STEEMIT_COMMENTS_PER_WINDOW;

/**
* Time window for voting by account
*/
uint16_t votes_window = STEEMIT_VOTES_WINDOW;

/**
* Maximum count of votes per one window by account
*/
uint16_t votes_per_window = STEEMIT_VOTES_PER_WINDOW;

void validate() const;

chain_properties_19& operator=(const chain_properties_17& src) {
Expand Down Expand Up @@ -1178,7 +1198,8 @@ FC_REFLECT_DERIVED(
(create_account_delegation_time)(min_delegation))
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))
(max_referral_interest_rate)(max_referral_term_sec)(max_referral_break_fee)
(comments_window)(comments_per_window)(votes_window)(votes_per_window))

FC_REFLECT_TYPENAME((golos::protocol::versioned_chain_properties))

Expand Down
4 changes: 4 additions & 0 deletions libraries/protocol/steem_operations.cpp
Expand Up @@ -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_LEGE(comments_window, 1, std::numeric_limits<uint16_t>::max() / 2);
GOLOS_CHECK_VALUE_LEGE(comments_per_window, 1, comments_window);
GOLOS_CHECK_VALUE_LEGE(votes_window, 1, std::numeric_limits<uint16_t>::max() / 2);
GOLOS_CHECK_VALUE_LEGE(votes_per_window, 1, votes_window);
}

void witness_update_operation::validate() const {
Expand Down
8 changes: 7 additions & 1 deletion libraries/wallet/include/golos/wallet/wallet.hpp
Expand Up @@ -48,6 +48,11 @@ namespace golos { namespace wallet {
fc::optional<uint16_t> max_referral_interest_rate;
fc::optional<uint32_t> max_referral_term_sec;
fc::optional<asset> max_referral_break_fee;

fc::optional<uint16_t> comments_window;
fc::optional<uint16_t> comments_per_window;
fc::optional<uint16_t> votes_window;
fc::optional<uint16_t> votes_per_window;
};

struct optional_private_box_query {
Expand Down Expand Up @@ -1493,7 +1498,8 @@ FC_REFLECT((golos::wallet::optional_chain_props),
(account_creation_fee)(maximum_block_size)(sbd_interest_rate)
(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))
(max_referral_interest_rate)(max_referral_term_sec)(max_referral_break_fee)
(comments_window)(comments_per_window)(votes_window)(votes_per_window))

FC_REFLECT(
(golos::wallet::message_body),
Expand Down
8 changes: 8 additions & 0 deletions libraries/wallet/wallet.cpp
Expand Up @@ -330,6 +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_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;
Expand Down Expand Up @@ -2194,6 +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_window);
SET_PROP(comments_per_window);
SET_PROP(votes_window);
SET_PROP(votes_per_window);
#undef SET_PROP

op.owner = witness_account_name;
Expand Down

0 comments on commit c092dcb

Please sign in to comment.