I would like to start a discussion regarding the following proposed changes to the reward processing and voting logic in the Steem blockchain. I'm particularly interested in hearing from @dan. There likely may be some ramifications to these changes that I wasn't able to foresee. Also, I think I have a good idea of the technical effort it would take to make the vote updating changes, but I would appreciate further clarification on that. And of course it is important for the community to discuss the philosophy behind these changes and whether we even think they are worth having.
Proposal
There are two main changes to the current protocol:
- For posts/comments that would not be paid out non-zero rewards (either due to negative net vote or because the positive net vote is so small that the payout is considered too small for the blockchain to bother paying out), the blockchain would not reset the net votes nor the list of who already voted for the post/comment. Those two items would only be reset after the blockchain actually pays out something to the author of the post/comment. Until then, the blockchain will allow new voters to continue voting for the post/comment.
- Votes can be updated. Updating the vote weight to 0 would be effectively the same as retracting one's vote (e.g. if they voted accidentally). However, updating a vote does not change the cashout time of the post/comment.
Details of the proposal
I think upvoted posts/comments that have rshares so low that the resulting sbd_payout_value is less than STEEMIT_MIN_PAYOUT_SBD should be "held back" in much the same way as posts/comments with negative rshares. Here are the changes that would be necessary (of course appropriate changes for hard forking logic are not included here, so you can take this more as pseudocode):
This line would be replaced with:
return 0;
These two lines would be replaced with:
auto reward_tokens = ( cur.net_rshares > 0 ) ? claim_rshare_reward( cur.net_rshares ) : 0;
if ( cur.net_rshares > 0 && reward_tokens != 0 ) {
This line would be replaced with:
if ( c.net_rshares > 0 && reward_tokens != 0 )
And these lines would be wrapped in an if statement:
if ( reward_tokens != 0 ) {
<Lines 1243 to 1249 go here>
}
Note that the above change also changes how negative net vote comments are treated. Currently, all votes are reset for such comments at cashout time. That means someone who voted before can vote again. Was this desired behavior? And if so why? I think it makes more sense to not let people who have already voted on a comment to vote again until the author of the comment has actually been paid. I can see a reason for wanting an upper bound on the time one has to wait after they voted one way before they are able to change their vote. But I think the more elegant solution there is allow for vote updating.
As far as I am able to tell the path dependence of voting only affects the cashout_time and vote_object weight (which affects curation payouts). The changes to net_rshares and abs_rshares in various places in the DB could be adjusted with vote updating. What I propose is to distinguish a difference between casting a vote on a comment for the first time after publishing or last paid cashout (which I call a new_vote_operation) and vote updating (which I call a vote_update_operation).
Nearly the same algorithm for voting (including cashout_time modification) would be used for a new_vote_operation, except the comment_vote_object would have three new fields: voted_rshares (which are the signed rshares calculated at the time of vote creation or vote update); voted_power (which is the used_power calculated at the time of vote creation or vote update); and last_update (this is just a timestamp of the last time comment_vote_object was modified which isn't necessary but may be useful for rate-limiting vote updates). A new_vote_operation by an account is not allowed on a comment that already has a comment_vote_object associated to that same account.
However, an unlimited number (possibly rate-limited) of vote_update_operations are allowed assuming the appropriate comment_vote_object already exists. These vote update operations would have a similar algorithm as the new_vote_operation except that they would not modify cashout_time and of course they would properly account for the net_rshares and abs_rshares changes needed throughout database (which is why the voted_rshares field was needed) as well as changes to total_vote_weight of the comment (it can use the existing weight field of the comment_vote_object to do this part of the accounting). Note that updating the vote to a new rshares value of 0 would be equivalent to "retracting one's vote". The voted_power field can be used if we want to give back some of the account's voting power which would be accounted for in the calculation of current_power before the rest of the algorithm continues.
I know this doesn't replicate the same behavior that would have occurred had the updated votes been used from the very beginning. The resulting cashout_timeout will of course be different from vote updating than if the user voted the way wanted to from the beginning. But the bigger difference is that the weight of the voter (used for curation rewards) will almost always be less than it would have been had the voter just voted the way they wanted to from the beginning (The one exception is if in the time between the last time the user voted on the comment and the current vote update operation on that comment, no one else voted on that comment. In that case, there is no reduction of their vote weight from a curation rewards perspective). Despite these differences in behavior, I don't think it is a problem or reason not to have vote updating. The point is that someone who accidentally upvoted when they meant to downvote, or vice versa, can correct their mistake without unfairly rewarding or penalizing someone else. And if they are quick to update their vote, they are unlikely to be penalized in any way.
So besides the vote updating benefits, what do the changes at the top of this post get us? In the current system someone that gets a slow trickle of small votes on their post/comment over some period of time may end up not getting any reward at all. For example, assuming there was one unique account that voted on the comment per day and they each had the similar voting power. Each vote alone would not result in a "props.total_reward_fund_steem.amount.value * net_rshares.value * net_rshares.value / props.total_reward_shares2" large enough to be worth the payout (meaning worth less than $0.02). Because of the current algorithm, the votes and net_rshares would be reset each day before the next vote comes in. With the changes I am proposing, subcent rewards could accumulate over time (even if it takes a few weeks) until it is worth enough for a payout. In fact, with this change, we would be free to raise the STEEMIT_MIN_PAYOUT_SBD value with little harm to the users. Perhaps a limit of $1 would make more sense. That way parents of that comment would be more likely to end up getting paid something.
Conclusion
This proposal gives users the ability to effectively retract or change their vote (with minimal downsides). More importantly, the proposal fixes an issue in the current system in which users who receive a steady (but weak) stream of only upvotes on their content receive no financial reward. Let's take an admittedly unusual example to show how big of a difference this could be for users. Imagine a user that has 100 comments that each get 1 cent of reward worth of votes from unique voters each day over the course of a year (i.e. each comment gets 1 vote per day from 365 unique users). Under the proposed changes, the user would earn $365 in that year. Under the current system, the user earns $0.