upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main_gui.cpp20
-rw-r--r--src/net.cpp93
-rw-r--r--src/net.h3
3 files changed, 115 insertions, 1 deletions
diff --git a/src/main_gui.cpp b/src/main_gui.cpp
index 63bdbb7..9f7e34e 100644
--- a/src/main_gui.cpp
+++ b/src/main_gui.cpp
@@ -61,6 +61,7 @@ static void PrintUsage()
61 printf("\n"); 61 printf("\n");
62 printf("Network:\n"); 62 printf("Network:\n");
63 printf(" /port=N (P2P listen port, default 8433)\n"); 63 printf(" /port=N (P2P listen port, default 8433)\n");
64 printf(" /btfseed=ADDRESS:ENCHEX (extra bootstrap peer, repeatable)\n");
64 printf("\n"); 65 printf("\n");
65 printf("Each option also accepts '-' instead of '/'.\n"); 66 printf("Each option also accepts '-' instead of '/'.\n");
66} 67}
@@ -117,6 +118,25 @@ static void ParseStartupArguments(int argc, char* argv[])
117 if (!announceRelay.empty()) 118 if (!announceRelay.empty())
118 strBtfAnnounceRelay = announceRelay; 119 strBtfAnnounceRelay = announceRelay;
119 120
121 // /btfseed=ADDRESS:ENCHEX -- extra bootstrap peers, repeatable. Useful for
122 // testing the seed path and for private networks that ship no compiled list.
123 for (int i = 1; i < argc; i++)
124 {
125 string s = argv[i];
126 size_t eq = s.find('=');
127 if (eq == string::npos) continue;
128 string key = s.substr(0, eq);
129 if (key != "/btfseed" && key != "-btfseed") continue;
130 string val = s.substr(eq + 1);
131 size_t colon = val.rfind(':');
132 if (colon == string::npos || colon + 1 >= val.size())
133 {
134 fprintf(stderr, "Ignoring %s: expected ADDRESS:ENCHEX\n", s.c_str());
135 continue;
136 }
137 vBtfExtraSeeds.push_back(make_pair(val.substr(0, colon), val.substr(colon + 1)));
138 }
139
120 // net.cpp has described nListenPort as "tunable via /port" since it was 140 // net.cpp has described nListenPort as "tunable via /port" since it was
121 // written, but nothing ever read the option, so the port was fixed at 8433 141 // written, but nothing ever read the option, so the port was fixed at 8433
122 // and a second node could not start on a machine already running one. 142 // and a second node could not start on a machine already running one.
diff --git a/src/net.cpp b/src/net.cpp
index 1d552cf..08a3348 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -414,6 +414,93 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting,
414 } 414 }
415} 415}
416 416
417//
418// Compiled-in bootstrap seeds.
419//
420// A node with no cache has nothing but the Nostr relays, and if those are down,
421// blocked or simply slow, a first run has no way into the network at all. Seeds
422// are the floor under that: a handful of long-lived peers baked into the binary.
423//
424// A seed entry is deliberately just an address and an encryption key -- no
425// meeting node. The rendezvous relay pairs on the service's public key, and a
426// `.btf` address *is* that key, so a client can find a seed by trying the known
427// relays in turn. Recording which relay a seed was on would rot the moment it
428// failed over, which is the exact failure this project spent a long time
429// chasing: advertising a rendezvous somebody is not registered at.
430//
431// Seeds are ordinary nodes with no special authority. They hand out signed,
432// self-certifying descriptors like any peer, so a hostile seed can stall a
433// bootstrap but cannot forge a peer or feed a false chain.
434//
435struct BtfSeed
436{
437 const char* btfAddr;
438 const char* encHex; // 64 hex chars, the peer's x25519 public key
439};
440
441static const BtfSeed pszBtfSeeds[] =
442{
443 // Dedicated bootstrap node, Almaty. Runs beside a rendezvous relay on the
444 // same host, holds no wallet balance and does not mine -- it exists only to
445 // answer a first dial. It is trusted for nothing: it serves the same signed
446 // descriptors any peer does.
447 { "ygffz37jczlmrkzicxok6chobauyratdexc7hfgwzjdabzvb2nkngqy.btf",
448 "de8284b9d4effa2132e7981b566c1a297c39c1857d9c128e8ae093ef511d3200" },
449};
450static const size_t nBtfSeeds = ARRAYLEN(pszBtfSeeds);
451
452// Extra seeds from the command line (/btfseed=ADDRESS:ENCHEX, repeatable).
453vector<pair<string, string> > vBtfExtraSeeds;
454
455static int TryBtfSeeds()
456{
457 vector<pair<string, string> > seeds;
458 for (size_t i = 0; i < nBtfSeeds; i++)
459 seeds.push_back(make_pair(string(pszBtfSeeds[i].btfAddr),
460 string(pszBtfSeeds[i].encHex)));
461 foreach(const PAIRTYPE(string, string)& s, vBtfExtraSeeds)
462 seeds.push_back(s);
463
464 if (seeds.empty())
465 return 0;
466
467 vector<string> relays = BtfAllRelays();
468 if (relays.empty())
469 return 0;
470
471 LogPrint("net", "btfseed: trying %zu seed(s) across %zu relay(s)\n",
472 seeds.size(), relays.size());
473
474 int nConnected = 0;
475 foreach(const PAIRTYPE(string, string)& s, seeds)
476 {
477 if (fShutdown) return nConnected;
478 unsigned char enc[32];
479 if (!HexToBytes(s.second, enc, 32))
480 {
481 LogPrint("net", "btfseed: %s has a malformed encryption key, skipped\n",
482 s.first.c_str());
483 continue;
484 }
485 // We do not know which relay this seed is registered at, so walk them.
486 foreach(const string& strRelay, relays)
487 {
488 if (fShutdown) return nConnected;
489 if (ConnectNodeBtfResolved(s.first, strRelay, enc))
490 {
491 LogPrint("net", "btfseed: reached %s via %s\n",
492 s.first.c_str(), strRelay.c_str());
493 nConnected++;
494 break; // found it; no need to try this seed's other relays
495 }
496 }
497 if (nConnected >= 4)
498 break; // enough of a foothold; the rest comes from discovery
499 }
500 LogPrint("net", "btfseed: %d seed(s) answered\n", nConnected);
501 return nConnected;
502}
503
417// Dial everything we reached last time, before the relays have said anything. 504// Dial everything we reached last time, before the relays have said anything.
418void ThreadReconnectCachedBtfPeers(void* parg) 505void ThreadReconnectCachedBtfPeers(void* parg)
419{ 506{
@@ -421,7 +508,11 @@ void ThreadReconnectCachedBtfPeers(void* parg)
421 LoadCachedBtfPeers(peers); 508 LoadCachedBtfPeers(peers);
422 if (peers.empty()) 509 if (peers.empty())
423 { 510 {
424 LogPrint("net", "btfpeers: no cache yet, waiting on relay discovery\n"); 511 // First run, or the cache aged out. Seeds are the only way in that does
512 // not depend on a relay answering.
513 LogPrint("net", "btfpeers: no cache yet, falling back to seeds\n");
514 if (TryBtfSeeds() == 0)
515 LogPrint("net", "btfpeers: no seed answered, waiting on relay discovery\n");
425 return; 516 return;
426 } 517 }
427 LogPrint("net", "btfpeers: trying %zu remembered peer(s) before discovery\n", 518 LogPrint("net", "btfpeers: trying %zu remembered peer(s) before discovery\n",
diff --git a/src/net.h b/src/net.h
index 7d70721..d13de61 100644
--- a/src/net.h
+++ b/src/net.h
@@ -29,6 +29,9 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting
29void ThreadBtfAccept(void* parg); 29void ThreadBtfAccept(void* parg);
30void ThreadBtfConnect(void* parg); 30void ThreadBtfConnect(void* parg);
31extern string strBtfConnect; 31extern string strBtfConnect;
32// Bootstrap seeds added at runtime with /btfseed=ADDRESS:ENCHEX (repeatable).
33// The compiled-in list lives in net.cpp; these are appended to it.
34extern std::vector<std::pair<std::string, std::string> > vBtfExtraSeeds;
32 35
33// --- .btf peer exchange --------------------------------------------------- 36// --- .btf peer exchange ---------------------------------------------------
34// Peers gossip signed descriptors so discovery survives a relay outage. Both 37// Peers gossip signed descriptors so discovery survives a relay outage. Both