diff options
| author | Bitflash <btf01@proton.me> | 2026-07-29 12:05:12 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-29 12:05:12 -0300 |
| commit | 137a166fe0b95ccdef444041e907358bd26bc226 (patch) | |
| tree | bab295f18576f5d139bd7746f3c141fbbdfea3e2 | |
| parent | 96a8e42bbc313f96d54377ae5886da84298e61a3 (diff) | |
Remove peer exchange from main; it was merged unreviewed (#27)
PR #25 was opened, reviewed and approved as a single-file change to net.cpp:
the .btf peer cache, +169/-0. I then pushed peer exchange and a /port option
onto that same branch while the PR was open, which silently widened it to six
files. The merge carried all of it in.
Nothing about the peer exchange had been validated. Its two-node test never
completed -- node B could not dial node A at all -- so what landed on main is
unproven network protocol code that no one agreed to take.
This restores main to what #25 actually described. The peer cache stays, with
its runtime numbers (36.3s to 2.1s to first peer). #26 stays. What comes out:
- the "btfpeers" message, both directions
- BtfPexCollect / BtfPexAccept and the per-message caps
- CNode::nLastPexRecv
- the `desc` field on the cached peer record
- BtfLocalDescriptor / BtfSecpContext
- /port
Peer exchange returns as its own pull request once its test passes. The /port
option is worth having on its own -- two nodes cannot share a machine without
it, which is what blocked the test -- and should go up separately rather than
ride along again.
Release v1.2.2 is unaffected: it was built from ba2de82, before either merge.
| -rw-r--r-- | src/main.cpp | 31 | ||||
| -rw-r--r-- | src/main_gui.cpp | 18 | ||||
| -rw-r--r-- | src/net.cpp | 115 | ||||
| -rw-r--r-- | src/net.h | 19 | ||||
| -rw-r--r-- | src/nostr.cpp | 30 | ||||
| -rw-r--r-- | src/nostr.h | 8 |
6 files changed, 2 insertions, 219 deletions
diff --git a/src/main.cpp b/src/main.cpp index bb317d2..a75bf54 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -1877,14 +1877,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 1877 | pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0)); | 1877 | pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), uint256(0)); |
| 1878 | } | 1878 | } |
| 1879 | 1879 | ||
| 1880 | // Introduce ourselves and hand over the .btf peers that answered us. | ||
| 1881 | // Everything in here is self-certifying, so this is safe to send to a | ||
| 1882 | // node we know nothing about, and safe for it to act on. | ||
| 1883 | vector<string> vPexOut; | ||
| 1884 | BtfPexCollect(vPexOut); | ||
| 1885 | if (!vPexOut.empty()) | ||
| 1886 | pfrom->PushMessage("btfpeers", vPexOut); | ||
| 1887 | |||
| 1888 | if (LogAcceptsCategory("net")) printf("version addrMe = %s\n", addrMe.ToString().c_str()); | 1880 | if (LogAcceptsCategory("net")) printf("version addrMe = %s\n", addrMe.ToString().c_str()); |
| 1889 | } | 1881 | } |
| 1890 | 1882 | ||
| @@ -1896,29 +1888,6 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 1896 | } | 1888 | } |
| 1897 | 1889 | ||
| 1898 | 1890 | ||
| 1899 | else if (strCommand == "btfpeers") | ||
| 1900 | { | ||
| 1901 | // Peer exchange. Nothing here is taken on trust: BtfPexAccept checks | ||
| 1902 | // every descriptor's signature against the key its .btf address | ||
| 1903 | // decodes to, and drops the rest. | ||
| 1904 | int64 nNow = GetTime(); | ||
| 1905 | if (nNow - pfrom->nLastPexRecv < PEX_MIN_INTERVAL) | ||
| 1906 | { | ||
| 1907 | if (LogAcceptsCategory("net")) | ||
| 1908 | printf("btfpeers: ignoring, %s is sending them too fast\n", | ||
| 1909 | pfrom->addr.ToString().c_str()); | ||
| 1910 | return true; | ||
| 1911 | } | ||
| 1912 | pfrom->nLastPexRecv = nNow; | ||
| 1913 | |||
| 1914 | vector<string> vDesc; | ||
| 1915 | vRecv >> vDesc; | ||
| 1916 | int nKept = BtfPexAccept(vDesc); | ||
| 1917 | LogPrint("net", "btfpeers: kept %d of %zu descriptor(s) from %s\n", | ||
| 1918 | nKept, vDesc.size(), pfrom->addr.ToString().c_str()); | ||
| 1919 | } | ||
| 1920 | |||
| 1921 | |||
| 1922 | else if (strCommand == "inv") | 1891 | else if (strCommand == "inv") |
| 1923 | { | 1892 | { |
| 1924 | vector<CInv> vInv; | 1893 | vector<CInv> vInv; |
diff --git a/src/main_gui.cpp b/src/main_gui.cpp index edc772d..842b0d5 100644 --- a/src/main_gui.cpp +++ b/src/main_gui.cpp | |||
| @@ -58,7 +58,6 @@ static void PrintUsage() | |||
| 58 | printf(" /connectbtf=PEER_BTF_ADDRESS\n"); | 58 | printf(" /connectbtf=PEER_BTF_ADDRESS\n"); |
| 59 | printf(" /rvrelay=HOST:PORT\n"); | 59 | printf(" /rvrelay=HOST:PORT\n"); |
| 60 | printf(" /announcerelay=HOST:PORT\n"); | 60 | printf(" /announcerelay=HOST:PORT\n"); |
| 61 | printf(" /port=N (P2P listen port, default 8433)\n"); | ||
| 62 | printf("\n"); | 61 | printf("\n"); |
| 63 | printf("Each option also accepts '-' instead of '/'.\n"); | 62 | printf("Each option also accepts '-' instead of '/'.\n"); |
| 64 | } | 63 | } |
| @@ -114,23 +113,6 @@ static void ParseStartupArguments(int argc, char* argv[]) | |||
| 114 | string announceRelay = argval2(argc, argv, "/announcerelay", "-announcerelay"); | 113 | string announceRelay = argval2(argc, argv, "/announcerelay", "-announcerelay"); |
| 115 | if (!announceRelay.empty()) | 114 | if (!announceRelay.empty()) |
| 116 | strBtfAnnounceRelay = announceRelay; | 115 | strBtfAnnounceRelay = announceRelay; |
| 117 | |||
| 118 | // net.cpp has claimed nListenPort was "tunable via /port" since it was | ||
| 119 | // written, but nothing ever read the option. Without it a second node | ||
| 120 | // cannot start on a machine that already runs one -- which is exactly what | ||
| 121 | // testing peer exchange needs. | ||
| 122 | string strPort = argval2(argc, argv, "/port", "-port"); | ||
| 123 | if (!strPort.empty()) | ||
| 124 | { | ||
| 125 | int nPort = atoi(strPort.c_str()); | ||
| 126 | if (nPort <= 0 || nPort > 65535) | ||
| 127 | fprintf(stderr, "Ignoring /port=%s: not a port number\n", strPort.c_str()); | ||
| 128 | else | ||
| 129 | { | ||
| 130 | nListenPort = htons((unsigned short)nPort); | ||
| 131 | addrLocalHost.port = nListenPort; // or we advertise a port we never bound | ||
| 132 | } | ||
| 133 | } | ||
| 134 | } | 116 | } |
| 135 | 117 | ||
| 136 | int main(int argc, char* argv[]) | 118 | int main(int argc, char* argv[]) |
diff --git a/src/net.cpp b/src/net.cpp index dfeb4a2..7b2ef83 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -285,13 +285,6 @@ struct CachedBtfPeer | |||
| 285 | string meeting; | 285 | string meeting; |
| 286 | string encHex; | 286 | string encHex; |
| 287 | int64 lastSeen; | 287 | int64 lastSeen; |
| 288 | // The peer's own signed descriptor, as it announced itself. Kept verbatim | ||
| 289 | // because that signature is what lets us hand this peer on to somebody | ||
| 290 | // else: the receiver checks it against the key the address decodes to and | ||
| 291 | // never has to take our word for anything. Empty for entries learned | ||
| 292 | // before peer exchange existed, or resolved through Nostr -- those are | ||
| 293 | // still dialable, just not relayable. | ||
| 294 | string desc; | ||
| 295 | }; | 288 | }; |
| 296 | 289 | ||
| 297 | static string BtfPeerCachePath() { return GetAppDir() + "/btfpeers.json"; } | 290 | static string BtfPeerCachePath() { return GetAppDir() + "/btfpeers.json"; } |
| @@ -343,8 +336,6 @@ void LoadCachedBtfPeers(vector<CachedBtfPeer>& out) | |||
| 343 | p.meeting = o["meeting"].get<string>(); | 336 | p.meeting = o["meeting"].get<string>(); |
| 344 | p.encHex = o["enc"].get<string>(); | 337 | p.encHex = o["enc"].get<string>(); |
| 345 | p.lastSeen = o.value("seen", (int64)0); | 338 | p.lastSeen = o.value("seen", (int64)0); |
| 346 | if (o.contains("desc") && o["desc"].is_string()) | ||
| 347 | p.desc = o["desc"].get<string>(); | ||
| 348 | if (nNow - p.lastSeen > CACHED_BTF_PEER_TTL) continue; // long gone | 339 | if (nNow - p.lastSeen > CACHED_BTF_PEER_TTL) continue; // long gone |
| 349 | out.push_back(p); | 340 | out.push_back(p); |
| 350 | } | 341 | } |
| @@ -358,35 +349,22 @@ void LoadCachedBtfPeers(vector<CachedBtfPeer>& out) | |||
| 358 | 349 | ||
| 359 | static CCriticalSection cs_btfPeerCache; | 350 | static CCriticalSection cs_btfPeerCache; |
| 360 | 351 | ||
| 361 | // strDesc is the peer's own signed descriptor when we have it (it announced | ||
| 362 | // itself over peer exchange), "" when we only resolved it through Nostr. An | ||
| 363 | // empty one never clears a descriptor already on file: dialing a peer we first | ||
| 364 | // learned about by exchange must not cost us the ability to pass it on. | ||
| 365 | static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | 352 | static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, |
| 366 | const unsigned char enc_pub[32], | 353 | const unsigned char enc_pub[32]) |
| 367 | const string& strDesc = string()) | ||
| 368 | { | 354 | { |
| 369 | CRITICAL_BLOCK(cs_btfPeerCache) | 355 | CRITICAL_BLOCK(cs_btfPeerCache) |
| 370 | { | 356 | { |
| 371 | vector<CachedBtfPeer> peers; | 357 | vector<CachedBtfPeer> peers; |
| 372 | LoadCachedBtfPeers(peers); | 358 | LoadCachedBtfPeers(peers); |
| 373 | 359 | ||
| 374 | string strKeepDesc = strDesc; | ||
| 375 | for (size_t i = 0; i < peers.size(); i++) | 360 | for (size_t i = 0; i < peers.size(); i++) |
| 376 | if (peers[i].btfAddr == strBtfAddr) | 361 | if (peers[i].btfAddr == strBtfAddr) { peers.erase(peers.begin() + i); break; } |
| 377 | { | ||
| 378 | if (strKeepDesc.empty()) | ||
| 379 | strKeepDesc = peers[i].desc; | ||
| 380 | peers.erase(peers.begin() + i); | ||
| 381 | break; | ||
| 382 | } | ||
| 383 | 362 | ||
| 384 | CachedBtfPeer p; | 363 | CachedBtfPeer p; |
| 385 | p.btfAddr = strBtfAddr; | 364 | p.btfAddr = strBtfAddr; |
| 386 | p.meeting = strMeeting; | 365 | p.meeting = strMeeting; |
| 387 | p.encHex = BytesToHex(enc_pub, 32); | 366 | p.encHex = BytesToHex(enc_pub, 32); |
| 388 | p.lastSeen = GetTime(); | 367 | p.lastSeen = GetTime(); |
| 389 | p.desc = strKeepDesc; | ||
| 390 | peers.insert(peers.begin(), p); // most recent first | 368 | peers.insert(peers.begin(), p); // most recent first |
| 391 | 369 | ||
| 392 | if (peers.size() > MAX_CACHED_BTF_PEERS) | 370 | if (peers.size() > MAX_CACHED_BTF_PEERS) |
| @@ -400,8 +378,6 @@ static void RememberBtfPeer(const string& strBtfAddr, const string& strMeeting, | |||
| 400 | o["meeting"] = q.meeting; | 378 | o["meeting"] = q.meeting; |
| 401 | o["enc"] = q.encHex; | 379 | o["enc"] = q.encHex; |
| 402 | o["seen"] = q.lastSeen; | 380 | o["seen"] = q.lastSeen; |
| 403 | if (!q.desc.empty()) | ||
| 404 | o["desc"] = q.desc; | ||
| 405 | arr.push_back(o); | 381 | arr.push_back(o); |
| 406 | } | 382 | } |
| 407 | FILE* f = fopen(BtfPeerCachePath().c_str(), "w"); | 383 | FILE* f = fopen(BtfPeerCachePath().c_str(), "w"); |
| @@ -443,93 +419,6 @@ void ThreadReconnectCachedBtfPeers(void* parg) | |||
| 443 | nConnected, peers.size()); | 419 | nConnected, peers.size()); |
| 444 | } | 420 | } |
| 445 | 421 | ||
| 446 | // | ||
| 447 | // .btf peer exchange | ||
| 448 | // | ||
| 449 | // Until now discovery depended entirely on the Nostr relays: two connected | ||
| 450 | // nodes never told each other who else existed, so a relay outage left a | ||
| 451 | // running network unable to grow, and a node that found one stale peer had no | ||
| 452 | // way to learn there was anything better. | ||
| 453 | // | ||
| 454 | // What travels here is each peer's own signed descriptor. The receiver checks | ||
| 455 | // the Schnorr signature against the key the `.btf` address decodes to, so the | ||
| 456 | // sender is trusted for nothing -- forging an entry would need somebody else's | ||
| 457 | // secret key. That leaves flooding: valid descriptors for keys the sender | ||
| 458 | // generated itself. The caps below bound one message, and the cache prefers | ||
| 459 | // peers that actually answered, so a flood costs a Sybil more than it costs us. | ||
| 460 | // | ||
| 461 | |||
| 462 | void BtfPexCollect(vector<string>& vDescOut) | ||
| 463 | { | ||
| 464 | vDescOut.clear(); | ||
| 465 | |||
| 466 | // Ours first -- the node on the other end may know nobody but us. | ||
| 467 | string strMine = BtfLocalDescriptor(); | ||
| 468 | if (!strMine.empty()) | ||
| 469 | vDescOut.push_back(strMine); | ||
| 470 | |||
| 471 | vector<CachedBtfPeer> peers; | ||
| 472 | CRITICAL_BLOCK(cs_btfPeerCache) | ||
| 473 | LoadCachedBtfPeers(peers); | ||
| 474 | |||
| 475 | // Most recently seen first: these answered us, they are not names copied | ||
| 476 | // off a relay listing. | ||
| 477 | foreach(const CachedBtfPeer& p, peers) | ||
| 478 | { | ||
| 479 | if (vDescOut.size() >= MAX_PEX_DESCRIPTORS) break; | ||
| 480 | if (p.desc.empty()) continue; // nothing provable to pass on | ||
| 481 | if (p.desc.size() > MAX_PEX_DESCRIPTOR_BYTES) continue; | ||
| 482 | vDescOut.push_back(p.desc); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | int BtfPexAccept(const vector<string>& vDesc) | ||
| 487 | { | ||
| 488 | void* ctx = BtfSecpContext(); | ||
| 489 | if (!ctx) | ||
| 490 | return 0; | ||
| 491 | |||
| 492 | string strSelf = BtfLocalAddress(); | ||
| 493 | int nKept = 0; | ||
| 494 | unsigned int nSeen = 0; | ||
| 495 | |||
| 496 | foreach(const string& strDesc, vDesc) | ||
| 497 | { | ||
| 498 | if (++nSeen > MAX_PEX_DESCRIPTORS) break; | ||
| 499 | if (strDesc.empty() || strDesc.size() > MAX_PEX_DESCRIPTOR_BYTES) continue; | ||
| 500 | |||
| 501 | // The descriptor names the key it belongs to, and taking that key from | ||
| 502 | // the blob is safe precisely because the signature must verify under | ||
| 503 | // it: nobody can produce a valid descriptor for a key they don't hold. | ||
| 504 | unsigned char pubkey[32]; | ||
| 505 | try | ||
| 506 | { | ||
| 507 | nlohmann::json v = nlohmann::json::parse(strDesc); | ||
| 508 | if (!v.is_object() || !v.contains("pubkey") || !v["pubkey"].is_string()) | ||
| 509 | continue; | ||
| 510 | if (!HexToBytes(v["pubkey"].get<string>(), pubkey, 32)) | ||
| 511 | continue; | ||
| 512 | } | ||
| 513 | catch (...) { continue; } // malformed JSON from an untrusted peer | ||
| 514 | |||
| 515 | btf::Descriptor d; | ||
| 516 | if (!btf::VerifyDescriptor(ctx, strDesc, pubkey, d)) | ||
| 517 | continue; | ||
| 518 | |||
| 519 | string strAddr = btf::Address(pubkey); | ||
| 520 | if (strAddr.empty() || strAddr == strSelf) | ||
| 521 | continue; // ourselves, nothing to learn | ||
| 522 | |||
| 523 | unsigned char enc[32]; | ||
| 524 | if (!HexToBytes(d.enc, enc, 32)) | ||
| 525 | continue; | ||
| 526 | |||
| 527 | RememberBtfPeer(strAddr, d.meeting_node, enc, strDesc); | ||
| 528 | nKept++; | ||
| 529 | } | ||
| 530 | return nKept; | ||
| 531 | } | ||
| 532 | |||
| 533 | static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32], | 422 | static CNode* ConnectNodeBtfTail(const string& strBtfAddr, const unsigned char pk[32], |
| 534 | const string& strMeeting, const unsigned char enc_pub[32]) | 423 | const string& strMeeting, const unsigned char enc_pub[32]) |
| 535 | { | 424 | { |
| @@ -29,21 +29,6 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting | |||
| 29 | void ThreadBtfAccept(void* parg); | 29 | void ThreadBtfAccept(void* parg); |
| 30 | void ThreadBtfConnect(void* parg); | 30 | void ThreadBtfConnect(void* parg); |
| 31 | extern string strBtfConnect; | 31 | extern string strBtfConnect; |
| 32 | |||
| 33 | // --- .btf peer exchange --------------------------------------------------- | ||
| 34 | // Peers gossip signed descriptors so discovery survives a relay outage. Both | ||
| 35 | // caps apply to a single "btfpeers" message; the generic header limit is 256 MB, | ||
| 36 | // which is no protection at all for something a stranger can send unprompted. | ||
| 37 | static const unsigned int MAX_PEX_DESCRIPTORS = 20; | ||
| 38 | static const unsigned int MAX_PEX_DESCRIPTOR_BYTES = 1024; | ||
| 39 | // Ignore a peer's exchange more often than this. One announcement per side per | ||
| 40 | // connection is the intended traffic; anything faster is someone else's idea. | ||
| 41 | static const int64 PEX_MIN_INTERVAL = 60; | ||
| 42 | |||
| 43 | // Descriptors to hand a peer: ours first, then peers that answered us. | ||
| 44 | void BtfPexCollect(std::vector<std::string>& vDescOut); | ||
| 45 | // Verify descriptors a peer sent and remember the good ones. Returns how many. | ||
| 46 | int BtfPexAccept(const std::vector<std::string>& vDesc); | ||
| 47 | void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); | 32 | void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); |
| 48 | bool AnySubscribed(unsigned int nChannel); | 33 | bool AnySubscribed(unsigned int nChannel); |
| 49 | void ThreadBitcoinMiner(void* parg); | 34 | void ThreadBitcoinMiner(void* parg); |
| @@ -482,9 +467,6 @@ public: | |||
| 482 | // publish and subscription | 467 | // publish and subscription |
| 483 | vector<char> vfSubscribe; | 468 | vector<char> vfSubscribe; |
| 484 | 469 | ||
| 485 | // Last "btfpeers" we accepted from this node, to rate-limit the exchange. | ||
| 486 | int64 nLastPexRecv; | ||
| 487 | |||
| 488 | 470 | ||
| 489 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) | 471 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) |
| 490 | { | 472 | { |
| @@ -501,7 +483,6 @@ public: | |||
| 501 | fDisconnect = false; | 483 | fDisconnect = false; |
| 502 | nRefCount = 0; | 484 | nRefCount = 0; |
| 503 | nReleaseTime = 0; | 485 | nReleaseTime = 0; |
| 504 | nLastPexRecv = 0; | ||
| 505 | vfSubscribe.assign(256, false); | 486 | vfSubscribe.assign(256, false); |
| 506 | 487 | ||
| 507 | // Push a version message | 488 | // Push a version message |
diff --git a/src/nostr.cpp b/src/nostr.cpp index 482a835..ec02c2e 100644 --- a/src/nostr.cpp +++ b/src/nostr.cpp | |||
| @@ -342,36 +342,6 @@ 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 | |||
| 375 | int GetDiscoveredPeerCount() | 345 | int GetDiscoveredPeerCount() |
| 376 | { | 346 | { |
| 377 | int n = 0; | 347 | int n = 0; |
diff --git a/src/nostr.h b/src/nostr.h index b5eb5e3..04149e3 100644 --- a/src/nostr.h +++ b/src/nostr.h | |||
| @@ -82,14 +82,6 @@ bool BtfGetIdentity(unsigned char pubkey[32], unsigned char enc_sk[32]); | |||
| 82 | // This node's printable .btf address, or "" if the identity failed to load. | 82 | // This node's printable .btf address, or "" if the identity failed to load. |
| 83 | std::string BtfLocalAddress(); | 83 | std::string BtfLocalAddress(); |
| 84 | 84 | ||
| 85 | // This node's own signed descriptor, ready to hand to a peer over the wire. | ||
| 86 | // "" until ThreadBtfAccept has registered at a rendezvous. | ||
| 87 | std::string BtfLocalDescriptor(); | ||
| 88 | |||
| 89 | // The shared secp256k1 context, for btf::VerifyDescriptor (which takes it as | ||
| 90 | // void* to keep headers free of secp). NULL if the identity failed to load. | ||
| 91 | void* BtfSecpContext(); | ||
| 92 | |||
| 93 | // Resolve a .btf address via the public discovery relays: fetch the owner's | 85 | // Resolve a .btf address via the public discovery relays: fetch the owner's |
| 94 | // self-certified descriptor and return its meeting node ("host:port") and | 86 | // self-certified descriptor and return its meeting node ("host:port") and |
| 95 | // x25519 public key for the end-to-end channel. | 87 | // x25519 public key for the end-to-end channel. |