upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/market.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-19 18:17:06 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-19 22:48:27 +0000
commit11766bec0ea465da263f78a6f473ca792da59280 (patch)
treef07c7eecabdf6a0b5f2299447dcf957472e7ef58 /src/market.cpp
parent88d30ade28d6836e64d0157da57896bdb320e8a2 (diff)
net: stop serving the 2009 marketplace to anonymous peers
Four inherited handlers took attacker-controlled input and wrote to disk with nothing authorising it. None of them had a caller left anywhere in the tree, so all four were reachable only from the outside. checkorder called GenerateNewKey() -- AddKey(), a wallet.dat write -- for any peer that asked, and handed back the pubkey. Its comment claims the cache keeps one key per ip, and on a 2009 network of routable addresses it did. Not here: inbound peers arrive through a rendezvous tunnel and are tagged by BtfMarkerAddr() over three random bytes, so addr.ip is fresh every connection and the cache never hits. Reconnect in a loop and the node mints a key per connection, none of them in any backup taken beforehand, which for a pre-BIP32 wallet is how coins go missing. The map holding them was static and never trimmed. submitorder AddToWallet()'d a CWalletTx from any peer that sent one. It had to be a valid transaction; it did not have to be ours. review checked a signature the sender made with its own key, which proves possession and authorises nothing, then appended to reviews.dat by reading the whole vector, pushing one entry and writing it all back -- quadratic disk on an unbounded map<string,string> off the socket -- then walked a link graph the same peer supplied and relayed the message to every other node. reply dispatched into CRequestTracker. Nothing ever called PushRequest, so the table was permanently empty and the handler was a parser and nothing else. Removed with the subsystem behind them: market.cpp, CProduct, CReview, CUser, CReviewDB, the advert publish templates and the subscribe channel machinery, none of which had an inbound handler either. MSG_REVIEW, MSG_PRODUCT and MSG_TABLE stay in the inv enum, unserved: CInv puts type on the wire as an integer and MSG_TX and MSG_BLOCK are shared with every other node. Unknown commands are already ignored for extensibility, so peers still running these lose nothing but an answer they never asked for. Verified by a clean build of bitflash-node. (cherry picked from commit ad9c393866c007a115f32d70a9017ce91066a7d1)
Diffstat (limited to 'src/market.cpp')
-rw-r--r--src/market.cpp264
1 files changed, 0 insertions, 264 deletions
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}