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.cpp239
1 files changed, 125 insertions, 114 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 4603d2d..4741f09 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -492,28 +492,9 @@ bool GetMyExternalIP(unsigned int& ipRet)
492 492
493 493
494 494
495void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) 495// AbandonRequests() lived here, sweeping CNode::mapRequests for a callback a
496{ 496// closing dialog had registered. Nothing ever registered one and nothing ever
497 // If the dialog might get closed before the reply comes back, 497// called this, so it went with CRequestTracker.
498 // call this in the destructor so it doesn't get called after it's deleted.
499 CRITICAL_BLOCK(cs_vNodes)
500 {
501 foreach(CNode* pnode, vNodes)
502 {
503 CRITICAL_BLOCK(pnode->cs_mapRequests)
504 {
505 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
506 {
507 CRequestTracker& tracker = (*mi).second;
508 if (tracker.fn == fn && tracker.param1 == param1)
509 pnode->mapRequests.erase(mi++);
510 else
511 mi++;
512 }
513 }
514 }
515 }
516}
517 498
518 499
519 500
@@ -521,25 +502,10 @@ void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
521 502
522 503
523 504
524// 505// The broadcast/subscribe channel system (AnySubscribed, CNode::IsSubscribed,
525// Subscription methods for the broadcast and subscription system. 506// Subscribe, CancelSubscribe) stood here. Its channels were MSG_TABLE and
526// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. 507// MSG_PRODUCT, there was never an inbound handler for "subscribe",
527// 508// "sub-cancel", "publish" or "pub-cancel", and the objects it carried are gone.
528// The subscription system uses a meet-in-the-middle strategy.
529// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
530// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
531//
532
533bool AnySubscribed(unsigned int nChannel)
534{
535 if (pnodeLocalHost->IsSubscribed(nChannel))
536 return true;
537 CRITICAL_BLOCK(cs_vNodes)
538 foreach(CNode* pnode, vNodes)
539 if (pnode->IsSubscribed(nChannel))
540 return true;
541 return false;
542}
543 509
544void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) 510void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
545{ 511{
@@ -552,55 +518,6 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
552 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); 518 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
553} 519}
554 520
555bool CNode::IsSubscribed(unsigned int nChannel)
556{
557 if (nChannel >= vfSubscribe.size())
558 return false;
559 return vfSubscribe[nChannel];
560}
561
562void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
563{
564 if (nChannel >= vfSubscribe.size())
565 return;
566
567 if (!AnySubscribed(nChannel))
568 {
569 // Relay subscribe
570 CRITICAL_BLOCK(cs_vNodes)
571 foreach(CNode* pnode, vNodes)
572 if (pnode != this)
573 pnode->PushMessage("subscribe", nChannel, nHops);
574 }
575
576 vfSubscribe[nChannel] = true;
577}
578
579void CNode::CancelSubscribe(unsigned int nChannel)
580{
581 if (nChannel >= vfSubscribe.size())
582 return;
583
584 // Prevent from relaying cancel if wasn't subscribed
585 if (!vfSubscribe[nChannel])
586 return;
587 vfSubscribe[nChannel] = false;
588
589 if (!AnySubscribed(nChannel))
590 {
591 // Relay subscription cancel
592 CRITICAL_BLOCK(cs_vNodes)
593 foreach(CNode* pnode, vNodes)
594 if (pnode != this)
595 pnode->PushMessage("sub-cancel", nChannel);
596
597 // Clear memory, no longer subscribed
598 if (nChannel == MSG_PRODUCT)
599 CRITICAL_BLOCK(cs_mapProducts)
600 mapProducts.clear();
601 }
602}
603
604 521
605 522
606 523
@@ -1176,6 +1093,18 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting
1176void ThreadBtfAccept(void* parg) 1093void ThreadBtfAccept(void* parg)
1177{ 1094{
1178 printf("ThreadBtfAccept started\n"); 1095 printf("ThreadBtfAccept started\n");
1096 // In operator mode the pool server registers this same node identity as a
1097 // stratum service at the rendezvous relays, and a relay only holds ONE
1098 // service registration per pubkey -- peer-accept and pool-accept would
1099 // kick each other off forever, breaking both. The pool's registration is
1100 // the one that must be stable (that's what miners resolve and dial), so
1101 // the node skips inbound rendezvous here and relies on outbound .btf
1102 // connections for block sync.
1103 if (nMineMode == MINE_OPERATOR)
1104 {
1105 printf("ThreadBtfAccept: operator mode -- skipping peer rendezvous registration\n");
1106 return;
1107 }
1179 unsigned char pk[32]; 1108 unsigned char pk[32];
1180 unsigned char sk[32]; 1109 unsigned char sk[32];
1181 while (!BtfGetIdentity(pk, sk)) 1110 while (!BtfGetIdentity(pk, sk))
@@ -1325,17 +1254,6 @@ void CNode::Disconnect()
1325 BtfCloseSocket(hSocket); 1254 BtfCloseSocket(hSocket);
1326 hSocket = INVALID_SOCKET; 1255 hSocket = INVALID_SOCKET;
1327 1256
1328 // All of a nodes broadcasts and subscriptions are automatically torn down
1329 // when it goes down, so a node has to stay up to keep its broadcast going.
1330
1331 CRITICAL_BLOCK(cs_mapProducts)
1332 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end();)
1333 AdvertRemoveSource(this, MSG_PRODUCT, 0, (*(mi++)).second);
1334
1335 // Cancel subscriptions
1336 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
1337 if (vfSubscribe[nChannel])
1338 CancelSubscribe(nChannel);
1339} 1257}
1340 1258
1341 1259
@@ -1460,7 +1378,6 @@ void ThreadSocketHandler2(void* parg)
1460 bool fDelete = false; 1378 bool fDelete = false;
1461 TRY_CRITICAL_BLOCK(pnode->cs_vSend) 1379 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1462 TRY_CRITICAL_BLOCK(pnode->cs_vRecv) 1380 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1463 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
1464 TRY_CRITICAL_BLOCK(pnode->cs_inventory) 1381 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
1465 fDelete = true; 1382 fDelete = true;
1466 if (fDelete) 1383 if (fDelete)
@@ -1568,6 +1485,27 @@ void ThreadSocketHandler2(void* parg)
1568 printf("dropping node %s: its socket is no longer valid\n", 1485 printf("dropping node %s: its socket is no longer valid\n",
1569 pnode->addr.ToString().c_str()); 1486 pnode->addr.ToString().c_str());
1570 pnode->fDisconnect = true; 1487 pnode->fDisconnect = true;
1488
1489 // Stop referring to it, or it goes into the next poll
1490 // set and fails it again.
1491 //
1492 // Marking fDisconnect is not enough: a node is only
1493 // removed from vNodes once it has drained or once
1494 // DISCONNECT_DRAIN_SECS has passed, so one dead
1495 // descriptor kept failing the wait for a full minute --
1496 // and a failed wait skips the service loop below
1497 // entirely, which means NO peer is read on that pass.
1498 // Measured on a wedged pool under the old select()
1499 // implementation: 1,027 consecutive passes over 61
1500 // seconds, one bad socket, the entire node deaf. poll()
1501 // reports a bad descriptor as POLLNVAL on that entry
1502 // rather than failing the whole call, so this path is
1503 // now the backstop rather than the common case.
1504 //
1505 // Not closed, only forgotten. getsockopt just told us
1506 // this descriptor is not ours any more; closing it now
1507 // is how an unrelated socket gets closed instead.
1508 pnode->hSocket = INVALID_SOCKET;
1571 } 1509 }
1572 } 1510 }
1573 } 1511 }
@@ -1841,6 +1779,13 @@ void ThreadMessageHandler(void* parg)
1841 } 1779 }
1842} 1780}
1843 1781
1782// When any peer last told us a height. A wedged node -- one that still has
1783// peers but has stopped hearing them -- is exactly a node where this stops
1784// advancing, and that is the one thing the height comparison itself cannot
1785// see: there is no height to compare.
1786static int64 nLastPeerHeightSeen = 0;
1787static int64 nPeerHeightFirstAsked = 0;
1788
1844int GetPeerMedianHeight() 1789int GetPeerMedianHeight()
1845{ 1790{
1846 vector<int> vHeights; 1791 vector<int> vHeights;
@@ -1852,10 +1797,26 @@ int GetPeerMedianHeight()
1852 if (vHeights.empty()) 1797 if (vHeights.empty())
1853 return -1; 1798 return -1;
1854 1799
1800 nLastPeerHeightSeen = GetTime();
1855 sort(vHeights.begin(), vHeights.end()); 1801 sort(vHeights.begin(), vHeights.end());
1856 return vHeights[vHeights.size() / 2]; 1802 return vHeights[vHeights.size() / 2];
1857} 1803}
1858 1804
1805// Seconds since any peer last reported a height.
1806//
1807// Before ever hearing one, measure from the first time somebody asked rather
1808// than from the epoch -- otherwise a node refuses jobs the instant it starts,
1809// before it has had a chance to complete a single handshake.
1810int64 GetPeerHeightAgeSecs()
1811{
1812 int64 nNow = GetTime();
1813 if (nPeerHeightFirstAsked == 0)
1814 nPeerHeightFirstAsked = nNow;
1815 if (nLastPeerHeightSeen == 0)
1816 return nNow - nPeerHeightFirstAsked;
1817 return nNow - nLastPeerHeightSeen;
1818}
1819
1859 1820
1860// Say out loud when we are behind the network. 1821// Say out loud when we are behind the network.
1861// 1822//
@@ -1992,7 +1953,21 @@ void ThreadBitcoinMiner(void* parg)
1992// Start the miners. Returns how many actually got off the ground. 1953// Start the miners. Returns how many actually got off the ground.
1993int StartMinerThreads() 1954int StartMinerThreads()
1994{ 1955{
1995 int nThreads = MinerThreadCount(); 1956 // MinerThreadCount() sizes the SOLO miner, where each thread hashes a
1957 // template of its own and more threads is simply more hashrate.
1958 //
1959 // Participant mode is not that shape. Every thread that enters
1960 // BitcoinMiner() takes the MINE_PARTICIPANT branch, and that branch is a
1961 // whole miner: its own Stratum session to the pool, its own payout address
1962 // from the rotation, and its own pool of /hashthreads worker threads. So
1963 // the two counts multiply instead of dividing, and the machine ends up
1964 // running MinerThreadCount() x nHashThreads hashing threads plus one pool
1965 // connection each. On a 12-core host with /hashthreads=2 that is 11
1966 // sessions and 22 hash threads -- roughly 2x the cores, which is not more
1967 // work done, only more contention -- and with /hashthreads unset it is 11
1968 // sessions of 11 workers. One session is the entirety of participant mode;
1969 // /hashthreads is what sizes it, and it can then mean what it says.
1970 int nThreads = (nMineMode == MINE_PARTICIPANT) ? 1 : MinerThreadCount();
1996 int nStarted = 0; 1971 int nStarted = 0;
1997 for (int i = 0; i < nThreads; i++) 1972 for (int i = 0; i < nThreads; i++)
1998 { 1973 {
@@ -2004,9 +1979,24 @@ int StartMinerThreads()
2004 // The dataset is one allocation shared by all of them; only the 2 MB 1979 // The dataset is one allocation shared by all of them; only the 2 MB
2005 // scratchpads multiply. Printed because "why is it using 2 GB" is the first 1980 // scratchpads multiply. Printed because "why is it using 2 GB" is the first
2006 // question anyone asks. 1981 // question anyone asks.
2007 printf("Mining with %d thread(s) of %u core(s) -- about %d MB " 1982 //
2008 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n", 1983 // Participant mode reports the workers that session will run, not the one
2009 nStarted, std::thread::hardware_concurrency(), 2080 + 2 * nStarted); 1984 // thread that runs it: the hash thread count is the number an operator
1985 // watches, and it is the number that was wrong here. It is otherwise only
1986 // logged under -debug, which is how 11 sessions ran unnoticed.
1987 if (nMineMode == MINE_PARTICIPANT)
1988 {
1989 int nWorkers = ParticipantHashThreadCount();
1990 printf("Mining for the pool with %d hash thread(s) of %u core(s) -- about %d MB "
1991 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1992 nWorkers, AvailableCoreCount(), 2080 + 2 * nWorkers);
1993 }
1994 else
1995 {
1996 printf("Mining with %d thread(s) of %u core(s) -- about %d MB "
1997 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1998 nStarted, AvailableCoreCount(), 2080 + 2 * nStarted);
1999 }
2010 return nStarted; 2000 return nStarted;
2011} 2001}
2012 2002
@@ -2077,20 +2067,41 @@ bool StartNode(string& strError)
2077 // IP address, and port for the socket that is being bound 2067 // IP address, and port for the socket that is being bound
2078 int nRetryLimit = 15; 2068 int nRetryLimit = 15;
2079 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr(); 2069 struct sockaddr_in sockaddr = addrLocalHost.GetSockAddr();
2080 // Keep addrLocalHost as this node's advertised address, but listen on all 2070 // Managed Tor forwards hidden-service traffic to 127.0.0.1:<port>, which a
2081 // local interfaces. Managed Tor forwards hidden-service traffic to 2071 // LAN-only bind cannot receive -- so a node that advertises an onion
2082 // 127.0.0.1:<port>, and binding only to the LAN address made that onion 2072 // endpoint must listen on all local interfaces. Upstream 1.2.19 bound
2083 // endpoint unreachable even though the P2P listener was running. 2073 // INADDR_ANY unconditionally, which also widened the P2P listener of every
2084 sockaddr.sin_addr.s_addr = INADDR_ANY; 2074 // non-Tor node to VPN tunnels, docker bridges and secondary NICs. Keep the
2075 // wildcard bind conditional on actually having an onion endpoint.
2076 if (!BtfLocalOnionEndpoint().empty())
2077 sockaddr.sin_addr.s_addr = INADDR_ANY;
2085 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR) 2078 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
2086 { 2079 {
2087 int nErr = WSAGetLastError(); 2080 int nErr = WSAGetLastError();
2088 if (nErr == WSAEADDRINUSE) 2081 if (nErr == WSAEADDRINUSE)
2089 strError = strprintf("Error: Unable to bind to port %s on this computer. The program is probably already running.", addrLocalHost.ToString().c_str()); 2082 {
2083 // Another local instance holds the default port. Fall back to an
2084 // ephemeral port: inbound direct-IP peering is optional, and .btf
2085 // rendezvous connectivity is unaffected by the local listen port.
2086 sockaddr.sin_port = htons(0);
2087 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
2088 {
2089 strError = strprintf("Error: Unable to bind any port on this computer (bind returned error %d)", WSAGetLastError());
2090 printf("%s\n", strError.c_str());
2091 return false;
2092 }
2093 struct sockaddr_in bound;
2094 socklen_t nBoundLen = sizeof(bound);
2095 if (getsockname(hListenSocket, (struct sockaddr*)&bound, &nBoundLen) == 0)
2096 addrLocalHost.port = bound.sin_port;
2097 printf("default port in use by another instance; bound to ephemeral %s instead\n", addrLocalHost.ToString().c_str());
2098 }
2090 else 2099 else
2100 {
2091 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr); 2101 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr);
2092 printf("%s\n", strError.c_str()); 2102 printf("%s\n", strError.c_str());
2093 return false; 2103 return false;
2104 }
2094 } 2105 }
2095 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str()); 2106 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str());
2096 2107