diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 159 |
1 files changed, 103 insertions, 56 deletions
diff --git a/src/main.cpp b/src/main.cpp index 33b57a5285..5cfb05b0d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -921,6 +921,17 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa REJECT_HIGHFEE, "absurdly-high-fee", strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000)); + // Calculate in-mempool ancestors, up to a limit. + CTxMemPool::setEntries setAncestors; + size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); + size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000; + size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); + size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; + std::string errString; + if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { + return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString); + } + // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) @@ -942,7 +953,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // Store transaction in memory - pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); + pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload()); } SyncWithWallets(tx, NULL); @@ -954,47 +965,45 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) { CBlockIndex *pindexSlow = NULL; + + LOCK(cs_main); + + if (mempool.lookup(hash, txOut)) { - LOCK(cs_main); - { - if (mempool.lookup(hash, txOut)) - { - return true; - } - } + return true; + } - if (fTxIndex) { - CDiskTxPos postx; - if (pblocktree->ReadTxIndex(hash, postx)) { - CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); - if (file.IsNull()) - return error("%s: OpenBlockFile failed", __func__); - CBlockHeader header; - try { - file >> header; - fseek(file.Get(), postx.nTxOffset, SEEK_CUR); - file >> txOut; - } catch (const std::exception& e) { - return error("%s: Deserialize or I/O error - %s", __func__, e.what()); - } - hashBlock = header.GetHash(); - if (txOut.GetHash() != hash) - return error("%s: txid mismatch", __func__); - return true; + if (fTxIndex) { + CDiskTxPos postx; + if (pblocktree->ReadTxIndex(hash, postx)) { + CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); + if (file.IsNull()) + return error("%s: OpenBlockFile failed", __func__); + CBlockHeader header; + try { + file >> header; + fseek(file.Get(), postx.nTxOffset, SEEK_CUR); + file >> txOut; + } catch (const std::exception& e) { + return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } + hashBlock = header.GetHash(); + if (txOut.GetHash() != hash) + return error("%s: txid mismatch", __func__); + return true; } + } - if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it - int nHeight = -1; - { - CCoinsViewCache &view = *pcoinsTip; - const CCoins* coins = view.AccessCoins(hash); - if (coins) - nHeight = coins->nHeight; - } - if (nHeight > 0) - pindexSlow = chainActive[nHeight]; + if (fAllowSlow) { // use coin database to locate block that contains transaction, and scan it + int nHeight = -1; + { + CCoinsViewCache &view = *pcoinsTip; + const CCoins* coins = view.AccessCoins(hash); + if (coins) + nHeight = coins->nHeight; } + if (nHeight > 0) + pindexSlow = chainActive[nHeight]; } if (pindexSlow) { @@ -1103,7 +1112,7 @@ bool IsInitialBlockDownload() if (lockIBDState) return false; bool state = (chainActive.Height() < pindexBestHeader->nHeight - 24 * 6 || - pindexBestHeader->GetBlockTime() < GetTime() - 24 * 60 * 60); + pindexBestHeader->GetBlockTime() < GetTime() - chainParams.MaxTipAge()); if (!state) lockIBDState = true; return state; @@ -2033,13 +2042,23 @@ bool static DisconnectTip(CValidationState &state) { if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED)) return false; // Resurrect mempool transactions from the disconnected block. + std::vector<uint256> vHashUpdate; BOOST_FOREACH(const CTransaction &tx, block.vtx) { // ignore validation errors in resurrected transactions list<CTransaction> removed; CValidationState stateDummy; - if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) + if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) { mempool.remove(tx, removed, true); + } else if (mempool.exists(tx.GetHash())) { + vHashUpdate.push_back(tx.GetHash()); + } } + // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have + // no in-mempool children, which is generally not true when adding + // previously-confirmed transactions back to the mempool. + // UpdateTransactionsFromBlock finds descendants of any transactions in this + // block that were added back and cleans up the mempool state. + mempool.UpdateTransactionsFromBlock(vHashUpdate); mempool.removeCoinbaseSpends(pcoinsTip, pindexDelete->nHeight); mempool.check(pcoinsTip); // Update chainActive and related variables. @@ -2294,15 +2313,14 @@ bool ActivateBestChain(CValidationState &state, const CBlock *pblock) { int nBlockEstimate = 0; if (fCheckpointsEnabled) nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainParams.Checkpoints()); - // Don't relay blocks if pruning -- could cause a peer to try to download, resulting - // in a stalled download if the block file is pruned before the request. - if (nLocalServices & NODE_NETWORK) { + { LOCK(cs_vNodes); BOOST_FOREACH(CNode* pnode, vNodes) if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); } // Notify external listeners about the new tip. + GetMainSignals().UpdatedBlockTip(pindexNewTip); uiInterface.NotifyBlockTip(hashNewTip); } } while(pindexMostWork != chainActive.Tip()); @@ -2565,6 +2583,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo { // These are checks that are independent of context. + if (block.fChecked) + return true; + // Check that the header is valid (particularly PoW). This is mostly // redundant with the call in AcceptBlockHeader. if (!CheckBlockHeader(block, state, fCheckPOW)) @@ -2573,7 +2594,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // Check the merkle root. if (fCheckMerkleRoot) { bool mutated; - uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); + uint256 hashMerkleRoot2 = block.ComputeMerkleRoot(&mutated); if (block.hashMerkleRoot != hashMerkleRoot2) return state.DoS(100, error("CheckBlock(): hashMerkleRoot mismatch"), REJECT_INVALID, "bad-txnmrklroot", true); @@ -2620,6 +2641,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), REJECT_INVALID, "bad-blk-sigops", true); + if (fCheckPOW && fCheckMerkleRoot) + block.fChecked = true; + return true; } @@ -4176,6 +4200,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); break; } + // If pruning, don't inv blocks unless we have on disk and are likely to still have + // for some reasonable time window (1 hour) that block relay might require. + const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / chainparams.GetConsensus().nPowTargetSpacing; + if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= chainActive.Tip()->nHeight - nPrunedBlocksLikelyToHave)) + { + LogPrint("net", " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); + break; + } pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash())); if (--nLimit <= 0) { @@ -4248,16 +4280,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, mapAlreadyAskedFor.erase(inv); + // Check for recently rejected (and do other quick existence checks) + if (AlreadyHave(inv)) + return true; + if (AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs)) { mempool.check(pcoinsTip); RelayTransaction(tx); vWorkQueue.push_back(inv.hash); - LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n", - pfrom->id, pfrom->cleanSubVer, + LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u)\n", + pfrom->id, tx.GetHash().ToString(), - mempool.mapTx.size()); + mempool.size()); // Recursively process any orphan transactions that depended on this one set<NodeId> setMisbehaving; @@ -4323,13 +4359,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (nEvicted > 0) LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted); } else { - // AcceptToMemoryPool() returned false, possibly because the tx is - // already in the mempool; if the tx isn't in the mempool that - // means it was rejected and we shouldn't ask for it again. - if (!mempool.exists(tx.GetHash())) { - assert(recentRejects); - recentRejects->insert(tx.GetHash()); - } + assert(recentRejects); + recentRejects->insert(tx.GetHash()); + if (pfrom->fWhitelisted) { // Always relay transactions received from whitelisted peers, even // if they were rejected from the mempool, allowing the node to @@ -4344,8 +4376,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nDoS = 0; if (state.IsInvalid(nDoS)) { - LogPrint("mempoolrej", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), - pfrom->id, pfrom->cleanSubVer, + LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), + pfrom->id, FormatStateMessage(state)); if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), @@ -4522,6 +4554,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (pingUsecTime > 0) { // Successful ping time measurement, replace previous pfrom->nPingUsecTime = pingUsecTime; + pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime); } else { // This should never happen sProblem = "Timing mishap"; @@ -4545,9 +4578,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } if (!(sProblem.empty())) { - LogPrint("net", "pong peer=%d %s: %s, %x expected, %x received, %u bytes\n", + LogPrint("net", "pong peer=%d: %s, %x expected, %x received, %u bytes\n", pfrom->id, - pfrom->cleanSubVer, sProblem, pfrom->nPingNonceSent, nonce, @@ -4590,6 +4622,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } + else if (!(nLocalServices & NODE_BLOOM) && + (strCommand == "filterload" || + strCommand == "filteradd" || + strCommand == "filterclear") && + //TODO: Remove this line after reasonable network upgrade + pfrom->nVersion >= NO_BLOOM_VERSION) + { + if (pfrom->nVersion >= NO_BLOOM_VERSION) + Misbehaving(pfrom->GetId(), 100); + //TODO: Enable this after reasonable network upgrade + //else + // pfrom->fDisconnect = true; + } + + else if (strCommand == "filterload") { CBloomFilter filter; |