Skip to content

Generalise event lifetime preferences #236

@hoytech

Description

@hoytech

Background

Implementing NIP-33 and NIP-40 for my relay (strfry) caused me to think a bit about user-specified event lifetime preferences. We can roughly classify these into the following categories:

  • Replaceable events, including parameterised replaceable (NIP-16, NIP-33): These indicate to a relay that an event can be removed when another more recent qualifying event is received
  • Ephemeral events (NIP-16): These events should be broadcast to all connected users with a matching filter, but then deleted (or not stored in the first place)
  • Expiring events (NIP-40): These events should be deleted when a specifed timestamp is reached

Note that if a relay supports NIP-09 deletions then all of the above could in principle be implemented with delete events:

  • Replaceable events could be deleted immediately before posting a replacing event
  • Ephemeral events could be deleted immediately after posting
  • Expiring events could be deleted at their expiration time

By using deletions, any of these categories of event lifetimes could be implemented for events of any kind.

Problems

Replaceable, parameterised replaceable, and ephemeral events are specified to only apply to events within ranges of kinds. To me this seems sub-optimal:

  • Protocols can't group their kinds together if they need different event lifetimes for different kinds. For instance, NIP-28 (public chat) reserves the range of kinds 40-49 but specified kind 41 to be replaceable, before NIP-16 was specified, I assume. With NIP-16, a non-contiguous kind in the 10000-19999 range would need to be reserved.
  • Kinds can't compose with event lifetimes. A new protocol might like to have some messages of the same kind have different event lifetimes. For example, a protocol might like to support editable (replaceable) postings as well as "permanent" postings using the same kind.
  • Users can't specify custom lifetimes for events of existing protocols. For example, you could imagine sending an ephemeral kind 1 message, as a "disappearing" temporary message that would pretty much just work on any existing client.
  • The 10k blocks of ranges are arbitrarily sized, and they could be either too small (new ranges would have to be reserved in the future) or too big (prime kind real-estate will forever go unused).
  • Users who aren't aware of the special handling of a particular kind mind start using it and get unexpected event lifetimes.

Importance of parameterised replaceable events

I believe NIP-33 is a very important specification and will be heavily used by future protocols.

The NIP itself doesn't contain any use-cases, but as a basic example, I could imagine using these types of event lifetimes for sharding and segregating your kind-3 contact lists. You could imagine having multiple different contact lists, like family, friends, co-workers, randos1, and randos2. This would future-proof contact lists growing too large, improve the efficiency of updates, and provide a natural organisation schema for users.

Furthermore, if it were possible to use parameterised replaceable events on kind 3, this would all work with minimal client changes and a reasonable backwards compatibility story. I'm not saying this is a good idea and we should do it, just pointing out the possibility.

Note that replaceable events are just a special case of parameterised replaceable events with a static replacement key.

Proposal

Here are two minor changes that I believe would generalise the protocol:

  • Extend NIP-40 to special-case an expiration tag with value 0. This would indicate that the event is intended to be ephemeral, and should be treated as described in NIP-16, regardless of kind.
  • Support the d tag on events of any kind. This indicates the event is to be treated as a parameterised replaceable event as described in NIP-33, using the value of this tag as a replacement key. This works for any kind, but the kinds of the replaced and replacing events must still match. The absence of a d tag does not result in an implicit empty d tag as described in NIP-33.

Disadvantages

  • Events that want replaceable behaviour become slightly larger, since they need to include a d tag.
  • A user could forget to include a d tag and unintentionally have multiple events of the same kind on a relay. However, when querying, clients that expect replaceable behaviour could take care to select the latest one (by created_at). Additionally, the user could correct this situation using a NIP-09 deletion.

Back-compat

The two above changes would not break any of the existing NIPs. However, I think it could make sense to create a NIP that supersedes NIPs 16 and 33, and mark the coupling of event lifetime with the 10k kind-ranges deprecated.

Additionally, here is how a relay could internally implement backwards compatibility using the d and expiration primitives:

  • Kinds 20000-29999 have an implicit expiration tag with value 0 added to the front of the tag list. NIP-40 is clarified to specify that in the case of multiple expiration tags, the first tag's value is to be used.
  • Kinds 0, 3, 41, 10000-19999, and 30000-39999 have implicit "d" tags with "" values added to the end of their tags list.

History

  • The original version of this proposal suggested using a replace tag instead of NIP-33's d tag, but this would not have been queryable as pointed out by @barkyq below.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions