nips icon indicating copy to clipboard operation
nips copied to clipboard

Make kind 7 act as parameterized repleaceable event

Open arthurfranca opened this issue 2 years ago • 11 comments

Considering NIP-25 is marked as a draft, thought of a way of fixing some problems with the reactions while not breaking current clients. Although the possible values of the d tag may look unusual, it is just specific to kind 7.

This should make it possible to:

  • react to all kinds of events (but ephemeral) or to a pubkey (profile)
  • react once to save relay disk space
  • allow edits to content
  • re-use relays existing parameterized repleaceable event handling logic to do edits
  • request just the reactions to an event (using { "kinds": [7], "#d": ["note id"] } filter), instead of including all thread reactions

I think it would be better to also suggest to include just 2 tags, the d tag (required) and only one p so that the owner of the reacted to post/profile can be notified, instead of everybody in the thread, while also saving space. But i didn't add it to not make current clients mad.

arthurfranca avatar Feb 16 '23 18:02 arthurfranca

Smart. Starts to get a bit heavy though if every reaction needs d, p, e tags, with probably one repetition (since the value of the d will probably match the value of one of the e, p). What do you think about this?

Also the reaction needs to include all the p, e, a tags from the event being reacted to? Seems a bit overkill, but I guess you agree with me on this point but don't want to make current clients mad.

barkyq avatar Feb 17 '23 07:02 barkyq

Smart. Starts to get a bit heavy though if every reaction needs d, p, e tags, with probably one repetition (since the value of the d will probably match the value of one of the e, p). What do you think about this?

Also the reaction needs to include all the p, e, a tags from the event being reacted to? Seems a bit overkill, but I guess you agree with me on this point but don't want to make current clients mad.

@barkyq I've pushed changes in this direction. I do think adding all those p, e, a tags are a waste of disk space (bigger event size) and also of bandwidth because one asks for direct reactions but receives "all" (the relay most likely will limit it anyway) thread reactions. It is also strange to put many p tags which would mess with notifications (why would someone want to be notified of a reaction to the reply to a reply to a reply to his post? =o)

arthurfranca avatar Feb 17 '23 12:02 arthurfranca

:+1: Nice that it blocks users from reacting multiple times on the same pubkey without requiring new relay logic. Also consistent with #236

barkyq avatar Feb 17 '23 16:02 barkyq

I think I would want to keep the e tag for reactions to replaceable events, or at least some reference to the id of the event originally reacted to. Without such a reference, the event may be replaced in a way that changes the context and meaning of the reaction, without any indication that the reaction was to an earlier event.

shafemtol avatar Feb 24 '23 20:02 shafemtol

@shafemtol it totally makes sense. However, if the created_at of the reaction is older than the created_at of the current version of a replaceable event, it is enough to know you liked a regular note before it changed into a pr0n ad. Per NIP-16 an event can only be replaced if it has newer timestamp. Is it enough or would you still require the original event id for your use case?

arthurfranca avatar Feb 24 '23 22:02 arthurfranca

I thought of the created_at timestamps, but in my mind relying on those would not be enough. The changed note could have a timestamp one second later than the original note and thus most likely have an earlier timestamp than any reactions.

shafemtol avatar Feb 24 '23 23:02 shafemtol

yes in order for the timestamp thing to work, relays need to not allow posting of events with old created_at

barkyq avatar Feb 25 '23 01:02 barkyq

yes in order for the timestamp thing to work, relays need to not allow posting of events with old created_at

That would just not be viable. That would mean that if you went out of sync with one of your relays for too long and then came back, some of your events on that relay would remain permanently unavailable or stale. At least until NIP-03 is widely deployed and actively used, relays have to take old timestamps at face value.

shafemtol avatar Feb 25 '23 12:02 shafemtol

The changed note could have a timestamp one second later than the original note

There is NIP-22 (Event created_at Limits) that could prevent it. But as it is optional, you are right, or else we would need to add it as a dependency to this NIP, which doesn't seem right. Also, the extra e tag allows a client to just fetch reactions to the current version of the replaceable event if it wished to hide stale reactions, instead of filtering client side. This would encourage just typo edits near the publish time instead of full edits.

arthurfranca avatar Feb 25 '23 13:02 arthurfranca

Isn't this a relay policy choice?

fiatjaf avatar Feb 25 '23 18:02 fiatjaf

Isn't this a relay policy choice?

Yes NIP-22 range is custom relay config indeed. One more reason to need the event id of the replaceable event.

arthurfranca avatar Feb 25 '23 19:02 arthurfranca

@fiatjaf do you think I should add something like "Because the previous version of this NIP relied on e tag instead of d tag, for a transition period the reaction event MAY include an e tag with the reacted to event id even if such event isn't replaceable."?

Is there anything else I can do to help this land?

arthurfranca avatar Mar 08 '23 15:03 arthurfranca

Yes. Change the NIP to say that relays must deduplicate reactions to the same event. Do not change anything else in the event format. Instead relays can be smart enough to do

if event.kind == 7:
  if current = get(kind = 7, #e = event.tags.e):
    replace(current, event)
  else:
    add(event)

fiatjaf avatar Mar 09 '23 11:03 fiatjaf

@fiatjaf What about this? It is very similar to contact lists that can leverage relays replaceable events logic by just doing:

function isReplaceableEvent (event) {
  return event.kind === eventKinds.CONTACT_LIST ||
    (event.kind >= 10000 && event.kind < 20000)
}

Relays would need to just update the isParameterizedReplaceableEvent function to also check for event.kind === eventKinds.REACTION. So no special logic just for a kind as in your example.

Relays that have implemented parameterized replaceable events will automatically treat today's reaction as having d = '' as per NIP-33 specs. The relays which haven't implemented it will work just like today, storing duplicates. Clients rely on external relays, so relays are kings. In the end of the day, relays dictate nostr protocol, not the clients. Even Damus would have to change eventually.

arthurfranca avatar Mar 09 '23 13:03 arthurfranca

I just don't see why add this extra d tag when we already have the e tag that can be used for replacement. And then require all clients to change when it's much easier for relays to change their behavior. Relays should probably do this for other kinds too.

fiatjaf avatar Mar 09 '23 14:03 fiatjaf

I just don't see why add this extra d tag when we already have the e tag that can be used for replacement

The previous version was a Frankestein because I tried to keep old text intact by not removing this: Including the e tags enables clients to pull all the reactions associated with individual posts or all the posts in a thread. Very unlikely to need all reactions to all posts in a thread. It would be massive amount of data. Please see updated version.

At first, there wasn't an official way to categorize an event as replaceable. Replaceable Events came as NIP-16 and Parameterized Replaceable Events followed at NIP-33.

"Set Metadata", ~"Channel Metadata"~ and "Contact List" are in essence Replaceable Events, but as they were created before NIP-16, they just aren't in NIP-16 kind range. But the logic to update them is the same as any replaceable event: find by kind and pubkey > check if new created_at is greater > replace it

My point is that reactions are in essence a parameterized replaceable events, though it is missing the d tag, cause it was created before NIP-33 even existed. With the d tag we can do: find by kind, pubkey and d tag > check if new created_at is greater > replace it.

Just like future event kinds that wish to be replaceable shouldn't expect special logic from relays. Just use the right kind range and, if needed, the d tag.

arthurfranca avatar Mar 09 '23 17:03 arthurfranca

My only problem with all your suggestions is that even though they are good you completely disregard the problematic effects to breaking things. Open https://nostr.net/ and see how many implementations of relays and clients exist today. It is really not worth making breaking changes to spec when all these codebases exist and are doing things in one way. It will just create massive confusion.

fiatjaf avatar Mar 09 '23 18:03 fiatjaf

I did pondered over the breaking change aspect. In this specific case of reactions, that aren't main functionality kind of events, on a NIP marked as draft, by applying changes that wouldn't break feed nor thread loading and would eventually be noticed by client authors when they see unexpected reaction counts, I thought it was a good idea. Yet I get you and others don't think the same way. Thanks for replying.

arthurfranca avatar Mar 09 '23 20:03 arthurfranca

Sorry, I feel bad rejecting all your suggestions given that you really seem to care.

fiatjaf avatar Mar 09 '23 20:03 fiatjaf

We are early on in the protocol and if reactions need fixing, we should fix them now.

Event deletion is a mess in a decentralized protocol and the only way of removing reactions right now. The deletion event has to be kept around in case the deleted event is still around, too ...

With a parametrized replaceable event, changing a reaction would work and we could even define that reaction "" is the implicit deletion.

As clients would have to be aware of this new way of doing reactions, I'm against touching kind-7 behaviour. We have nip33 for a reason and relays that implemented it would not need further changes to support these reactions on kind-30007 for example.

e- and p-tags would not be needed as clients requesting reactions to profiles/events would ask for respective d-tags. We might add an "e" or "p" somewhere though so that clients could find e/p if the reaction is all they know. Following Alice I might only find she liked something and want to know what it was. Maybe tag ["d",$eventId,"e"].

First clients to implement kind-30007 could author both kinds of reactions and de-dupe reactions accordingly and we retire kind-7 once the new way catches on.

Giszmo avatar Mar 17 '23 15:03 Giszmo

I think this ship has sailed, adding a MUST here is a little too strong for an event type of which we have millions. I think @fiatjaf is right that this is a relay policy issue, and should probably be added to NIP 07 as an additional requirement for relays. Closing for that reason and for inactivity.

staab avatar May 13 '23 05:05 staab