zeitgeist
zeitgeist copied to clipboard
Implement Global Disputes
Fixes #654 Fixes #489
Problem There is no implementation for voting on multiple outcomes. Solution https://github.com/zeitgeistpm/zeitgeist/blob/0f197fcf68e087043dc97b494924acf7cb7bd72f/zrml/global-disputes/README.md
This is not a complete review, just a few general remarks. We should probably discuss there in an extra meeting:
-
You implement the
DisputeApi
forglobal-disputes
. That's fine by me. But you also addGlobalDisputes
to theDisputeMechanism
enum. That seems like a mistake to me. The global disputes were never supposed to be an alternative to the other dispute mechanisms, but rather as a solution for when the market is disputed forMaxDisputes
times. -
The voting options made available to the token holders are the outcomes reported in disputes, right? So if the oracle reports A, someone disputes B and then someone disputes C, the token holders can vote on A, B and C, but not D, E, etc.?This means there's a potential attack vector: Dispute back and forth using multiple accounts to limit the options available during the global dispute. For example: A market has three options, A, B and C. I know that C is true, but I want to make sure the market resolves to A or B. So I dispute back an forth between A and B (I can do this in a single block), causing a global dispute, in which A and B are the only voting options. It doesn't even cost me anything, since the amounts of my funds that are slashed are distributed amongs the accounts which reported correctly, which all belong to me.
This can be fixed for categorical markets by just allowing all options to be voted on, but for scalar markets, things get more complicated (there's a solution there using so called bump functions where votes vote on a small weighted range of possible values, but this might be computationally difficult).
-
(This is just food for thought, doesn't have to be considered right now) In terms of game theory,
global-disputes
doesn't give us a Schelling point because the votes are visible before the end of the dispute. There might be a solution where people encrypt their commitment and then reveal it when the voting is done (we will do something similar in court). -
I am not a fan of burning, transferring the assets of the "loosing" accounts (which voted not on the dispute with the most stake), because it leads to a fear of voting for the once with lower stake. Additionally a big wale makes vote sniping at the end of the DisputePeriod and gets even bigger (or if it goes to the treasury, then Zeitgeist gets even bigger).
The alternative is to let malicous actors get away scot-free. That's not good either. Furthermore, if voting isn't incentivized, turnout will be low, making it easier for whales to throw their weight around.
To be honest, I'm starting to like the idea of encrytping commitments, because that seems to solve a lot of these issues.
Thank you so much for your deep and well thoughts. I follow your structure with my comments.
- I took thought into it, that we "start" a global dispute after reaching
MaxDisputes
. What speaks against a new dispute mechanism (so a replacement of simple disputes)? But sure, I could start allowing the voting afterMaxDisputes
. For this speaks, that the influence of the token holders is mitigated, untilMaxDisputes
is reached (and only the one with the most dispute bond wins). But on the other hand it's more complicated to block the resolution until enough votes are present. I mean, that we would probably add a time period and another state, just for allowing anybody to vote. This is added to the overall resolution time, instead of allowing anybody to vote as the dispute comes in. I understand your thought and we should ask @lsaether for that. The current implementation allows a long voting period, which I would like as a user. - I already thought about this, but I forgot it, so good point! This could be mitigated if we remove the maximum number of disputes
MaxDisputes
. This leads to the option, that anybody with enough funds can dispute as long as theDisputePeriod
is not over. But I mean the task is to select one outcome out of the disputes. Especially in scalar markets, you pointed out, that this would be not so easy. So I would probably go with allowing many disputes and let the token holders choose which one is the right. With this method, it's disincentivised to spam disputes, because you'll most likely loose your funds. And I think, it's already disallowed to dispute on the same outcome here. I just realised, that this only checks the last dispute, but not all of them. Another thing: I meansimple_disputes
had the same flaw, that I could ping pong untilMaxDisputes
and rule the final decision (that you pointed out here). So I agree, we need to address that! - Ok, this adds much complexity. I think for the time I took, it's cool to have a first working version.
- Mhh, that's a hard major decision. I probably go for the solution with locking. It's reasonable for the ZeitgeistPM wales to make the final shot, because it's in their best interest to decide for the truth, otherwise users wouldn't use the protocol. Ok, the best solution is to have a well-defined algorithm which can calculate the truth, but we live in a complex world, in which not everything can be measured and calculated with the current computers. The turnout would be low, but if it's important / relevant enough, it will get more turnout and apart from that, it's sufficient to have a low turnout when it's the truth.
Again, thank you for your important food for thought.
I want to discuss bullet point two again. That current solution should work for categorical markets fine, because at one point, all the categories are reached. But for scalar markets this is harder to solve, because there is no upper limit to the number of possible disputes. So this would run as long as there are users which have enough funds to cover the increasingly rising dispute bonds. After the last bond it continues until the DisputePeriod
is over. But it's disincentivised to dispute further, because the most votes will get on early and correct disputes, so nobody wants to loose funds (as it is likely when you dispute late after most of the votes are catched). But for scalar markets someone with huge amounts of funds could run the dispute period a very long time, but this essentially burns money (which goes to the disputor with the most votes).
Bullet point one:
Apart from that: Maybe replace the zrml-simple-disputes
with zrml-global-disputes
entirely and thus the enum value.
Review in progress.
We should also add the information that this pallet was added to docs/changelog_for_devs.md, like it was done for the Styx pallet. Ideally we name (or put a reference to) all changes that are relevant downstream, such as dispatchable calls and events.
I've not managed to completely exclude the addition of the feature with-global-disputes
from the main-net, because the common runtime would like to know, what happens if the feature is enabled from each derived runtime. But the effect is the same, if we avoid using with-global-disputes
for the main-net and just use this feature for Battery-Station.
@maltekliemann
Does the pallet create any imbalances when resolving a market? In other words, does the total issuance during resolution?
In terms of using NegativeImbalance
or PositiveImbalance
the zrml-global-disputes pallet does not use these kinds of types. There is no increase or decrease in total issuance for zrml-global-disputes. There is a transfer
for the constant fee to pay to add a voting outcome and there is the set_lock
or extend_lock
to lock funds for voting.
When I vote on an outcome, I become an owner, correct?
There is add_vote_outcome
and vote_on_outcome
. With add_vote_outcome
, you become the sole owner of that outcome. vote_on_outcome
just lets you vote on outcomes added with add_vote_outcome
(or push_voting_outcome
). You don't become an owner of the outcome, when you just vote on one with vote_on_outcome
.
But when the set of owners is full, my vote still goes through, I just don't become an owner? (If not, then there's a Sybil attack where you clog the set of owners with your accounts and then no one can vote anymore.)
The set of owners can only be full in the following scenarios:
-
add_vote_outcome
is already called for an outcome (maximum limit of owners for this is one) -
push_voting_outcome
is a private API call and adds up toMaxOwners
owners. This is useful, because the current prediction markets pallet allows multiple disputes (with different account ids, who published the disputes) on the same outcome. Because there areMaxDisputes
possible disputes, I usedMaxOwners = MaxDisputes
as the config parameter. I know, that we would like to restructure the whole dispute system in the pm-pallet, but at the point of writingzrml-global-disputes
, it wasn't clear enough how, so I allowed this flexibility of having multiple owners. The reason for usingpush_voting_outcome
at all, is to initialise a global dispute with a higher number of possible voting outcomes (otherwise it is zero at the start of the global dispute). Additional comment here and here.
I understand your thought with the assumption that for a vote you become an owner of a vote. Then yes, your example with the Sybil attack is possible in this case. I separate the addition of voting outcomes to the actual voting. Only the ones, who added the voting outcome, become the owner, because they paid a fee (or a reserve for the dispute bond). The simple voters are not in risk of loosing funds, because they only use the thin layer of LockableCurrency
.
If I'm not the owner, I don't get rewarded for voting, correct?
There are no rewards for normal voters. Your point might be: Why should anyone vote then?
- all participants vote, who have something to loose (outcome owners)
- Zeitgeist and Big Whales are most likely financially interested in making good protocol decisions (and might want to disallow false outcomes and vote for true outcomes instead)
- If the attention is high enough on a particular market resolution (I see YouTube videos in the future for controversial voting decisions), even small fishes are motivated to vote.
Ok, but nonetheless I truly see your point, that small fishes have no interest, especially if they feel not strong enough alone, to vote. But when we think about rewarding all voters, you come to the following point. Say for example you have sum X to spend for all voters. Now you come to the question: How to spend those funds on all voters? You might think: Okay let's reward proportional to the stake they gave into the sum of all votes. But then you end up with the situation, that Big Whales earn even more. So how would you like to reward voters?
I would just leave it as it is for now and hope for a future, in which communities are growing and vote together, because they see, that they are strong together. Until then, Zeitgeist has the most interest to vote in doubt for running a right service.
Does being an owner serve any other purpose?
Having the owner/s in storage is useful for the transfer
of funds from the ones, who proposed the wrong outcomes, to the others, who proposed the right outcome.
Why can't we just make everyone an owner?
Who do you mean with everyone
? When we make everyone an owner, then we might have the problem, who to reward in the end.
I'm worried that the notion of owner is too complicated.
Yeah, the owner system in zrml-global-dispute
is only complicated, because zrml-prediction-markets
allows multiple disputes with the same outcome. If this was not the case, so that there exist only unique outcomes in the disputes, then it would be a lot easier on the zrml-global-disputes
site. Then I would store instead of a BoundedVec
just an AccountId
.
First of all, it might solve some basic problem of storage restrictions, etc. but introduce new problems which are just harder to recognize.
I really thought hard about efficient storage usage in this pallet. Because there is the limit of one owner per add_vote_outcome
call, the BoundedVec contains only one account id (which could be the final voting winner, and thus reward this account id).
push_voting_outcome
with the current pm-pallet hardly gets over two owners per outcome, because this means with the current implementation, that the disputes were made on the same outcome for more than three times.
In terms of social decision theory, we're flying completely blind here, right? Or is there literature suggesting that this type of voting system is sufficiently difficult to exploit?
I have not based my implementation on any literature, I just used the pallet_democracy
implementation and my common sense for the voting outcome addition, which is based on the basic idea: Reward the winners with the loosers funds.
In addition to that, the number of voting outcomes is naturally limited by the fear of the users to loose the fee. And it's naturally incentivised to add a voting outcome early, otherwise the major amount of votings are already done (which naturally happens only, when the voters think, that a specific outcome is already true, so they don't need a new outcome).
I think doing "ping-pong" disputes until a global dispute is triggered is somewhat exploitable (depending on the answers to the question above).
Only one outcome wins in the end. When you "ping-pong" disputes this means, that you reserve MaxDisputes
dispute bonds. The attacker would be uncertain about the actual voting winner. It's guaranteed, that the attacker looses some of the dispute bonds. When it's an attacker it's even likely, that the attacker looses all of the dispute bonds, because another users adds a voting outcome (which is different from the attackers) and all voters vote for this new voting outcome in order to hurt the attacker the most.
But yeah, you are right, that an attacker could trigger a global dispute. In what way is that a problem? Is it, because we would like to make it hard to trigger a global dispute? In the battery-station we wanted to test it out, so it's even desired to trigger it more easily on the test-net for a transitory time (until court is finished).
I'm petty certain that the dispute bonds in prediction-markets should increase exponentially to ensure that escalating the dispute to the next stage costs about twice much as all funds that are already in the "pot". I've compared bonds that ramp up linearly with Limit Poker, where playing the odds often means staying in the hand because the proportion of bet size to pot size is super small. A significant amount of 7 Card Stud hands make it to showdown. Ramping bonds exponentially is more like pot sizes develop in Hold'em, where showdown occurs less often.
There is no implementation problem for me on this, but could we please do this in another PR? I would be glad to implement that, if you really think, that this is required. On the other hand it means for me, that zrml-global-disputes
is triggered much less often. Maybe it's okay for the testing purposes to let it grow linearly to trigger global disputes more often on the test-net.
Starting my review now...