diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-08-09 02:43:44 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-08-19 22:48:26 +0000 |
| commit | 82ac5bbc05a1de2be752e2f89110af1e424bc863 (patch) | |
| tree | 4498fd222a5391130db055c66bc16526fecea4c7 /src/rpc.cpp | |
| parent | 06bceb4d3e368bec47c4c2eaafdc1c1071625d30 (diff) | |
pool: wait to be paired before wrapping the rendezvous socket
Upstream #30 split rendezvous registration from waiting for a dial, so
RvServiceRegister now returns as soon as the relay lists the service and
no longer consumes the relay's 0x01 pairing byte. It updated its own
caller in net.cpp and left this one behind.
AcceptOneFn went straight from RvServiceRegister to BtfServiceWrap, so
BtfServiceWrap read that 0x01 as the first byte of the miner's 32-byte
ephemeral key and every byte after it was shifted by one. The X25519
handshake has no confirmation step, so it completed against a garbage
shared secret, the tunnel was handed to the Stratum event loop, and
nothing failed loudly: the pool logged a miner arriving and then dropped
it as "never authorized", while the miner logged a pool that closed on it
with gotSubscribeAck=0. Loopback miners were unaffected, which is exactly
what made it look like a relay problem.
Block in RvServiceWaitPaired before wrapping, and close and re-register if
the relay drops us first.
test_rvaccept.cpp covers both shapes against a real bitflashd on loopback:
the pre-fix order establishes a tunnel that carries no bytes, the fixed
order round-trips. Also corrects the btftunnel.h contract comment, which
still described the pre-#30 behaviour and is what the old code was written
against -- upstream's own test_relayproc.cpp, test_btftunnel.cpp and
test_btfrv.cpp are still on that stale contract and fail the same way.
(cherry picked from commit 3e3a36b2bf1e6ffb4861507089b743688619377f)
Diffstat (limited to 'src/rpc.cpp')
| -rw-r--r-- | src/rpc.cpp | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp index 3dd05bb..21a8d77 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp | |||
| @@ -6,8 +6,8 @@ | |||
| 6 | // Architecture: | 6 | // Architecture: |
| 7 | // PoolEventLoop -- single thread, owns all miner fds, all job/share/payout | 7 | // PoolEventLoop -- single thread, owns all miner fds, all job/share/payout |
| 8 | // state. No locks needed on any of that data. | 8 | // state. No locks needed on any of that data. |
| 9 | // AcceptOneFn -- one thread per relay. Blocks on RvServiceRegister + | 9 | // AcceptOneFn -- one thread per relay. Registers, waits to be paired, |
| 10 | // BtfServiceWrap, pushes finished socket to gReadyQueue. | 10 | // wraps the tunnel, pushes finished socket to gReadyQueue. |
| 11 | // AcceptLoopFn -- spawns AcceptOneFn threads, re-polls relay list every | 11 | // AcceptLoopFn -- spawns AcceptOneFn threads, re-polls relay list every |
| 12 | // 60s so dynamically discovered relays get picked up. | 12 | // 60s so dynamically discovered relays get picked up. |
| 13 | // | 13 | // |
| @@ -1388,12 +1388,11 @@ static void AcceptOneFn(void* arg) | |||
| 1388 | LogPrint("pool", "[pool] accept thread started for relay %s\n", relay.c_str()); | 1388 | LogPrint("pool", "[pool] accept thread started for relay %s\n", relay.c_str()); |
| 1389 | 1389 | ||
| 1390 | while (!fShutdown && gPoolRunning) { | 1390 | while (!fShutdown && gPoolRunning) { |
| 1391 | // Advertise this relay as the pool's meeting node BEFORE registering: | 1391 | // Advertise this relay as the pool's meeting node BEFORE registering, |
| 1392 | // RvServiceRegister blocks until a miner pairs, and miners can only | 1392 | // so that miners which resolve our descriptor find a relay where the |
| 1393 | // find us if the published descriptor already names a relay where the | ||
| 1394 | // pool (not the node's peer-accept) holds the registration. | 1393 | // pool (not the node's peer-accept) holds the registration. |
| 1395 | BtfSetActiveRelay(relay); | 1394 | BtfSetActiveRelay(relay); |
| 1396 | // Blocks until a miner connects to us at this relay | 1395 | // Returns as soon as the relay lists us -- registered, not yet paired. |
| 1397 | btf::RvSocket rv = btf::RvServiceRegister(host.c_str(), (unsigned short)port, pk); | 1396 | btf::RvSocket rv = btf::RvServiceRegister(host.c_str(), (unsigned short)port, pk); |
| 1398 | 1397 | ||
| 1399 | if (fShutdown || !gPoolRunning) { | 1398 | if (fShutdown || !gPoolRunning) { |
| @@ -1407,6 +1406,23 @@ static void AcceptOneFn(void* arg) | |||
| 1407 | continue; | 1406 | continue; |
| 1408 | } | 1407 | } |
| 1409 | 1408 | ||
| 1409 | // Block for a miner to actually arrive. RvServiceRegister used to do | ||
| 1410 | // this itself and returned with the relay's 0x01 pairing byte already | ||
| 1411 | // consumed; it no longer does. Without waiting here, BtfServiceWrap | ||
| 1412 | // reads that 0x01 as the first byte of the miner's 32-byte ephemeral | ||
| 1413 | // key -- every subsequent byte is shifted by one, so the X25519 | ||
| 1414 | // handshake completes against a garbage shared secret (it has no | ||
| 1415 | // confirmation step to catch it), the tunnel is handed to the event | ||
| 1416 | // loop, and the miner's mining.subscribe never decrypts into a valid | ||
| 1417 | // line. The miner sees the pool close on it; the pool sees a peer that | ||
| 1418 | // never authorized. | ||
| 1419 | if (!btf::RvServiceWaitPaired(rv)) { | ||
| 1420 | btf::RvClose(rv); | ||
| 1421 | LogPrint("pool", "[pool] relay %s: dropped us before any miner dialed" | ||
| 1422 | " -- re-registering\n", relay.c_str()); | ||
| 1423 | continue; | ||
| 1424 | } | ||
| 1425 | |||
| 1410 | // Echan handshake -- blocking but fast (local + relay round-trip) | 1426 | // Echan handshake -- blocking but fast (local + relay round-trip) |
| 1411 | btf_socket_t fd = btf::BtfServiceWrap(rv, sk); | 1427 | btf_socket_t fd = btf::BtfServiceWrap(rv, sk); |
| 1412 | if (fd == INVALID_SOCKET) { | 1428 | if (fd == INVALID_SOCKET) { |