upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/net.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 07:09:45 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 07:09:45 +0000
commit0b566b4869b9e86c90162befd87f9882b6dd143c (patch)
tree978c6a3d0ecf729fa72ab38468280d195843996a /src/net.cpp
parenta44c9402c20493f0964a1296dd38d313216fbd4d (diff)
net: a refused thread spawn drops one peer, not the node
std::thread throws std::system_error when pthread_create is refused (RLIMIT_NPROC, a container's pids cgroup, memory pressure), and nothing caught it, so the node died by std::terminate. Threads are spawned per peer connection, so the pressure that triggers this scales with peer count, which is attacker-influenced. Observed killing a healthy participant worker mid-mining. Every spawn site in the node build, and what a failure now does: - btftunnel.cpp: both tunnel pumps are guarded. The inbound pump starts first because it owns cleanup of the pump end and rendezvous socket; if the second spawn is refused, shutdown() wakes the first out of its read and it cleans up itself -- closing those descriptors from the failure path instead would race it onto reused descriptors. Both paths return INVALID_SOCKET, which every caller already treats as "this connection failed". - btfrv.cpp: the relay's accept loop drops the connection it cannot serve and stops accepting for a moment -- longer after consecutive failures, capped at 5s -- instead of dying at an arbitrary one. The per-pair second pump now runs on the handling thread itself, leaving exactly one spawn to guard and nothing running yet to race. - main.cpp: a participant that cannot spawn its hash workers stops the ones that did start, drops the pool connection, and returns to the reconnect loop, the same way an ordinary disconnect does. - randomx_pow.cpp: dataset init joins the workers it got, releases the dataset, and stays in light mode -- the same trade the allocation failure path above it already makes. - rpc.cpp, net.cpp: the remaining unchecked _beginthread calls (which report failure by value, they cannot throw) now say precisely what did not start. The pool's accept and payout threads failing silently left the pool running deaf -- nobody accepts, nobody gets paid, and nothing in the log says why. Left alone deliberately: the per-relay accept spawns (rpc.cpp) already check, log and retry on the next poll; startup-critical spawns in net.cpp keep failing hard; the selftest-only std::thread uses may abort a selftest run, which is acceptable where dying over one peer is not. Verified: full node rebuilds clean and links; pool-stratum selftest passes; a scratch harness under RLIMIT_NPROC=1 confirms _beginthread reports -1 and std::thread throws system_error, the premises of every path above.
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp5
1 files changed, 3 insertions, 2 deletions
diff --git a/src/net.cpp b/src/net.cpp
index fed6123..16038c8 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2090,7 +2090,7 @@ bool StartNode(string& strError)
2090 if (addrIncoming.ip) 2090 if (addrIncoming.ip)
2091 addrLocalHost.ip = addrIncoming.ip; 2091 addrLocalHost.ip = addrIncoming.ip;
2092 2092
2093 _beginthread([](void*) { 2093 if (_beginthread([](void*) {
2094 unsigned int ip = addrLocalHost.ip; 2094 unsigned int ip = addrLocalHost.ip;
2095 if (GetMyExternalIP(ip)) { 2095 if (GetMyExternalIP(ip)) {
2096 addrLocalHost.ip = ip; 2096 addrLocalHost.ip = ip;
@@ -2098,7 +2098,8 @@ bool StartNode(string& strError)
2098 CWalletDB().WriteSetting("addrIncoming", addrIncoming); 2098 CWalletDB().WriteSetting("addrIncoming", addrIncoming);
2099 printf("External IP updated: %s\n", addrLocalHost.ToStringIP().c_str()); 2099 printf("External IP updated: %s\n", addrLocalHost.ToStringIP().c_str());
2100 } 2100 }
2101 }, 0, NULL); 2101 }, 0, NULL) == (uintptr_t)-1)
2102 printf("Error: _beginthread(GetMyExternalIP) failed\n");
2102 2103
2103 // Peers that answered last time, dialled straight away. The relays are the 2104 // Peers that answered last time, dialled straight away. The relays are the
2104 // only way to find anyone otherwise, and reaching them plus walking their 2105 // only way to find anyone otherwise, and reaching them plus walking their