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 3660735..35baf21 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 }
@@ -1812,6 +1750,13 @@ void ThreadMessageHandler(void* parg)
1812 } 1750 }
1813} 1751}
1814 1752
1753// When any peer last told us a height. A wedged node -- one that still has
1754// peers but has stopped hearing them -- is exactly a node where this stops
1755// advancing, and that is the one thing the height comparison itself cannot
1756// see: there is no height to compare.
1757static int64 nLastPeerHeightSeen = 0;
1758static int64 nPeerHeightFirstAsked = 0;
1759
1815int GetPeerMedianHeight() 1760int GetPeerMedianHeight()
1816{ 1761{
1817 vector<int> vHeights; 1762 vector<int> vHeights;
@@ -1823,10 +1768,26 @@ int GetPeerMedianHeight()
1823 if (vHeights.empty()) 1768 if (vHeights.empty())
1824 return -1; 1769 return -1;
1825 1770
1771 nLastPeerHeightSeen = GetTime();
1826 sort(vHeights.begin(), vHeights.end()); 1772 sort(vHeights.begin(), vHeights.end());
1827 return vHeights[vHeights.size() / 2]; 1773 return vHeights[vHeights.size() / 2];
1828} 1774}
1829 1775
1776// Seconds since any peer last reported a height.
1777//
1778// Before ever hearing one, measure from the first time somebody asked rather
1779// than from the epoch -- otherwise a node refuses jobs the instant it starts,
1780// before it has had a chance to complete a single handshake.
1781int64 GetPeerHeightAgeSecs()
1782{
1783 int64 nNow = GetTime();
1784 if (nPeerHeightFirstAsked == 0)
1785 nPeerHeightFirstAsked = nNow;
1786 if (nLastPeerHeightSeen == 0)
1787 return nNow - nPeerHeightFirstAsked;
1788 return nNow - nLastPeerHeightSeen;
1789}
1790
1830 1791
1831// Say out loud when we are behind the network. 1792// Say out loud when we are behind the network.
1832// 1793//
@@ -1963,7 +1924,21 @@ void ThreadBitcoinMiner(void* parg)
1963// Start the miners. Returns how many actually got off the ground. 1924// Start the miners. Returns how many actually got off the ground.
1964int StartMinerThreads() 1925int StartMinerThreads()
1965{ 1926{
1966 int nThreads = MinerThreadCount(); 1927 // MinerThreadCount() sizes the SOLO miner, where each thread hashes a
1928 // template of its own and more threads is simply more hashrate.
1929 //
1930 // Participant mode is not that shape. Every thread that enters
1931 // BitcoinMiner() takes the MINE_PARTICIPANT branch, and that branch is a
1932 // whole miner: its own Stratum session to the pool, its own payout address
1933 // from the rotation, and its own pool of /hashthreads worker threads. So
1934 // the two counts multiply instead of dividing, and the machine ends up
1935 // running MinerThreadCount() x nHashThreads hashing threads plus one pool
1936 // connection each. On a 12-core host with /hashthreads=2 that is 11
1937 // sessions and 22 hash threads -- roughly 2x the cores, which is not more
1938 // work done, only more contention -- and with /hashthreads unset it is 11
1939 // sessions of 11 workers. One session is the entirety of participant mode;
1940 // /hashthreads is what sizes it, and it can then mean what it says.
1941 int nThreads = (nMineMode == MINE_PARTICIPANT) ? 1 : MinerThreadCount();
1967 int nStarted = 0; 1942 int nStarted = 0;
1968 for (int i = 0; i < nThreads; i++) 1943 for (int i = 0; i < nThreads; i++)
1969 { 1944 {
@@ -1975,9 +1950,24 @@ int StartMinerThreads()
1975 // The dataset is one allocation shared by all of them; only the 2 MB 1950 // The dataset is one allocation shared by all of them; only the 2 MB
1976 // scratchpads multiply. Printed because "why is it using 2 GB" is the first 1951 // scratchpads multiply. Printed because "why is it using 2 GB" is the first
1977 // question anyone asks. 1952 // question anyone asks.
1978 printf("Mining with %d thread(s) of %u core(s) -- about %d MB " 1953 //
1979 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n", 1954 // Participant mode reports the workers that session will run, not the one
1980 nStarted, std::thread::hardware_concurrency(), 2080 + 2 * nStarted); 1955 // thread that runs it: the hash thread count is the number an operator
1956 // watches, and it is the number that was wrong here. It is otherwise only
1957 // logged under -debug, which is how 11 sessions ran unnoticed.
1958 if (nMineMode == MINE_PARTICIPANT)
1959 {
1960 int nWorkers = ParticipantHashThreadCount();
1961 printf("Mining for the pool with %d hash thread(s) of %u core(s) -- about %d MB "
1962 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1963 nWorkers, AvailableCoreCount(), 2080 + 2 * nWorkers);
1964 }
1965 else
1966 {
1967 printf("Mining with %d thread(s) of %u core(s) -- about %d MB "
1968 "(~2080 MB shared RandomX dataset + ~2 MB per thread)\n",
1969 nStarted, AvailableCoreCount(), 2080 + 2 * nStarted);
1970 }
1981 return nStarted; 1971 return nStarted;
1982} 1972}
1983 1973
@@ -2057,11 +2047,29 @@ bool StartNode(string& strError)
2057 { 2047 {
2058 int nErr = WSAGetLastError(); 2048 int nErr = WSAGetLastError();
2059 if (nErr == WSAEADDRINUSE) 2049 if (nErr == WSAEADDRINUSE)
2060 strError = strprintf("Error: Unable to bind to port %s on this computer. The program is probably already running.", addrLocalHost.ToString().c_str()); 2050 {
2051 // Another local instance holds the default port. Fall back to an
2052 // ephemeral port: inbound direct-IP peering is optional, and .btf
2053 // rendezvous connectivity is unaffected by the local listen port.
2054 sockaddr.sin_port = htons(0);
2055 if (bind(hListenSocket, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == SOCKET_ERROR)
2056 {
2057 strError = strprintf("Error: Unable to bind any port on this computer (bind returned error %d)", WSAGetLastError());
2058 printf("%s\n", strError.c_str());
2059 return false;
2060 }
2061 struct sockaddr_in bound;
2062 socklen_t nBoundLen = sizeof(bound);
2063 if (getsockname(hListenSocket, (struct sockaddr*)&bound, &nBoundLen) == 0)
2064 addrLocalHost.port = bound.sin_port;
2065 printf("default port in use by another instance; bound to ephemeral %s instead\n", addrLocalHost.ToString().c_str());
2066 }
2061 else 2067 else
2068 {
2062 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr); 2069 strError = strprintf("Error: Unable to bind to port %s on this computer (bind returned error %d)", addrLocalHost.ToString().c_str(), nErr);
2063 printf("%s\n", strError.c_str()); 2070 printf("%s\n", strError.c_str());
2064 return false; 2071 return false;
2072 }
2065 } 2073 }
2066 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str()); 2074 printf("bound to addrLocalHost = %s\n\n", addrLocalHost.ToString().c_str());
2067 2075