Skip to content

NIP-77 negentropy: only 20% of relays support it, 91% of those are strfry #25

Description

@alltheseas

Survey results

We ran a 3-layer NIP-77 support survey across 1,044 live relays (from NIP-66 monitor data):

Layer Method NIP-77 count % of total
NIP-66 monitor supportedNips from kind 30166 268 25.7%
NIP-11 direct HTTP GET with Accept: application/nostr+json 263 25.2%
Live NEG-OPEN WebSocket probe with actual negentropy handshake 211 20.2%

Software breakdown (live-confirmed)

Software Relays NIP-77 Rate
strfry 268 218 (191 live-confirmed) 81%
nostr-rs-relay 210 0 0%
haven (khatru) 82 0 0%
nostream 51 0 0%
khatru (direct) 48 1 2%
pyramid 19 18 95%

Key finding: khatru has the code but it's not wired up

Khatru already has a full NIP-77 implementation in negentropy.go using go-nostr/nip77/negentropy. However, it's gated behind a Negentropy bool field that defaults to false:

// relay.go line 103-104
// set this to true to support negentropy
Negentropy bool

The WebSocket message parser only tries NIP-77 parsing when this flag is true (handlers.go:154):

if err == nostr.UnknownLabel && rl.Negentropy {
    envelope = nip77.ParseNegMessage(message)
}

We confirmed this by probing fiatjaf.com (fiatjaf's own khatru relay): NOTICE: failed to parse envelope: unknown envelope label.

Why this matters for outbox

Our outbox relay benchmark measures a 77% relay-list availability → 24% event recall gap. The #1 cause is the write-side gap: when users change relay lists, old events don't migrate. NIP-77 negentropy is the only efficient solution for this — it enables set reconciliation without transferring full event payloads.

But at 20% relay support (strfry-only), negentropy-based migration is not viable as a general strategy.

Adoption path

Three changes would push NIP-77 from 20% to ~55% of relays:

Target Instances Effort Notes
khatru (enable by default or config flag) 48 + ~82 cascade to haven Low Code exists, needs wiring. Tradeoff: in-memory Vector per session adds memory/CPU load. Maybe config opt-in rather than default-on?
nostr-rs-relay 210 Medium Rust negentropy crate v0.5.0 exists. Issue #234 open, no work started
nostream 51 High Reference JS impl exists. Last commit Oct 2024 — may be abandoned

Questions for relay devs

  1. khatru/haven operators: Would you enable negentropy if it were a config option? What are your concerns about memory/CPU overhead?
  2. nostr-rs-relay contributors: Anyone interested in implementing NIP-77? The negentropy Rust crate handles protocol logic; main work is WebSocket routing + SQLite query adapter (~200-400 lines)
  3. Is the in-memory Vector approach good enough? strfry uses persistent LMDB B-trees for negentropy storage. khatru rebuilds from scratch per session. For personal relays (haven's use case) this is probably fine, but worth discussing.
  4. Should negentropy be opt-in or default-on in relay frameworks? fiatjaf made it explicitly opt-in in khatru. Is that the right call?

Survey script

The probe script is at bench/probe-nip77.ts — run with --live for WebSocket verification. Full results cached in bench/.cache/nip77_survey.json.

Cross-reference

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions