nostr-protocol / nips

Nostr Implementation Possibilities
2.39k stars 582 forks source link

Reinstate NIP-88: Polls on Nostr #1507

Open abhay-raizada opened 2 months ago

abhay-raizada commented 2 months ago

Since the drama that caused NIP 88 to be removed: https://github.com/nostr-protocol/nips/pull/1501

There have been major updates:

I have made very slight changes according to some of the concerns raised in the comment thread.

@fiatjaf @vitorpamplona @staab @smolgrrr @alexgleason

mikedilger commented 2 months ago

This looks about right. I didn't study it in detail, but I like the non-replaceable response event, the use of an 'e' tag instead of a 'd' tag, the option for multiple choice, and explaining how to count.

smolgrrr commented 1 month ago

bump

alexgleason commented 1 month ago

This should still use a replaceable event for votes. That was never addressed. Say something that actually makes sense about it please, that's all I ask.

abhay-raizada commented 1 month ago

@alexgleason explain how you can achieve expiration polls, with PREs, where the tally of the results doesn't change post expiration, when a user updates their PRE vote.

alexgleason commented 1 month ago

@abhay-raizada You would simply query votes with the "until" filter, and you would HAVE to be querying from a trusted relay that enforces the created_at timestamp to be within a reasonable range of the current time when it accepts events. This is true for both the regular and replaceable event scenario.

The edge case where a user responds after the poll has ended because their malfunctioning client allowed them to, and the relay deletes the old version of their event, is not a sensible argument. So I will ask you again to please say something that makes sense.

abhay-raizada commented 1 month ago

@alexgleason This edge case argument makes perfect sense to me, since I want to be able to trust the polls I create. An editable vote with no paper trail is just manipulation.

You being non chalant about it is what doesn't make sense.

alexgleason commented 1 month ago

What you're describing is a buggy client behavior that does not benefit the person who voted in the poll. It would potentially allow a user to rescind their vote. People can already do that after a poll ends with kind 5 deletions. Why are you so worried about people rescinding their vote?

abhay-raizada commented 1 month ago

@alexgleason They can manipulate the tally, they could pump fake votes and then rescind their votes even after the poll has expired. This could be a huge deal when poll results have actual outcomes, like decisions being taken or awards being given on the basis of these polls.

Manipulating the tally IS the incentive in this case and DOES benefit the manipulator(s).

With this spec I could run my own relay with slight adjustments (honor current time, no delete for votes), which already exists on a lot of existing relays, to make sure the poll remains authentic, with PREs there's no guarantee without heavy modifications.

alexgleason commented 1 month ago

Okay so explain why people can't do that with kind 5 events.

alexgleason commented 1 month ago

If you have to build a custom relay for your implementation to work, then your argument against replaceable events is moot. Because no matter what you have to build a custom relays for polls to work perfectly.

There may be an argument in favor of regular events. But until you can form a coherent argument for it, I am totally against this MR.

I want us to only merge NIPs where thoughtful choices have been made. Not ones with senseless reasons. Because then developers will suffer from those choices forever.

abhay-raizada commented 1 month ago

Ouch. I'm of the opinion that devs and users will suffer if we go the PRE route.

The point isn't to win an argument it's to have a good spec. Both options need custom relays, but this method works using relay features that are out even NOW. It doesn't make the point moot, which you would want to win your stupid argument.

I can also begin talking about uneditable votes and other things which are easier to do with the current spec, but arguing with you at 2:00 am in the night is not worth it.

If you don't want to merge it, don't. My job was to write a decent spec, and a decent implementation for polls and I believe I've done that. I'll just continue making it better, if anybody else wants to use It, It's right here.

vitorpamplona commented 1 month ago

The only benefit of regular events is simplicity: clients don't need to code the PRE system (deal witha indexes, PRE deletions, etc). PREs are better for those of us that already implemented the PRE system (which is a requirement), but it is terrible for new clients.

The only benefit of doing PRE is to offer fast-changing votes. Yes, this could be done by kind:5 deleting and re-submiting a regular event, but that will fill up the relay's database quickly. In non-fast-changing votes, PRE doesn't really save much data.

Expiration polls can be offered with both systems, but with regular events votes after the date are downloaded and discarded while with PRE public keys that voted a second time after the date get removed from the tally for cheating.

Neither option protects against tally manipulation. Frankly, I would never take the results of these pools seriously, since spammers, real users, and relays can all manipulate the tally, both while people are voting AND after the vote has finished.

abhay-raizada commented 1 month ago

but with regular events votes after the date are downloaded and discarded

@vitorpamplona How? I only query regular votes until poll expiration time?

Neither option protects against tally manipulation.

@vitorpamplona do you mean they don't protect against tally manipulation by default? because I can see both of the methods offer protection against tally manipulation given relays with custom rules.

vitorpamplona commented 1 month ago

but with regular events votes after the date are downloaded and discarded

@vitorpamplona How? I only query regular votes until poll expiration time?

Yes, isnt it what you want?

Neither option protects against tally manipulation.

@vitorpamplona do you mean they don't protect against tally manipulation by default? because I can see both of the methods offer protection against tally manipulation given relays with custom rules.

Sure, custom relays can make both cases work. And regular relays don't offer any protection.

But I wouldn't build custom relays for this. It's too niche. No one will know how to use it. Instead, you can simply make a DVM that confirms each vote with a new event by whatever rule the DVM is tallying.

abhay-raizada commented 1 month ago

Instead, you can simply make a DVM that confirms each vote with a new event by whatever rule the DVM is tallying.

that still doesn't solve manipulation? just makes applying rules easier, Also with regular events the custom-poll relays are not complicated, only needs to handle back dating and deletes , I'll see if i can add an implementation for it soon.

Yes, isnt it what you want?

Yes what i'm pointing out is that, votes after the date are not downloaded even for regular events.

vitorpamplona commented 1 month ago

If you do DVM tallying, the author could select the DVM that is counting the votes and then clients can just download what the DVM is signing instead of the user's votes. The DVM can just output the results with a bloom filter of the events included in the tally, for each option.

But that feels like it could be its own event kind.

Basic bloomfilter spec if you want to try: https://github.com/nostr-protocol/nips/pull/1497

abhay-raizada commented 1 month ago

Understood, a very round about way to go at it, but it could work. How does a DVM know if an event is back dated though?

vitorpamplona commented 1 month ago

Understood, a very roundabout way to go at it, but it could work

It depends on how serious you want these polls. If it is really serious, you want to separate the responsibility of tallying from storing. You also don't want clients to tally at all. People can choose 3-4 relays to store, but only one service to tally. And that service is the final result. There is no client, relay shenanigans where vote can keep changing over time if the client allows it.

How does a DVM know if an event is back dated though?

The DVM either runs while the poll is active and allows users to confirm their vote was counted OR it runs only at the end. Either way, the DVM stops when the poll closes and counts from everything it can download from relays.

Separating them from relays also allow anyone out there to code custom tallying methods, like checking for membership in lists or groups, etc.

dluvian commented 1 month ago

I have implemented this nip in Voyage with the caveats that only nip22 replies are supported for commenting/replying on polls and kind:1068 is always interpreted as a singlevotepoll. Other poll types should have different kind numbers.

abhay-raizada commented 1 month ago

After giving this some thought, I am of the opinion that single and multiple choice voting should still be the same kind interpreted through tags, one is just the superset of the other and existence of one doesn't break the other as well, multiple choice can easily be interpreted as single choice in other clients and even vice versa without breaking other clients.

I do however think ranked choice will break this, and I should move it to a different kind, I will update this.

abhay-raizada commented 1 month ago

@dluvian removed ranked choice from the NIP, may add it as a different kind once I implement it on pollerama.fun

dluvian commented 1 month ago

@abhay-raizada I'm ok with this but I still think having different kinds is the cleaner way. No need for a polltype tag and clients could decide which poll types they want to fetch.