diff options
| author | Bitflash <btf01@proton.me> | 2026-07-29 14:11:58 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-29 14:11:58 -0300 |
| commit | 41b2ba748531605a1afd84fdb967330c0efc529f (patch) | |
| tree | 4675efd69a09bee537bb7606bd895bd1a4995827 /src/nostr.cpp | |
| parent | 997e511e120272e8f2ddd29716b486e597410f02 (diff) | |
net: exchange signed .btf descriptors between peers (#32)
Discovery has depended entirely on the Nostr relays. Two connected nodes never
told each other who else existed, so a relay outage left a running network
unable to grow, and a node that found one stale peer had no way to learn there
was anything better. The old `addr` gossip went out with the IRC seed.
Peers now trade signed descriptors over a new "btfpeers" message: our own
first, then peers that actually answered us. The receiver checks each Schnorr
signature against the key the `.btf` address decodes to, so the sender is
trusted for nothing -- forging an entry needs somebody else's secret key. That
leaves flooding with self-generated keys, which the per-message caps and the
"peers that answered" ordering are there to blunt.
Unknown commands are ignored (main.cpp), so nodes without this just drop the
message; nothing here is a protocol break.
The cache from the peer-cache change now keeps each peer's descriptor verbatim
alongside the parsed fields, because that signature is what makes a peer
relayable. Entries without one -- resolved through Nostr, or written before
this -- stay dialable, just not passed on. A dial never clears a descriptor
already on file.
Diffstat (limited to 'src/nostr.cpp')
| -rw-r--r-- | src/nostr.cpp | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/nostr.cpp b/src/nostr.cpp index ec02c2e..482a835 100644 --- a/src/nostr.cpp +++ b/src/nostr.cpp | |||
| @@ -342,6 +342,36 @@ std::string BtfLocalAddress() | |||
| 342 | return g_nostrKey.BtfAddress(); | 342 | return g_nostrKey.BtfAddress(); |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | // This node's own descriptor, signed and self-certifying -- the same blob | ||
| 346 | // PublishDescriptor puts on Nostr, but handed straight to a peer instead. | ||
| 347 | // | ||
| 348 | // Reads strBtfActiveRelay directly rather than going through BtfActiveRelay(): | ||
| 349 | // only a rendezvous we actually registered at is worth announcing. Handing out | ||
| 350 | // a meeting node we are not reachable at would make every peer that receives | ||
| 351 | // it burn a dial, and over peer exchange that mistake travels further than it | ||
| 352 | // does over Nostr. | ||
| 353 | std::string BtfLocalDescriptor() | ||
| 354 | { | ||
| 355 | if (!EnsureNostrKey()) | ||
| 356 | return ""; | ||
| 357 | string meeting; | ||
| 358 | CRITICAL_BLOCK(cs_activeRelay) | ||
| 359 | meeting = strBtfActiveRelay; | ||
| 360 | if (meeting.empty()) | ||
| 361 | return ""; | ||
| 362 | return btf::SignDescriptor(g_nostrKey.ctx, g_nostrKey.seckey, | ||
| 363 | g_nostrKey.EncPubHex(), meeting, (uint64_t)GetTime()); | ||
| 364 | } | ||
| 365 | |||
| 366 | // The shared secp256k1 context, so net.cpp can verify descriptors that arrive | ||
| 367 | // from peers. NULL if the identity could not be loaded. | ||
| 368 | void* BtfSecpContext() | ||
| 369 | { | ||
| 370 | if (!EnsureNostrKey()) | ||
| 371 | return NULL; | ||
| 372 | return (void*)g_nostrKey.ctx; | ||
| 373 | } | ||
| 374 | |||
| 345 | int GetDiscoveredPeerCount() | 375 | int GetDiscoveredPeerCount() |
| 346 | { | 376 | { |
| 347 | int n = 0; | 377 | int n = 0; |