NIP-134: define DNS record set format in event content#7
Conversation
Specifies a JSON record set for the content field of kind 31034 events, turning an event into a complete signed zone for <pubkey>.nostr: - Records as [type, name, ttl, data] arrays with data in DNS presentation format - MUST support A, AAAA, CNAME, TXT, SRV; unknown types ignored - Latest created_at wins via the parameterized replaceable range, mirroring PKARR's BEP44 sequence numbers - Freshness and caching guidance for resolvers
There was a problem hiding this comment.
Pull request overview
This PR extends the DNSTR/NIP-134 documentation to define a concrete on-wire format for carrying a full DNS record set inside kind 31034 event content, enabling events to represent complete signed zones for <pubkey>.nostr.
Changes:
- Updates the kind
31034contentdescription to allow either empty content or a DNS record set. - Adds a new “DNS record set” section specifying a JSON encoding, required record types, and caching/conflict-resolution semantics.
- Provides an example event showing how a record set is embedded in the
contentstring.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -46,6 +46,45 @@ Example event: | |||
|
|
|||
| Services and tools that wish to make use of this NIP SHOULD first verify the authenticity of the event by checking the signature and then map the domain name specified in the content to `npub.nostr` or `pubkey.nostr`. | |||
There was a problem hiding this comment.
Fixed in ceb5dca — now says the domain mapping comes from the u tag.
|
|
||
| ## Implementation | ||
|
|
||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and use the field in the content as the domain. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. |
There was a problem hiding this comment.
Fixed in ceb5dca — the implementation section now points at the u tag for the domain and treats content as the record set.
- Domain mapping comes from the u tag, not content; fix the two sentences that still said otherwise - TTL is a non-negative integer - Quote the TXT RDATA in the example per DNS presentation format
| ``` | ||
|
|
||
| Services and tools that wish to make use of this NIP SHOULD first verify the authenticity of the event by checking the signature and then map the domain name specified in the content to `npub.nostr` or `pubkey.nostr`. | ||
| Services and tools that wish to make use of this NIP SHOULD first verify the authenticity of the event by checking the signature and then map the domain name specified in the `u` tag to `npub.nostr` or `pubkey.nostr`. |
There was a problem hiding this comment.
Fixed in 401f31b — reworded so the .nostr name resolves to the u tag domain.
| ## Implementation | ||
|
|
||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and use the field in the content as the domain. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. | ||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and use the `u` tag as the domain, treating the `content` (if present) as the DNS record set. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. |
There was a problem hiding this comment.
Fixed in 401f31b — lookup guidance now says to filter on the d tag (empty string).
|
|
||
| Kind `31034` falls in the parameterized replaceable range, so relays retain only the newest event per `pubkey` and `d` tag. The record set with the highest `created_at` wins, serving the same role as PKARR's BEP44 sequence numbers. | ||
|
|
||
| Resolvers SHOULD cache verified record sets for the record TTL, and MAY apply a freshness policy that treats record sets as stale when `created_at` is older than a policy-defined age, prompting a re-query of relays. |
There was a problem hiding this comment.
Fixed in 401f31b — caching now honours each record's own ttl (optionally capped) rather than one TTL for the whole set.
- Fix mapping direction: .nostr name resolves to the u tag domain - Lookup queries filter on d tag (empty string) - Caching honours each record's own ttl, not one TTL for the set
|
|
||
| ### Freshness and conflict resolution | ||
|
|
||
| Kind `31034` falls in the parameterized replaceable range, so relays retain only the newest event per `pubkey` and `d` tag. The record set with the highest `created_at` wins, serving the same role as PKARR's BEP44 sequence numbers. |
There was a problem hiding this comment.
Fixed in 48b5446 — replaceable semantics are now SHOULD-level for relays, with an explicit client rule to select the highest created_at.
| ## Implementation | ||
|
|
||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and use the field in the content as the domain. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. | ||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and the `d` tag set to the empty string, then use the `u` tag as the domain, treating the `content` (if present) as the DNS record set. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. |
There was a problem hiding this comment.
Fixed in 48b5446 — the Use Case section now verifies the u tag, with content as the optional record set.
- Use <npub>.nostr / <pubkey>.nostr placeholders so they don't read as literal hostnames - State replaceable semantics at SHOULD level with an explicit client selection rule - Fix the Use Case section to verify the u tag, not content
|
|
||
| The `content` field MAY contain a DNS record set, making the event a complete signed zone for `<pubkey>.nostr` (or `<npub>.nostr`). Because Nostr events are signed, this gives signed record sets in the manner of PKARR's `SignedPacket` without any additional machinery. | ||
|
|
||
| The record set is encoded as a JSON object with a `records` array. Each record is an array of four elements: |
| } | ||
| ``` | ||
|
|
||
| A `content` that is empty or does not parse as a JSON object with a `records` array MUST be treated as an empty record set; the `u` tag mapping continues to apply regardless. |
| ## Implementation | ||
|
|
||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and use the field in the content as the domain. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. | ||
| In order to lookup a .nostr domain you simply query the pubkey with kind=31034 and the `d` tag set to the empty string, then use the `u` tag as the domain, treating the `content` (if present) as the DNS record set. Some lookup services may choose to fallback to profile web page or nip-05 origin, as desired. |
Closes #2
Extends NIP-134 so the
contentfield of a kind 31034 event carries a full DNS record set, making the event a complete signed zone for<pubkey>.nostr— the PKARRSignedPacketidea, but signatures come free with Nostr events.Format
JSON object with a
recordsarray; each record is[type, name, ttl, data]:type—A,AAAA,CNAME,TXT,SRVMUST be supported; unknown types MUST be ignored (extensible)name— relative to the<pubkey>.nostrzone,@for apexttl— seconds; resolvers MAY capdata— DNS presentation format, as in a zone fileSemantics
created_atwins, mirroring PKARR's BEP44 sequence numberscontent= empty record set; theutag mapping is unaffected, so existing events remain validcreated_atThis unblocks the DNS/DoH bridge (#3) and dual-stack pkarr publishing (#4).