upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/nostr.cpp
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-07-29 11:51:37 -0300
committerGitHub <noreply@github.com>2026-07-29 11:51:37 -0300
commit7f6fdbab6c90360ab3b2d391a7b5aedc6f9721ac (patch)
tree4a5504cb39d72d15b85e1a05f2493f6fa04b2eb3 /src/nostr.cpp
parentba2de82b76aeeabe1c45877e02b0e8fe5b59bed3 (diff)
nostr: never advertise a rendezvous we are not registered at (#26)
BtfActiveRelay() fell back to vBtfMeetingRelays[0] whenever registration had not completed yet. ThreadNostrSeed and ThreadBtfAccept start in parallel (net.cpp), so at boot that fallback was exactly what PublishDescriptor wrote into the descriptor -- including the one-time self-test, which publishes to every relay in the list. Peers reading it dialed a rendezvous this node was never registered at, and whenever the first seed happened to be down (92.246.128.180 was, for part of today) every one of those dials was wasted. BtfActiveRelay() now returns only the relay ThreadBtfAccept confirmed, and PublishDescriptor skips publishing until there is one. The seed loop republishes on every pass, so the only cost is the delay until registration succeeds; the self-test waits up to 60s for it so it still measures the publish/resolve chain instead of losing the race against it. Also fix the WebSocket handshake reader. On headers past the cap it did a bare break, leaving the socket parked in the middle of the header block -- and since the status line had already been read, the " 101 " check still passed, so the caller got a "connected" socket whose next bytes were leftover HTTP that the frame parser then read as garbage frames. It now errors out instead, and the cap is 8192 because relays behind Cloudflare send large header blocks.
Diffstat (limited to 'src/nostr.cpp')
-rw-r--r--src/nostr.cpp36
1 files changed, 30 insertions, 6 deletions
diff --git a/src/nostr.cpp b/src/nostr.cpp
index 6f3b6a7..ec02c2e 100644
--- a/src/nostr.cpp
+++ b/src/nostr.cpp
@@ -100,13 +100,17 @@ vector<string> vBtfMeetingRelays = {
100string strBtfActiveRelay; 100string strBtfActiveRelay;
101static CCriticalSection cs_activeRelay; 101static CCriticalSection cs_activeRelay;
102 102
103// Only the rendezvous we actually registered at (BtfSetActiveRelay, called from
104// ThreadBtfAccept once registration succeeds). Empty until then, on purpose: it
105// used to fall back to vBtfMeetingRelays[0], and since ThreadNostrSeed and
106// ThreadBtfAccept start in parallel (net.cpp), that fallback is what got
107// published at boot -- a descriptor telling peers to dial a relay we were not
108// registered at. When that first seed was down, every peer that read the
109// descriptor burned a dial on a dead rendezvous.
103string BtfActiveRelay() 110string BtfActiveRelay()
104{ 111{
105 CRITICAL_BLOCK(cs_activeRelay) 112 CRITICAL_BLOCK(cs_activeRelay)
106 if (!strBtfActiveRelay.empty()) 113 return strBtfActiveRelay;
107 return strBtfActiveRelay;
108 if (!vBtfMeetingRelays.empty())
109 return vBtfMeetingRelays[0];
110 return ""; 114 return "";
111} 115}
112 116
@@ -542,7 +546,13 @@ public:
542 int n = RawRead(&c, 1); 546 int n = RawRead(&c, 1);
543 if (n <= 0) return error("Nostr: no handshake response from %s", host.c_str()); 547 if (n <= 0) return error("Nostr: no handshake response from %s", host.c_str());
544 resp += c; 548 resp += c;
545 if (resp.size() > 4096) break; 549 // Bail out instead of breaking: breaking left the socket parked in
550 // the middle of the header block, and since the status line is read
551 // first the " 101 " check below still passed -- so the caller got a
552 // "connected" socket whose next bytes were leftover HTTP, which the
553 // frame parser then read as garbage frames.
554 if (resp.size() > 8192)
555 return error("Nostr: handshake headers too large from %s", host.c_str());
546 } 556 }
547 if (resp.find(" 101 ") == string::npos) 557 if (resp.find(" 101 ") == string::npos)
548 return error("Nostr: handshake refused by %s", host.c_str()); 558 return error("Nostr: handshake refused by %s", host.c_str());
@@ -749,7 +759,14 @@ static void PublishDescriptor(CWebSocket& ws, CNostrKey& key)
749 // (ThreadBtfAccept in net.cpp) is registered at -- where clients dial us. 759 // (ThreadBtfAccept in net.cpp) is registered at -- where clients dial us.
750 string meeting_node = BtfActiveRelay(); 760 string meeting_node = BtfActiveRelay();
751 if (meeting_node.empty()) 761 if (meeting_node.empty())
752 meeting_node = "rendezvous-pending"; 762 {
763 // Not registered anywhere yet. Publishing now would advertise a meeting
764 // node we can't be reached at, and peers would waste dials on it. The
765 // ThreadNostrSeed loop republishes on every pass, so skipping costs
766 // nothing but the delay until ThreadBtfAccept registers.
767 LogPrint("nostr", "Nostr: skipping descriptor publish, no rendezvous registered yet\n");
768 return;
769 }
753 string desc = btf::SignDescriptor(key.ctx, key.seckey, key.EncPubHex(), 770 string desc = btf::SignDescriptor(key.ctx, key.seckey, key.EncPubHex(),
754 meeting_node, (uint64_t)GetTime()); 771 meeting_node, (uint64_t)GetTime());
755 if (desc.empty()) 772 if (desc.empty())
@@ -1564,6 +1581,13 @@ void ThreadNostrSeed(void* parg)
1564 LogPrint("nostr", "Nostr: node pubkey = %s\n", key.PubKeyHex().c_str()); 1581 LogPrint("nostr", "Nostr: node pubkey = %s\n", key.PubKeyHex().c_str());
1565 LogPrint("nostr", "Nostr: node .btf address = %s\n", key.BtfAddress().c_str()); 1582 LogPrint("nostr", "Nostr: node .btf address = %s\n", key.BtfAddress().c_str());
1566 1583
1584 // The self-test below publishes a real descriptor, and PublishDescriptor now
1585 // refuses to publish before ThreadBtfAccept has registered a rendezvous. Give
1586 // registration a bounded head start so the test measures the publish/resolve
1587 // chain instead of losing the race against it.
1588 for (int i = 0; i < 60 && !fShutdown && BtfActiveRelay().empty(); i++)
1589 Sleep(1000);
1590
1567 // One-time self-test of the rendezvous: publish our descriptor to a relay, 1591 // One-time self-test of the rendezvous: publish our descriptor to a relay,
1568 // then resolve our OWN .btf address back and verify it self-certifies. Proves 1592 // then resolve our OWN .btf address back and verify it self-certifies. Proves
1569 // the .btf publish/resolve/verify chain works against real public relays. 1593 // the .btf publish/resolve/verify chain works against real public relays.