diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index 8443ec102e..1f57a06dee 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -2331,10 +2331,16 @@ namespace golos { namespace chain { return delegators_reward; } - void database::pay_curator(const comment_vote_object& cvo, const uint64_t& claim, const account_name_type& author, const std::string& permlink) { + uint64_t database::pay_curator(const comment_vote_object& cvo, const uint64_t& claim, const account_name_type& author, const std::string& permlink) { const auto &voter = get(cvo.voter); auto voter_claim = claim; + uint64_t to_author = 0; + if (has_hardfork(STEEMIT_HARDFORK_0_21__1014)) { + to_author = uint128_t(voter_claim * cvo.author_promote_rate / STEEMIT_100_PERCENT).to_uint64(); + voter_claim -= to_author; + } + if (has_hardfork(STEEMIT_HARDFORK_0_19__756)) { voter_claim -= pay_delegators(voter, cvo, claim); } @@ -2346,6 +2352,8 @@ namespace golos { namespace chain { modify(voter, [&](account_object &a) { a.curation_rewards += voter_claim; }); + + return to_author; } /** * This method will iterate through all comment_vote_objects and give them @@ -2384,7 +2392,7 @@ namespace golos { namespace chain { if (claim > 0) { // min_amt is non-zero satoshis unclaimed_rewards -= claim; - pay_curator(*itr->vote, claim, c.comment.author, to_string(c.comment.permlink)); + unclaimed_rewards += pay_curator(*itr->vote, claim, c.comment.author, to_string(c.comment.permlink)); } else { break; } @@ -2393,8 +2401,7 @@ namespace golos { namespace chain { // pay needed claim + rest unclaimed tokens (close to zero value) to curator with greates weight // BTW: it has to be unclaimed_rewards.value not heaviest_vote_after_auw_weight + unclaimed_rewards.value, coz // unclaimed_rewards already contains this. - pay_curator(*heaviest_itr->vote, unclaimed_rewards.value, c.comment.author, to_string(c.comment.permlink)); - unclaimed_rewards = 0; + unclaimed_rewards = pay_curator(*heaviest_itr->vote, unclaimed_rewards.value, c.comment.author, to_string(c.comment.permlink)); } } if (!c.comment.allow_curation_rewards) { @@ -3090,6 +3097,7 @@ namespace golos { namespace chain { _my->_evaluator_registry.register_evaluator(); _my->_evaluator_registry.register_evaluator(); _my->_evaluator_registry.register_evaluator(); + _my->_evaluator_registry.register_evaluator(); _my->_evaluator_registry.register_evaluator(); _my->_evaluator_registry.register_evaluator(); _my->_evaluator_registry.register_evaluator(); diff --git a/libraries/chain/hardfork.d/0_21.hf b/libraries/chain/hardfork.d/0_21.hf index 2be5d222b5..9ffa33aca4 100644 --- a/libraries/chain/hardfork.d/0_21.hf +++ b/libraries/chain/hardfork.d/0_21.hf @@ -5,6 +5,7 @@ #define STEEMIT_HARDFORK_0_21__1009 (STEEMIT_HARDFORK_0_21) // Remove limit on min curation percent witness prop #define STEEMIT_HARDFORK_0_21__1010 (STEEMIT_HARDFORK_0_21) // Fix post bandwidth #define STEEMIT_HARDFORK_0_21__1045 (STEEMIT_HARDFORK_0_21) // Two payout strategies for vesting delegations with interest +#define STEEMIT_HARDFORK_0_21__1014 (STEEMIT_HARDFORK_0_21) // Vote author promote rate #ifdef STEEMIT_BUILD_TESTNET #define STEEMIT_HARDFORK_0_21_TIME 1547787600 // 18 jan 2019 12:00:00 MSK diff --git a/libraries/chain/include/golos/chain/comment_object.hpp b/libraries/chain/include/golos/chain/comment_object.hpp index c7b0cbb856..9a6b72df4f 100644 --- a/libraries/chain/include/golos/chain/comment_object.hpp +++ b/libraries/chain/include/golos/chain/comment_object.hpp @@ -147,6 +147,8 @@ namespace golos { int8_t num_changes = 0; ///< Count of vote changes (while consensus). If = -1 then related post is archived & vote no more needed for consensus bip::vector> delegator_vote_interest_rates; + + uint16_t author_promote_rate = GOLOS_MIN_VOTE_AUTHOR_PROMOTE_RATE; }; struct by_comment_voter; diff --git a/libraries/chain/include/golos/chain/database.hpp b/libraries/chain/include/golos/chain/database.hpp index 749d3e6a8b..13e281ebed 100644 --- a/libraries/chain/include/golos/chain/database.hpp +++ b/libraries/chain/include/golos/chain/database.hpp @@ -632,7 +632,7 @@ namespace golos { namespace chain { bool _resize(uint32_t block_num); - void pay_curator(const comment_vote_object& cvo, const uint64_t& claim, const account_name_type& author, const std::string& permlink); + uint64_t pay_curator(const comment_vote_object& cvo, const uint64_t& claim, const account_name_type& author, const std::string& permlink); void adjust_sbd_balance(const account_object &a, const asset &delta); diff --git a/libraries/chain/include/golos/chain/steem_evaluator.hpp b/libraries/chain/include/golos/chain/steem_evaluator.hpp index 89d24dfe89..7ddc1951dd 100644 --- a/libraries/chain/include/golos/chain/steem_evaluator.hpp +++ b/libraries/chain/include/golos/chain/steem_evaluator.hpp @@ -55,6 +55,7 @@ namespace golos { namespace chain { DEFINE_EVALUATOR(break_free_referral) DEFINE_EVALUATOR(delegate_vesting_shares_with_interest) DEFINE_EVALUATOR(reject_vesting_shares_delegation) + DEFINE_EVALUATOR(vote_options) class proposal_create_evaluator: public evaluator_impl { public: diff --git a/libraries/chain/steem_evaluator.cpp b/libraries/chain/steem_evaluator.cpp index 0e0c7ebbc9..44562580ff 100644 --- a/libraries/chain/steem_evaluator.cpp +++ b/libraries/chain/steem_evaluator.cpp @@ -1786,6 +1786,41 @@ namespace golos { namespace chain { } FC_CAPTURE_AND_RETHROW((o)) } + struct vote_options_extension_visitor { + vote_options_extension_visitor(const comment_vote_object& vote, database& db) + : _vote(vote), _db(db) { + } + + const comment_vote_object& _vote; + database& _db; + + using result_type = void; + + void operator()(const vote_author_promote_rate& vapr) const { + _db.modify(_vote, [&](comment_vote_object& c) { + c.author_promote_rate = vapr.rate; + }); + } + }; + + void vote_options_evaluator::do_apply(const vote_options_operation& o) { + ASSERT_REQ_HF(STEEMIT_HARDFORK_0_21__1014, "vote_options_operation"); + + const auto& comment = _db.get_comment(o.author, o.permlink); + const auto& voter = _db.get_account(o.voter); + + const auto& vote_idx = _db.get_index(); + const auto vote_itr = vote_idx.find(std::make_tuple(comment.id, voter.id)); + + if (vote_itr == vote_idx.end()) { + GOLOS_THROW_MISSING_OBJECT("comment_vote_object", fc::mutable_variant_object()("voter",o.voter)("author",o.author)("permlink",o.permlink)); + } + + for (auto& e : o.extensions) { + e.visit(vote_options_extension_visitor(*vote_itr, _db)); + } + } + void custom_evaluator::do_apply(const custom_operation &o) { } diff --git a/libraries/protocol/include/golos/protocol/config.hpp b/libraries/protocol/include/golos/protocol/config.hpp index 395321b673..e946a8556d 100644 --- a/libraries/protocol/include/golos/protocol/config.hpp +++ b/libraries/protocol/include/golos/protocol/config.hpp @@ -167,6 +167,9 @@ #define STEEMIT_DEF_CURATION_PERCENT (25*STEEMIT_1_PERCENT) // 25% #define STEEMIT_MAX_CURATION_PERCENT STEEMIT_100_PERCENT +#define GOLOS_MIN_VOTE_AUTHOR_PROMOTE_RATE (0*STEEMIT_1_PERCENT) +#define GOLOS_MAX_VOTE_AUTHOR_PROMOTE_RATE (100*STEEMIT_1_PERCENT) + #define STEEMIT_ACTIVE_CHALLENGE_FEE asset(2000, STEEM_SYMBOL) #define STEEMIT_OWNER_CHALLENGE_FEE asset(30000, STEEM_SYMBOL) #define STEEMIT_ACTIVE_CHALLENGE_COOLDOWN fc::days(1) @@ -410,6 +413,9 @@ #define STEEMIT_DEF_CURATION_PERCENT (25*STEEMIT_1_PERCENT) // 25% #define STEEMIT_MAX_CURATION_PERCENT STEEMIT_100_PERCENT +#define GOLOS_MIN_VOTE_AUTHOR_PROMOTE_RATE (0*STEEMIT_1_PERCENT) +#define GOLOS_MAX_VOTE_AUTHOR_PROMOTE_RATE (100*STEEMIT_1_PERCENT) + #define STEEMIT_ACTIVE_CHALLENGE_FEE asset(2000, STEEM_SYMBOL) #define STEEMIT_OWNER_CHALLENGE_FEE asset(30000, STEEM_SYMBOL) #define STEEMIT_ACTIVE_CHALLENGE_COOLDOWN fc::days(1) diff --git a/libraries/protocol/include/golos/protocol/operations.hpp b/libraries/protocol/include/golos/protocol/operations.hpp index a7b2e8e54b..427455df0f 100644 --- a/libraries/protocol/include/golos/protocol/operations.hpp +++ b/libraries/protocol/include/golos/protocol/operations.hpp @@ -70,6 +70,7 @@ namespace golos { namespace protocol { break_free_referral_operation, delegate_vesting_shares_with_interest_operation, reject_vesting_shares_delegation_operation, + vote_options_operation, worker_proposal_operation, worker_proposal_delete_operation, worker_techspec_operation, @@ -98,6 +99,7 @@ namespace golos { namespace protocol { producer_reward_operation, delegation_reward_operation, auction_window_reward_operation, + vote_author_promote_reward_operation, techspec_reward_operation, worker_reward_operation, techspec_expired_operation diff --git a/libraries/protocol/include/golos/protocol/steem_operations.hpp b/libraries/protocol/include/golos/protocol/steem_operations.hpp index 20cef98702..e9151663c5 100644 --- a/libraries/protocol/include/golos/protocol/steem_operations.hpp +++ b/libraries/protocol/include/golos/protocol/steem_operations.hpp @@ -265,6 +265,38 @@ namespace golos { namespace protocol { } }; + struct vote_author_promote_rate { + vote_author_promote_rate() { + } + + vote_author_promote_rate(uint16_t r) + : rate(r) { + } + + uint16_t rate = GOLOS_MIN_VOTE_AUTHOR_PROMOTE_RATE; + + void validate() const; + }; + + using vote_options_extension = static_variant < + vote_author_promote_rate + >; + + using vote_options_extensions_type = flat_set; + + struct vote_options_operation : public base_operation { + account_name_type voter; + account_name_type author; + string permlink; + vote_options_extensions_type extensions; + + void validate() const; + + void get_required_posting_authorities(flat_set &a) const { + a.insert(voter); + } + }; + /** * @ingroup operations @@ -1476,6 +1508,11 @@ FC_REFLECT((golos::protocol::account_witness_vote_operation), (account)(witness) FC_REFLECT((golos::protocol::account_witness_proxy_operation), (account)(proxy)) FC_REFLECT((golos::protocol::comment_operation), (parent_author)(parent_permlink)(author)(permlink)(title)(body)(json_metadata)) FC_REFLECT((golos::protocol::vote_operation), (voter)(author)(permlink)(weight)) + +FC_REFLECT((golos::protocol::vote_author_promote_rate), (rate)); +FC_REFLECT_TYPENAME((golos::protocol::vote_options_extension)); +FC_REFLECT((golos::protocol::vote_options_operation), (voter)(author)(permlink)(extensions)) + FC_REFLECT((golos::protocol::custom_operation), (required_auths)(id)(data)) FC_REFLECT((golos::protocol::custom_json_operation), (required_auths)(required_posting_auths)(id)(json)) FC_REFLECT((golos::protocol::custom_binary_operation), (required_owner_auths)(required_active_auths)(required_posting_auths)(required_auths)(id)(data)) diff --git a/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp b/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp index 744371285e..adcd6801ff 100644 --- a/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp +++ b/libraries/protocol/include/golos/protocol/steem_virtual_operations.hpp @@ -258,6 +258,19 @@ namespace golos { namespace protocol { asset vesting_shares; }; + struct vote_author_promote_reward_operation : public virtual_operation { + vote_author_promote_reward_operation() { + } + vote_author_promote_reward_operation(const account_name_type& v, const account_name_type& a, const string& p, const asset& r) + : voter(v), author(a), permlink(p), reward(r) { + } + + account_name_type voter; + account_name_type author; + string permlink; + asset reward; + }; + struct techspec_expired_operation : public virtual_operation { techspec_expired_operation() { } @@ -288,6 +301,7 @@ FC_REFLECT((golos::protocol::comment_benefactor_reward_operation), (benefactor)( FC_REFLECT((golos::protocol::return_vesting_delegation_operation), (account)(vesting_shares)) FC_REFLECT((golos::protocol::producer_reward_operation), (producer)(vesting_shares)) FC_REFLECT((golos::protocol::delegation_reward_operation), (delegator)(delegatee)(payout_strategy)(vesting_shares)) +FC_REFLECT((golos::protocol::vote_author_promote_reward_operation), (voter)(author)(permlink)(reward)) FC_REFLECT((golos::protocol::techspec_reward_operation), (author)(permlink)(reward)) FC_REFLECT((golos::protocol::worker_reward_operation), (worker)(worker_techspec_author)(worker_techspec_permlink)(reward)) FC_REFLECT((golos::protocol::techspec_expired_operation), (author)(permlink)(was_approved)) diff --git a/libraries/protocol/steem_operations.cpp b/libraries/protocol/steem_operations.cpp index a9b66ed265..ba7b59b462 100644 --- a/libraries/protocol/steem_operations.cpp +++ b/libraries/protocol/steem_operations.cpp @@ -212,6 +212,32 @@ namespace golos { namespace protocol { GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); } + struct vote_options_extension_validate_visitor { + vote_options_extension_validate_visitor() { + } + + using result_type = void; + + void operator()(const vote_author_promote_rate& vapr) const { + vapr.validate(); + } + }; + + void vote_author_promote_rate::validate() const { + GOLOS_CHECK_PARAM(rate, { + GOLOS_CHECK_VALUE_LEGE(rate, GOLOS_MIN_VOTE_AUTHOR_PROMOTE_RATE, GOLOS_MAX_VOTE_AUTHOR_PROMOTE_RATE); + }); + } + + void vote_options_operation::validate() const { + GOLOS_CHECK_PARAM(voter, validate_account_name(voter)); + GOLOS_CHECK_PARAM(author, validate_account_name(author)); + GOLOS_CHECK_PARAM(permlink, validate_permlink(permlink)); + for (auto& e : extensions) { + e.visit(vote_options_extension_validate_visitor()); + } + } + void transfer_operation::validate() const { try { GOLOS_CHECK_PARAM(from, validate_account_name(from)); diff --git a/plugins/account_history/plugin.cpp b/plugins/account_history/plugin.cpp index 2f40f5e1b4..3396a96e44 100644 --- a/plugins/account_history/plugin.cpp +++ b/plugins/account_history/plugin.cpp @@ -328,6 +328,10 @@ if (options.count(name)) { \ insert_pair(op.voter, op.author); } + void operator()(const vote_options_operation& op) { + insert_pair(op.voter, op.author); + } + void operator()(const author_reward_operation& op) { insert_receiver(op.author); } @@ -494,6 +498,10 @@ if (options.count(name)) { \ insert_pair(op.delegatee, op.delegator); } + void operator()(const vote_author_promote_reward_operation& op) { + insert_pair(op.voter, op.author); + } + // todo: proposal tx signers are receivers void operator()(const proposal_create_operation& op) { insert_dual(op.author); diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp index 46b7c8f9be..72c511c3e2 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_operations.hpp @@ -17,6 +17,7 @@ namespace mongo_db { operation_writer(); result_type operator()(const vote_operation& op); + result_type operator()(const vote_options_operation& op); result_type operator()(const comment_operation& op); result_type operator()(const transfer_operation& op); result_type operator()(const transfer_to_vesting_operation& op); @@ -94,6 +95,7 @@ namespace mongo_db { // result_type operator()(const chain_properties_update_operation& op); result_type operator()(const delegation_reward_operation& op); + result_type operator()(const vote_author_promote_reward_operation& op); result_type operator()(const auction_window_reward_operation& op); result_type operator()(const techspec_reward_operation& op); result_type operator()(const techspec_expired_operation& op); diff --git a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp index 5e1a2a0480..5165b7a052 100644 --- a/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp +++ b/plugins/mongo_db/include/golos/plugins/mongo_db/mongo_db_state.hpp @@ -23,6 +23,7 @@ namespace mongo_db { state_writer(db_map& bmi_to_add, const signed_block& block); result_type operator()(const vote_operation& op); + result_type operator()(const vote_options_operation& op); result_type operator()(const comment_operation& op); result_type operator()(const transfer_operation& op); result_type operator()(const transfer_to_vesting_operation& op); @@ -96,6 +97,7 @@ namespace mongo_db { result_type operator()(const return_vesting_delegation_operation& op); result_type operator()(const chain_properties_update_operation& op); result_type operator()(const delegation_reward_operation& op); + result_type operator()(const vote_author_promote_reward_operation& op); result_type operator()(const auction_window_reward_operation& op); result_type operator()(const techspec_reward_operation& op); result_type operator()(const techspec_expired_operation& op); diff --git a/plugins/mongo_db/mongo_db_operations.cpp b/plugins/mongo_db/mongo_db_operations.cpp index 5d746846d6..e9b5c33fda 100644 --- a/plugins/mongo_db/mongo_db_operations.cpp +++ b/plugins/mongo_db/mongo_db_operations.cpp @@ -77,6 +77,12 @@ namespace mongo_db { return body; } + auto operation_writer::operator()(const vote_options_operation& op) -> result_type { + result_type body; + + return body; + } + auto operation_writer::operator()(const comment_operation& op) -> result_type { result_type body; @@ -817,6 +823,11 @@ namespace mongo_db { return body; } + auto operation_writer::operator()(const vote_author_promote_reward_operation& op) -> result_type { + result_type body; + return body; + } + auto operation_writer::operator()(const auction_window_reward_operation& op) -> result_type { result_type body; return body; diff --git a/plugins/mongo_db/mongo_db_state.cpp b/plugins/mongo_db/mongo_db_state.cpp index 845be0df21..8259339dfe 100644 --- a/plugins/mongo_db/mongo_db_state.cpp +++ b/plugins/mongo_db/mongo_db_state.cpp @@ -789,6 +789,10 @@ namespace mongo_db { } } + auto state_writer::operator()(const vote_options_operation& op) -> result_type { + + } + auto state_writer::operator()(const comment_operation& op) -> result_type { format_comment(op.author, op.permlink); format_account(op.author); @@ -1973,6 +1977,10 @@ namespace mongo_db { } + auto state_writer::operator()(const vote_author_promote_reward_operation& op) -> result_type { + + } + auto state_writer::operator()(const auction_window_reward_operation& op) -> result_type { }