upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile4
-rw-r--r--src/db.cpp16
-rw-r--r--src/db.h23
-rw-r--r--src/headers_core.h1
-rw-r--r--src/main.cpp115
-rw-r--r--src/makefile.mingw4
-rw-r--r--src/market.cpp264
-rw-r--r--src/market.h182
-rw-r--r--src/net.cpp109
-rw-r--r--src/net.h138
10 files changed, 69 insertions, 787 deletions
diff --git a/src/Makefile b/src/Makefile
index 3577dd6..171afe0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -48,14 +48,14 @@ LIBS = -L$(SECP_LIB) -lsecp256k1 \
48# binary. Nothing crashed here, and nothing would say so if it had. 48# binary. Nothing crashed here, and nothing would say so if it had.
49HEADERS = headers_core.h headers.h util.h main.h serialize.h uint256.h \ 49HEADERS = headers_core.h headers.h util.h main.h serialize.h uint256.h \
50 key.h bignum.h script.h db.h base58.h net.h nostr.h \ 50 key.h bignum.h script.h db.h base58.h net.h nostr.h \
51 randomx_pow.h btfaddr.h btfchan.h btfrv.h btftunnel.h market.h \ 51 randomx_pow.h btfaddr.h btfchan.h btfrv.h btftunnel.h \
52 selftest.h walletcmd.h compat.h sockcount.h font_roboto.h 52 selftest.h walletcmd.h compat.h sockcount.h font_roboto.h
53 53
54IMGUI_OBJS = obj/imgui.o obj/imgui_draw.o obj/imgui_tables.o \ 54IMGUI_OBJS = obj/imgui.o obj/imgui_draw.o obj/imgui_tables.o \
55 obj/imgui_widgets.o obj/imgui_impl_glfw.o obj/imgui_impl_opengl3.o 55 obj/imgui_widgets.o obj/imgui_impl_glfw.o obj/imgui_impl_opengl3.o
56 56
57NODE_OBJS = obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o \ 57NODE_OBJS = obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o \
58 obj/market.o obj/sha.o obj/nostr.o obj/randomx_pow.o \ 58 obj/sha.o obj/nostr.o obj/randomx_pow.o \
59 obj/btfaddr.o obj/btfchan.o obj/btfrv.o obj/btftunnel.o obj/rpc.o \ 59 obj/btfaddr.o obj/btfchan.o obj/btfrv.o obj/btftunnel.o obj/rpc.o \
60 obj/selftest.o obj/bip32.o obj/walletcmd.o 60 obj/selftest.o obj/bip32.o obj/walletcmd.o
61 61
diff --git a/src/db.cpp b/src/db.cpp
index c8642e9..6f9461b 100644
--- a/src/db.cpp
+++ b/src/db.cpp
@@ -598,20 +598,12 @@ bool CTxDB::LoadBlockIndex()
598 598
599 599
600// 600//
601// CReviewDB 601// CReviewDB is gone with the "review" handler. Its write path was
602// read-whole-vector / append-one / write-whole-vector, driven straight from an
603// unauthenticated peer, which is quadratic disk on an unbounded record.
604// Existing reviews.dat files are simply left alone and never opened.
602// 605//
603 606
604bool CReviewDB::ReadReviews(uint256 hash, vector<CReview>& vReviews)
605{
606 vReviews.size(); // msvc workaround, just need to do anything with vReviews
607 return Read(make_pair(string("reviews"), hash), vReviews);
608}
609
610bool CReviewDB::WriteReviews(uint256 hash, const vector<CReview>& vReviews)
611{
612 return Write(make_pair(string("reviews"), hash), vReviews);
613}
614
615 607
616 608
617 609
diff --git a/src/db.h b/src/db.h
index 4fb5cfd..37a252f 100644
--- a/src/db.h
+++ b/src/db.h
@@ -8,8 +8,6 @@ class CTxIndex;
8class CDiskBlockIndex; 8class CDiskBlockIndex;
9class CDiskTxPos; 9class CDiskTxPos;
10class COutPoint; 10class COutPoint;
11class CUser;
12class CReview;
13class CAddress; 11class CAddress;
14class CWalletTx; 12class CWalletTx;
15 13
@@ -314,27 +312,6 @@ public:
314 312
315 313
316 314
317class CReviewDB : public CDB
318{
319public:
320 CReviewDB(const char* pszMode="r+", bool fTxn=false) : CDB("reviews.dat", pszMode, fTxn) { }
321private:
322 CReviewDB(const CReviewDB&);
323 void operator=(const CReviewDB&);
324public:
325 bool ReadUser(uint256 hash, CUser& user)
326 {
327 return Read(make_pair(string("user"), hash), user);
328 }
329
330 bool WriteUser(uint256 hash, const CUser& user)
331 {
332 return Write(make_pair(string("user"), hash), user);
333 }
334
335 bool ReadReviews(uint256 hash, vector<CReview>& vReviews);
336 bool WriteReviews(uint256 hash, const vector<CReview>& vReviews);
337};
338 315
339 316
340 317
diff --git a/src/headers_core.h b/src/headers_core.h
index 6c0c602..6a60b52 100644
--- a/src/headers_core.h
+++ b/src/headers_core.h
@@ -66,7 +66,6 @@ inline typename std::common_type<T1,T2>::type max(const T1& a, const T2& b)
66#include "nostr.h" 66#include "nostr.h"
67#include "randomx_pow.h" 67#include "randomx_pow.h"
68#include "main.h" 68#include "main.h"
69#include "market.h"
70 69
71// GUI callback -- implemented in gui.cpp (or as no-op in headless builds) 70// GUI callback -- implemented in gui.cpp (or as no-op in headless builds)
72void MainFrameRepaint(); 71void MainFrameRepaint();
diff --git a/src/main.cpp b/src/main.cpp
index 62068d2..efff96c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2782,9 +2782,10 @@ bool AlreadyHave(CTxDB& txdb, const CInv& inv)
2782 { 2782 {
2783 case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash); 2783 case MSG_TX: return mapTransactions.count(inv.hash) || txdb.ContainsTx(inv.hash);
2784 case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash); 2784 case MSG_BLOCK: return mapBlockIndex.count(inv.hash) || mapOrphanBlocks.count(inv.hash);
2785 case MSG_REVIEW: return true;
2786 case MSG_PRODUCT: return mapProducts.count(inv.hash);
2787 } 2785 }
2786 // MSG_REVIEW / MSG_PRODUCT / MSG_TABLE are the 2009 marketplace inventory
2787 // types. Nothing announces or serves them any more (see ProcessMessage),
2788 // so they fall through to the default and are never requested.
2788 // Don't know what it is, just say we already got one 2789 // Don't know what it is, just say we already got one
2789 return true; 2790 return true;
2790} 2791}
@@ -2942,7 +2943,6 @@ bool ProcessMessages(CNode* pfrom)
2942 2943
2943bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) 2944bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
2944{ 2945{
2945 static map<unsigned int, vector<unsigned char> > mapReuseKey;
2946 if (LogAcceptsCategory("net")) { printf("received: %-12s (%d bytes) ", strCommand.c_str(), (int)vRecv.size()); for (int i = 0; i < min(vRecv.size(), (unsigned int)25); i++) printf("%02x ", vRecv[i] & 0xff); printf("\n"); } 2946 if (LogAcceptsCategory("net")) { printf("received: %-12s (%d bytes) ", strCommand.c_str(), (int)vRecv.size()); for (int i = 0; i < min(vRecv.size(), (unsigned int)25); i++) printf("%02x ", vRecv[i] & 0xff); printf("\n"); }
2947 if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0) 2947 if (nDropMessagesTest > 0 && GetRand(nDropMessagesTest) == 0)
2948 { 2948 {
@@ -3181,22 +3181,18 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
3181 } 3181 }
3182 3182
3183 3183
3184 else if (strCommand == "review") 3184 // "review" used to be handled here. It took a CReview off the wire from an
3185 { 3185 // unauthenticated peer, checked a signature the sender had made with a key
3186 CDataStream vMsg(vRecv); 3186 // of its own choosing -- which proves possession of that key and authorises
3187 CReview review; 3187 // nothing -- and then appended the message to reviews.dat by reading the
3188 vRecv >> review; 3188 // whole vector for the target hash, pushing one entry, and writing all of
3189 3189 // it back. That is quadratic disk for a stream an attacker controls, on a
3190 CInv inv(MSG_REVIEW, review.GetHash()); 3190 // record whose mapValue is an unbounded map<string,string> read straight
3191 pfrom->AddInventoryKnown(inv); 3191 // from the socket, followed by AddAtomsAndPropagate walking a link graph
3192 3192 // the same peer supplied, and finally RelayMessage forwarding it to every
3193 if (review.AcceptReview()) 3193 // other node. Unbounded remote disk growth with network amplification and
3194 { 3194 // no authorisation anywhere in the path. The marketplace it belonged to has
3195 // Relay the original message as-is in case it's a higher version than we know how to parse 3195 // not existed since 2009; the handler is gone rather than bounded.
3196 RelayMessage(inv, vMsg);
3197 mapAlreadyAskedFor.erase(inv);
3198 }
3199 }
3200 3196
3201 3197
3202 else if (strCommand == "block") 3198 else if (strCommand == "block")
@@ -3229,65 +3225,28 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
3229 } 3225 }
3230 3226
3231 3227
3232 else if (strCommand == "checkorder") 3228 // "checkorder", "submitorder" and "reply" -- the 2009 buy-from-a-merchant
3233 { 3229 // exchange -- used to be handled here. All three are gone.
3234 uint256 hashReply; 3230 //
3235 CWalletTx order; 3231 // "checkorder" called GenerateNewKey() for any peer that asked, which is
3236 vRecv >> hashReply >> order; 3232 // AddKey() and a wallet.dat write, and handed the pubkey back. The comment
3237 3233 // said "keep giving the same key to the same ip until they use it", and on
3238 /// we have a chance to check the order here 3234 // a 2009 network of routable IPs that held. It does not hold here: every
3239 3235 // inbound peer arrives through a rendezvous tunnel and is tagged with
3240 // Keep giving the same key to the same ip until they use it 3236 // BtfMarkerAddr() over three random bytes (net.cpp), so addr.ip is freshly
3241 if (!mapReuseKey.count(pfrom->addr.ip)) 3237 // random per connection and the cache never hits. Reconnect in a loop and
3242 mapReuseKey[pfrom->addr.ip] = GenerateNewKey(); 3238 // the node mints a key per connection -- unbounded wallet growth, unbounded
3243 3239 // growth of the static map that held them, and every one of those keys
3244 // Send back approval of order and pubkey to use 3240 // missing from every backup taken beforehand, which for this pre-BIP32
3245 CScript scriptPubKey; 3241 // wallet is how coins are lost.
3246 scriptPubKey << mapReuseKey[pfrom->addr.ip] << OP_CHECKSIG; 3242 //
3247 pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey); 3243 // "submitorder" took a CWalletTx from an unauthenticated peer and, if it
3248 } 3244 // was merely a valid transaction, AddToWallet()'d it. Valid is not the same
3249 3245 // as ours: any peer could write chosen transactions into wallet.dat.
3250 3246 //
3251 else if (strCommand == "submitorder") 3247 // "reply" dispatched to a CRequestTracker callback. Nothing in this tree
3252 { 3248 // has ever called PushRequest, so mapRequests was permanently empty and the
3253 uint256 hashReply; 3249 // handler could only ever be a parser for hostile input.
3254 CWalletTx wtxNew;
3255 vRecv >> hashReply >> wtxNew;
3256
3257 // Broadcast
3258 if (!wtxNew.AcceptWalletTransaction())
3259 {
3260 pfrom->PushMessage("reply", hashReply, (int)1);
3261 return error("submitorder AcceptWalletTransaction() failed, returning error 1");
3262 }
3263 wtxNew.fTimeReceivedIsTxTime = true;
3264 AddToWallet(wtxNew);
3265 wtxNew.RelayWalletTransaction();
3266 mapReuseKey.erase(pfrom->addr.ip);
3267
3268 // Send back confirmation
3269 pfrom->PushMessage("reply", hashReply, (int)0);
3270 }
3271
3272
3273 else if (strCommand == "reply")
3274 {
3275 uint256 hashReply;
3276 vRecv >> hashReply;
3277
3278 CRequestTracker tracker;
3279 CRITICAL_BLOCK(pfrom->cs_mapRequests)
3280 {
3281 map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
3282 if (mi != pfrom->mapRequests.end())
3283 {
3284 tracker = (*mi).second;
3285 pfrom->mapRequests.erase(mi);
3286 }
3287 }
3288 if (!tracker.IsNull())
3289 tracker.fn(tracker.param1, vRecv);
3290 }
3291 3250
3292 3251
3293 else if (strCommand == "ping") 3252 else if (strCommand == "ping")
diff --git a/src/makefile.mingw b/src/makefile.mingw
index e076c49..72f8bbf 100644
--- a/src/makefile.mingw
+++ b/src/makefile.mingw
@@ -40,7 +40,7 @@ IMGUI_OBJS = obj/imgui.o obj/imgui_draw.o obj/imgui_tables.o \
40 obj/imgui_widgets.o obj/imgui_impl_glfw.o obj/imgui_impl_opengl3.o 40 obj/imgui_widgets.o obj/imgui_impl_glfw.o obj/imgui_impl_opengl3.o
41 41
42NODE_OBJS = obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o \ 42NODE_OBJS = obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o \
43 obj/market.o obj/sha.o obj/nostr.o obj/randomx_pow.o \ 43 obj/sha.o obj/nostr.o obj/randomx_pow.o \
44 obj/btfaddr.o obj/btfchan.o obj/btfrv.o obj/btftunnel.o obj/rpc.o \ 44 obj/btfaddr.o obj/btfchan.o obj/btfrv.o obj/btftunnel.o obj/rpc.o \
45 obj/selftest.o obj/bip32.o obj/walletcmd.o 45 obj/selftest.o obj/bip32.o obj/walletcmd.o
46 46
@@ -55,7 +55,7 @@ GUI_OBJS = obj/gui.o obj/main_gui.o obj/bitflash_res.o
55# binary. Nothing crashed here, and nothing would say so if it had. 55# binary. Nothing crashed here, and nothing would say so if it had.
56HEADERS = headers_core.h headers.h util.h main.h serialize.h uint256.h \ 56HEADERS = headers_core.h headers.h util.h main.h serialize.h uint256.h \
57 key.h bignum.h script.h db.h base58.h net.h nostr.h \ 57 key.h bignum.h script.h db.h base58.h net.h nostr.h \
58 randomx_pow.h btfaddr.h btfchan.h btfrv.h btftunnel.h market.h \ 58 randomx_pow.h btfaddr.h btfchan.h btfrv.h btftunnel.h \
59 selftest.h walletcmd.h sockcount.h compat.h font_roboto.h 59 selftest.h walletcmd.h sockcount.h compat.h font_roboto.h
60 60
61all: bitflash.exe 61all: bitflash.exe
diff --git a/src/market.cpp b/src/market.cpp
deleted file mode 100644
index e5d34f4..0000000
--- a/src/market.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
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
5#include "headers.h"
6
7
8
9
10
11
12
13
14
15
16//
17// Global state variables
18//
19
20//// later figure out how these are persisted
21map<uint256, CProduct> mapMyProducts;
22
23
24
25
26map<uint256, CProduct> mapProducts;
27CCriticalSection cs_mapProducts;
28
29bool AdvertInsert(const CProduct& product)
30{
31 uint256 hash = product.GetHash();
32 bool fNew = false;
33 bool fUpdated = false;
34
35 CRITICAL_BLOCK(cs_mapProducts)
36 {
37 // Insert or find existing product
38 pair<map<uint256, CProduct>::iterator, bool> item = mapProducts.insert(make_pair(hash, product));
39 CProduct* pproduct = &(*(item.first)).second;
40 fNew = item.second;
41
42 // Update if newer
43 if (product.nSequence > pproduct->nSequence)
44 {
45 *pproduct = product;
46 fUpdated = true;
47 }
48 }
49
50 //if (fNew)
51 // NotifyProductAdded(hash);
52 //else if (fUpdated)
53 // NotifyProductUpdated(hash);
54
55 return (fNew || fUpdated);
56}
57
58void AdvertErase(const CProduct& product)
59{
60 uint256 hash = product.GetHash();
61 CRITICAL_BLOCK(cs_mapProducts)
62 mapProducts.erase(hash);
63 //NotifyProductDeleted(hash);
64}
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84template<typename T>
85unsigned int Union(T& v1, T& v2)
86{
87 // v1 = v1 union v2
88 // v1 and v2 must be sorted
89 // returns the number of elements added to v1
90
91 ///// need to check that this is equivalent, then delete this comment
92 //vector<unsigned short> vUnion(v1.size() + v2.size());
93 //vUnion.erase(set_union(v1.begin(), v1.end(),
94 // v2.begin(), v2.end(),
95 // vUnion.begin()),
96 // vUnion.end());
97
98 T vUnion;
99 vUnion.reserve(v1.size() + v2.size());
100 set_union(v1.begin(), v1.end(),
101 v2.begin(), v2.end(),
102 back_inserter(vUnion));
103 unsigned int nAdded = vUnion.size() - v1.size();
104 if (nAdded > 0)
105 v1 = vUnion;
106 return nAdded;
107}
108
109void CUser::AddAtom(unsigned short nAtom, bool fOrigin)
110{
111 // Ignore duplicates
112 if (binary_search(vAtomsIn.begin(), vAtomsIn.end(), nAtom) ||
113 find(vAtomsNew.begin(), vAtomsNew.end(), nAtom) != vAtomsNew.end())
114 return;
115
116 //// instead of zero atom, should change to free atom that propagates,
117 //// limited to lower than a certain value like 5 so conflicts quickly
118 // The zero atom never propagates,
119 // new atoms always propagate through the user that created them
120 if (nAtom == 0 || fOrigin)
121 {
122 vector<unsigned short> vTmp(1, nAtom);
123 Union(vAtomsIn, vTmp);
124 if (fOrigin)
125 vAtomsOut.push_back(nAtom);
126 return;
127 }
128
129 vAtomsNew.push_back(nAtom);
130
131 if (vAtomsNew.size() >= nFlowthroughRate || vAtomsOut.empty())
132 {
133 // Select atom to flow through to vAtomsOut
134 vAtomsOut.push_back(vAtomsNew[GetRand(vAtomsNew.size())]);
135
136 // Merge vAtomsNew into vAtomsIn
137 sort(vAtomsNew.begin(), vAtomsNew.end());
138 Union(vAtomsIn, vAtomsNew);
139 vAtomsNew.clear();
140 }
141}
142
143bool AddAtomsAndPropagate(uint256 hashUserStart, const vector<unsigned short>& vAtoms, bool fOrigin)
144{
145 CReviewDB reviewdb;
146 map<uint256, vector<unsigned short> > pmapPropagate[2];
147 pmapPropagate[0][hashUserStart] = vAtoms;
148
149 for (int side = 0; !pmapPropagate[side].empty(); side = 1 - side)
150 {
151 map<uint256, vector<unsigned short> >& mapFrom = pmapPropagate[side];
152 map<uint256, vector<unsigned short> >& mapTo = pmapPropagate[1 - side];
153
154 for (map<uint256, vector<unsigned short> >::iterator mi = mapFrom.begin(); mi != mapFrom.end(); ++mi)
155 {
156 const uint256& hashUser = (*mi).first;
157 const vector<unsigned short>& vReceived = (*mi).second;
158
159 ///// this would be a lot easier on the database if it put the new atom at the beginning of the list,
160 ///// so the change would be right next to the vector size.
161
162 // Read user
163 CUser user;
164 reviewdb.ReadUser(hashUser, user);
165 unsigned int nIn = user.vAtomsIn.size();
166 unsigned int nNew = user.vAtomsNew.size();
167 unsigned int nOut = user.vAtomsOut.size();
168
169 // Add atoms received
170 foreach(unsigned short nAtom, vReceived)
171 user.AddAtom(nAtom, fOrigin);
172 fOrigin = false;
173
174 // Don't bother writing to disk if no changes
175 if (user.vAtomsIn.size() == nIn && user.vAtomsNew.size() == nNew)
176 continue;
177
178 // Propagate
179 if (user.vAtomsOut.size() > nOut)
180 foreach(const uint256& hash, user.vLinksOut)
181 mapTo[hash].insert(mapTo[hash].end(), user.vAtomsOut.begin() + nOut, user.vAtomsOut.end());
182
183 // Write back
184 if (!reviewdb.WriteUser(hashUser, user))
185 return false;
186 }
187 mapFrom.clear();
188 }
189 return true;
190}
191
192
193
194
195
196
197bool CReview::AcceptReview()
198{
199 // Timestamp
200 nTime = GetTime();
201
202 // Check signature
203 if (!CKey::Verify(vchPubKeyFrom, GetSigHash(), vchSig))
204 return false;
205
206 CReviewDB reviewdb;
207
208 // Add review text to recipient
209 vector<CReview> vReviews;
210 reviewdb.ReadReviews(hashTo, vReviews);
211 vReviews.push_back(*this);
212 if (!reviewdb.WriteReviews(hashTo, vReviews))
213 return false;
214
215 // Add link from sender
216 CUser user;
217 uint256 hashFrom = Hash(vchPubKeyFrom.begin(), vchPubKeyFrom.end());
218 reviewdb.ReadUser(hashFrom, user);
219 user.vLinksOut.push_back(hashTo);
220 if (!reviewdb.WriteUser(hashFrom, user))
221 return false;
222
223 reviewdb.Close();
224
225 // Propagate atoms to recipient
226 vector<unsigned short> vZeroAtom(1, 0);
227 if (!AddAtomsAndPropagate(hashTo, user.vAtomsOut.size() ? user.vAtomsOut : vZeroAtom, false))
228 return false;
229
230 return true;
231}
232
233
234
235
236
237bool CProduct::CheckSignature()
238{
239 return (CKey::Verify(vchPubKeyFrom, GetSigHash(), vchSig));
240}
241
242bool CProduct::CheckProduct()
243{
244 if (!CheckSignature())
245 return false;
246
247 // Make sure it's a summary product
248 if (!mapDetails.empty() || !vOrderForm.empty())
249 return false;
250
251 // Look up seller's atom count
252 CReviewDB reviewdb("r");
253 CUser user;
254 reviewdb.ReadUser(GetUserHash(), user);
255 nAtoms = user.GetAtomCount();
256 reviewdb.Close();
257
258 ////// delme, this is now done by AdvertInsert
259 //// Store to memory
260 //CRITICAL_BLOCK(cs_mapProducts)
261 // mapProducts[GetHash()] = *this;
262
263 return true;
264}
diff --git a/src/market.h b/src/market.h
deleted file mode 100644
index b5c8b3b..0000000
--- a/src/market.h
+++ /dev/null
@@ -1,182 +0,0 @@
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 CUser;
6class CReview;
7class CProduct;
8
9static const unsigned int nFlowthroughRate = 2;
10
11
12
13
14bool AdvertInsert(const CProduct& product);
15void AdvertErase(const CProduct& product);
16bool AddAtomsAndPropagate(uint256 hashUserStart, const vector<unsigned short>& vAtoms, bool fOrigin);
17
18
19
20
21
22
23
24
25class CUser
26{
27public:
28 vector<unsigned short> vAtomsIn;
29 vector<unsigned short> vAtomsNew;
30 vector<unsigned short> vAtomsOut;
31 vector<uint256> vLinksOut;
32
33 CUser()
34 {
35 }
36
37 IMPLEMENT_SERIALIZE
38 (
39 if (!(nType & SER_GETHASH))
40 READWRITE(nVersion);
41 READWRITE(vAtomsIn);
42 READWRITE(vAtomsNew);
43 READWRITE(vAtomsOut);
44 READWRITE(vLinksOut);
45 )
46
47 void SetNull()
48 {
49 vAtomsIn.clear();
50 vAtomsNew.clear();
51 vAtomsOut.clear();
52 vLinksOut.clear();
53 }
54
55 uint256 GetHash() const { return SerializeHash(*this); }
56
57
58 int GetAtomCount() const
59 {
60 return (vAtomsIn.size() + vAtomsNew.size());
61 }
62
63 void AddAtom(unsigned short nAtom, bool fOrigin);
64};
65
66
67
68
69
70
71
72class CReview
73{
74public:
75 int nVersion;
76 uint256 hashTo;
77 map<string, string> mapValue;
78 vector<unsigned char> vchPubKeyFrom;
79 vector<unsigned char> vchSig;
80
81 // memory only
82 unsigned int nTime;
83 int nAtoms;
84
85
86 CReview()
87 {
88 nVersion = 1;
89 hashTo = 0;
90 nTime = 0;
91 nAtoms = 0;
92 }
93
94 IMPLEMENT_SERIALIZE
95 (
96 READWRITE(this->nVersion);
97 nVersion = this->nVersion;
98 if (!(nType & SER_DISK))
99 READWRITE(hashTo);
100 READWRITE(mapValue);
101 READWRITE(vchPubKeyFrom);
102 if (!(nType & SER_GETHASH))
103 READWRITE(vchSig);
104 )
105
106 uint256 GetHash() const { return SerializeHash(*this); }
107 uint256 GetSigHash() const { return SerializeHash(*this, SER_GETHASH|SER_SKIPSIG); }
108 uint256 GetUserHash() const { return Hash(vchPubKeyFrom.begin(), vchPubKeyFrom.end()); }
109
110
111 bool AcceptReview();
112};
113
114
115
116
117
118
119
120class CProduct
121{
122public:
123 int nVersion;
124 CAddress addr;
125 map<string, string> mapValue;
126 map<string, string> mapDetails;
127 vector<pair<string, string> > vOrderForm;
128 unsigned int nSequence;
129 vector<unsigned char> vchPubKeyFrom;
130 vector<unsigned char> vchSig;
131
132 // disk only
133 int nAtoms;
134
135 // memory only
136 set<unsigned int> setSources;
137
138 CProduct()
139 {
140 nVersion = 1;
141 nAtoms = 0;
142 nSequence = 0;
143 }
144
145 IMPLEMENT_SERIALIZE
146 (
147 READWRITE(this->nVersion);
148 nVersion = this->nVersion;
149 READWRITE(addr);
150 READWRITE(mapValue);
151 if (!(nType & SER_GETHASH))
152 {
153 READWRITE(mapDetails);
154 READWRITE(vOrderForm);
155 READWRITE(nSequence);
156 }
157 READWRITE(vchPubKeyFrom);
158 if (!(nType & SER_GETHASH))
159 READWRITE(vchSig);
160 if (nType & SER_DISK)
161 READWRITE(nAtoms);
162 )
163
164 uint256 GetHash() const { return SerializeHash(*this); }
165 uint256 GetSigHash() const { return SerializeHash(*this, SER_GETHASH|SER_SKIPSIG); }
166 uint256 GetUserHash() const { return Hash(vchPubKeyFrom.begin(), vchPubKeyFrom.end()); }
167
168
169 bool CheckSignature();
170 bool CheckProduct();
171};
172
173
174
175
176
177
178
179
180extern map<uint256, CProduct> mapProducts;
181extern CCriticalSection cs_mapProducts;
182extern map<uint256, CProduct> mapMyProducts;
diff --git a/src/net.cpp b/src/net.cpp
index 72a7fda..e08f6f7 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -444,28 +444,9 @@ bool GetMyExternalIP(unsigned int& ipRet)
444 444
445 445
446 446
447void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1) 447// AbandonRequests() lived here, sweeping CNode::mapRequests for a callback a
448{ 448// closing dialog had registered. Nothing ever registered one and nothing ever
449 // If the dialog might get closed before the reply comes back, 449// called this, so it went with CRequestTracker.
450 // call this in the destructor so it doesn't get called after it's deleted.
451 CRITICAL_BLOCK(cs_vNodes)
452 {
453 foreach(CNode* pnode, vNodes)
454 {
455 CRITICAL_BLOCK(pnode->cs_mapRequests)
456 {
457 for (map<uint256, CRequestTracker>::iterator mi = pnode->mapRequests.begin(); mi != pnode->mapRequests.end();)
458 {
459 CRequestTracker& tracker = (*mi).second;
460 if (tracker.fn == fn && tracker.param1 == param1)
461 pnode->mapRequests.erase(mi++);
462 else
463 mi++;
464 }
465 }
466 }
467 }
468}
469 450
470 451
471 452
@@ -473,25 +454,10 @@ void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1)
473 454
474 455
475 456
476// 457// The broadcast/subscribe channel system (AnySubscribed, CNode::IsSubscribed,
477// Subscription methods for the broadcast and subscription system. 458// Subscribe, CancelSubscribe) stood here. Its channels were MSG_TABLE and
478// Channel numbers are message numbers, i.e. MSG_TABLE and MSG_PRODUCT. 459// MSG_PRODUCT, there was never an inbound handler for "subscribe",
479// 460// "sub-cancel", "publish" or "pub-cancel", and the objects it carried are gone.
480// The subscription system uses a meet-in-the-middle strategy.
481// With 100,000 nodes, if senders broadcast to 1000 random nodes and receivers
482// subscribe to 1000 random nodes, 99.995% (1 - 0.99^1000) of messages will get through.
483//
484
485bool AnySubscribed(unsigned int nChannel)
486{
487 if (pnodeLocalHost->IsSubscribed(nChannel))
488 return true;
489 CRITICAL_BLOCK(cs_vNodes)
490 foreach(CNode* pnode, vNodes)
491 if (pnode->IsSubscribed(nChannel))
492 return true;
493 return false;
494}
495 461
496void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) 462void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
497{ 463{
@@ -504,55 +470,6 @@ void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd)
504 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd); 470 PushMessage("getblocks", CBlockLocator(pindexBegin), hashEnd);
505} 471}
506 472
507bool CNode::IsSubscribed(unsigned int nChannel)
508{
509 if (nChannel >= vfSubscribe.size())
510 return false;
511 return vfSubscribe[nChannel];
512}
513
514void CNode::Subscribe(unsigned int nChannel, unsigned int nHops)
515{
516 if (nChannel >= vfSubscribe.size())
517 return;
518
519 if (!AnySubscribed(nChannel))
520 {
521 // Relay subscribe
522 CRITICAL_BLOCK(cs_vNodes)
523 foreach(CNode* pnode, vNodes)
524 if (pnode != this)
525 pnode->PushMessage("subscribe", nChannel, nHops);
526 }
527
528 vfSubscribe[nChannel] = true;
529}
530
531void CNode::CancelSubscribe(unsigned int nChannel)
532{
533 if (nChannel >= vfSubscribe.size())
534 return;
535
536 // Prevent from relaying cancel if wasn't subscribed
537 if (!vfSubscribe[nChannel])
538 return;
539 vfSubscribe[nChannel] = false;
540
541 if (!AnySubscribed(nChannel))
542 {
543 // Relay subscription cancel
544 CRITICAL_BLOCK(cs_vNodes)
545 foreach(CNode* pnode, vNodes)
546 if (pnode != this)
547 pnode->PushMessage("sub-cancel", nChannel);
548
549 // Clear memory, no longer subscribed
550 if (nChannel == MSG_PRODUCT)
551 CRITICAL_BLOCK(cs_mapProducts)
552 mapProducts.clear();
553 }
554}
555
556 473
557 474
558 475
@@ -1215,17 +1132,6 @@ void CNode::Disconnect()
1215 BtfCloseSocket(hSocket); 1132 BtfCloseSocket(hSocket);
1216 hSocket = INVALID_SOCKET; 1133 hSocket = INVALID_SOCKET;
1217 1134
1218 // All of a nodes broadcasts and subscriptions are automatically torn down
1219 // when it goes down, so a node has to stay up to keep its broadcast going.
1220
1221 CRITICAL_BLOCK(cs_mapProducts)
1222 for (map<uint256, CProduct>::iterator mi = mapProducts.begin(); mi != mapProducts.end();)
1223 AdvertRemoveSource(this, MSG_PRODUCT, 0, (*(mi++)).second);
1224
1225 // Cancel subscriptions
1226 for (unsigned int nChannel = 0; nChannel < vfSubscribe.size(); nChannel++)
1227 if (vfSubscribe[nChannel])
1228 CancelSubscribe(nChannel);
1229} 1135}
1230 1136
1231 1137
@@ -1350,7 +1256,6 @@ void ThreadSocketHandler2(void* parg)
1350 bool fDelete = false; 1256 bool fDelete = false;
1351 TRY_CRITICAL_BLOCK(pnode->cs_vSend) 1257 TRY_CRITICAL_BLOCK(pnode->cs_vSend)
1352 TRY_CRITICAL_BLOCK(pnode->cs_vRecv) 1258 TRY_CRITICAL_BLOCK(pnode->cs_vRecv)
1353 TRY_CRITICAL_BLOCK(pnode->cs_mapRequests)
1354 TRY_CRITICAL_BLOCK(pnode->cs_inventory) 1259 TRY_CRITICAL_BLOCK(pnode->cs_inventory)
1355 fDelete = true; 1260 fDelete = true;
1356 if (fDelete) 1261 if (fDelete)
diff --git a/src/net.h b/src/net.h
index 0317676..8b0245a 100644
--- a/src/net.h
+++ b/src/net.h
@@ -5,7 +5,6 @@
5class CMessageHeader; 5class CMessageHeader;
6class CAddress; 6class CAddress;
7class CInv; 7class CInv;
8class CRequestTracker;
9class CNode; 8class CNode;
10// Defined in main.h, which is included after this file. Only ever used here as 9// Defined in main.h, which is included after this file. Only ever used here as
11// a pointer, so the forward declaration is enough. 10// a pointer, so the forward declaration is enough.
@@ -14,7 +13,6 @@ class CBlockIndex;
14 13
15 14
16static const unsigned short DEFAULT_PORT = htons(8433); 15static const unsigned short DEFAULT_PORT = htons(8433);
17static const unsigned int PUBLISH_HOPS = 5;
18enum 16enum
19{ 17{
20 NODE_NETWORK = (1 << 0), 18 NODE_NETWORK = (1 << 0),
@@ -214,8 +212,6 @@ void BtfChurnNoteHandshakeTimeout(const string& strBtfAddr, const string& strMee
214void BtfPexCollect(std::vector<std::string>& vDescOut); 212void BtfPexCollect(std::vector<std::string>& vDescOut);
215// Verify descriptors a peer sent and remember the good ones. Returns how many. 213// Verify descriptors a peer sent and remember the good ones. Returns how many.
216int BtfPexAccept(const std::vector<std::string>& vDesc); 214int BtfPexAccept(const std::vector<std::string>& vDesc);
217void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1);
218bool AnySubscribed(unsigned int nChannel);
219void ThreadBitcoinMiner(void* parg); 215void ThreadBitcoinMiner(void* parg);
220// Starts MinerThreadCount() miners; returns how many came up. 216// Starts MinerThreadCount() miners; returns how many came up.
221int StartMinerThreads(); 217int StartMinerThreads();
@@ -489,13 +485,19 @@ public:
489 485
490 486
491 487
488// MSG_REVIEW, MSG_PRODUCT and MSG_TABLE no longer have a handler, a producer
489// or a store -- the marketplace they belonged to is gone. They stay in the
490// enum, and their names stay in ppszTypeName below, because CInv serialises
491// `type` as a plain integer: dropping them would renumber nothing today but
492// would make it tempting to renumber later, and MSG_TX and MSG_BLOCK are wire
493// values shared with every other node. Reserved, never emitted, never served.
492enum 494enum
493{ 495{
494 MSG_TX = 1, 496 MSG_TX = 1,
495 MSG_BLOCK, 497 MSG_BLOCK,
496 MSG_REVIEW, 498 MSG_REVIEW, // reserved, dead
497 MSG_PRODUCT, 499 MSG_PRODUCT, // reserved, dead
498 MSG_TABLE, 500 MSG_TABLE, // reserved, dead
499}; 501};
500 502
501static const char* ppszTypeName[] = 503static const char* ppszTypeName[] =
@@ -582,23 +584,9 @@ public:
582 584
583 585
584 586
585class CRequestTracker 587// CRequestTracker and the PushRequest/"reply" round trip lived here. Nothing
586{ 588// in this tree ever called PushRequest, so the table was always empty and the
587public: 589// "reply" handler was pure inbound parser. Both removed.
588 void (*fn)(void*, CDataStream&);
589 void* param1;
590
591 explicit CRequestTracker(void (*fnIn)(void*, CDataStream&)=NULL, void* param1In=NULL)
592 {
593 fn = fnIn;
594 param1 = param1In;
595 }
596
597 bool IsNull()
598 {
599 return fn == NULL;
600 }
601};
602 590
603 591
604 592
@@ -644,9 +632,6 @@ protected:
644public: 632public:
645 int64 nReleaseTime; 633 int64 nReleaseTime;
646 int64 nDisconnectSince; 634 int64 nDisconnectSince;
647 map<uint256, CRequestTracker> mapRequests;
648 CCriticalSection cs_mapRequests;
649
650 // inventory based relay 635 // inventory based relay
651 set<CInv> setInventoryKnown; 636 set<CInv> setInventoryKnown;
652 set<CInv> setInventoryKnown2; 637 set<CInv> setInventoryKnown2;
@@ -654,9 +639,6 @@ public:
654 CCriticalSection cs_inventory; 639 CCriticalSection cs_inventory;
655 multimap<int64, CInv> mapAskFor; 640 multimap<int64, CInv> mapAskFor;
656 641
657 // publish and subscription
658 vector<char> vfSubscribe;
659
660 // Last "btfpeers" we accepted from this node, to rate-limit the exchange. 642 // Last "btfpeers" we accepted from this node, to rate-limit the exchange.
661 int64 nLastPexRecv; 643 int64 nLastPexRecv;
662 644
@@ -723,7 +705,6 @@ public:
723 strBtfAddr.clear(); 705 strBtfAddr.clear();
724 strBtfMeeting.clear(); 706 strBtfMeeting.clear();
725 nStartingHeight = -1; 707 nStartingHeight = -1;
726 vfSubscribe.assign(256, false);
727 708
728 // Push a version message 709 // Push a version message
729 /// when NTP implemented, change to just nTime = GetAdjustedTime() 710 /// when NTP implemented, change to just nTime = GetAdjustedTime()
@@ -1002,49 +983,6 @@ public:
1002 } 983 }
1003 984
1004 985
1005 void PushRequest(const char* pszCommand,
1006 void (*fn)(void*, CDataStream&), void* param1)
1007 {
1008 uint256 hashReply;
1009 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
1010
1011 CRITICAL_BLOCK(cs_mapRequests)
1012 mapRequests[hashReply] = CRequestTracker(fn, param1);
1013
1014 PushMessage(pszCommand, hashReply);
1015 }
1016
1017 template<typename T1>
1018 void PushRequest(const char* pszCommand, const T1& a1,
1019 void (*fn)(void*, CDataStream&), void* param1)
1020 {
1021 uint256 hashReply;
1022 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
1023
1024 CRITICAL_BLOCK(cs_mapRequests)
1025 mapRequests[hashReply] = CRequestTracker(fn, param1);
1026
1027 PushMessage(pszCommand, hashReply, a1);
1028 }
1029
1030 template<typename T1, typename T2>
1031 void PushRequest(const char* pszCommand, const T1& a1, const T2& a2,
1032 void (*fn)(void*, CDataStream&), void* param1)
1033 {
1034 uint256 hashReply;
1035 RAND_bytes((unsigned char*)&hashReply, sizeof(hashReply));
1036
1037 CRITICAL_BLOCK(cs_mapRequests)
1038 mapRequests[hashReply] = CRequestTracker(fn, param1);
1039
1040 PushMessage(pszCommand, hashReply, a1, a2);
1041 }
1042
1043
1044
1045 bool IsSubscribed(unsigned int nChannel);
1046 void Subscribe(unsigned int nChannel, unsigned int nHops=0);
1047 void CancelSubscribe(unsigned int nChannel);
1048 void Disconnect(); 986 void Disconnect();
1049}; 987};
1050 988
@@ -1101,50 +1039,8 @@ inline void RelayMessage<>(const CInv& inv, const CDataStream& ss)
1101 1039
1102 1040
1103 1041
1104// 1042// The publish/subscribe advert templates that used to close this file
1105// Templates for the publish and subscription system. 1043// (AdvertStartPublish / AdvertStopPublish / AdvertRemoveSource) are gone along
1106// The object being published as T& obj needs to have: 1044// with the marketplace objects they carried. Nothing ever handled an inbound
1107// a set<unsigned int> setSources member 1045// "publish" or "pub-cancel", so the machinery only ever pushed; what it pushed
1108// specializations of AdvertInsert and AdvertErase 1046// was CProduct, which no longer exists.
1109// Currently implemented for CTable and CProduct.
1110//
1111
1112template<typename T>
1113void AdvertStartPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1114{
1115 // Add to sources
1116 obj.setSources.insert(pfrom->addr.ip);
1117
1118 if (!AdvertInsert(obj))
1119 return;
1120
1121 // Relay
1122 CRITICAL_BLOCK(cs_vNodes)
1123 foreach(CNode* pnode, vNodes)
1124 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
1125 pnode->PushMessage("publish", nChannel, nHops, obj);
1126}
1127
1128template<typename T>
1129void AdvertStopPublish(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1130{
1131 uint256 hash = obj.GetHash();
1132
1133 CRITICAL_BLOCK(cs_vNodes)
1134 foreach(CNode* pnode, vNodes)
1135 if (pnode != pfrom && (nHops < PUBLISH_HOPS || pnode->IsSubscribed(nChannel)))
1136 pnode->PushMessage("pub-cancel", nChannel, nHops, hash);
1137
1138 AdvertErase(obj);
1139}
1140
1141template<typename T>
1142void AdvertRemoveSource(CNode* pfrom, unsigned int nChannel, unsigned int nHops, T& obj)
1143{
1144 // Remove a source
1145 obj.setSources.erase(pfrom->addr.ip);
1146
1147 // If no longer supported by any sources, cancel it
1148 if (obj.setSources.empty())
1149 AdvertStopPublish(pfrom, nChannel, nHops, obj);
1150}