upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/nostr.cpp
AgeCommit message (Collapse)Author
2026-08-19net: stop closing a descriptor number that now belongs to somebody elsebitflash-maintainer
THE WEDGE. CNode::Disconnect() closed hSocket and left the member holding the stale number. ~CNode's only guard is 'hSocket != INVALID_SOCKET' and nothing in the tree ever assigned that sentinel, so the destructor closed the same number a second time. The two closes are five minutes apart by design: ThreadSocketHandler2 disconnects a node, sets nReleaseTime to GetTime() + 5*60, and parks it in vNodesDisconnected; GetRefCount() reports it busy until that expires, so 'delete pnode' -- and the second close -- cannot run before then. Linux hands out the lowest free descriptor. Measured on the pool: 202 open descriptors with a high-water mark of 216, so a freed number is reissued within seconds -- to a Nostr relay TLS socket, a rendezvous socket, a tunnel end, or a miner connection. Five minutes later the destructor closes it. The victim gets no error and no log line. It simply stops. That is the whole signature, including the part that never made sense: .btf block delivery and Nostr descriptor lookup share no lock, no queue and no thread, so they should not fail together. They share the file descriptor table, and a stray close is drawn from all of it. It also explains why #78 did not help and may have hurt. #78 drops stuck nodes -- it fired 41 times in one window -- and every drop is another Disconnect(), which is another delayed close armed against an innocent socket. Second bug, same symptom, different subsystem: the pooled relay sockets. ResolveDescriptor returned the instant a descriptor verified, leaving the relay's EOSE unread on a socket that goes straight back into g_relayPool, so the next caller read our leftovers as its own answer -- permanently one message out of step, and no code path anywhere inspected the subscription id that would have caught it. Worse, BtfResolve set lease.fOk = true on every failure path including a dead RecvText, labelling it 'exchange completed, just no match'. fOk = false is the only thing that ever closes a pooled socket or clears fConnected, so a relay connection that died was pinned in the pool, reported healthy, and reused for the life of the process. That is 'no Nostr descriptor found' for a descriptor that nak can see, cleared only by a restart. Now: read to EOSE before returning, match the subscription id, and keep a pooled socket only when the relay actually finished the conversation. (cherry picked from commit ed4640c306cc46dbdbd92cb6dc55e7528651269c)
2026-08-19payout: zero-initialise blockHash; nostr: drop four dead relaysbitflash-maintainer
Two fixes. uint256's default constructor is empty (uint256.h:514), so the blockHash field added in 6963862 was uninitialised garbage on every PendingPayout built without an explicit hash -- which is every entry loaded from a ledger written before that commit. Those entries were meant to be grandfathered past the orphan check on a zero hash; instead each carried a random value that matched no block in mapBlockIndex, and the first maturity sweep after deploy voided the whole loaded ledger: 100 entries, 4950 BTF. Only one "was orphaned -- voiding" line reached the log because LogPrint collapsed the other 99 as duplicates, so the destruction was nearly silent. Nothing had been paid at that point and the file was restored from a pre-deploy backup, so no obligation was lost. Assigning 0 explicitly is all that was missing. Separately, four of the twelve relays are dead. Probed all twelve from two independent networks (a residential line and the pool's VPS) over v4 and v6, with DNS confirmed against 1.1.1.1: relay.current.fyi, relay.nostr.bg -- NXDOMAIN, no A and no AAAA. The domains are gone. (A getaddrinfo call on the VPS reports an address for them, but that is the VPS's own IPv6 handed back by its local resolver, not a real host.) relay.nostr.band, nostr.fmt.wiz.biz -- DNS resolves and TCP connects, but the TLS handshake never completes, from either network. Whether they are down or refusing non-browser clients, this node cannot use them. The remaining eight all complete a WebSocket upgrade. A dead relay is not free: each holds a connect/retry slot and delays discovery for no added redundancy. (cherry picked from commit 144bc96f150d23507d57d29cb339f177dcd6b092)
2026-08-19nostr: verify relay certificates -- wss:// was fully MITM-ablebitflash-maintainer
SSL_CTX_new leaves verification at SSL_VERIFY_NONE and loads no trust store, and nothing here ever changed that. SNI was set, a certificate was received, and it was then ignored: every wss:// relay connection this node has ever made would have completed against an attacker's certificate. Signed events limit the damage -- a MITM cannot forge an announcement attributable to our key -- but it can drop the rendezvous registration so miners never find the pool, censor subscriptions, or answer them with arbitrary content, which is the input the allocation bounds exist to contain. Load the system trust store, require SSL_VERIFY_PEER, and bind the check to the host we dialed with SSL_set1_host, since chain validation alone would accept any certificate a trusted CA ever issued for any name. Floor the protocol at TLS 1.2. Verification failures report the specific X509 reason rather than a generic handshake error, and a missing CA store is a hard failure instead of a silent downgrade to trusting everything. (cherry picked from commit 6020740e68463deb1cc3c5b477372fcd1a245adb)
2026-08-19operator: /noannounce flag -- serve miners without publishing pool announcementsbitflash-maintainer
Descriptor (38501) still published so miners can resolve the pool; only the public pool listing event (38503) is suppressed. (cherry picked from commit 17bbdae1ec97945c37c1d5b2486e5c01a4d7ad87)
2026-08-19nostr: make /rvrelay a true pin -- never merge discovered relaysbitflash-maintainer
A pool started with /rvrelay=ONE still spawned an accept thread for every Nostr-discovered relay (BtfAllRelays always merged g_discoveredRelays), and each thread optimistically overwrote the advertised meeting node before registering -- so a discovered Tailscale-only relay (a mesh host) flapped the published .btf descriptor and public miners could not connect. fBtfRelayPinned (set only when /rvrelay parses) makes BtfAllRelays return exactly the pinned list. Also validate the /rvrelay value at parse time: with the pin in place no discovered relay can mask a typo. (cherry picked from commit 0a4d2b02fa5382c5e788b5f0e2f8a844695dec47)
2026-08-19pool: sync-gate job creation, retry failed payouts; widen nostr relay setbitflash-maintainer
- RebuildJob: no jobs with zero peers or a tip older than 30min; mining unsynced produced orphaned blocks and payouts that can never be paid (observed in production: 8 orphan 'found blocks') - payout exec: on SendMoney failure requeue with 60s backoff, up to 30 attempts, instead of silently forfeiting the payment - nostr: add oxtr.dev, nos.social, fmt.wiz.biz, current.fyi, nostr.bg (12 relays total) for announcement redundancy (cherry picked from commit f1986cd7e4a6f69469a2256eb96ff03f3f146792)
2026-08-04public commitbitflash-coin