diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-08-19 18:17:06 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-08-23 04:37:36 +0000 |
| commit | a7744058c49b1ba2c605f9e8380d9c3e8665bbc0 (patch) | |
| tree | c0128ca95c6d761689e299c64e5d27b86f1c5e32 | |
| parent | ee7613be2f1d679c7ea6e3948c44110313d230b1 (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)
| -rw-r--r-- | src/Makefile | 4 | ||||
| -rw-r--r-- | src/db.cpp | 16 | ||||
| -rw-r--r-- | src/db.h | 23 | ||||
| -rw-r--r-- | src/headers_core.h | 1 | ||||
| -rw-r--r-- | src/main.cpp | 115 | ||||
| -rw-r--r-- | src/makefile.mingw | 4 | ||||
| -rw-r--r-- | src/market.cpp | 264 | ||||
| -rw-r--r-- | src/market.h | 182 | ||||
| -rw-r--r-- | src/net.cpp | 109 | ||||
| -rw-r--r-- | src/net.h | 138 |
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. |
| 49 | HEADERS = headers_core.h headers.h util.h main.h serialize.h uint256.h \ | 49 | HEADERS = 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 | ||
| 54 | IMGUI_OBJS = obj/imgui.o obj/imgui_draw.o obj/imgui_tables.o \ | 54 | IMGUI_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 | ||
| 57 | NODE_OBJS = obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o \ | 57 | NODE_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 | ||
| @@ -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 | ||
| 604 | bool 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 | |||
| 610 | bool 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 | ||
| @@ -8,8 +8,6 @@ class CTxIndex; | |||
| 8 | class CDiskBlockIndex; | 8 | class CDiskBlockIndex; |
| 9 | class CDiskTxPos; | 9 | class CDiskTxPos; |
| 10 | class COutPoint; | 10 | class COutPoint; |
| 11 | class CUser; | ||
| 12 | class CReview; | ||
| 13 | class CAddress; | 11 | class CAddress; |
| 14 | class CWalletTx; | 12 | class CWalletTx; |
| 15 | 13 | ||
| @@ -314,27 +312,6 @@ public: | |||
| 314 | 312 | ||
| 315 | 313 | ||
| 316 | 314 | ||
| 317 | class CReviewDB : public CDB | ||
| 318 | { | ||
| 319 | public: | ||
| 320 | CReviewDB(const char* pszMode="r+", bool fTxn=false) : CDB("reviews.dat", pszMode, fTxn) { } | ||
| 321 | private: | ||
| 322 | CReviewDB(const CReviewDB&); | ||
| 323 | void operator=(const CReviewDB&); | ||
| 324 | public: | ||
| 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) |
| 72 | void MainFrameRepaint(); | 71 | void 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 | ||
| 2943 | bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | 2944 | bool 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 | ||
| 42 | NODE_OBJS = obj/util.o obj/script.o obj/db.o obj/net.o obj/main.o \ | 42 | NODE_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. |
| 56 | HEADERS = headers_core.h headers.h util.h main.h serialize.h uint256.h \ | 56 | HEADERS = 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 | ||
| 61 | all: bitflash.exe | 61 | all: 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 | ||
| 21 | map<uint256, CProduct> mapMyProducts; | ||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | |||
| 26 | map<uint256, CProduct> mapProducts; | ||
| 27 | CCriticalSection cs_mapProducts; | ||
| 28 | |||
| 29 | bool 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 | |||
| 58 | void 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 | |||
| 84 | template<typename T> | ||
| 85 | unsigned 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 | |||
| 109 | void 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 | |||
| 143 | bool 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 | |||
| 197 | bool 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 | |||
| 237 | bool CProduct::CheckSignature() | ||
| 238 | { | ||
| 239 | return (CKey::Verify(vchPubKeyFrom, GetSigHash(), vchSig)); | ||
| 240 | } | ||
| 241 | |||
| 242 | bool 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 | |||
| 5 | class CUser; | ||
| 6 | class CReview; | ||
| 7 | class CProduct; | ||
| 8 | |||
| 9 | static const unsigned int nFlowthroughRate = 2; | ||
| 10 | |||
| 11 | |||
| 12 | |||
| 13 | |||
| 14 | bool AdvertInsert(const CProduct& product); | ||
| 15 | void AdvertErase(const CProduct& product); | ||
| 16 | bool AddAtomsAndPropagate(uint256 hashUserStart, const vector<unsigned short>& vAtoms, bool fOrigin); | ||
| 17 | |||
| 18 | |||
| 19 | |||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | |||
| 24 | |||
| 25 | class CUser | ||
| 26 | { | ||
| 27 | public: | ||
| 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 | |||
| 72 | class CReview | ||
| 73 | { | ||
| 74 | public: | ||
| 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 | |||
| 120 | class CProduct | ||
| 121 | { | ||
| 122 | public: | ||
| 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 | |||
| 180 | extern map<uint256, CProduct> mapProducts; | ||
| 181 | extern CCriticalSection cs_mapProducts; | ||
| 182 | extern 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 | ||
| 447 | void 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 | |||
| 485 | bool 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 | ||
| 496 | void CNode::PushGetBlocks(CBlockIndex* pindexBegin, uint256 hashEnd) | 462 | void 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 | ||
| 507 | bool CNode::IsSubscribed(unsigned int nChannel) | ||
| 508 | { | ||
| 509 | if (nChannel >= vfSubscribe.size()) | ||
| 510 | return false; | ||
| 511 | return vfSubscribe[nChannel]; | ||
| 512 | } | ||
| 513 | |||
| 514 | void 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 | |||
| 531 | void 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) |
| @@ -5,7 +5,6 @@ | |||
| 5 | class CMessageHeader; | 5 | class CMessageHeader; |
| 6 | class CAddress; | 6 | class CAddress; |
| 7 | class CInv; | 7 | class CInv; |
| 8 | class CRequestTracker; | ||
| 9 | class CNode; | 8 | class 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 | ||
| 16 | static const unsigned short DEFAULT_PORT = htons(8433); | 15 | static const unsigned short DEFAULT_PORT = htons(8433); |
| 17 | static const unsigned int PUBLISH_HOPS = 5; | ||
| 18 | enum | 16 | enum |
| 19 | { | 17 | { |
| 20 | NODE_NETWORK = (1 << 0), | 18 | NODE_NETWORK = (1 << 0), |
| @@ -214,8 +212,6 @@ void BtfChurnNoteHandshakeTimeout(const string& strBtfAddr, const string& strMee | |||
| 214 | void BtfPexCollect(std::vector<std::string>& vDescOut); | 212 | void 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. |
| 216 | int BtfPexAccept(const std::vector<std::string>& vDesc); | 214 | int BtfPexAccept(const std::vector<std::string>& vDesc); |
| 217 | void AbandonRequests(void (*fn)(void*, CDataStream&), void* param1); | ||
| 218 | bool AnySubscribed(unsigned int nChannel); | ||
| 219 | void ThreadBitcoinMiner(void* parg); | 215 | void ThreadBitcoinMiner(void* parg); |
| 220 | // Starts MinerThreadCount() miners; returns how many came up. | 216 | // Starts MinerThreadCount() miners; returns how many came up. |
| 221 | int StartMinerThreads(); | 217 | int 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. | ||
| 492 | enum | 494 | enum |
| 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 | ||
| 501 | static const char* ppszTypeName[] = | 503 | static const char* ppszTypeName[] = |
| @@ -582,23 +584,9 @@ public: | |||
| 582 | 584 | ||
| 583 | 585 | ||
| 584 | 586 | ||
| 585 | class 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 |
| 587 | public: | 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: | |||
| 644 | public: | 632 | public: |
| 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 | |||
| 1112 | template<typename T> | ||
| 1113 | void 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 | |||
| 1128 | template<typename T> | ||
| 1129 | void 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 | |||
| 1141 | template<typename T> | ||
| 1142 | void 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 | } | ||