diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/btfrv.cpp | 16 | ||||
| -rw-r--r-- | src/btfrv.h | 19 | ||||
| -rw-r--r-- | src/btftunnel.cpp | 37 | ||||
| -rw-r--r-- | src/btftunnel.h | 25 | ||||
| -rw-r--r-- | src/main.cpp | 106 |
5 files changed, 182 insertions, 21 deletions
diff --git a/src/btfrv.cpp b/src/btfrv.cpp index 8ab735c..7d705ef 100644 --- a/src/btfrv.cpp +++ b/src/btfrv.cpp | |||
| @@ -377,17 +377,29 @@ bool RvServiceWaitPaired(RvSocket s, int nTimeoutSecs) | |||
| 377 | } | 377 | } |
| 378 | 378 | ||
| 379 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, | 379 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, |
| 380 | const unsigned char target_pubkey[32]) | 380 | const unsigned char target_pubkey[32], |
| 381 | RvClientFail* pFail) | ||
| 381 | { | 382 | { |
| 383 | if (pFail) *pFail = RVC_FAIL_DIAL; | ||
| 382 | if (!RvInit()) return RV_INVALID; | 384 | if (!RvInit()) return RV_INVALID; |
| 383 | SOCKET s = ConnectTo(relay_host, port); | 385 | SOCKET s = ConnectTo(relay_host, port); |
| 384 | if (s == INVALID_SOCKET) return RV_INVALID; | 386 | if (s == INVALID_SOCKET) return RV_INVALID; |
| 387 | if (pFail) *pFail = RVC_FAIL_PAIR; | ||
| 385 | unsigned char hdr[33]; | 388 | unsigned char hdr[33]; |
| 386 | hdr[0] = (unsigned char)'C'; | 389 | hdr[0] = (unsigned char)'C'; |
| 387 | memcpy(hdr + 1, target_pubkey, 32); | 390 | memcpy(hdr + 1, target_pubkey, 32); |
| 388 | if (!WriteN(s, hdr, 33)) { CLOSESOCK(s); return RV_INVALID; } | 391 | if (!WriteN(s, hdr, 33)) { CLOSESOCK(s); return RV_INVALID; } |
| 389 | unsigned char paired = 0; | 392 | unsigned char paired = 0; |
| 390 | if (!ReadN(s, &paired, 1) || paired != 0x01) { CLOSESOCK(s); return RV_INVALID; } | 393 | if (!ReadN(s, &paired, 1)) { CLOSESOCK(s); return RV_INVALID; } |
| 394 | if (paired != 0x01) | ||
| 395 | { | ||
| 396 | // The relay answered and declined: HandleIncoming writes 0x00 and | ||
| 397 | // closes when no service is parked under this pubkey right now. | ||
| 398 | if (pFail) *pFail = RVC_FAIL_REFUSED; | ||
| 399 | CLOSESOCK(s); | ||
| 400 | return RV_INVALID; | ||
| 401 | } | ||
| 402 | if (pFail) *pFail = RVC_FAIL_NONE; | ||
| 391 | return (RvSocket)s; | 403 | return (RvSocket)s; |
| 392 | } | 404 | } |
| 393 | 405 | ||
diff --git a/src/btfrv.h b/src/btfrv.h index 9cd7476..1e85cb0 100644 --- a/src/btfrv.h +++ b/src/btfrv.h | |||
| @@ -57,10 +57,25 @@ RvSocket RvServiceRegister(const char* relay_host, unsigned short port, | |||
| 57 | bool RvServiceWaitPaired(RvSocket s, int nTimeoutSecs = 0); | 57 | bool RvServiceWaitPaired(RvSocket s, int nTimeoutSecs = 0); |
| 58 | 58 | ||
| 59 | // ---- client side (the node dialing a .btf address) ---- | 59 | // ---- client side (the node dialing a .btf address) ---- |
| 60 | // Where a failed RvClientConnect stopped. RV_INVALID alone collapses three | ||
| 61 | // different situations -- relay unreachable, relay reachable but nobody | ||
| 62 | // registered, connection died mid-pairing -- and they point at different | ||
| 63 | // components. The caller can only report the right one if this side says | ||
| 64 | // which it saw. | ||
| 65 | enum RvClientFail | ||
| 66 | { | ||
| 67 | RVC_FAIL_NONE = 0, | ||
| 68 | RVC_FAIL_DIAL, // TCP connect to the relay itself failed | ||
| 69 | RVC_FAIL_REFUSED, // relay answered 0x00: no service registered under this pubkey | ||
| 70 | RVC_FAIL_PAIR, // relay connection died before pairing completed | ||
| 71 | }; | ||
| 72 | |||
| 60 | // Connect through the relay to the service registered under `target_pubkey`. | 73 | // Connect through the relay to the service registered under `target_pubkey`. |
| 61 | // Returns the paired socket, or RV_INVALID on error. | 74 | // Returns the paired socket, or RV_INVALID on error -- with `pFail`, if |
| 75 | // given, naming the stage that failed. | ||
| 62 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, | 76 | RvSocket RvClientConnect(const char* relay_host, unsigned short port, |
| 63 | const unsigned char target_pubkey[32]); | 77 | const unsigned char target_pubkey[32], |
| 78 | RvClientFail* pFail = 0); | ||
| 64 | 79 | ||
| 65 | // Blocking read/write of exactly n bytes over a rendezvous socket. Return false | 80 | // Blocking read/write of exactly n bytes over a rendezvous socket. Return false |
| 66 | // on error/EOF. | 81 | // on error/EOF. |
diff --git a/src/btftunnel.cpp b/src/btftunnel.cpp index 4acca1a..4058f6b 100644 --- a/src/btftunnel.cpp +++ b/src/btftunnel.cpp | |||
| @@ -231,18 +231,47 @@ static btf_socket_t StartTunnel(RvSocket rv, const unsigned char shared[32]) | |||
| 231 | return appEnd; | 231 | return appEnd; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | const char* TunnelFailText(TunnelFail f) | ||
| 235 | { | ||
| 236 | switch (f) | ||
| 237 | { | ||
| 238 | case TUNNEL_FAIL_NONE: return "no failure"; | ||
| 239 | case TUNNEL_FAIL_INIT: return "local socket/crypto init failed"; | ||
| 240 | case TUNNEL_FAIL_DIAL: return "meeting node unreachable (tcp dial failed)"; | ||
| 241 | case TUNNEL_FAIL_REFUSED: return "relay reachable, but no service registered there for this address"; | ||
| 242 | case TUNNEL_FAIL_PAIR: return "relay connection died before pairing completed"; | ||
| 243 | case TUNNEL_FAIL_HANDSHAKE: return "end-to-end handshake failed"; | ||
| 244 | case TUNNEL_FAIL_LOCAL: return "local tunnel setup failed"; | ||
| 245 | } | ||
| 246 | return "unknown failure"; | ||
| 247 | } | ||
| 248 | |||
| 234 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, | 249 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, |
| 235 | const unsigned char target_pubkey[32], | 250 | const unsigned char target_pubkey[32], |
| 236 | const unsigned char service_enc_pub[32]) | 251 | const unsigned char service_enc_pub[32], |
| 252 | TunnelFail* pFail) | ||
| 237 | { | 253 | { |
| 254 | if (pFail) *pFail = TUNNEL_FAIL_INIT; | ||
| 238 | if (!TunnelInit()) return INVALID_SOCKET; | 255 | if (!TunnelInit()) return INVALID_SOCKET; |
| 239 | RvSocket rv = RvClientConnect(meeting_host, port, target_pubkey); | 256 | RvClientFail rvFail = RVC_FAIL_NONE; |
| 240 | if (rv == RV_INVALID) return INVALID_SOCKET; | 257 | RvSocket rv = RvClientConnect(meeting_host, port, target_pubkey, &rvFail); |
| 258 | if (rv == RV_INVALID) | ||
| 259 | { | ||
| 260 | if (pFail) | ||
| 261 | *pFail = rvFail == RVC_FAIL_DIAL ? TUNNEL_FAIL_DIAL | ||
| 262 | : rvFail == RVC_FAIL_REFUSED ? TUNNEL_FAIL_REFUSED | ||
| 263 | : TUNNEL_FAIL_PAIR; | ||
| 264 | return INVALID_SOCKET; | ||
| 265 | } | ||
| 241 | 266 | ||
| 242 | unsigned char eph_pub[32], shared[32]; | 267 | unsigned char eph_pub[32], shared[32]; |
| 268 | if (pFail) *pFail = TUNNEL_FAIL_HANDSHAKE; | ||
| 243 | if (!ChanClientHandshake(service_enc_pub, eph_pub, shared)) { RvClose(rv); return INVALID_SOCKET; } | 269 | if (!ChanClientHandshake(service_enc_pub, eph_pub, shared)) { RvClose(rv); return INVALID_SOCKET; } |
| 244 | if (!RvWriteN(rv, eph_pub, 32)) { RvClose(rv); return INVALID_SOCKET; } | 270 | if (!RvWriteN(rv, eph_pub, 32)) { RvClose(rv); return INVALID_SOCKET; } |
| 245 | return StartTunnel(rv, shared); | 271 | if (pFail) *pFail = TUNNEL_FAIL_LOCAL; |
| 272 | btf_socket_t app = StartTunnel(rv, shared); | ||
| 273 | if (app != INVALID_SOCKET && pFail) *pFail = TUNNEL_FAIL_NONE; | ||
| 274 | return app; | ||
| 246 | } | 275 | } |
| 247 | 276 | ||
| 248 | btf_socket_t BtfServiceWrap(RvSocket rv, const unsigned char my_enc_sk[32]) | 277 | btf_socket_t BtfServiceWrap(RvSocket rv, const unsigned char my_enc_sk[32]) |
diff --git a/src/btftunnel.h b/src/btftunnel.h index 24a7509..3cc87cd 100644 --- a/src/btftunnel.h +++ b/src/btftunnel.h | |||
| @@ -36,12 +36,33 @@ namespace btf | |||
| 36 | // Initialize (sockets + libsodium). Idempotent. | 36 | // Initialize (sockets + libsodium). Idempotent. |
| 37 | bool TunnelInit(); | 37 | bool TunnelInit(); |
| 38 | 38 | ||
| 39 | // Which stage of BtfClientTunnel failed. INVALID_SOCKET alone says only "no | ||
| 40 | // tunnel"; a caller that then guesses at causes in its log line sends whoever | ||
| 41 | // reads it to the wrong component (issue #17: "relay unreachable or pool not | ||
| 42 | // listening" blamed two healthy parts). The stage is what this side actually | ||
| 43 | // knows -- report that. | ||
| 44 | enum TunnelFail | ||
| 45 | { | ||
| 46 | TUNNEL_FAIL_NONE = 0, | ||
| 47 | TUNNEL_FAIL_INIT, // local socket/crypto init failed | ||
| 48 | TUNNEL_FAIL_DIAL, // TCP connect to the meeting node failed | ||
| 49 | TUNNEL_FAIL_REFUSED, // relay reachable, but no service registered under the pubkey | ||
| 50 | TUNNEL_FAIL_PAIR, // relay connection died before pairing completed | ||
| 51 | TUNNEL_FAIL_HANDSHAKE, // end-to-end channel handshake failed | ||
| 52 | TUNNEL_FAIL_LOCAL, // local pump plumbing (socket pair / threads) failed | ||
| 53 | }; | ||
| 54 | |||
| 55 | // Short description of a TunnelFail for log lines. | ||
| 56 | const char* TunnelFailText(TunnelFail f); | ||
| 57 | |||
| 39 | // Client: dial the service registered under `target_pubkey` at the meeting node | 58 | // Client: dial the service registered under `target_pubkey` at the meeting node |
| 40 | // (host:port), box to its static x25519 `service_enc_pub`, and return a local | 59 | // (host:port), box to its static x25519 `service_enc_pub`, and return a local |
| 41 | // plaintext SOCKET tunneled end-to-end to the service. INVALID_SOCKET on error. | 60 | // plaintext SOCKET tunneled end-to-end to the service. INVALID_SOCKET on error |
| 61 | // -- with `pFail`, if given, naming the stage that failed. | ||
| 42 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, | 62 | btf_socket_t BtfClientTunnel(const char* meeting_host, unsigned short port, |
| 43 | const unsigned char target_pubkey[32], | 63 | const unsigned char target_pubkey[32], |
| 44 | const unsigned char service_enc_pub[32]); | 64 | const unsigned char service_enc_pub[32], |
| 65 | TunnelFail* pFail = 0); | ||
| 45 | 66 | ||
| 46 | // Service: wrap an already-paired rendezvous socket (RvServiceRegister followed | 67 | // Service: wrap an already-paired rendezvous socket (RvServiceRegister followed |
| 47 | // by RvServiceWaitPaired -- the pairing byte MUST already be consumed) with | 68 | // by RvServiceWaitPaired -- the pairing byte MUST already be consumed) with |
diff --git a/src/main.cpp b/src/main.cpp index 681673c..6b8e0de 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -3970,6 +3970,14 @@ static void ParticipantHashWorker(ParticipantJobShared* sh, int idx, int nWorker | |||
| 3970 | RandomXDestroyMinerVM(vm); | 3970 | RandomXDestroyMinerVM(vm); |
| 3971 | } | 3971 | } |
| 3972 | 3972 | ||
| 3973 | // Run one participant session: resolve the pool, open the tunnel, subscribe, | ||
| 3974 | // hash, submit shares. Returns true only if the pool actually handed out work | ||
| 3975 | // -- at least one well-formed mining.notify arrived. Everything else is false, | ||
| 3976 | // including a tunnel that opened and was dropped before any job. | ||
| 3977 | // | ||
| 3978 | // The caller's reconnect backoff keys off this return value, so any path added | ||
| 3979 | // here that leaves the session without work MUST return false. "The session | ||
| 3980 | // ended tidily" is not the question being asked. | ||
| 3973 | static bool PoolParticipantMiner() | 3981 | static bool PoolParticipantMiner() |
| 3974 | { | 3982 | { |
| 3975 | // ------------------------------------------------------------------ | 3983 | // ------------------------------------------------------------------ |
| @@ -4047,6 +4055,33 @@ static bool PoolParticipantMiner() | |||
| 4047 | } | 4055 | } |
| 4048 | LogPrint("worker", "[worker] pool resolved to meeting node %s\n", meetingHostPort.c_str()); | 4056 | LogPrint("worker", "[worker] pool resolved to meeting node %s\n", meetingHostPort.c_str()); |
| 4049 | 4057 | ||
| 4058 | // The descriptor names ONE meeting node, but the pool parks a | ||
| 4059 | // registration at every relay it knows (one accept thread per relay, | ||
| 4060 | // rpc.cpp:AcceptOneFn), so any seed relay can pair us. Insisting on the | ||
| 4061 | // advertised entry forever turns one bad path into a miner that idles | ||
| 4062 | // indefinitely while a working path exists (issue #17); after a few | ||
| 4063 | // consecutive tunnel failures, rotate the seed relays into the attempts | ||
| 4064 | // too. Only ONE participant session runs (StartMinerThreads), so these | ||
| 4065 | // statics are single-threaded. | ||
| 4066 | static const int TUNNEL_FAILOVER_AFTER = 3; | ||
| 4067 | static int nTunnelFails = 0; // consecutive tunnel failures, this pool | ||
| 4068 | static size_t iFailoverRelay = 0; // rotation cursor over vBtfMeetingRelays | ||
| 4069 | static std::string strFailPool; // pool the counters belong to | ||
| 4070 | if (strFailPool != strParticipantPool) { | ||
| 4071 | strFailPool = strParticipantPool; | ||
| 4072 | nTunnelFails = 0; | ||
| 4073 | iFailoverRelay = 0; | ||
| 4074 | } | ||
| 4075 | if (nTunnelFails >= TUNNEL_FAILOVER_AFTER && !vBtfMeetingRelays.empty()) { | ||
| 4076 | std::string alt = vBtfMeetingRelays[iFailoverRelay++ % vBtfMeetingRelays.size()]; | ||
| 4077 | if (alt != meetingHostPort) { | ||
| 4078 | LogPrint("worker", "[worker] advertised meeting node %s failed %d" | ||
| 4079 | " times in a row -- trying seed relay %s instead\n", | ||
| 4080 | meetingHostPort.c_str(), nTunnelFails, alt.c_str()); | ||
| 4081 | meetingHostPort = alt; | ||
| 4082 | } | ||
| 4083 | } | ||
| 4084 | |||
| 4050 | size_t colon = meetingHostPort.rfind(':'); | 4085 | size_t colon = meetingHostPort.rfind(':'); |
| 4051 | if (colon == std::string::npos) { | 4086 | if (colon == std::string::npos) { |
| 4052 | LogPrint("worker", "[worker] bad meeting node format '%s'\n", meetingHostPort.c_str()); | 4087 | LogPrint("worker", "[worker] bad meeting node format '%s'\n", meetingHostPort.c_str()); |
| @@ -4066,15 +4101,18 @@ static bool PoolParticipantMiner() | |||
| 4066 | // Step 2b: open encrypted tunnel to pool | 4101 | // Step 2b: open encrypted tunnel to pool |
| 4067 | // ------------------------------------------------------------------ | 4102 | // ------------------------------------------------------------------ |
| 4068 | SetParticipantMiningStatus("opening tunnel"); | 4103 | SetParticipantMiningStatus("opening tunnel"); |
| 4104 | btf::TunnelFail tunnelFail = btf::TUNNEL_FAIL_NONE; | ||
| 4069 | s = btf::BtfClientTunnel(host.c_str(), (unsigned short)port, | 4105 | s = btf::BtfClientTunnel(host.c_str(), (unsigned short)port, |
| 4070 | target_pubkey, service_enc_pub); | 4106 | target_pubkey, service_enc_pub, &tunnelFail); |
| 4071 | if (s == INVALID_SOCKET) { | 4107 | if (s == INVALID_SOCKET) { |
| 4072 | LogPrint("worker", "[worker] tunnel connect FAILED via %s" | 4108 | nTunnelFails++; |
| 4073 | " (relay unreachable or pool not listening)\n", | 4109 | LogPrint("worker", "[worker] tunnel connect FAILED via %s: %s\n", |
| 4074 | meetingHostPort.c_str()); | 4110 | meetingHostPort.c_str(), btf::TunnelFailText(tunnelFail)); |
| 4075 | SetParticipantMiningStatus("tunnel connect failed"); | 4111 | SetParticipantMiningStatus(std::string("tunnel connect failed: ") |
| 4112 | + btf::TunnelFailText(tunnelFail)); | ||
| 4076 | return false; | 4113 | return false; |
| 4077 | } | 4114 | } |
| 4115 | nTunnelFails = 0; | ||
| 4078 | LogPrint("worker", "[worker] tunnel open via %s\n", meetingHostPort.c_str()); | 4116 | LogPrint("worker", "[worker] tunnel open via %s\n", meetingHostPort.c_str()); |
| 4079 | SetParticipantMiningStatus("tunnel open"); | 4117 | SetParticipantMiningStatus("tunnel open"); |
| 4080 | } | 4118 | } |
| @@ -4253,6 +4291,7 @@ connected: | |||
| 4253 | int nBestHeightResolved = -1; // nBestHeight when we last resolved | 4291 | int nBestHeightResolved = -1; // nBestHeight when we last resolved |
| 4254 | double currentDifficulty = 1.0; // updated by mining.set_difficulty from pool | 4292 | double currentDifficulty = 1.0; // updated by mining.set_difficulty from pool |
| 4255 | bool haveJob = false; | 4293 | bool haveJob = false; |
| 4294 | bool gotAnyJob = false; // any job at all this session -- the return value | ||
| 4256 | bool gotSubscribeAck = false; | 4295 | bool gotSubscribeAck = false; |
| 4257 | bool gotAuthorizeAck = false; | 4296 | bool gotAuthorizeAck = false; |
| 4258 | int64 authWaitStart = 0; | 4297 | int64 authWaitStart = 0; |
| @@ -4369,8 +4408,9 @@ connected: | |||
| 4369 | jobId = newJobId; | 4408 | jobId = newJobId; |
| 4370 | memcpy(header, hdrBytes.data(), 80); | 4409 | memcpy(header, hdrBytes.data(), 80); |
| 4371 | memcpy(&target, tgtBytes.data(), 32); | 4410 | memcpy(&target, tgtBytes.data(), 32); |
| 4372 | haveJob = true; | 4411 | haveJob = true; |
| 4373 | nNonce = 1; | 4412 | gotAnyJob = true; |
| 4413 | nNonce = 1; | ||
| 4374 | { | 4414 | { |
| 4375 | std::lock_guard<std::mutex> lk(jobShared.mtx); | 4415 | std::lock_guard<std::mutex> lk(jobShared.mtx); |
| 4376 | memcpy(jobShared.header, header, 80); | 4416 | memcpy(jobShared.header, header, 80); |
| @@ -4562,7 +4602,11 @@ connected: | |||
| 4562 | (unsigned long long)hashesSinceSample, | 4602 | (unsigned long long)hashesSinceSample, |
| 4563 | (unsigned long long)sessionSharesSent, | 4603 | (unsigned long long)sessionSharesSent, |
| 4564 | (unsigned long long)sessionSharesAccepted); | 4604 | (unsigned long long)sessionSharesAccepted); |
| 4565 | return true; | 4605 | // Not "we got here", which is true of a tunnel the pool accepted and then |
| 4606 | // dropped without ever sending a job -- exactly the case the caller's | ||
| 4607 | // backoff exists for. Reaching the end of the session is not evidence the | ||
| 4608 | // session was worth anything; a job is. | ||
| 4609 | return gotAnyJob; | ||
| 4566 | } | 4610 | } |
| 4567 | 4611 | ||
| 4568 | // --------------------------------------------------------------------------- | 4612 | // --------------------------------------------------------------------------- |
| @@ -4759,11 +4803,51 @@ bool BitcoinMiner(int nThreadId) | |||
| 4759 | // Participant mode: connect to external pool instead of mining solo/operator | 4803 | // Participant mode: connect to external pool instead of mining solo/operator |
| 4760 | if (nMineMode == MINE_PARTICIPANT) | 4804 | if (nMineMode == MINE_PARTICIPANT) |
| 4761 | { | 4805 | { |
| 4806 | // An attempt that never got work backs off (10s doubling to 120s) | ||
| 4807 | // instead of hammering the same path every flat 10s, and a streak | ||
| 4808 | // lasting minutes is said at printf level: the identical once-per-10s | ||
| 4809 | // LogPrint line is how a worker idled all night unnoticed (issue #17). | ||
| 4810 | // | ||
| 4811 | // Only a session the pool actually sent a job to resets either. The | ||
| 4812 | // weaker test -- "the session returned" -- was gameable: a pool that | ||
| 4813 | // completes the tunnel and drops without ever sending work leaves by | ||
| 4814 | // the same tidy cleanup path a healthy one does, which would pin the | ||
| 4815 | // retry at 10s forever and defeat the backoff in exactly the scenario | ||
| 4816 | // it exists for. | ||
| 4817 | int nRetrySecs = 10; | ||
| 4818 | int64 nFailingSince = 0; | ||
| 4762 | while (fGenerateBitcoins && nMineMode == MINE_PARTICIPANT && !fShutdown) { | 4819 | while (fGenerateBitcoins && nMineMode == MINE_PARTICIPANT && !fShutdown) { |
| 4763 | PoolParticipantMiner(); | 4820 | bool fGotWork = PoolParticipantMiner(); |
| 4764 | if (fGenerateBitcoins && nMineMode == MINE_PARTICIPANT && !fShutdown) { | 4821 | if (fGenerateBitcoins && nMineMode == MINE_PARTICIPANT && !fShutdown) { |
| 4765 | LogPrint("worker", "PoolParticipantMiner: reconnecting in 10s\n"); | 4822 | if (fGotWork) { |
| 4766 | for (int i = 0; i < 10 && !fShutdown; i++) Sleep(1000); | 4823 | nRetrySecs = 10; |
| 4824 | nFailingSince = 0; | ||
| 4825 | } else { | ||
| 4826 | if (nFailingSince == 0) | ||
| 4827 | nFailingSince = GetTime(); | ||
| 4828 | int64 nMins = (GetTime() - nFailingSince) / 60; | ||
| 4829 | if (nMins >= 1) | ||
| 4830 | printf("[worker] connection to pool %s has been failing" | ||
| 4831 | " for %lld minutes\n", | ||
| 4832 | strParticipantPool.c_str(), (long long)nMins); | ||
| 4833 | } | ||
| 4834 | LogPrint("worker", "PoolParticipantMiner: reconnecting in %ds\n", | ||
| 4835 | nRetrySecs); | ||
| 4836 | // Poll everything the enclosing while polls, not just | ||
| 4837 | // fShutdown. Raising the ceiling to 120s made a | ||
| 4838 | // shutdown-only predicate expensive: after the operator | ||
| 4839 | // clears Generate or switches to Relay, the session -- and | ||
| 4840 | // the vfThreadRunning[3] slot that gates restarting it -- | ||
| 4841 | // would stay held for up to two minutes. Measured 119s | ||
| 4842 | // before, 1s after. | ||
| 4843 | for (int i = 0; i < nRetrySecs && !fShutdown && fGenerateBitcoins | ||
| 4844 | && nMineMode == MINE_PARTICIPANT; i++) | ||
| 4845 | Sleep(1000); | ||
| 4846 | if (!fGotWork && nRetrySecs < 120) { | ||
| 4847 | nRetrySecs *= 2; | ||
| 4848 | if (nRetrySecs > 120) | ||
| 4849 | nRetrySecs = 120; | ||
| 4850 | } | ||
| 4767 | } | 4851 | } |
| 4768 | } | 4852 | } |
| 4769 | return true; | 4853 | return true; |