X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.cpp;h=f2932804e376bbb5e71a059eccd6d6e4ad04a9b4;hb=da7bbd9dfdb8914977fc254b0c9b1bb3025726c8;hp=8103c8ad82f2bc44e7aee6a06a2c885b7423958f;hpb=e7e6ae210458e37a012d5557cd0267b2d86d9fa8;p=novacoin.git diff --git a/src/main.cpp b/src/main.cpp index 8103c8a..f293280 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,11 +18,6 @@ using namespace boost; // Global state // -// Name of client reported in the 'version' message. Report the same name -// for both bitcoind and bitcoin-qt, to make it harder for attackers to -// target servers or GUI users specifically. -const std::string CLIENT_NAME("Satoshi"); - CCriticalSection cs_setpwalletRegistered; set setpwalletRegistered; @@ -57,22 +52,12 @@ CScript COINBASE_FLAGS; const string strMessageMagic = "Bitcoin Signed Message:\n"; - double dHashesPerSec; int64 nHPSTimerStart; // Settings -int fGenerateBitcoins = false; int64 nTransactionFee = 0; -int fLimitProcessors = false; -int nLimitProcessors = 1; -int fMinimizeToTray = true; -int fMinimizeOnClose = true; -#if USE_UPNP -int fUseUPnP = true; -#else -int fUseUPnP = false; -#endif + ////////////////////////////////////////////////////////////////////////////// @@ -85,16 +70,16 @@ int fUseUPnP = false; void RegisterWallet(CWallet* pwalletIn) { - CRITICAL_BLOCK(cs_setpwalletRegistered) { + LOCK(cs_setpwalletRegistered); setpwalletRegistered.insert(pwalletIn); } } void UnregisterWallet(CWallet* pwalletIn) { - CRITICAL_BLOCK(cs_setpwalletRegistered) { + LOCK(cs_setpwalletRegistered); setpwalletRegistered.erase(pwalletIn); } } @@ -177,13 +162,14 @@ void static ResendWalletTransactions() // mapOrphanTransactions // -void static AddOrphanTx(const CDataStream& vMsg) +void AddOrphanTx(const CDataStream& vMsg) { CTransaction tx; CDataStream(vMsg) >> tx; uint256 hash = tx.GetHash(); if (mapOrphanTransactions.count(hash)) return; + CDataStream* pvMsg = mapOrphanTransactions[hash] = new CDataStream(vMsg); BOOST_FOREACH(const CTxIn& txin, tx.vin) mapOrphanTransactionsByPrev.insert(make_pair(txin.prevout.hash, pvMsg)); @@ -211,6 +197,23 @@ void static EraseOrphanTx(uint256 hash) mapOrphanTransactions.erase(hash); } +int LimitOrphanTxSize(int nMaxOrphans) +{ + int nEvicted = 0; + while (mapOrphanTransactions.size() > nMaxOrphans) + { + // Evict a random orphan: + std::vector randbytes(32); + RAND_bytes(&randbytes[0], 32); + uint256 randomhash(randbytes); + map::iterator it = mapOrphanTransactions.lower_bound(randomhash); + if (it == mapOrphanTransactions.end()) + it = mapOrphanTransactions.begin(); + EraseOrphanTx(it->first); + ++nEvicted; + } + return nEvicted; +} @@ -470,9 +473,11 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi // Do we already have it? uint256 hash = GetHash(); - CRITICAL_BLOCK(cs_mapTransactions) + { + LOCK(cs_mapTransactions); if (mapTransactions.count(hash)) return false; + } if (fCheckInputs) if (txdb.ContainsTx(hash)) return false; @@ -544,8 +549,8 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi static int64 nLastTime; int64 nNow = GetTime(); - CRITICAL_BLOCK(cs) { + LOCK(cs); // Use an exponentially decaying ~10-minute window: dFreeCount *= pow(1.0 - 1.0/600.0, (double)(nNow - nLastTime)); nLastTime = nNow; @@ -568,8 +573,8 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi } // Store transaction in memory - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); if (ptxOld) { printf("AcceptToMemoryPool() : replacing tx %s with new version\n", ptxOld->GetHash().ToString().c_str()); @@ -587,12 +592,6 @@ bool CTransaction::AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs, bool* pfMi return true; } -bool CTransaction::AcceptToMemoryPool(bool fCheckInputs, bool* pfMissingInputs) -{ - CTxDB txdb("r"); - return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs); -} - uint64 nPooledTx = 0; bool CTransaction::AddToMemoryPoolUnchecked() @@ -600,8 +599,8 @@ bool CTransaction::AddToMemoryPoolUnchecked() printf("AcceptToMemoryPoolUnchecked(): size %lu\n", mapTransactions.size()); // Add to memory pool without checking anything. Don't call this directly, // call AcceptToMemoryPool to properly check the transaction first. - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); uint256 hash = GetHash(); mapTransactions[hash] = *this; for (int i = 0; i < vin.size(); i++) @@ -616,8 +615,8 @@ bool CTransaction::AddToMemoryPoolUnchecked() bool CTransaction::RemoveFromMemoryPool() { // Remove transaction from memory pool - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); uint256 hash = GetHash(); if (mapTransactions.count(hash)) { @@ -694,8 +693,9 @@ bool CMerkleTx::AcceptToMemoryPool() bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) { - CRITICAL_BLOCK(cs_mapTransactions) + { + LOCK(cs_mapTransactions); // Add previous supporting transactions first BOOST_FOREACH(CMerkleTx& tx, vtxPrev) { @@ -968,8 +968,10 @@ bool CTransaction::DisconnectInputs(CTxDB& txdb) } // Remove transaction from index - if (!txdb.EraseTxIndex(*this)) - return error("DisconnectInputs() : EraseTxPos failed"); + // This can fail if a duplicate of this transaction was in a chain that got + // reorganized away. This is only possible if this transaction was completely + // spent, so erasing it would be a no-op anway. + txdb.EraseTxIndex(*this); return true; } @@ -1014,8 +1016,8 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTes if (!fFound || txindex.pos == CDiskTxPos(1,1,1)) { // Get prev tx from single transactions in memory - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); if (!mapTransactions.count(prevout.hash)) return error("FetchInputs() : %s mapTransactions prev not found %s", GetHash().ToString().substr(0,10).c_str(), prevout.hash.ToString().substr(0,10).c_str()); txPrev = mapTransactions[prevout.hash]; @@ -1138,7 +1140,14 @@ bool CTransaction::ConnectInputs(MapPrevTx inputs, { // Verify signature if (!VerifySignature(txPrev, *this, i, fStrictPayToScriptHash, 0)) + { + // only during transition phase for P2SH: do not invoke anti-DoS code for + // potentially old clients relaying bad P2SH transactions + if (fStrictPayToScriptHash && VerifySignature(txPrev, *this, i, false, 0)) + return error("ConnectInputs() : %s P2SH VerifySignature failed", GetHash().ToString().substr(0,10).c_str()); + return DoS(100,error("ConnectInputs() : %s VerifySignature failed", GetHash().ToString().substr(0,10).c_str())); + } } // Mark outpoints as spent @@ -1173,8 +1182,8 @@ bool CTransaction::ClientConnectInputs() return false; // Take over previous transactions' spent pointers - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK(cs_mapTransactions); int64 nValueIn = 0; for (int i = 0; i < vin.size(); i++) { @@ -1241,12 +1250,33 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex) if (!CheckBlock()) return false; - // To avoid being on the short end of a block-chain split, - // don't do secondary validation of pay-to-script-hash transactions - // until blocks with timestamps after paytoscripthashtime (see init.cpp for default). - // This code can be removed once a super-majority of the network has upgraded. - int64 nEvalSwitchTime = GetArg("-paytoscripthashtime", std::numeric_limits::max()); - bool fStrictPayToScriptHash = (pindex->nTime >= nEvalSwitchTime); + // Do not allow blocks that contain transactions which 'overwrite' older transactions, + // unless those are already completely spent. + // If such overwrites are allowed, coinbases and transactions depending upon those + // can be duplicated to remove the ability to spend the first instance -- even after + // being sent to another address. + // See BIP30 and http://r6.ca/blog/20120206T005236Z.html for more information. + // This logic is not necessary for memory pool transactions, as AcceptToMemoryPool + // already refuses previously-known transaction id's entirely. + // This rule applies to all blocks whose timestamp is after March 15, 2012, 0:00 UTC. + // On testnet it is enabled as of februari 20, 2012, 0:00 UTC. + if (pindex->nTime > 1331769600 || (fTestNet && pindex->nTime > 1329696000)) + { + BOOST_FOREACH(CTransaction& tx, vtx) + { + CTxIndex txindexOld; + if (txdb.ReadTxIndex(tx.GetHash(), txindexOld)) + { + BOOST_FOREACH(CDiskTxPos &pos, txindexOld.vSpent) + if (pos.IsNull()) + return false; + } + } + } + + // BIP16 didn't become active until Apr 1 2012 (Feb 15 on testnet) + int64 nBIP16SwitchTime = fTestNet ? 1329264000 : 1333238400; + bool fStrictPayToScriptHash = (pindex->nTime >= nBIP16SwitchTime); //// issue here: it doesn't know the version unsigned int nTxPos = pindex->nBlockPos + ::GetSerializeSize(CBlock(), SER_DISK) - 1 + GetSizeOfCompactSize(vtx.size()); @@ -1345,6 +1375,9 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) vConnect.push_back(pindex); reverse(vConnect.begin(), vConnect.end()); + printf("REORGANIZE: Disconnect %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Connect %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + // Disconnect shorter branch vector vResurrect; BOOST_FOREACH(CBlockIndex* pindex, vDisconnect) @@ -1353,7 +1386,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) if (!block.ReadFromDisk(pindex)) return error("Reorganize() : ReadFromDisk for disconnect failed"); if (!block.DisconnectBlock(txdb, pindex)) - return error("Reorganize() : DisconnectBlock failed"); + return error("Reorganize() : DisconnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); // Queue memory transactions to resurrect BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -1373,7 +1406,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) { // Invalid block txdb.TxnAbort(); - return error("Reorganize() : ConnectBlock failed"); + return error("Reorganize() : ConnectBlock %s failed", pindex->GetBlockHash().ToString().substr(0,20).c_str()); } // Queue memory transactions to delete @@ -1405,8 +1438,7 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) BOOST_FOREACH(CTransaction& tx, vDelete) tx.RemoveFromMemoryPool(); - printf("REORGANIZE: Disconnected %i blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); - printf("REORGANIZE: Connected %i blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: done\n"); return true; } @@ -1420,6 +1452,31 @@ runCommand(std::string strCommand) printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr); } +// Called from inside SetBestChain: attaches a block to the new best chain being built +bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew) +{ + uint256 hash = GetHash(); + + // Adding to current best branch + if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) + { + txdb.TxnAbort(); + InvalidChainFound(pindexNew); + return false; + } + if (!txdb.TxnCommit()) + return error("SetBestChain() : TxnCommit failed"); + + // Add to current best branch + pindexNew->pprev->pnext = pindexNew; + + // Delete redundant memory transactions + BOOST_FOREACH(CTransaction& tx, vtx) + tx.RemoveFromMemoryPool(); + + return true; +} + bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) { uint256 hash = GetHash(); @@ -1434,32 +1491,50 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } else if (hashPrevBlock == hashBestChain) { - // Adding to current best branch - if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash)) + if (!SetBestChainInner(txdb, pindexNew)) + return error("SetBestChain() : SetBestChainInner failed"); + } + else + { + // the first block in the new chain that will cause it to become the new best chain + CBlockIndex *pindexIntermediate = pindexNew; + + // list of blocks that need to be connected afterwards + std::vector vpindexSecondary; + + // Reorganize is costly in terms of db load, as it works in a single db transaction. + // Try to limit how much needs to be done inside + while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork) { - txdb.TxnAbort(); - InvalidChainFound(pindexNew); - return error("SetBestChain() : ConnectBlock failed"); + vpindexSecondary.push_back(pindexIntermediate); + pindexIntermediate = pindexIntermediate->pprev; } - if (!txdb.TxnCommit()) - return error("SetBestChain() : TxnCommit failed"); - // Add to current best branch - pindexNew->pprev->pnext = pindexNew; + if (!vpindexSecondary.empty()) + printf("Postponing %i reconnects\n", vpindexSecondary.size()); - // Delete redundant memory transactions - BOOST_FOREACH(CTransaction& tx, vtx) - tx.RemoveFromMemoryPool(); - } - else - { - // New best branch - if (!Reorganize(txdb, pindexNew)) + // Switch to new best branch + if (!Reorganize(txdb, pindexIntermediate)) { txdb.TxnAbort(); InvalidChainFound(pindexNew); return error("SetBestChain() : Reorganize failed"); } + + // Connect futher blocks + BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary) + { + CBlock block; + if (!block.ReadFromDisk(pindex)) + { + printf("SetBestChain() : ReadFromDisk failed\n"); + break; + } + txdb.TxnBegin(); + // errors now are not fatal, we still did a reorganisation to a new chain in a valid way + if (!block.SetBestChainInner(txdb, pindex)) + break; + } } // Update best block in wallet (so we can detect restored wallets) @@ -1626,11 +1701,14 @@ bool CBlock::AcceptBlock() return error("AcceptBlock() : AddToBlockIndex failed"); // Relay inventory, but don't relay old inventory during initial block download + int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); if (hashBestChain == hash) - CRITICAL_BLOCK(cs_vNodes) - BOOST_FOREACH(CNode* pnode, vNodes) - if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 140700)) - pnode->PushInventory(CInv(MSG_BLOCK, hash)); + { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hash)); + } return true; } @@ -1655,7 +1733,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) int64 deltaTime = pblock->GetBlockTime() - pcheckpoint->nTime; if (deltaTime < 0) { - pfrom->Misbehaving(100); + if (pfrom) + pfrom->Misbehaving(100); return error("ProcessBlock() : block with timestamp before last checkpoint"); } CBigNum bnNewBlock; @@ -1664,7 +1743,8 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime)); if (bnNewBlock > bnRequired) { - pfrom->Misbehaving(100); + if (pfrom) + pfrom->Misbehaving(100); return error("ProcessBlock() : block with too little proof-of-work"); } } @@ -1729,8 +1809,8 @@ bool CheckDiskSpace(uint64 nAdditionalBytes) string strMessage = _("Warning: Disk space is low "); strMiscWarning = strMessage; printf("*** %s\n", strMessage.c_str()); - ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION); - CreateThread(Shutdown, NULL); + ThreadSafeMessageBox(strMessage, "Bitcoin", wxOK | wxICON_EXCLAMATION | wxMODAL); + QueueShutdown(); return false; } return true; @@ -1740,7 +1820,7 @@ FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszM { if (nFile == -1) return NULL; - FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode); + FILE* file = fopen((GetDataDir() / strprintf("blk%04d.dat", nFile)).string().c_str(), pszMode); if (!file) return NULL; if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w')) @@ -1970,8 +2050,8 @@ string GetWarnings(string strFor) } // Alerts - CRITICAL_BLOCK(cs_mapAlerts) { + LOCK(cs_mapAlerts); BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) { const CAlert& alert = item.second; @@ -1998,8 +2078,8 @@ bool CAlert::ProcessAlert() if (!IsInEffect()) return false; - CRITICAL_BLOCK(cs_mapAlerts) { + LOCK(cs_mapAlerts); // Cancel previous alerts for (map::iterator mi = mapAlerts.begin(); mi != mapAlerts.end();) { @@ -2105,7 +2185,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe; if (pfrom->nVersion < 209) { - // Since Februari 20, 2012, the protocol is initiated at version 209, + // Since February 20, 2012, the protocol is initiated at version 209, // and earlier versions are no longer supported printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion); pfrom->fDisconnect = true; @@ -2153,11 +2233,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Get recent addresses - if (pfrom->nVersion >= 31402 || mapAddresses.size() < 1000) + if (pfrom->nVersion >= 31402 || addrman.size() < 1000) { pfrom->PushMessage("getaddr"); pfrom->fGetAddr = true; } + addrman.Good(pfrom->addr); + } else { + if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom) + { + addrman.Add(addrFrom, addrFrom); + addrman.Good(addrFrom); + } } // Ask the first connected node for block updates @@ -2171,9 +2258,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Relay alerts - CRITICAL_BLOCK(cs_mapAlerts) + { + LOCK(cs_mapAlerts); BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts) item.second.RelayTo(pfrom); + } pfrom->fSuccessfullyConnected = true; @@ -2203,7 +2292,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> vAddr; // Don't want addr from older versions unless seeding - if (pfrom->nVersion < 31402 && mapAddresses.size() > 1000) + if (pfrom->nVersion < 31402 && addrman.size() > 1000) return true; if (vAddr.size() > 1000) { @@ -2212,8 +2301,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } // Store the new addresses - CAddrDB addrDB; - addrDB.TxnBegin(); int64 nNow = GetAdjustedTime(); int64 nSince = nNow - 10 * 60; BOOST_FOREACH(CAddress& addr, vAddr) @@ -2225,13 +2312,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) continue; if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60) addr.nTime = nNow - 5 * 24 * 60 * 60; - AddAddress(addr, 2 * 60 * 60, &addrDB); pfrom->AddAddressKnown(addr); if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable()) { // Relay to a limited number of other nodes - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); // Use deterministic randomness to send to the same nodes for 24 hours // at a time so the setAddrKnowns of the chosen nodes prevent repeats static uint256 hashSalt; @@ -2257,7 +2343,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } } } - addrDB.TxnCommit(); // Save addresses (it's ok if this fails) + addrman.Add(vAddr, pfrom->addr, 2 * 60 * 60); if (vAddr.size() < 1000) pfrom->fGetAddr = false; } @@ -2274,8 +2360,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } CTxDB txdb("r"); - BOOST_FOREACH(const CInv& inv, vInv) + for (int nInv = 0; nInv < vInv.size(); nInv++) { + const CInv &inv = vInv[nInv]; + if (fShutdown) return true; pfrom->AddInventoryKnown(inv); @@ -2284,9 +2372,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (fDebug) printf(" got inventory: %s %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new"); - if (!fAlreadyHave) + // Always request the last block in an inv bundle (even if we already have it), as it is the + // trigger for the other side to send further invs. If we are stuck on a (very long) side chain, + // this is necessary to connect earlier received orphan blocks to the chain again. + if (!fAlreadyHave || (inv.type == MSG_BLOCK && nInv==vInv.size()-1)) pfrom->AskFor(inv); - else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) + if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); // Track requests for our stuff @@ -2337,8 +2428,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (inv.IsKnownType()) { // Send stream from relay memory - CRITICAL_BLOCK(cs_mapRelay) { + LOCK(cs_mapRelay); map::iterator mi = mapRelay.find(inv); if (mi != mapRelay.end()) pfrom->PushMessage(inv.GetCommand(), (*mi).second); @@ -2413,8 +2504,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) } vector vHeaders; - int nLimit = 2000 + locator.GetDistanceBack(); - printf("getheaders %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit); + int nLimit = 2000; + printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str()); for (; pindex; pindex = pindex->pnext) { vHeaders.push_back(pindex->GetBlockHeader()); @@ -2429,6 +2520,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { vector vWorkQueue; CDataStream vMsg(vRecv); + CTxDB txdb("r"); CTransaction tx; vRecv >> tx; @@ -2436,7 +2528,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) pfrom->AddInventoryKnown(inv); bool fMissingInputs = false; - if (tx.AcceptToMemoryPool(true, &fMissingInputs)) + if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs)) { SyncWithWallets(tx, NULL, true); RelayMessage(inv, vMsg); @@ -2456,7 +2548,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CDataStream(vMsg) >> tx; CInv inv(MSG_TX, tx.GetHash()); - if (tx.AcceptToMemoryPool(true)) + if (tx.AcceptToMemoryPool(txdb, true)) { printf(" accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); SyncWithWallets(tx, NULL, true); @@ -2474,6 +2566,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { printf("storing orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str()); AddOrphanTx(vMsg); + + // DoS prevention: do not allow mapOrphanTransactions to grow unbounded + int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS); + if (nEvicted > 0) + printf("mapOrphan overflow, removed %d tx\n", nEvicted); } if (tx.nDoS) pfrom->Misbehaving(tx.nDoS); } @@ -2498,25 +2595,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else if (strCommand == "getaddr") { - // Nodes rebroadcast an addr every 24 hours pfrom->vAddrToSend.clear(); - int64 nSince = GetAdjustedTime() - 3 * 60 * 60; // in the last 3 hours - CRITICAL_BLOCK(cs_mapAddresses) - { - unsigned int nCount = 0; - BOOST_FOREACH(const PAIRTYPE(vector, CAddress)& item, mapAddresses) - { - const CAddress& addr = item.second; - if (addr.nTime > nSince) - nCount++; - } - BOOST_FOREACH(const PAIRTYPE(vector, CAddress)& item, mapAddresses) - { - const CAddress& addr = item.second; - if (addr.nTime > nSince && GetRand(nCount) < 2500) - pfrom->PushAddress(addr); - } - } + vector vAddr = addrman.GetAddr(); + BOOST_FOREACH(const CAddress &addr, vAddr) + pfrom->PushAddress(addr); } @@ -2553,8 +2635,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) vRecv >> hashReply; CRequestTracker tracker; - CRITICAL_BLOCK(pfrom->cs_mapRequests) { + LOCK(pfrom->cs_mapRequests); map::iterator mi = pfrom->mapRequests.find(hashReply); if (mi != pfrom->mapRequests.end()) { @@ -2581,9 +2663,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { // Relay pfrom->setKnown.insert(alert.GetHash()); - CRITICAL_BLOCK(cs_vNodes) + { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) alert.RelayTo(pnode); + } } } @@ -2682,8 +2766,10 @@ bool ProcessMessages(CNode* pfrom) bool fRet = false; try { - CRITICAL_BLOCK(cs_main) + { + LOCK(cs_main); fRet = ProcessMessage(pfrom, strCommand, vMsg); + } if (fShutdown) return true; } @@ -2721,8 +2807,8 @@ bool ProcessMessages(CNode* pfrom) bool SendMessages(CNode* pto, bool fSendTrickle) { - CRITICAL_BLOCK(cs_main) { + LOCK(cs_main); // Don't send anything until we get their version message if (pto->nVersion == 0) return true; @@ -2738,8 +2824,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle) static int64 nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { - CRITICAL_BLOCK(cs_vNodes) { + LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) { // Periodically clear setAddrKnown to allow refresh broadcasts @@ -2758,35 +2844,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) nLastRebroadcast = GetTime(); } - // Clear out old addresses periodically so it's not too much work at once - static int64 nLastClear; - if (nLastClear == 0) - nLastClear = GetTime(); - if (GetTime() - nLastClear > 10 * 60 && vNodes.size() >= 3) - { - nLastClear = GetTime(); - CRITICAL_BLOCK(cs_mapAddresses) - { - CAddrDB addrdb; - int64 nSince = GetAdjustedTime() - 14 * 24 * 60 * 60; - for (map, CAddress>::iterator mi = mapAddresses.begin(); - mi != mapAddresses.end();) - { - const CAddress& addr = (*mi).second; - if (addr.nTime < nSince) - { - if (mapAddresses.size() < 1000 || GetTime() > nLastClear + 20) - break; - addrdb.EraseAddress(addr); - mapAddresses.erase(mi++); - } - else - mi++; - } - } - } - - // // Message: addr // @@ -2819,8 +2876,8 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // vector vInv; vector vInvWait; - CRITICAL_BLOCK(pto->cs_inventory) { + LOCK(pto->cs_inventory); vInv.reserve(pto->vInventoryToSend.size()); vInvWait.reserve(pto->vInventoryToSend.size()); BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend) @@ -3035,9 +3092,8 @@ CBlock* CreateNewBlock(CReserveKey& reservekey) // Collect memory pool transactions into the block int64 nFees = 0; - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapTransactions) { + LOCK2(cs_main, cs_mapTransactions); CTxDB txdb("r"); // Priority order to process transactions @@ -3265,8 +3321,8 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); // Found a solution - CRITICAL_BLOCK(cs_main) { + LOCK(cs_main); if (pblock->hashPrevBlock != hashBestChain) return error("BitcoinMiner : generated block is stale"); @@ -3274,8 +3330,10 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) reservekey.KeepKey(); // Track how many getdata requests this block gets - CRITICAL_BLOCK(wallet.cs_wallet) + { + LOCK(wallet.cs_wallet); wallet.mapRequestCount[pblock->GetHash()] = 0; + } // Process this block the same as if we had received it from another node if (!ProcessBlock(NULL, pblock)) @@ -3287,6 +3345,10 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) void static ThreadBitcoinMiner(void* parg); +static bool fGenerateBitcoins = false; +static bool fLimitProcessors = false; +static int nLimitProcessors = -1; + void static BitcoinMiner(CWallet *pwallet) { printf("BitcoinMiner started\n"); @@ -3298,8 +3360,6 @@ void static BitcoinMiner(CWallet *pwallet) while (fGenerateBitcoins) { - if (AffinityBugWorkaround(ThreadBitcoinMiner)) - return; if (fShutdown) return; while (vNodes.empty() || IsInitialBlockDownload()) @@ -3387,15 +3447,13 @@ void static BitcoinMiner(CWallet *pwallet) if (GetTimeMillis() - nHPSTimerStart > 4000) { static CCriticalSection cs; - CRITICAL_BLOCK(cs) { + LOCK(cs); if (GetTimeMillis() - nHPSTimerStart > 4000) { dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart); nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; - string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0); - UIThreadCall(boost::bind(CalledSetStatusBar, strStatus, 0)); static int64 nLogTime; if (GetTime() - nLogTime > 30 * 60) { @@ -3452,7 +3510,6 @@ void static ThreadBitcoinMiner(void* parg) vnThreadsRunning[THREAD_MINER]--; PrintException(NULL, "ThreadBitcoinMiner()"); } - UIThreadCall(boost::bind(CalledSetStatusBar, "", 0)); nHPSTimerStart = 0; if (vnThreadsRunning[THREAD_MINER] == 0) dHashesPerSec = 0; @@ -3462,13 +3519,13 @@ void static ThreadBitcoinMiner(void* parg) void GenerateBitcoins(bool fGenerate, CWallet* pwallet) { - if (fGenerateBitcoins != fGenerate) - { - fGenerateBitcoins = fGenerate; - WriteSetting("fGenerateBitcoins", fGenerateBitcoins); - MainFrameRepaint(); - } - if (fGenerateBitcoins) + fGenerateBitcoins = fGenerate; + nLimitProcessors = GetArg("-genproclimit", -1); + if (nLimitProcessors == 0) + fGenerateBitcoins = false; + fLimitProcessors = (nLimitProcessors != -1); + + if (fGenerate) { int nProcessors = boost::thread::hardware_concurrency(); printf("%d processors\n", nProcessors);