feat(nip05): Namecoin .bit identifier resolution via ElectrumX#43
Closed
mstrofnone wants to merge 1 commit into
Closed
feat(nip05): Namecoin .bit identifier resolution via ElectrumX#43mstrofnone wants to merge 1 commit into
mstrofnone wants to merge 1 commit into
Conversation
Adds NIP-05 resolution backed by Namecoin .bit names — the cypherpunk
twin of DNS-based NIP-05.
API mirrors DnsIdentifier 1:1 so callers don't have to branch:
NamecoinIdentifier.isBit(id)
NamecoinIdentifier.fetch(id, {client})
NamecoinIdentifier.verify(identifier, pubkey, {client})
NamecoinIdentifier.lookupUri(id)
NostrIdentifier.fetch(id, {client}) // dispatches by shape
NostrIdentifier.verify(...)
Accepted shapes (case-insensitive, optional nostr: URI prefix):
- alice@example.bit
- example.bit
- d/<name>
- id/<name>
Both name-value forms are supported:
- simple: "nostr": "hex-pubkey"
- extended: "nostr": { "names": {...}, "relays": {...} }
Implementation
--------------
- pure Dart, no new mandatory dependencies
- WebSocket-over-TLS transport via dart:io WebSocket.connect, with
pluggable HttpClient for pinned-cert trust
- failover across 3 default servers; definitive misses short-circuit
- name-script parsing handles direct push / OP_PUSHDATA1 / OP_PUSHDATA2
- expiry check at NameExpireDepth = 36000 blocks (~250 days)
Ported from the canonical Go reference at
mstrofnone/nostrlib-nip05-namecoin and the JS twin in nostr-tools
PR #533. Behaviour matches the Kotlin Amethyst port.
Tests
-----
29 new test cases in test/nips/nip_005_namecoin_test.dart:
- isBit / parseIdentifier shape detection (10 cases)
- JSON value extraction across simple, extended, and id/ shapes (8)
- script utilities incl. PUSHDATA1/2 round-trips (5)
- lookupUri (2)
- 3 live-Namecoin blockchain smoke tests (m@testls.bit,
testls.bit, non-existent .bit) — same pattern as the existing
damus@damus.io live-DNS tests in nip_005_test.dart
449/449 tests pass (420 existing + 29 new).
Live-verified on the real Namecoin blockchain via ElectrumX:
m@testls.bit → 6cdebccabda1dfa058ab85352a79509b592b2bdfa0370325e28ec1cb4f18667d
testls.bit → 460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c
nonexistent → null
Back-compat
-----------
- No breaking changes. Existing DnsIdentifier (Nip5) untouched.
- New types are additive: NamecoinIdentifier, NostrIdentifier,
ElectrumxClient, DefaultElectrumxClient, ElectrumxServer,
defaultElectrumxServers, NameNotFoundException,
NameExpiredException, ElectrumxUnreachableException.
- web_socket_channel was already a transitive dep (used by nip_046);
this PR uses dart:io WebSocket directly so no new dependency lines
in pubspec.yaml.
References
----------
- Go: mstrofnone/nostrlib-nip05-namecoin
- JS: nbd-wtf/nostr-tools PR #533
- Kotlin: vitorpamplona/amethyst PRs #1547 / #2595 / #2612
- Swift: nostur-com/nostur-ios-public PR #60
- Spec: namecoin/proposals ifa-0001
8 tasks
Owner
|
Hey @mstrofnone this is very appreciated ! I was going to implement it myself, at some point… I'm busy this week but be sure I will review that over this week-end or the next one |
Owner
|
merged in #44 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds NIP-05 identifier resolution backed by Namecoin
.bitnames — the cypherpunk twin of DNS-based NIP-05.A user can drop
alice@example.bit,example.bit,d/example, orid/aliceinto anywhereNip5.fetch(...)is called today, anddart-nostrwill resolve it through a public Namecoin ElectrumX server instead ofhttps://example.com/.well-known/nostr.json.This is the Dart port of an already-shipping, multi-language ecosystem of
.bitNIP-05 resolvers — see References below for the Kotlin / Swift / Go / JS / Rust ports this matches behaviour-for-behaviour.API surface
Mirrors
DnsIdentifier1:1 so call sites don't have to branch:NamecoinIdentifier.isBit(id)DnsIdentifier.fetch(id)NamecoinIdentifier.fetch(id, {client})DnsIdentifier.verify(...)NamecoinIdentifier.verify(..., {client})DnsIdentifier.verificationUrl(id)NamecoinIdentifier.lookupUri(id)Plus a thin dispatcher for callers that accept either form:
NamecoinIdentifier.fetchreturns the sameDnsDatatype thatDnsIdentifier.fetchreturns, so any consumer that already handles aFuture<DnsData?>works unchanged.Accepted identifier shapes
Case-insensitive, optional
nostr:URI prefix tolerated:alice@example.bitexample.bit(uses the_root entry)d/example(domain namespace)id/alice(identity namespace)Name-value shapes supported
Both the simple and extended forms documented in namecoin/proposals ifa-0001 and the
.bitNIP-05 draft:Implementation
dart:io WebSocket.connect, with a pluggableHttpClientfor callers that need pinned-cert trust (the public Namecoin ElectrumX servers ship self-signed certs).electrumx.testls.space:50004,nmc2.bitcoins.sk:57004,46.229.238.187:57004). Definitive misses short-circuit; transport errors fall through.OP_PUSHDATA1/OP_PUSHDATA2.OP_PUSHDATA4accepted defensively (Namecoin values fit in 520 bytes per consensus rules).NameExpireDepth = 36000blocks (~250 days, matchesconsensus.nNameExpirationDepthin Namecoin Core).The implementation is split into 5 small files under
lib/src/namecoin/:script.dartNAME_UPDATEoutputselectrumx_server.dartElectrumxServertype + default server listelectrumx_client.dartElectrumxClientinterface +DefaultElectrumxClientimplidentifier.dart.bit/d//id/shapes (private)value.dartPublic surface exposed through
lib/nostr.dart:NamecoinIdentifier/Nip5Namecoin(public-facing, mirrorsDnsIdentifier)NostrIdentifier(dispatcher)ElectrumxClient/DefaultElectrumxClient(transport, pluggable)ElectrumxServer/defaultElectrumxServersNameNotFoundException/NameExpiredException/ElectrumxUnreachableExceptionTests
29 new test cases in
test/nips/nip_005_namecoin_test.dart:isBit.bit/d//id//nostr:shapesparseIdentifierlookupUriextractNostrFromValueNamecoin script utilitiesNAME_UPDATEround-trip,PUSHDATA1/PUSHDATA2m@testls.bit,testls.bit, non-existent — same pattern asdamus@damus.ioinnip_005_test.dart449/449 tests pass (420 existing + 29 new). Run with:
dart test test/nips/nip_005_namecoin_test.dartLive verification
Captured against the real Namecoin blockchain just before opening this PR:
Same pubkeys as the JS port (
nostr-toolsPR #533), the Go port (nostrlib-nip05-namecoin), and the Kotlin/Amethyst port — so any client mixing dart-nostr with one of those agrees byte-for-byte on identity.Back-compat
DnsIdentifier/Nip5is untouched.NamecoinIdentifier,Nip5Namecointypedef,NostrIdentifier,ElectrumxClient,DefaultElectrumxClient,ElectrumxServer,defaultElectrumxServers, three exception types.web_socket_channelwas already a transitive dependency (vianip_046); this PR usesdart:io WebSocketdirectly so no new lines inpubspec.yaml.Security properties
alice@sub.example.bitonly consultsd/example'snames.alice, not_'s pubkey. (Tested explicitly.)DnsData.NameNotFound/NameExpiredshort-circuit — definitive blockchain answers from one server propagate immediately rather than burning the rest of the failover list.DefaultElectrumxClientuses platform trust; callers must explicitly inject anHttpClientwithbadCertificateCallbackfor the public test servers. (See_trustAllHttpClientin the test file for the pattern; production should pin specific cert fingerprints.)References
This PR ports an already-shipping pattern. The Dart implementation matches:
mstrofnone/nostrlib-nip05-namecoin— proposednostr/nip05/namecoinsubpackage forfiatjaf.com/nostrnbd-wtf/nostr-toolsPR #533 —nostr-tools/nip05namecoinsubpackagevitorpamplona/amethystPR #1547, PR #2595, PR #2612nostur-com/nostur-ios-publicPR #60mikedilger/gossipPR #1018nostr-protocol/nips/05.mdA follow-up PR will add the relay-resolver counterpart (
wss://relay.example.bit/→ real wss endpoint with TLSA pin records). Posting that as a separate PR so each is independently reviewable.Checklist
dart analyze— no issuesdart format— formatteddart test— 449/449 pass