upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/rpc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc.cpp')
-rw-r--r--src/rpc.cpp90
1 files changed, 71 insertions, 19 deletions
diff --git a/src/rpc.cpp b/src/rpc.cpp
index a4b53ca..bd5fd8b 100644
--- a/src/rpc.cpp
+++ b/src/rpc.cpp
@@ -1732,7 +1732,9 @@ static void FlushMaturePayouts()
1732 } 1732 }
1733 int64 total = 0; 1733 int64 total = 0;
1734 for (auto& kv : it->amounts) total += kv.second; 1734 for (auto& kv : it->amounts) total += kv.second;
1735 LogPrint("payout", "[payout] block %d (%s) was orphaned -- voiding %zu" 1735 // Always: one line per voided entry, never a collapsed summary.
1736 // A reorg voids these in a burst from this one source line.
1737 LogPrintAlways("payout", "[payout] block %d (%s) was orphaned -- voiding %zu"
1736 " payment(s) totalling %s\n", 1738 " payment(s) totalling %s\n",
1737 it->blockHeight, it->blockHash.ToString().substr(0, 14).c_str(), 1739 it->blockHeight, it->blockHash.ToString().substr(0, 14).c_str(),
1738 it->amounts.size(), FormatMoney(total).c_str()); 1740 it->amounts.size(), FormatMoney(total).c_str());
@@ -1931,7 +1933,7 @@ static void RecordPayoutTxid(const PayingRecord& r, const std::string& txid)
1931// disagreeing. 1933// disagreeing.
1932static void ForfeitPayoutRecipient(const PayingRecord& r, const std::string& reason) 1934static void ForfeitPayoutRecipient(const PayingRecord& r, const std::string& reason)
1933{ 1935{
1934 LogPrint("payout", "[payout] writing off %s owed to %s for block %d: %s\n", 1936 LogPrintAlways("payout", "[payout] writing off %s owed to %s for block %d: %s\n",
1935 FormatMoney(r.amount).c_str(), r.address.c_str(), r.blockHeight, 1937 FormatMoney(r.amount).c_str(), r.address.c_str(), r.blockHeight,
1936 reason.c_str()); 1938 reason.c_str());
1937 VersionedBlob blob; 1939 VersionedBlob blob;
@@ -2036,7 +2038,7 @@ static void PayoutThreadFn(void*)
2036 // funding block can land at any point in that window. Upstream has 2038 // funding block can land at any point in that window. Upstream has
2037 // no equivalent -- it decides once, when the entry matures. 2039 // no equivalent -- it decides once, when the entry matures.
2038 if (!PayoutBlockStillOnChain(r.blockHash)) { 2040 if (!PayoutBlockStillOnChain(r.blockHash)) {
2039 LogPrint("payout", "[payout] block %d (%s) orphaned while queued" 2041 LogPrintAlways("payout", "[payout] block %d (%s) orphaned while queued"
2040 " -- dropping %s to %s\n", 2042 " -- dropping %s to %s\n",
2041 r.blockHeight, r.blockHash.ToString().substr(0, 14).c_str(), 2043 r.blockHeight, r.blockHash.ToString().substr(0, 14).c_str(),
2042 FormatMoney(r.amount).c_str(), r.address.c_str()); 2044 FormatMoney(r.amount).c_str(), r.address.c_str());
@@ -2080,7 +2082,7 @@ static void PayoutThreadFn(void*)
2080 const std::string reason = 2082 const std::string reason =
2081 strprintf("'%s' is not a valid address, so no transaction" 2083 strprintf("'%s' is not a valid address, so no transaction"
2082 " can pay it", r.address.c_str()); 2084 " can pay it", r.address.c_str());
2083 LogPrint("payout", "[payout] SKIPPED bad address '%s' --" 2085 LogPrintAlways("payout", "[payout] SKIPPED bad address '%s' --"
2084 " %s owed for block %d cannot be paid\n", 2086 " %s owed for block %d cannot be paid\n",
2085 r.address.c_str(), FormatMoney(r.amount).c_str(), 2087 r.address.c_str(), FormatMoney(r.amount).c_str(),
2086 r.blockHeight); 2088 r.blockHeight);
@@ -2205,7 +2207,7 @@ static void PayoutThreadFn(void*)
2205 // described by at least one of them at every instant. 2207 // described by at least one of them at every instant.
2206 RecordPayoutTxid(r, wtx.GetHash().GetHex()); 2208 RecordPayoutTxid(r, wtx.GetHash().GetHex());
2207 ForgetPayment(r); 2209 ForgetPayment(r);
2208 LogPrint("payout", "[payout] paid %s to %s (tx %s)\n", 2210 LogPrintAlways("payout", "[payout] paid %s to %s (tx %s)\n",
2209 FormatMoney(r.amount).c_str(), r.address.c_str(), 2211 FormatMoney(r.amount).c_str(), r.address.c_str(),
2210 wtx.GetHash().ToString().substr(0, 12).c_str()); 2212 wtx.GetHash().ToString().substr(0, 12).c_str());
2211 } else { 2213 } else {
@@ -2263,7 +2265,7 @@ static void PayoutThreadFn(void*)
2263 // going away must not turn the log into one line a minute 2265 // going away must not turn the log into one line a minute
2264 // forever, and must not go quiet either. 2266 // forever, and must not go quiet either.
2265 if (r.retries <= 5 || r.retries % 60 == 0) 2267 if (r.retries <= 5 || r.retries % 60 == 0)
2266 LogPrint("payout", "[payout] FAILED to pay %s to %s" 2268 LogPrintAlways("payout", "[payout] FAILED to pay %s to %s"
2267 " (%s spendable, wallet unlocked, block %d on" 2269 " (%s spendable, wallet unlocked, block %d on"
2268 " the main chain) -- attempt %d, retrying in" 2270 " the main chain) -- attempt %d, retrying in"
2269 " 60s; this debt stands until it is paid\n", 2271 " 60s; this debt stands until it is paid\n",
@@ -4947,13 +4949,19 @@ static void AcceptOneFn(void* arg)
4947 std::string host = relay.substr(0, colon); 4949 std::string host = relay.substr(0, colon);
4948 int port = atoi(relay.substr(colon + 1).c_str()); 4950 int port = atoi(relay.substr(colon + 1).c_str());
4949 4951
4950 LogPrint("pool", "[pool] accept thread started for relay %s\n", relay.c_str()); 4952 LogPrint("pool", "[pool] accept thread started for relay %s%s\n", relay.c_str(),
4953 fBtfRelayPinned ? " (/rvrelay pin)" : "");
4954
4955 // Registration health for this relay. A pin has no fallback, so a pin that
4956 // never registers means the pool is simply unreachable -- and that has to
4957 // be loud. The 2026-07-30 incident went unnoticed because this loop logged
4958 // failures at one flat line and success not at all, so "which relay is this
4959 // pool actually registered at" could not be answered from the log.
4960 int nConsecFail = 0;
4961 int64 nFirstFail = 0;
4962 bool fEverRegistered = false;
4951 4963
4952 while (!fShutdown && gPoolRunning) { 4964 while (!fShutdown && gPoolRunning) {
4953 // Advertise this relay as the pool's meeting node BEFORE registering,
4954 // so that miners which resolve our descriptor find a relay where the
4955 // pool (not the node's peer-accept) holds the registration.
4956 BtfSetActiveRelay(relay);
4957 // Returns as soon as the relay lists us -- registered, not yet paired. 4965 // Returns as soon as the relay lists us -- registered, not yet paired.
4958 btf::RvSocket rv = btf::RvServiceRegister(host.c_str(), (unsigned short)port, pk); 4966 btf::RvSocket rv = btf::RvServiceRegister(host.c_str(), (unsigned short)port, pk);
4959 4967
@@ -4962,12 +4970,36 @@ static void AcceptOneFn(void* arg)
4962 break; 4970 break;
4963 } 4971 }
4964 if (rv == btf::RV_INVALID) { 4972 if (rv == btf::RV_INVALID) {
4965 LogPrint("pool", "[pool] relay %s: RvServiceRegister failed" 4973 nConsecFail++;
4966 " -- backing off 30s before retry\n", relay.c_str()); 4974 if (nFirstFail == 0) nFirstFail = GetTime();
4975 LogPrint("pool", "[pool] relay %s: registration failed (attempt %d,"
4976 " failing for %llds) -- backing off 30s before retry\n",
4977 relay.c_str(), nConsecFail, (long long)(GetTime() - nFirstFail));
4978 if (fBtfRelayPinned && (nConsecFail == 3 || nConsecFail % 10 == 0))
4979 LogPrint("pool", "[pool] WARNING: pinned relay %s refused registration"
4980 " %d times running (%llds); /rvrelay leaves no fallback, so"
4981 " miners cannot reach this pool%s\n",
4982 relay.c_str(), nConsecFail, (long long)(GetTime() - nFirstFail),
4983 fEverRegistered ? "" : " -- it has never registered once");
4967 for (int i = 0; i < 30 && !fShutdown && gPoolRunning; i++) Sleep(1000); 4984 for (int i = 0; i < 30 && !fShutdown && gPoolRunning; i++) Sleep(1000);
4968 continue; 4985 continue;
4969 } 4986 }
4970 4987
4988 // Advertise THIS relay only now. Setting it before the call published a
4989 // meeting node we were not yet listed at, so a miner resolving the
4990 // descriptor inside that window burned its dial on a relay holding no
4991 // registration for us. net.cpp's peer-accept has always ordered it this
4992 // way round; the pool had not.
4993 BtfSetActiveRelay(relay);
4994 if (!fEverRegistered || nConsecFail > 0)
4995 LogPrint("pool", "[pool] registered at relay %s%s%s -- advertising it as"
4996 " the pool's meeting node\n", relay.c_str(),
4997 fBtfRelayPinned ? " (/rvrelay pin)" : "",
4998 nConsecFail > 0 ? ", recovered" : "");
4999 fEverRegistered = true;
5000 nConsecFail = 0;
5001 nFirstFail = 0;
5002
4971 // Block for a miner to actually arrive. RvServiceRegister used to do 5003 // Block for a miner to actually arrive. RvServiceRegister used to do
4972 // this itself and returned with the relay's 0x01 pairing byte already 5004 // this itself and returned with the relay's 0x01 pairing byte already
4973 // consumed; it no longer does. Without waiting here, BtfServiceWrap 5005 // consumed; it no longer does. Without waiting here, BtfServiceWrap
@@ -5022,9 +5054,21 @@ static void AcceptLoopFn(void*)
5022 LogPrint("pool", "[pool] .btf identity ready after %ds\n", waitSecs * 2); 5054 LogPrint("pool", "[pool] .btf identity ready after %ds\n", waitSecs * 2);
5023 5055
5024 std::set<std::string> spawned; // relays we've already started a thread for 5056 std::set<std::string> spawned; // relays we've already started a thread for
5057 std::set<std::string> skipped; // discovered relays the pin excluded, logged once each
5025 5058
5026 while (!fShutdown && gPoolRunning) { 5059 while (!fShutdown && gPoolRunning) {
5060 // BtfAllRelays() already honours the pin: with /rvrelay set it returns
5061 // vBtfMeetingRelays alone, so no thread is ever spawned for a
5062 // discovered relay. Name the ones it drops -- a pool registering at a
5063 // stranger's relay is exactly the thing that should not be silent.
5027 vector<string> relays = BtfAllRelays(); 5064 vector<string> relays = BtfAllRelays();
5065 if (fBtfRelayPinned) {
5066 for (const string& r : BtfDiscoveredRelays())
5067 if (std::find(relays.begin(), relays.end(), r) == relays.end() &&
5068 skipped.insert(r).second)
5069 LogPrint("pool", "[pool] not registering at discovered relay %s"
5070 " -- /rvrelay pins the relay list\n", r.c_str());
5071 }
5028 if (relays.empty()) { 5072 if (relays.empty()) {
5029 LogPrint("pool", "[pool] no relays available -- miners cannot connect yet\n"); 5073 LogPrint("pool", "[pool] no relays available -- miners cannot connect yet\n");
5030 } else { 5074 } else {
@@ -5040,8 +5084,9 @@ static void AcceptLoopFn(void*)
5040 relay.c_str()); 5084 relay.c_str());
5041 } else { 5085 } else {
5042 spawned.insert(relay); 5086 spawned.insert(relay);
5043 LogPrint("pool", "[pool] accept thread spawned for relay %s" 5087 LogPrint("pool", "[pool] accept thread spawned for relay %s%s"
5044 " (%zu total)\n", relay.c_str(), spawned.size()); 5088 " (%zu total)\n", relay.c_str(),
5089 fBtfRelayPinned ? " (/rvrelay pin)" : "", spawned.size());
5045 } 5090 }
5046 } 5091 }
5047 } 5092 }
@@ -5077,10 +5122,17 @@ void ThreadRPCServer(void*)
5077 // armed for its one wallet probe before it is allowed to send. 5122 // armed for its one wallet probe before it is allowed to send.
5078 ReconcilePayouts(); 5123 ReconcilePayouts();
5079 5124
5080 _beginthread(AcceptLoopFn, 0, NULL); 5125 // _beginthread cannot throw (it reports -1), but an unchecked failure
5081 _beginthread(LocalAcceptFn, 0, NULL); 5126 // leaves the pool running deaf: nobody accepts, announces, or pays, and
5082 _beginthread(ThreadBtfPoolAnnouncer, 0, NULL); 5127 // nothing in the log says why.
5083 _beginthread(PayoutThreadFn, 0, NULL); 5128 if (_beginthread(AcceptLoopFn, 0, NULL) == (uintptr_t)-1)
5129 LogPrint("pool", "[pool] FATAL: accept loop thread failed to spawn -- miners cannot connect\n");
5130 if (_beginthread(LocalAcceptFn, 0, NULL) == (uintptr_t)-1)
5131 LogPrint("pool", "[pool] local accept thread failed to spawn\n");
5132 if (_beginthread(ThreadBtfPoolAnnouncer, 0, NULL) == (uintptr_t)-1)
5133 LogPrint("pool", "[pool] announcer thread failed to spawn -- pool will not be advertised\n");
5134 if (_beginthread(PayoutThreadFn, 0, NULL) == (uintptr_t)-1)
5135 LogPrint("pool", "[pool] FATAL: payout thread failed to spawn -- no one gets paid\n");
5084 5136
5085 PoolEventLoop(); // blocks until gPoolRunning = false or fShutdown 5137 PoolEventLoop(); // blocks until gPoolRunning = false or fShutdown
5086 5138