inertia186 / drotto

Pay-to-play voting bot.
Other
30 stars 42 forks source link

No refund for bids after post was voted (same day) #5

Open html-code opened 6 years ago

html-code commented 6 years ago

This issue was discovered on Golos where we have Booster bot.

  1. Steps to reproduce:

    • User makes bid for his post
    • Booster upvotes post
    • User (accidentally?) makes bid for the same post
  2. What should happen Booster refunds bid to user.

  3. What happens Booster gets bid and don't refund it.

  4. Additional info. I see other returns for voted posts, so feature exists. But looks like drotto (Booster) thinks it voted a post correctly if several bids transferred in the same day.

  5. Partial solution. Compare bid timestamp and upvote timestamp. Return bids, which transferred after upvote. !But there are edge cases. Bid can came after "round close" and before post upvote. It's not very rare, coz bids frequently placed near round end (to append in this case).

  6. Real World Examples (Golos):

a. Normal

(2017-11-15 06:01:18) 10 gbg bid for post tx (2017-11-15 06:42:00) upvote: tx (2017-11-15 13:11:45) 10 gbg bid for the same post: tx

b. Edge case:

(2017-11-15 22:59:12) oksana0407 (A) bids 8 gbg tx (2017-11-15 23:10:24) cryptobandera bids 10 gbg tx - not counted, already voted (like in case a.) (2017-11-15 23:18:24) now (B) bids 100 gbg tx (2017-11-15 23:25:24) santa-barbara (C) bids 15 gbg tx (2017-11-15 23:26:39) eee (D) bids 197 gbg tx

(2017-11-15 23:32:48) now (A) bids 51 gbg tx

(there are also some <0.3gbg bids, which passed to next rounds or refunded later)

upvotes start

So let calculate received upvote percents:

what without last bid with last bid
Bids sum 8+100+15+197 = 320 8+100+15+197+51 = 371
Upvote A 10/320 = 3.13% 10/371 = 2.70%
Upvote B 100/320 = 31.25% (100+51)/373 = 40.48%
Upvote C 15/320 = 4.68% 15/371 = 4.04%
Upvote D 197/320 = 61.56 197/371 = 53.01%

If we check check blockchain, we'll get exactly same percents (31.25%, 61.56%, 4.68%) as in "without last bid" column. So round was closed before it, but there were no refund for that bid.

inertia186 commented 6 years ago

The main rake bounce task won't refund posts if their age exceeds the max_age setting. Normally, this situation is handled by the rake bounce_stream task. But at the moment, Golos APIs does not return the information Dr. Otto requires.

https://github.com/GolosChain/golos/issues/281

I do plan on investigating a way to use get_ops_in_block, but I don't like this option because it doubles the number of API calls while streaming the blockchain.

The other option vik suggests is to decode the transaction id from the signature, which would be a nice feature.

inertia186 commented 6 years ago

image image image

Also, I believe this is the full window you're referring to.

html-code commented 6 years ago

Ohh, yeah, I see, it's not the edge case, it's out of window. But drotte thinks it's in.

As about max_age - maybe it's possible to check "mode" = "first_payout" instead? (from get_content)

inertia186 commented 6 years ago

I do have some re-vote logic in the works, but it's quite tricky. Another thing that makes golos tricky is that posts can stay in the first_payout longer than 24 hours when that mode is extended by upvotes. Dr. Otto does not consider extended payouts. Not sure if it ever will. If the operator wants to vote into the extended and second_payout timeframe, they can increase max_age.

html-code commented 6 years ago

I believe 24hr limit it's not a problem if not upvoted bids refund properly.

And second_payout window is not needed. It will be removed soon (I hope) with hardfork, which we waiting in week-two-month

html-code commented 6 years ago

Also, I believe this is the full window you're referring to.

I've rechecked and it's true edge case. Here we see:

  1. Booster (drotto) receives bids
  2. Booster closes window and start upvouting (ce6ed2a8).
  3. Booster gets one more bid, before upvote for that post.
    • It's not counted because window is closed and vote percents are calculated.
    • It's not refunded because it looks inside window. But vote percents say, that it's outside.

Possible solution is to store votes and related bids. I don't like outer storage, so it should be inside blockchain. The good place to store that data is Booster comment about vote, bids hashes can be added there. The somewhat bad side: comments need 20sec delay.

html-code commented 6 years ago

Also it's possible to store with custom_json.

inertia186 commented 6 years ago

I believe the majority of issues related to multiple bids cast for the same post will be handled by rake bounce_stream. If the vote has not been cast, multiple bids should stack into one large bid. If the window is in the middle of being processed, it should be handled manually, for the moment.

I like the idea of adding metadata about the applied bids. This would be useful for to verify bid stacking. This data could be used to improve bounce logic blind spots.

At this time, the develop branch now has a working rake bounce_stream, as of 81b15e7bdddded996decc0daedb3218c8fdfd677.