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.cpp226
1 files changed, 117 insertions, 109 deletions
diff --git a/src/net.cpp b/src/net.cpp
index c24547e..bb39122 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -464,28 +464,9 @@ bool GetMyExternalIP(unsigned int& ipRet)
464 464
465 465
466 466
467void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) 467// AbandonRequests() lived here, sweeping CNode::mapRequests for a callback a
468{ 468// closing dialog had registered. Nothing ever registered one and nothing ever
469 // If the dialog might get closed before the reply comes back, 469// called this, so it went with CRequestTracker.
470 // call this in the destructor so it doesn't get called after it's deleted.
471 CRITICAL_BLOCK(cs_vNodes)
472 {
473 foreach(CNode* pnode, vNodes)
474 {
475 CRITICAL_BLOCK(pnode->cs_mapRequests)
476 {
477 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
478 {
479 CRequestTracker& tracker = (*mi).second;
480 if (tracker.fn == fn && tracker.param1 == param1)
481 pnode->mapRequests.erase(mi++);
482 else
483 mi++;
484 }
485 }
486 }
487 }
488}
489 470
490 471
491 472
@@ -493,25 +474,10 @@ void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
493 474
494 475
495 476
496// 477// The broadcast/subscribe channel system (AnySubscribed, CNode::IsSubscribed,
497// Subscription methods for the broadcast and subscription system. 478// Subscribe, CancelSubscribe) stood here. Its channels were MSG_TABLE and
498// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. 479// MSG_PRODUCT, there was never an inbound handler for "subscribe",
499// 480// "sub-cancel", "publish" or "pub-cancel", and the objects it carried are gone.
500// The subscription system uses a meet-in-the-middle strategy.
501// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
502// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
503//
504
505bool AnySubscribed(unsigned int nChannel)
506{
507 if (pnodeLocalHost->IsSubscribed(nChannel))
508 return true;
509 CRITICAL_BLOCK(cs_vNodes)
510 foreach(CNode* pnode, vNodes)
511 if (pnode->IsSubscribed(nChannel))
512 return true;
513 return false;
514}
515 481
516void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) 482void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
517{ 483{
@@ -524,55 +490,6 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
524 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); 490 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
525} 491}
526 492
527bool CNode::IsSubscribed(unsigned int nChannel)
528{
529 if (nChannel >= vfSubscribe.size())
530 return false;
531 return vfSubscribe[nChannel];
532}
533
534void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
535{
536 if (nChannel >= vfSubscribe.size())
537 return;
538
539 if (!AnySubscribed(nChannel))
540 {
541 // Relay subscribe
542 CRITICAL_BLOCK(cs_vNodes)
543 foreach(CNode* pnode, vNodes)
544 if (pnode != this)
545 pnode->PushMessage("subscribe", nChannel, nHops);
546 }
547
548 vfSubscribe[nChannel] = true;
549}
550
551void CNode::CancelSubscribe(unsigned int nChannel)
552{
553 if (nChannel >= vfSubscribe.size())
554 return;
555
556 // Prevent from relaying cancel if wasn't subscribed
557 if (!vfSubscribe[nChannel])
558 return;
559 vfSubscribe[nChannel] = false;
560
561 if (!AnySubscribed(nChannel))
562 {
563 // Relay subscription cancel
564 CRITICAL_BLOCK(cs_vNodes)
565 foreach(CNode* pnode, vNodes)
566 if (pnode != this)
567 pnode->PushMessage("sub-cancel", nChannel);
568
569 // Clear memory, no longer subscribed
570 if (nChannel == MSG_PRODUCT)
571 CRITICAL_BLOCK(cs_mapProducts)
572 mapProducts.clear();
573 }
574}
575
576 493
577 494
578 495
@@ -1074,6 +991,18 @@ CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting
1074void ThreadBtfAccept(void* parg) 991void ThreadBtfAccept(void* parg)
1075{ 992{
1076 printf("ThreadBtfAccept started\n"); 993 printf("ThreadBtfAccept started\n");
994 // In operator mode the pool server registers this same node identity as a
995 // stratum service at the rendezvous relays, and a relay only holds ONE
996 // service registration per pubkey -- peer-accept and pool-accept would
997 // kick each other off forever, breaking both. The pool's registration is
998 // the one that must be stable (that's what miners resolve and dial), so
999 // the node skips inbound rendezvous here and relies on outbound .btf
1000 // connections for block sync.
1001 if (nMineMode == MINE_OPERATOR)
1002 {
1003 printf("ThreadBtfAccept: operator mode -- skipping peer rendezvous registration\n");
1004 return;
1005 }
1077 unsigned char pk[32]; 1006 unsigned char pk[32];
1078 unsigned char sk[32]; 1007 unsigned char sk[32];
1079 while (!BtfGetIdentity(pk, sk)) 1008 while (!BtfGetIdentity(pk, sk))
@@ -1223,17 +1152,6 @@ void CNode::Disconnect()
1223 BtfCloseSocket(hSocket); 1152 BtfCloseSocket(hSocket);
1224 hSocket = INVALID_SOCKET; 1153 hSocket = INVALID_SOCKET;
1225 1154
1226 // All of a nodes broadcasts and subscriptions are automatically torn down
1227 // when it goes down, so a node has to stay up to keep its broadcast going.
1228
1229 CRITICAL_BLOCK(cs_mapProducts)
1230 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end();)
1231 AdvertRemoveSource(this, MSG_PRODUCT, 0, (*(mi++)).second);
1232
1233 // Cancel subscriptions
1234 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
1235 if (vfSubscribe[nChannel])
1236 CancelSubscribe(nChannel);
1237} 1155}
1238 1156
1239 1157
@@ -1358,7 +1276,6 @@ void ThreadSocketHandler2(void* parg)
1358 bool fDelete = false; 1276 bool fDelete = false;
1359 TRY_CRITICAL_BLOCK(pnode->cs_vSend) 1277 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1360 TRY_CRITICAL_BLOCK(pnode->cs_vRecv) 1278 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1361 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
1362 TRY_CRITICAL_BLOCK(pnode->cs_inventory) 1279 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
1363 fDelete = true; 1280 fDelete = true;
1364 if (fDelete) 1281 if (fDelete)
@@ -1466,6 +1383,27 @@ void ThreadSocketHandler2(void* parg)
1466 printf("dropping node %s: its socket is no longer valid\n", 1383 printf("dropping node %s: its socket is no longer valid\n",
1467 pnode->addr.ToString().c_str()); 1384 pnode->addr.ToString().c_str());
1468 pnode->fDisconnect = true; 1385 pnode->fDisconnect = true;
1386
1387 // Stop referring to it, or it goes into the next poll
1388 // set and fails it again.
1389 //
1390 // Marking fDisconnect is not enough: a node is only
1391 // removed from vNodes once it has drained or once
1392 // DISCONNECT_DRAIN_SECS has passed, so one dead
1393 // descriptor kept failing the wait for a full minute --
1394 // and a failed wait skips the service loop below
1395 // entirely, which means NO peer is read on that pass.
1396 // Measured on a wedged pool under the old select()
1397 // implementation: 1,027 consecutive passes over 61
1398 // seconds, one bad socket, the entire node deaf. poll()
1399 // reports a bad descriptor as POLLNVAL on that entry
1400 // rather than failing the whole call, so this path is
1401 // now the backstop rather than the common case.
1402 //
1403 // Not closed, only forgotten. getsockopt just told us
1404 // this descriptor is not ours any more; closing it now
1405 // is how an unrelated socket gets closed instead.
1406 pnode->hSocket = INVALID_SOCKET;
1469 } 1407 }
1470 } 1408 }
1471 } 1409 }
@@ -1710,6 +1648,13 @@ void ThreadMessageHandler(void* parg)
1710 } 1648 }
1711} 1649}
1712 1650
1651// When any peer last told us a height. A wedged node -- one that still has
1652// peers but has stopped hearing them -- is exactly a node where this stops
1653// advancing, and that is the one thing the height comparison itself cannot
1654// see: there is no height to compare.
1655static int64 nLastPeerHeightSeen = 0;
1656static int64 nPeerHeightFirstAsked = 0;
1657
1713int GetPeerMedianHeight() 1658int GetPeerMedianHeight()
1714{ 1659{
1715 vector<int> vHeights; 1660 vector<int> vHeights;
@@ -1721,10 +1666,26 @@ int GetPeerMedianHeight()
1721 if (vHeights.empty()) 1666 if (vHeights.empty())
1722 return -1; 1667 return -1;
1723 1668
1669 nLastPeerHeightSeen = GetTime();
1724 sort(vHeights.begin(), vHeights.end()); 1670 sort(vHeights.begin(), vHeights.end());
1725 return vHeights[vHeights.size() / 2]; 1671 return vHeights[vHeights.size() / 2];
1726} 1672}
1727 1673
1674// Seconds since any peer last reported a height.
1675//
1676// Before ever hearing one, measure from the first time somebody asked rather
1677// than from the epoch -- otherwise a node refuses jobs the instant it starts,
1678// before it has had a chance to complete a single handshake.
1679int64 GetPeerHeightAgeSecs()
1680{
1681 int64 nNow = GetTime();
1682 if (nPeerHeightFirstAsked == 0)
1683 nPeerHeightFirstAsked = nNow;
1684 if (nLastPeerHeightSeen == 0)
1685 return nNow - nPeerHeightFirstAsked;
1686 return nNow - nLastPeerHeightSeen;
1687}
1688
1728 1689
1729// Say out loud when we are behind the network. 1690// Say out loud when we are behind the network.
1730// 1691//
@@ -1861,7 +1822,21 @@ void ThreadBitcoinMiner(void* parg)
1861// Start the miners. Returns how many actually got off the ground. 1822// Start the miners. Returns how many actually got off the ground.
1862int StartMinerThreads() 1823int StartMinerThreads()
1863{ 1824{
1864 int nThreads = MinerThreadCount(); 1825 // MinerThreadCount() sizes the SOLO miner, where each thread hashes a
1826 // template of its own and more threads is simply more hashrate.
1827 //
1828 // Participant mode is not that shape. Every thread that enters
1829 // BitcoinMiner() takes the MINE_PARTICIPANT branch, and that branch is a
1830 // whole miner: its own Stratum session to the pool, its own payout address
1831 // from the rotation, and its own pool of /hashthreads worker threads. So
1832 // the two counts multiply instead of dividing, and the machine ends up
1833 // running MinerThreadCount() x nHashThreads hashing threads plus one pool
1834 // connection each. On a 12-core host with /hashthreads=2 that is 11
1835 // sessions and 22 hash threads -- roughly 2x the cores, which is not more
1836 // work done, only more contention -- and with /hashthreads unset it is 11
1837 // sessions of 11 workers. One session is the entirety of participant mode;
1838 // /hashthreads is what sizes it, and it can then mean what it says.
1839 int nThreads = (nMineMode == MINE_PARTICIPANT) ? 1 : MinerThreadCount();
1865 int nStarted = 0; 1840 int nStarted = 0;
1866 for (int i = 0; i < nThreads; i++) 1841 for (int i = 0; i < nThreads; i++)
1867 { 1842 {
@@ -1873,9 +1848,24 @@ int StartMinerThreads()
1873 // The dataset is one allocation shared by all of them; only the 2 MB 1848 // The dataset is one allocation shared by all of them; only the 2 MB
1874 // scratchpads multiply. Printed because "why is it using 2 GB" is the first 1849 // scratchpads multiply. Printed because "why is it using 2 GB" is the first
1875 // question anyone asks. 1850 // question anyone asks.
1876 printf("Mining with %d thread(s) of %u core(s) -- about %d MB " 1851 //
1877 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n", 1852 // Participant mode reports the workers that session will run, not the one
1878 nStarted, std::thread::hardware_concurrency(), 2080 + 2 * nStarted); 1853 // thread that runs it: the hash thread count is the number an operator
1854 // watches, and it is the number that was wrong here. It is otherwise only
1855 // logged under -debug, which is how 11 sessions ran unnoticed.
1856 if (nMineMode == MINE_PARTICIPANT)
1857 {
1858 int nWorkers = ParticipantHashThreadCount();
1859 printf("Mining for the pool with %d hash thread(s) of %u core(s) -- about %d MB "
1860 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1861 nWorkers, AvailableCoreCount(), 2080 + 2 * nWorkers);
1862 }
1863 else
1864 {
1865 printf("Mining with %d thread(s) of %u core(s) -- about %d MB "
1866 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1867 nStarted, AvailableCoreCount(), 2080 + 2 * nStarted);
1868 }
1879 return nStarted; 1869 return nStarted;
1880} 1870}
1881 1871
@@ -1950,11 +1940,29 @@ bool StartNode(string& strError)
1950 { 1940 {
1951 int nErr = WSAGetLastError(); 1941 int nErr = WSAGetLastError();
1952 if (nErr == WSAEADDRINUSE) 1942 if (nErr == WSAEADDRINUSE)
1953 strError = strprintf("Error: Unable to bind to port %s on this computer. The program is probably already running.", addrLocalHost.ToString().c_str()); 1943 {
1944 // Another local instance holds the default port. Fall back to an
1945 // ephemeral port: inbound direct-IP peering is optional, and .btf
1946 // rendezvous connectivity is unaffected by the local listen port.
1947 sockaddr.sin_port = htons(0);
1948 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
1949 {
1950 strError = strprintf("Error: Unable to bind any port on this computer (bind returned error %d)", WSAGetLastError());
1951 printf("%s\n", strError.c_str());
1952 return false;
1953 }
1954 struct sockaddr_in bound;
1955 socklen_t nBoundLen = sizeof(bound);
1956 if (getsockname(hListenSocket, (struct sockaddr*)&bound, &nBoundLen) == 0)
1957 addrLocalHost.port = bound.sin_port;
1958 printf("default port in use by another instance; bound to ephemeral %s instead\n", addrLocalHost.ToString().c_str());
1959 }
1954 else 1960 else
1961 {
1955 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr); 1962 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr);
1956 printf("%s\n", strError.c_str()); 1963 printf("%s\n", strError.c_str());
1957 return false; 1964 return false;
1965 }
1958 } 1966 }
1959 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str()); 1967 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str());
1960 1968