upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/net.h
diff options
context:
space:
mode:
authorBitflash-sh <btf01@proton.me>2026-07-24 11:18:11 -0300
committerBitflash-sh <btf01@proton.me>2026-07-24 11:18:11 -0300
commit51d617e70f90a972185917ea0096c1ecef2bfa8b (patch)
tree9fbbcd867de9de9d0776afdd02f594ba312c46eb /src/net.h
Bitflash: fair-launch release
Satoshi's bitcoin-0.1.0 reborn with RandomX CPU proof of work, anonymous .btf addressing over Nostr with CGNAT rendezvous, automatic peer discovery, a headless Linux node, and Windows GUI wallet. Fair launch, no premine, 21M cap.
Diffstat (limited to 'src/net.h')
-rw-r--r--src/net.h863
1 files changed, 863 insertions, 0 deletions
diff --git a/src/net.h b/src/net.h
new file mode 100644
index 0000000..6e62126
--- /dev/null
+++ b/src/net.h
@@ -0,0 +1,863 @@
1// Copyright (c) 2009 Satoshi Nakamoto
2// Distributed under the MIT/X11 software license, see the accompanying
3// file license.txt or http://www.opensource.org/licenses/mit-license.php.
4
5class CMessageHeader;
6class CAddress;
7class CInv;
8class CRequestTracker;
9class CNode;
10
11
12
13static const unsigned short DEFAULT_PORT = htons(8433);
14static const unsigned int PUBLISH_HOPS = 5;
15enum
16{
17 NODE_NETWORK = (1 << 0),
18};
19
20
21
22
23
24
25bool ConnectSocket(const CAddress& addrConnect, SOCKET& hSocketRet);
26bool GetMyExternalIP(unsigned int& ipRet);
27bool AddAddress(CAddrDB& addrdb, const CAddress& addr);
28CNode* FindNode(unsigned int ip);
29CNode* ConnectNode(CAddress addrConnect, int64 nTimeout=0);
30CNode* ConnectNodeBtf(const string& strBtfAddr);
31void ThreadBtfAccept(void* parg);
32void ThreadBtfConnect(void* parg);
33extern string strBtfConnect;
34void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
35bool AnySubscribed(unsigned int nChannel);
36void ThreadBitcoinMiner(void* parg);
37bool StartNode(string& strError=REF(string()));
38bool StopNode();
39void CheckForShutdown(int n);
40
41
42
43
44
45
46
47
48
49//
50// Message header
51// (4) message start
52// (12) command
53// (4) size
54
55// The message start string is designed to be unlikely to occur in normal data.
56// The characters are rarely used upper ascii, not valid as UTF-8, and produce
57// a large 4-byte int at any alignment.
58// Magic bytes unique to the Bitflash network (0xbf = "BF"). Second byte bumped
59// to 0x20 for the 2026 stable relaunch so the old test chain can't interfere.
60static const char pchMessageStart[4] = { 0xbf, 0x20, 0x5c, 0xfd };
61
62class CMessageHeader
63{
64public:
65 enum { COMMAND_SIZE=12 };
66 char pchMessageStart[sizeof(::pchMessageStart)];
67 char pchCommand[COMMAND_SIZE];
68 unsigned int nMessageSize;
69
70 CMessageHeader()
71 {
72 memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
73 memset(pchCommand, 0, sizeof(pchCommand));
74 pchCommand[1] = 1;
75 nMessageSize = -1;
76 }
77
78 CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn)
79 {
80 memcpy(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart));
81 strncpy(pchCommand, pszCommand, COMMAND_SIZE);
82 nMessageSize = nMessageSizeIn;
83 }
84
85 IMPLEMENT_SERIALIZE
86 (
87 READWRITE(FLATDATA(pchMessageStart));
88 READWRITE(FLATDATA(pchCommand));
89 READWRITE(nMessageSize);
90 )
91
92 string GetCommand()
93 {
94 if (pchCommand[COMMAND_SIZE-1] == 0)
95 return string(pchCommand, pchCommand + strlen(pchCommand));
96 else
97 return string(pchCommand, pchCommand + COMMAND_SIZE);
98 }
99
100 bool IsValid()
101 {
102 // Check start string
103 if (memcmp(pchMessageStart, ::pchMessageStart, sizeof(pchMessageStart)) != 0)
104 return false;
105
106 // Check the command string for errors
107 for (char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
108 {
109 if (*p1 == 0)
110 {
111 // Must be all zeros after the first zero
112 for (; p1 < pchCommand + COMMAND_SIZE; p1++)
113 if (*p1 != 0)
114 return false;
115 }
116 else if (*p1 < ' ' || *p1 > 0x7E)
117 return false;
118 }
119
120 // Message size
121 if (nMessageSize > 0x10000000)
122 {
123 printf("CMessageHeader::IsValid() : nMessageSize too large %u\n", nMessageSize);
124 return false;
125 }
126
127 return true;
128 }
129};
130
131
132
133
134
135
136static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff };
137
138class CAddress
139{
140public:
141 uint64 nServices;
142 unsigned char pchReserved[12];
143 unsigned int ip;
144 unsigned short port;
145
146 // disk only
147 unsigned int nTime;
148
149 // memory only
150 unsigned int nLastFailed;
151
152 CAddress()
153 {
154 nServices = 0;
155 memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
156 ip = 0;
157 port = DEFAULT_PORT;
158 nTime = GetAdjustedTime();
159 nLastFailed = 0;
160 }
161
162 CAddress(unsigned int ipIn, unsigned short portIn, uint64 nServicesIn=0)
163 {
164 nServices = nServicesIn;
165 memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
166 ip = ipIn;
167 port = portIn;
168 nTime = GetAdjustedTime();
169 nLastFailed = 0;
170 }
171
172 explicit CAddress(const struct sockaddr_in& sockaddr, uint64 nServicesIn=0)
173 {
174 nServices = nServicesIn;
175 memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
176 ip = sockaddr.sin_addr.s_addr;
177 port = sockaddr.sin_port;
178 nTime = GetAdjustedTime();
179 nLastFailed = 0;
180 }
181
182 explicit CAddress(const char* pszIn, uint64 nServicesIn=0)
183 {
184 nServices = nServicesIn;
185 memcpy(pchReserved, pchIPv4, sizeof(pchReserved));
186 ip = 0;
187 port = DEFAULT_PORT;
188 nTime = GetAdjustedTime();
189 nLastFailed = 0;
190
191 char psz[100];
192 if (strlen(pszIn) > ARRAYLEN(psz)-1)
193 return;
194 strcpy(psz, pszIn);
195 unsigned int a, b, c, d, e;
196 if (sscanf(psz, "%u.%u.%u.%u:%u", &a, &b, &c, &d, &e) < 4)
197 return;
198 char* pszPort = strchr(psz, ':');
199 if (pszPort)
200 {
201 *pszPort++ = '\0';
202 port = htons(atoi(pszPort));
203 }
204 ip = inet_addr(psz);
205 }
206
207 IMPLEMENT_SERIALIZE
208 (
209 if (nType & SER_DISK)
210 {
211 READWRITE(nVersion);
212 READWRITE(nTime);
213 }
214 READWRITE(nServices);
215 READWRITE(FLATDATA(pchReserved));
216 READWRITE(ip);
217 READWRITE(port);
218 )
219
220 friend inline bool operator==(const CAddress& a, const CAddress& b)
221 {
222 return (memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved)) == 0 &&
223 a.ip == b.ip &&
224 a.port == b.port);
225 }
226
227 friend inline bool operator<(const CAddress& a, const CAddress& b)
228 {
229 int ret = memcmp(a.pchReserved, b.pchReserved, sizeof(a.pchReserved));
230 if (ret < 0)
231 return true;
232 else if (ret == 0)
233 {
234 if (ntohl(a.ip) < ntohl(b.ip))
235 return true;
236 else if (a.ip == b.ip)
237 return ntohs(a.port) < ntohs(b.port);
238 }
239 return false;
240 }
241
242 vector<unsigned char> GetKey() const
243 {
244 CDataStream ss;
245 ss.reserve(18);
246 ss << FLATDATA(pchReserved) << ip << port;
247
248 #if defined(_MSC_VER) && _MSC_VER < 1300
249 return vector<unsigned char>((unsigned char*)&ss.begin()[0], (unsigned char*)&ss.end()[0]);
250 #else
251 return vector<unsigned char>(ss.begin(), ss.end());
252 #endif
253 }
254
255 struct sockaddr_in GetSockAddr() const
256 {
257 struct sockaddr_in sockaddr;
258 sockaddr.sin_family = AF_INET;
259 sockaddr.sin_addr.s_addr = ip;
260 sockaddr.sin_port = port;
261 return sockaddr;
262 }
263
264 bool IsIPv4() const
265 {
266 return (memcmp(pchReserved, pchIPv4, sizeof(pchIPv4)) == 0);
267 }
268
269 bool IsRoutable() const
270 {
271 return !(GetByte(3) == 10 || (GetByte(3) == 192 && GetByte(2) == 168));
272 }
273
274 unsigned char GetByte(int n) const
275 {
276 return ((unsigned char*)&ip)[3-n];
277 }
278
279 string ToStringIPPort() const
280 {
281 return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
282 }
283
284 string ToStringIP() const
285 {
286 return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
287 }
288
289 string ToString() const
290 {
291 return strprintf("%u.%u.%u.%u:%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0), ntohs(port));
292 //return strprintf("%u.%u.%u.%u", GetByte(3), GetByte(2), GetByte(1), GetByte(0));
293 }
294
295 void print() const
296 {
297 printf("CAddress(%s)\n", ToString().c_str());
298 }
299};
300
301
302
303
304
305
306
307enum
308{
309 MSG_TX = 1,
310 MSG_BLOCK,
311 MSG_REVIEW,
312 MSG_PRODUCT,
313 MSG_TABLE,
314};
315
316static const char* ppszTypeName[] =
317{
318 "ERROR",
319 "tx",
320 "block",
321 "review",
322 "product",
323 "table",
324};
325
326class CInv
327{
328public:
329 int type;
330 uint256 hash;
331
332 CInv()
333 {
334 type = 0;
335 hash = 0;
336 }
337
338 CInv(int typeIn, const uint256& hashIn)
339 {
340 type = typeIn;
341 hash = hashIn;
342 }
343
344 CInv(const string& strType, const uint256& hashIn)
345 {
346 int i;
347 for (i = 1; i < ARRAYLEN(ppszTypeName); i++)
348 {
349 if (strType == ppszTypeName[i])
350 {
351 type = i;
352 break;
353 }
354 }
355 if (i == ARRAYLEN(ppszTypeName))
356 throw std::out_of_range(strprintf("CInv::CInv(string, uint256) : unknown type '%s'", strType.c_str()));
357 hash = hashIn;
358 }
359
360 IMPLEMENT_SERIALIZE
361 (
362 READWRITE(type);
363 READWRITE(hash);
364 )
365
366 friend inline bool operator<(const CInv& a, const CInv& b)
367 {
368 return (a.type < b.type || (a.type == b.type && a.hash < b.hash));
369 }
370
371 bool IsKnownType() const
372 {
373 return (type >= 1 && type < ARRAYLEN(ppszTypeName));
374 }
375
376 const char* GetCommand() const
377 {
378 if (!IsKnownType())
379 throw std::out_of_range(strprintf("CInv::GetCommand() : type=% unknown type", type));
380 return ppszTypeName[type];
381 }
382
383 string ToString() const
384 {
385 return strprintf("%s %s", GetCommand(), hash.ToString().substr(0,14).c_str());
386 }
387
388 void print() const
389 {
390 printf("CInv(%s)\n", ToString().c_str());
391 }
392};
393
394
395
396
397
398class CRequestTracker
399{
400public:
401 void (*fn)(void*, CDataStream&);
402 void* param1;
403
404 explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
405 {
406 fn = fnIn;
407 param1 = param1In;
408 }
409
410 bool IsNull()
411 {
412 return fn == NULL;
413 }
414};
415
416
417
418
419
420extern bool fClient;
421extern uint64 nLocalServices;
422extern CAddress addrLocalHost;
423extern unsigned short nListenPort;
424extern CNode* pnodeLocalHost;
425extern bool fShutdown;
426extern array<bool, 10> vfThreadRunning;
427extern vector<CNode*> vNodes;
428extern CCriticalSection cs_vNodes;
429extern map<vector<unsigned char>, CAddress> mapAddresses;
430extern CCriticalSection cs_mapAddresses;
431extern map<CInv, CDataStream> mapRelay;
432extern deque<pair<int64, CInv> > vRelayExpiration;
433extern CCriticalSection cs_mapRelay;
434extern map<CInv, int64> mapAlreadyAskedFor;
435extern CAddress addrProxy;
436
437
438
439
440
441class CNode
442{
443public:
444 // socket
445 uint64 nServices;
446 SOCKET hSocket;
447 CDataStream vSend;
448 CDataStream vRecv;
449 CCriticalSection cs_vSend;
450 CCriticalSection cs_vRecv;
451 unsigned int nPushPos;
452 CAddress addr;
453 int nVersion;
454 bool fClient;
455 bool fInbound;
456 bool fNetworkNode;
457 bool fDisconnect;
458protected:
459 int nRefCount;
460public:
461 int64 nReleaseTime;
462 map<uint256, CRequestTracker> mapRequests;
463 CCriticalSection cs_mapRequests;
464
465 // flood
466 vector<CAddress> vAddrToSend;
467 set<CAddress> setAddrKnown;
468
469 // inventory based relay
470 set<CInv> setInventoryKnown;
471 set<CInv> setInventoryKnown2;
472 vector<CInv> vInventoryToSend;
473 CCriticalSection cs_inventory;
474 multimap<int64, CInv> mapAskFor;
475
476 // publish and subscription
477 vector<char> vfSubscribe;
478
479
480 CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false)
481 {
482 nServices = 0;
483 hSocket = hSocketIn;
484 vSend.SetType(SER_NETWORK);
485 vRecv.SetType(SER_NETWORK);
486 nPushPos = -1;
487 addr = addrIn;
488 nVersion = 0;
489 fClient = false; // set by version message
490 fInbound = fInboundIn;
491 fNetworkNode = false;
492 fDisconnect = false;
493 nRefCount = 0;
494 nReleaseTime = 0;
495 vfSubscribe.assign(256, false);
496
497 // Push a version message
498 /// when NTP implemented, change to just nTime = GetAdjustedTime()
499 int64 nTime = (fInbound ? GetAdjustedTime() : GetTime());
500 PushMessage("version", VERSION, nLocalServices, nTime, addr);
501 }
502
503 ~CNode()
504 {
505 if (hSocket != INVALID_SOCKET)
506 closesocket(hSocket);
507 }
508
509private:
510 CNode(const CNode&);
511 void operator=(const CNode&);
512public:
513
514
515 bool ReadyToDisconnect()
516 {
517 return fDisconnect || GetRefCount() <= 0;
518 }
519
520 int GetRefCount()
521 {
522 return max(nRefCount, 0) + (GetTime() < nReleaseTime ? 1 : 0);
523 }
524
525 void AddRef(int64 nTimeout=0)
526 {
527 if (nTimeout != 0)
528 nReleaseTime = max(nReleaseTime, GetTime() + nTimeout);
529 else
530 nRefCount++;
531 }
532
533 void Release()
534 {
535 nRefCount--;
536 }
537
538
539
540 void AddInventoryKnown(const CInv& inv)
541 {
542 CRITICAL_BLOCK(cs_inventory)
543 setInventoryKnown.insert(inv);
544 }
545
546 void PushInventory(const CInv& inv)
547 {
548 CRITICAL_BLOCK(cs_inventory)
549 if (!setInventoryKnown.count(inv))
550 vInventoryToSend.push_back(inv);
551 }
552
553 void AskFor(const CInv& inv)
554 {
555 // We're using mapAskFor as a priority queue,
556 // the key is the earliest time the request can be sent
557 int64& nRequestTime = mapAlreadyAskedFor[inv];
558 printf("askfor %s %I64d\n", inv.ToString().c_str(), nRequestTime);
559
560 // Make sure not to reuse time indexes to keep things in the same order
561 int64 nNow = (GetTime() - 1) * 1000000;
562 static int64 nLastTime;
563 nLastTime = nNow = max(nNow, ++nLastTime);
564
565 // Each retry is 2 minutes after the last
566 nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow);
567 mapAskFor.insert(make_pair(nRequestTime, inv));
568 }
569
570
571
572 void BeginMessage(const char* pszCommand)
573 {
574 EnterCriticalSection(&cs_vSend);
575 if (nPushPos != -1)
576 AbortMessage();
577 nPushPos = vSend.size();
578 vSend << CMessageHeader(pszCommand, 0);
579 printf("sending: %-12s ", pszCommand);
580 }
581
582 void AbortMessage()
583 {
584 if (nPushPos == -1)
585 return;
586 vSend.resize(nPushPos);
587 nPushPos = -1;
588 LeaveCriticalSection(&cs_vSend);
589 printf("(aborted)\n");
590 }
591
592 void EndMessage()
593 {
594 extern int nDropMessagesTest;
595 if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0)
596 {
597 printf("dropmessages DROPPING SEND MESSAGE\n");
598 AbortMessage();
599 return;
600 }
601
602 if (nPushPos == -1)
603 return;
604
605 // Patch in the size
606 unsigned int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader);
607 memcpy((char*)&vSend[nPushPos] + offsetof(CMessageHeader, nMessageSize), &nSize, sizeof(nSize));
608
609 printf("(%d bytes) ", nSize);
610 //for (int i = nPushPos+sizeof(CMessageHeader); i < min(vSend.size(), nPushPos+sizeof(CMessageHeader)+20U); i++)
611 // printf("%02x ", vSend[i] & 0xff);
612 printf("\n");
613
614 nPushPos = -1;
615 LeaveCriticalSection(&cs_vSend);
616 }
617
618 void EndMessageAbortIfEmpty()
619 {
620 if (nPushPos == -1)
621 return;
622 int nSize = vSend.size() - nPushPos - sizeof(CMessageHeader);
623 if (nSize > 0)
624 EndMessage();
625 else
626 AbortMessage();
627 }
628
629 const char* GetMessageCommand() const
630 {
631 if (nPushPos == -1)
632 return "";
633 return &vSend[nPushPos] + offsetof(CMessageHeader, pchCommand);
634 }
635
636
637
638
639 void PushMessage(const char* pszCommand)
640 {
641 try
642 {
643 BeginMessage(pszCommand);
644 EndMessage();
645 }
646 catch (...)
647 {
648 AbortMessage();
649 throw;
650 }
651 }
652
653 template<typename T1>
654 void PushMessage(const char* pszCommand, const T1& a1)
655 {
656 try
657 {
658 BeginMessage(pszCommand);
659 vSend << a1;
660 EndMessage();
661 }
662 catch (...)
663 {
664 AbortMessage();
665 throw;
666 }
667 }
668
669 template<typename T1, typename T2>
670 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2)
671 {
672 try
673 {
674 BeginMessage(pszCommand);
675 vSend << a1 << a2;
676 EndMessage();
677 }
678 catch (...)
679 {
680 AbortMessage();
681 throw;
682 }
683 }
684
685 template<typename T1, typename T2, typename T3>
686 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3)
687 {
688 try
689 {
690 BeginMessage(pszCommand);
691 vSend << a1 << a2 << a3;
692 EndMessage();
693 }
694 catch (...)
695 {
696 AbortMessage();
697 throw;
698 }
699 }
700
701 template<typename T1, typename T2, typename T3, typename T4>
702 void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4)
703 {
704 try
705 {
706 BeginMessage(pszCommand);
707 vSend << a1 << a2 << a3 << a4;
708 EndMessage();
709 }
710 catch (...)
711 {
712 AbortMessage();
713 throw;
714 }
715 }
716
717
718 void PushRequest(const char* pszCommand,
719 void (*fn)(void*, CDataStream&), void* param1)
720 {
721 uint256 hashReply;
722 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
723
724 CRITICAL_BLOCK(cs_mapRequests)
725 mapRequests[hashReply] = CRequestTracker(fn, param1);
726
727 PushMessage(pszCommand, hashReply);
728 }
729
730 template<typename T1>
731 void PushRequest(const char* pszCommand, const T1& a1,
732 void (*fn)(void*, CDataStream&), void* param1)
733 {
734 uint256 hashReply;
735 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
736
737 CRITICAL_BLOCK(cs_mapRequests)
738 mapRequests[hashReply] = CRequestTracker(fn, param1);
739
740 PushMessage(pszCommand, hashReply, a1);
741 }
742
743 template<typename T1, typename T2>
744 void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
745 void (*fn)(void*, CDataStream&), void* param1)
746 {
747 uint256 hashReply;
748 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
749
750 CRITICAL_BLOCK(cs_mapRequests)
751 mapRequests[hashReply] = CRequestTracker(fn, param1);
752
753 PushMessage(pszCommand, hashReply, a1, a2);
754 }
755
756
757
758 bool IsSubscribed(unsigned int nChannel);
759 void Subscribe(unsigned int nChannel, unsigned int nHops=0);
760 void CancelSubscribe(unsigned int nChannel);
761 void Disconnect();
762};
763
764
765
766
767
768
769
770
771
772
773inline void RelayInventory(const CInv& inv)
774{
775 // Put on lists to offer to the other nodes
776 CRITICAL_BLOCK(cs_vNodes)
777 foreach(CNode* pnode, vNodes)
778 pnode->PushInventory(inv);
779}
780
781template<typename T>
782void RelayMessage(const CInv& inv, const T& a)
783{
784 CDataStream ss(SER_NETWORK);
785 ss.reserve(10000);
786 ss << a;
787 RelayMessage(inv, ss);
788}
789
790template<>
791inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
792{
793 CRITICAL_BLOCK(cs_mapRelay)
794 {
795 // Expire old relay messages
796 while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
797 {
798 mapRelay.erase(vRelayExpiration.front().second);
799 vRelayExpiration.pop_front();
800 }
801
802 // Save original serialized message so newer versions are preserved
803 mapRelay[inv] = ss;
804 vRelayExpiration.push_back(make_pair(GetTime() + 15 * 60, inv));
805 }
806
807 RelayInventory(inv);
808}
809
810
811
812
813
814
815
816
817//
818// Templates for the publish and subscription system.
819// The object being published as T& obj needs to have:
820// a set<unsigned int> setSources member
821// specializations of AdvertInsert and AdvertErase
822// Currently implemented for CTable and CProduct.
823//
824
825template<typename T>
826void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
827{
828 // Add to sources
829 obj.setSources.insert(pfrom->addr.ip);
830
831 if (!AdvertInsert(obj))
832 return;
833
834 // Relay
835 CRITICAL_BLOCK(cs_vNodes)
836 foreach(CNode* pnode, vNodes)
837 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
838 pnode->PushMessage("publish", nChannel, nHops, obj);
839}
840
841template<typename T>
842void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
843{
844 uint256 hash = obj.GetHash();
845
846 CRITICAL_BLOCK(cs_vNodes)
847 foreach(CNode* pnode, vNodes)
848 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
849 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
850
851 AdvertErase(obj);
852}
853
854template<typename T>
855void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
856{
857 // Remove a source
858 obj.setSources.erase(pfrom->addr.ip);
859
860 // If no longer supported by any sources, cancel it
861 if (obj.setSources.empty())
862 AdvertStopPublish(pfrom, nChannel, nHops, obj);
863}