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:
Diffstat (limited to 'src/net.cpp')
-rw-r--r--src/net.cpp244
1 files changed, 128 insertions, 116 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 287a4bd..0576402 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -521,28 +521,9 @@ bool GetMyExternalIP(unsigned int& ipRet)
521 521
522 522
523 523
524void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) 524// AbandonRequests() lived here, sweeping CNode::mapRequests for a callback a
525{ 525// closing dialog had registered. Nothing ever registered one and nothing ever
526 // If the dialog might get closed before the reply comes back, 526// called this, so it went with CRequestTracker.
527 // call this in the destructor so it doesn't get called after it's deleted.
528 CRITICAL_BLOCK(cs_vNodes)
529 {
530 foreach(CNode* pnode, vNodes)
531 {
532 CRITICAL_BLOCK(pnode->cs_mapRequests)
533 {
534 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
535 {
536 CRequestTracker& tracker = (*mi).second;
537 if (tracker.fn == fn && tracker.param1 == param1)
538 pnode->mapRequests.erase(mi++);
539 else
540 mi++;
541 }
542 }
543 }
544 }
545}
546 527
547 528
548 529
@@ -550,25 +531,10 @@ void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
550 531
551 532
552 533
553// 534// The broadcast/subscribe channel system (AnySubscribed, CNode::IsSubscribed,
554// Subscription methods for the broadcast and subscription system. 535// Subscribe, CancelSubscribe) stood here. Its channels were MSG_TABLE and
555// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. 536// MSG_PRODUCT, there was never an inbound handler for "subscribe",
556// 537// "sub-cancel", "publish" or "pub-cancel", and the objects it carried are gone.
557// The subscription system uses a meet-in-the-middle strategy.
558// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
559// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
560//
561
562bool AnySubscribed(unsigned int nChannel)
563{
564 if (pnodeLocalHost->IsSubscribed(nChannel))
565 return true;
566 CRITICAL_BLOCK(cs_vNodes)
567 foreach(CNode* pnode, vNodes)
568 if (pnode->IsSubscribed(nChannel))
569 return true;
570 return false;
571}
572 538
573void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) 539void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
574{ 540{
@@ -581,55 +547,6 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
581 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); 547 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
582} 548}
583 549
584bool CNode::IsSubscribed(unsigned int nChannel)
585{
586 if (nChannel >= vfSubscribe.size())
587 return false;
588 return vfSubscribe[nChannel];
589}
590
591void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
592{
593 if (nChannel >= vfSubscribe.size())
594 return;
595
596 if (!AnySubscribed(nChannel))
597 {
598 // Relay subscribe
599 CRITICAL_BLOCK(cs_vNodes)
600 foreach(CNode* pnode, vNodes)
601 if (pnode != this)
602 pnode->PushMessage("subscribe", nChannel, nHops);
603 }
604
605 vfSubscribe[nChannel] = true;
606}
607
608void CNode::CancelSubscribe(unsigned int nChannel)
609{
610 if (nChannel >= vfSubscribe.size())
611 return;
612
613 // Prevent from relaying cancel if wasn't subscribed
614 if (!vfSubscribe[nChannel])
615 return;
616 vfSubscribe[nChannel] = false;
617
618 if (!AnySubscribed(nChannel))
619 {
620 // Relay subscription cancel
621 CRITICAL_BLOCK(cs_vNodes)
622 foreach(CNode* pnode, vNodes)
623 if (pnode != this)
624 pnode->PushMessage("sub-cancel", nChannel);
625
626 // Clear memory, no longer subscribed
627 if (nChannel == MSG_PRODUCT)
628 CRITICAL_BLOCK(cs_mapProducts)
629 mapProducts.clear();
630 }
631}
632
633 550
634 551
635 552
@@ -1205,6 +1122,18 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting
1205void ThreadBtfAccept(void* parg) 1122void ThreadBtfAccept(void* parg)
1206{ 1123{
1207 printf("ThreadBtfAccept started\n"); 1124 printf("ThreadBtfAccept started\n");
1125 // In operator mode the pool server registers this same node identity as a
1126 // stratum service at the rendezvous relays, and a relay only holds ONE
1127 // service registration per pubkey -- peer-accept and pool-accept would
1128 // kick each other off forever, breaking both. The pool's registration is
1129 // the one that must be stable (that's what miners resolve and dial), so
1130 // the node skips inbound rendezvous here and relies on outbound .btf
1131 // connections for block sync.
1132 if (nMineMode == MINE_OPERATOR)
1133 {
1134 printf("ThreadBtfAccept: operator mode -- skipping peer rendezvous registration\n");
1135 return;
1136 }
1208 unsigned char pk[32]; 1137 unsigned char pk[32];
1209 unsigned char sk[32]; 1138 unsigned char sk[32];
1210 while (!BtfGetIdentity(pk, sk)) 1139 while (!BtfGetIdentity(pk, sk))
@@ -1354,17 +1283,6 @@ void CNode::Disconnect()
1354 BtfCloseSocket(hSocket); 1283 BtfCloseSocket(hSocket);
1355 hSocket = INVALID_SOCKET; 1284 hSocket = INVALID_SOCKET;
1356 1285
1357 // All of a nodes broadcasts and subscriptions are automatically torn down
1358 // when it goes down, so a node has to stay up to keep its broadcast going.
1359
1360 CRITICAL_BLOCK(cs_mapProducts)
1361 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end();)
1362 AdvertRemoveSource(this, MSG_PRODUCT, 0, (*(mi++)).second);
1363
1364 // Cancel subscriptions
1365 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
1366 if (vfSubscribe[nChannel])
1367 CancelSubscribe(nChannel);
1368} 1286}
1369 1287
1370 1288
@@ -1489,7 +1407,6 @@ void ThreadSocketHandler2(void* parg)
1489 bool fDelete = false; 1407 bool fDelete = false;
1490 TRY_CRITICAL_BLOCK(pnode->cs_vSend) 1408 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1491 TRY_CRITICAL_BLOCK(pnode->cs_vRecv) 1409 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1492 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
1493 TRY_CRITICAL_BLOCK(pnode->cs_inventory) 1410 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
1494 fDelete = true; 1411 fDelete = true;
1495 if (fDelete) 1412 if (fDelete)
@@ -1597,6 +1514,27 @@ void ThreadSocketHandler2(void* parg)
1597 printf("dropping node %s: its socket is no longer valid\n", 1514 printf("dropping node %s: its socket is no longer valid\n",
1598 pnode->addr.ToString().c_str()); 1515 pnode->addr.ToString().c_str());
1599 pnode->fDisconnect = true; 1516 pnode->fDisconnect = true;
1517
1518 // Stop referring to it, or it goes into the next poll
1519 // set and fails it again.
1520 //
1521 // Marking fDisconnect is not enough: a node is only
1522 // removed from vNodes once it has drained or once
1523 // DISCONNECT_DRAIN_SECS has passed, so one dead
1524 // descriptor kept failing the wait for a full minute --
1525 // and a failed wait skips the service loop below
1526 // entirely, which means NO peer is read on that pass.
1527 // Measured on a wedged pool under the old select()
1528 // implementation: 1,027 consecutive passes over 61
1529 // seconds, one bad socket, the entire node deaf. poll()
1530 // reports a bad descriptor as POLLNVAL on that entry
1531 // rather than failing the whole call, so this path is
1532 // now the backstop rather than the common case.
1533 //
1534 // Not closed, only forgotten. getsockopt just told us
1535 // this descriptor is not ours any more; closing it now
1536 // is how an unrelated socket gets closed instead.
1537 pnode->hSocket = INVALID_SOCKET;
1600 } 1538 }
1601 } 1539 }
1602 } 1540 }
@@ -1870,6 +1808,13 @@ void ThreadMessageHandler(void* parg)
1870 } 1808 }
1871} 1809}
1872 1810
1811// When any peer last told us a height. A wedged node -- one that still has
1812// peers but has stopped hearing them -- is exactly a node where this stops
1813// advancing, and that is the one thing the height comparison itself cannot
1814// see: there is no height to compare.
1815static int64 nLastPeerHeightSeen = 0;
1816static int64 nPeerHeightFirstAsked = 0;
1817
1873int GetPeerMedianHeight() 1818int GetPeerMedianHeight()
1874{ 1819{
1875 vector<int> vHeights; 1820 vector<int> vHeights;
@@ -1881,10 +1826,26 @@ int GetPeerMedianHeight()
1881 if (vHeights.empty()) 1826 if (vHeights.empty())
1882 return -1; 1827 return -1;
1883 1828
1829 nLastPeerHeightSeen = GetTime();
1884 sort(vHeights.begin(), vHeights.end()); 1830 sort(vHeights.begin(), vHeights.end());
1885 return vHeights[vHeights.size() / 2]; 1831 return vHeights[vHeights.size() / 2];
1886} 1832}
1887 1833
1834// Seconds since any peer last reported a height.
1835//
1836// Before ever hearing one, measure from the first time somebody asked rather
1837// than from the epoch -- otherwise a node refuses jobs the instant it starts,
1838// before it has had a chance to complete a single handshake.
1839int64 GetPeerHeightAgeSecs()
1840{
1841 int64 nNow = GetTime();
1842 if (nPeerHeightFirstAsked == 0)
1843 nPeerHeightFirstAsked = nNow;
1844 if (nLastPeerHeightSeen == 0)
1845 return nNow - nPeerHeightFirstAsked;
1846 return nNow - nLastPeerHeightSeen;
1847}
1848
1888 1849
1889// Say out loud when we are behind the network. 1850// Say out loud when we are behind the network.
1890// 1851//
@@ -2021,7 +1982,21 @@ void ThreadBitcoinMiner(void* parg)
2021// Start the miners. Returns how many actually got off the ground. 1982// Start the miners. Returns how many actually got off the ground.
2022int StartMinerThreads() 1983int StartMinerThreads()
2023{ 1984{
2024 int nThreads = MinerThreadCount(); 1985 // MinerThreadCount() sizes the SOLO miner, where each thread hashes a
1986 // template of its own and more threads is simply more hashrate.
1987 //
1988 // Participant mode is not that shape. Every thread that enters
1989 // BitcoinMiner() takes the MINE_PARTICIPANT branch, and that branch is a
1990 // whole miner: its own Stratum session to the pool, its own payout address
1991 // from the rotation, and its own pool of /hashthreads worker threads. So
1992 // the two counts multiply instead of dividing, and the machine ends up
1993 // running MinerThreadCount() x nHashThreads hashing threads plus one pool
1994 // connection each. On a 12-core host with /hashthreads=2 that is 11
1995 // sessions and 22 hash threads -- roughly 2x the cores, which is not more
1996 // work done, only more contention -- and with /hashthreads unset it is 11
1997 // sessions of 11 workers. One session is the entirety of participant mode;
1998 // /hashthreads is what sizes it, and it can then mean what it says.
1999 int nThreads = (nMineMode == MINE_PARTICIPANT) ? 1 : MinerThreadCount();
2025 int nStarted = 0; 2000 int nStarted = 0;
2026 for (int i = 0; i < nThreads; i++) 2001 for (int i = 0; i < nThreads; i++)
2027 { 2002 {
@@ -2033,9 +2008,24 @@ int StartMinerThreads()
2033 // The dataset is one allocation shared by all of them; only the 2 MB 2008 // The dataset is one allocation shared by all of them; only the 2 MB
2034 // scratchpads multiply. Printed because "why is it using 2 GB" is the first 2009 // scratchpads multiply. Printed because "why is it using 2 GB" is the first
2035 // question anyone asks. 2010 // question anyone asks.
2036 printf("Mining with %d thread(s) of %u core(s) -- about %d MB " 2011 //
2037 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n", 2012 // Participant mode reports the workers that session will run, not the one
2038 nStarted, std::thread::hardware_concurrency(), 2080 + 2 * nStarted); 2013 // thread that runs it: the hash thread count is the number an operator
2014 // watches, and it is the number that was wrong here. It is otherwise only
2015 // logged under -debug, which is how 11 sessions ran unnoticed.
2016 if (nMineMode == MINE_PARTICIPANT)
2017 {
2018 int nWorkers = ParticipantHashThreadCount();
2019 printf("Mining for the pool with %d hash thread(s) of %u core(s) -- about %d MB "
2020 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
2021 nWorkers, AvailableCoreCount(), 2080 + 2 * nWorkers);
2022 }
2023 else
2024 {
2025 printf("Mining with %d thread(s) of %u core(s) -- about %d MB "
2026 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
2027 nStarted, AvailableCoreCount(), 2080 + 2 * nStarted);
2028 }
2039 return nStarted; 2029 return nStarted;
2040} 2030}
2041 2031
@@ -2106,20 +2096,41 @@ bool StartNode(string& strError)
2106 // IP address, and port for the socket that is being bound 2096 // IP address, and port for the socket that is being bound
2107 int nRetryLimit = 15; 2097 int nRetryLimit = 15;
2108 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr(); 2098 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr();
2109 // Keep addrLocalHost as this node's advertised address, but listen on all 2099 // Managed Tor forwards hidden-service traffic to 127.0.0.1:<port>, which a
2110 // local interfaces. Managed Tor forwards hidden-service traffic to 2100 // LAN-only bind cannot receive -- so a node that advertises an onion
2111 // 127.0.0.1:<port>, and binding only to the LAN address made that onion 2101 // endpoint must listen on all local interfaces. Upstream 1.2.19 bound
2112 // endpoint unreachable even though the P2P listener was running. 2102 // INADDR_ANY unconditionally, which also widened the P2P listener of every
2113 sockaddr.sin_addr.s_addr = INADDR_ANY; 2103 // non-Tor node to VPN tunnels, docker bridges and secondary NICs. Keep the
2104 // wildcard bind conditional on actually having an onion endpoint.
2105 if (!BtfLocalOnionEndpoint().empty())
2106 sockaddr.sin_addr.s_addr = INADDR_ANY;
2114 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) 2107 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
2115 { 2108 {
2116 int nErr = WSAGetLastError(); 2109 int nErr = WSAGetLastError();
2117 if (nErr == WSAEADDRINUSE) 2110 if (nErr == WSAEADDRINUSE)
2118 strError = strprintf("Error: Unable to bind to port %s on this computer. The program is probably already running.", addrLocalHost.ToString().c_str()); 2111 {
2112 // Another local instance holds the default port. Fall back to an
2113 // ephemeral port: inbound direct-IP peering is optional, and .btf
2114 // rendezvous connectivity is unaffected by the local listen port.
2115 sockaddr.sin_port = htons(0);
2116 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
2117 {
2118 strError = strprintf("Error: Unable to bind any port on this computer (bind returned error %d)", WSAGetLastError());
2119 printf("%s\n", strError.c_str());
2120 return false;
2121 }
2122 struct sockaddr_in bound;
2123 socklen_t nBoundLen = sizeof(bound);
2124 if (getsockname(hListenSocket, (struct sockaddr*)&bound, &nBoundLen) == 0)
2125 addrLocalHost.port = bound.sin_port;
2126 printf("default port in use by another instance; bound to ephemeral %s instead\n", addrLocalHost.ToString().c_str());
2127 }
2119 else 2128 else
2129 {
2120 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr); 2130 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr);
2121 printf("%s\n", strError.c_str()); 2131 printf("%s\n", strError.c_str());
2122 return false; 2132 return false;
2133 }
2123 } 2134 }
2124 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str()); 2135 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str());
2125 2136
@@ -2137,7 +2148,7 @@ bool StartNode(string& strError)
2137 if (addrIncoming.ip) 2148 if (addrIncoming.ip)
2138 addrLocalHost.ip = addrIncoming.ip; 2149 addrLocalHost.ip = addrIncoming.ip;
2139 2150
2140 _beginthread([](void*) { 2151 if (_beginthread([](void*) {
2141 unsigned int ip = addrLocalHost.ip; 2152 unsigned int ip = addrLocalHost.ip;
2142 if (GetMyExternalIP(ip)) { 2153 if (GetMyExternalIP(ip)) {
2143 addrLocalHost.ip = ip; 2154 addrLocalHost.ip = ip;
@@ -2145,7 +2156,8 @@ bool StartNode(string& strError)
2145 CWalletDB().WriteSetting("addrIncoming", addrIncoming); 2156 CWalletDB().WriteSetting("addrIncoming", addrIncoming);
2146 printf("External IP updated: %s\n", addrLocalHost.ToStringIP().c_str()); 2157 printf("External IP updated: %s\n", addrLocalHost.ToStringIP().c_str());
2147 } 2158 }
2148 }, 0, NULL); 2159 }, 0, NULL) == (uintptr_t)-1)
2160 printf("Error: _beginthread(GetMyExternalIP) failed\n");
2149 2161
2150 // Peers that answered last time, dialled straight away. The relays are the 2162 // Peers that answered last time, dialled straight away. The relays are the
2151 // only way to find anyone otherwise, and reaching them plus walking their 2163 // only way to find anyone otherwise, and reaching them plus walking their