From fbf44e6f3e55d25aa40ca466be3dbfd55de6170a Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 09:47:01 +0200 Subject: [PATCH 1/6] Add debug message to CValidationState for optional extra information Add a field `strDebugMessage` which can be passed to DoS or Invalid, and queried using GetDebugMessage() to add extra troubleshooting information to the validation state. --- src/consensus/validation.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 719e090a4..d6051edc3 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -30,14 +30,17 @@ private: std::string strRejectReason; unsigned int chRejectCode; bool corruptionPossible; + std::string strDebugMessage; public: CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {} bool DoS(int level, bool ret = false, - unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", - bool corruptionIn=false) { + unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="", + bool corruptionIn=false, + const std::string &strDebugMessageIn="") { chRejectCode = chRejectCodeIn; strRejectReason = strRejectReasonIn; corruptionPossible = corruptionIn; + strDebugMessage = strDebugMessageIn; if (mode == MODE_ERROR) return ret; nDoS += level; @@ -45,8 +48,9 @@ public: return ret; } bool Invalid(bool ret = false, - unsigned int _chRejectCode=0, std::string _strRejectReason="") { - return DoS(0, ret, _chRejectCode, _strRejectReason); + unsigned int _chRejectCode=0, const std::string &_strRejectReason="", + const std::string &_strDebugMessage="") { + return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage); } bool Error(const std::string& strRejectReasonIn) { if (mode == MODE_VALID) @@ -75,6 +79,7 @@ public: } unsigned int GetRejectCode() const { return chRejectCode; } std::string GetRejectReason() const { return strRejectReason; } + std::string GetDebugMessage() const { return strDebugMessage; } }; #endif // BITCOIN_CONSENSUS_VALIDATION_H From dc58258adf1fb1e05002c3057045f113aa214cb7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 09:51:36 +0200 Subject: [PATCH 2/6] Introduce REJECT_INTERNAL codes for local AcceptToMempool errors Add status codes specific to AcceptToMempool procession of transactions. These can never happen due to block validation, and must never be sent over the P2P network. Add assertions where appropriate. --- src/main.cpp | 18 ++++++++++-------- src/main.h | 11 ++++++++++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 79cc60685..5949e5285 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -811,7 +811,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // is it already in the memory pool? uint256 hash = tx.GetHash(); if (pool.exists(hash)) - return false; + return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool"); // Check for conflicts with in-memory transactions { @@ -822,7 +822,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (pool.mapNextTx.count(outpoint)) { // Disable replacement feature for now - return false; + return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); } } } @@ -839,7 +839,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // do we already have it? if (view.HaveCoins(hash)) - return false; + return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known"); // do all inputs exist? // Note that this does not check for the presence of actual outputs (see the next check for that), @@ -848,7 +848,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (!view.HaveCoins(txin.prevout.hash)) { if (pfMissingInputs) *pfMissingInputs = true; - return false; + return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid() } } @@ -868,7 +868,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check for non-standard pay-to-script-hash in inputs if (fRequireStandard && !AreInputsStandard(tx, view)) - return error("AcceptToMemoryPool: nonstandard transaction input"); + return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs"); // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction @@ -1239,7 +1239,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state if (state.IsInvalid(nDoS)) { std::map::iterator it = mapBlockSource.find(pindex->GetBlockHash()); if (it != mapBlockSource.end() && State(it->second)) { - assert(state.GetRejectCode() < 0x100); + assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()}; State(it->second)->rejects.push_back(reject); if (nDoS > 0) @@ -4358,8 +4358,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), pfrom->id, pfrom->cleanSubVer, state.GetRejectReason()); - pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); + if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P + pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), + state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) Misbehaving(pfrom->GetId(), nDoS); } @@ -4439,6 +4440,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL); int nDoS; if (state.IsInvalid(nDoS)) { + assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); if (nDoS > 0) { diff --git a/src/main.h b/src/main.h index eec7e6fa5..5c54b11d4 100644 --- a/src/main.h +++ b/src/main.h @@ -455,7 +455,16 @@ extern CBlockTreeDB *pblocktree; */ int GetSpendHeight(const CCoinsViewCache& inputs); -/** local "reject" message codes for RPC which can not be triggered by p2p trasactions */ +/** Reject codes greater or equal to this can be returned by AcceptToMemPool + * for transactions, to signal internal conditions. They cannot and should not + * be sent over the P2P network. + */ +static const unsigned int REJECT_INTERNAL = 0x100; +/** Too high fee. Can not be triggered by P2P transactions */ static const unsigned int REJECT_HIGHFEE = 0x100; +/** Transaction is already known (either in mempool or blockchain) */ +static const unsigned int REJECT_ALREADY_KNOWN = 0x101; +/** Transaction conflicts with a transaction already known */ +static const unsigned int REJECT_CONFLICT = 0x102; #endif // BITCOIN_MAIN_H From 9003c7cdd88402986e48ec126258fc10d6742fc7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 09:53:24 +0200 Subject: [PATCH 3/6] Add function to convert CValidationState to a human-readable message It is necessary to be able to concisely log a validation state. Convert CValidationState to a human-readable message for logging. --- src/main.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 5949e5285..3d7a62043 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -778,6 +778,14 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF return nMinFee; } +/** Convert CValidationState to a human-readable message for logging */ +static std::string FormatStateMessage(const CValidationState &state) +{ + return strprintf("%s%s (code %i)", + state.GetRejectReason(), + state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(), + state.GetRejectCode()); +} bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool* pfMissingInputs, bool fRejectAbsurdFee) From 6cab80827277a66a339f1035c58a8f26e347e191 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 09:59:09 +0200 Subject: [PATCH 4/6] Remove most logging from transaction validation Remove unnecessary direct logging in CheckTransaction, AcceptToMemoryPool, CheckTxInputs, CScriptCheck::operator() All status information should be returned in the CValidationState. Relevant debug information is also added to the CValidationState using the recently introduced debug message. Do keep the "BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags" error as it is meant to appear as bug in the log. --- src/main.cpp | 94 +++++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 59 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3d7a62043..947bd8ef1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -696,30 +696,24 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) { // Basic checks that don't depend on any context if (tx.vin.empty()) - return state.DoS(10, error("CheckTransaction(): vin empty"), - REJECT_INVALID, "bad-txns-vin-empty"); + return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); if (tx.vout.empty()) - return state.DoS(10, error("CheckTransaction(): vout empty"), - REJECT_INVALID, "bad-txns-vout-empty"); + return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); // Size limits if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) - return state.DoS(100, error("CheckTransaction(): size limits failed"), - REJECT_INVALID, "bad-txns-oversize"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); // Check for negative or overflow output values CAmount nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { if (txout.nValue < 0) - return state.DoS(100, error("CheckTransaction(): txout.nValue negative"), - REJECT_INVALID, "bad-txns-vout-negative"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative"); if (txout.nValue > MAX_MONEY) - return state.DoS(100, error("CheckTransaction(): txout.nValue too high"), - REJECT_INVALID, "bad-txns-vout-toolarge"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge"); nValueOut += txout.nValue; if (!MoneyRange(nValueOut)) - return state.DoS(100, error("CheckTransaction(): txout total out of range"), - REJECT_INVALID, "bad-txns-txouttotal-toolarge"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge"); } // Check for duplicate inputs @@ -727,23 +721,20 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) BOOST_FOREACH(const CTxIn& txin, tx.vin) { if (vInOutPoints.count(txin.prevout)) - return state.DoS(100, error("CheckTransaction(): duplicate inputs"), - REJECT_INVALID, "bad-txns-inputs-duplicate"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate"); vInOutPoints.insert(txin.prevout); } if (tx.IsCoinBase()) { if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100) - return state.DoS(100, error("CheckTransaction(): coinbase script size"), - REJECT_INVALID, "bad-cb-length"); + return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); } else { BOOST_FOREACH(const CTxIn& txin, tx.vin) if (txin.prevout.IsNull()) - return state.DoS(10, error("CheckTransaction(): prevout is null"), - REJECT_INVALID, "bad-txns-prevout-null"); + return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); } return true; @@ -795,26 +786,22 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa *pfMissingInputs = false; if (!CheckTransaction(tx, state)) - return error("AcceptToMemoryPool: CheckTransaction failed"); + return false; // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"), - REJECT_INVALID, "coinbase"); + return state.DoS(100, false, REJECT_INVALID, "coinbase"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) string reason; if (fRequireStandard && !IsStandardTx(tx, reason)) - return state.DoS(0, - error("AcceptToMemoryPool: nonstandard transaction: %s", reason), - REJECT_NONSTANDARD, reason); + return state.DoS(0, false, REJECT_NONSTANDARD, reason); // Only accept nLockTime-using transactions that can be mined in the next // block; we don't want our mempool filled up with transactions that can't // be mined yet. if (!CheckFinalTx(tx)) - return state.DoS(0, error("AcceptToMemoryPool: non-final"), - REJECT_NONSTANDARD, "non-final"); + return state.DoS(0, false, REJECT_NONSTANDARD, "non-final"); // is it already in the memory pool? uint256 hash = tx.GetHash(); @@ -862,8 +849,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // are the actual inputs available? if (!view.HaveInputs(tx)) - return state.Invalid(error("AcceptToMemoryPool: inputs already spent"), - REJECT_DUPLICATE, "bad-txns-inputs-spent"); + return state.Invalid(false, REJECT_DUPLICATE, "bad-txns-inputs-spent"); // Bring the best block into scope view.GetBestBlock(); @@ -886,10 +872,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa unsigned int nSigOps = GetLegacySigOpCount(tx); nSigOps += GetP2SHSigOpCount(tx, view); if (nSigOps > MAX_STANDARD_TX_SIGOPS) - return state.DoS(0, - error("AcceptToMemoryPool: too many sigops %s, %d > %d", - hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS), - REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); + return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, + strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS)); CAmount nValueOut = tx.GetValueOut(); CAmount nFees = nValueIn-nValueOut; @@ -901,9 +885,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Don't accept it if it can't get into a block CAmount txMinFee = GetMinRelayFee(tx, nSize, true); if (fLimitFree && nFees < txMinFee) - return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d", - hash.ToString(), nFees, txMinFee), - REJECT_INSUFFICIENTFEE, "insufficient fee"); + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false, + strprintf("%d < %d", nFees, txMinFee)); // Require that free transactions have sufficient priority to be mined in the next block. if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) { @@ -928,24 +911,20 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // -limitfreerelay unit is thousand-bytes-per-minute // At default rate it would take over a month to fill 1GB if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000) - return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"), - REJECT_INSUFFICIENTFEE, "rate limited free transaction"); + return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction"); LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize); dFreeCount += nSize; } if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000) - return state.Invalid(error("AcceptToMemoryPool: absurdly high fees %s, %d > %d", - hash.ToString(), - nFees, ::minRelayTxFee.GetFee(nSize) * 10000), - REJECT_HIGHFEE, "absurdly-high-fee"); + return state.Invalid(false, + REJECT_HIGHFEE, "absurdly-high-fee", + strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000)); // 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)) - { - return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString()); - } + return false; // Check again against just the consensus-critical mandatory script // verification flags, in case of bugs in the standard flags that cause @@ -958,7 +937,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // can be exploited as a DoS attack. if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) { - return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); + return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s", + __func__, hash.ToString(), FormatStateMessage(state)); } // Store transaction in memory @@ -1298,7 +1278,7 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) { - return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error)); + return false; } return true; } @@ -1316,7 +1296,7 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins // This doesn't trigger the DoS code on purpose; if it did, it would make it easier // for an attacker to attempt to split the network. if (!inputs.HaveInputs(tx)) - return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString())); + return state.Invalid(false, 0, "", "Inputs unavailable"); CAmount nValueIn = 0; CAmount nFees = 0; @@ -1329,33 +1309,29 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins // If prev is coinbase, check that it's matured if (coins->IsCoinBase()) { if (nSpendHeight - coins->nHeight < COINBASE_MATURITY) - return state.Invalid( - error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight), - REJECT_INVALID, "bad-txns-premature-spend-of-coinbase"); + return state.Invalid(false, + REJECT_INVALID, "bad-txns-premature-spend-of-coinbase", + strprintf("tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight)); } // Check for negative or overflow input values nValueIn += coins->vout[prevout.n].nValue; if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn)) - return state.DoS(100, error("CheckInputs(): txin values out of range"), - REJECT_INVALID, "bad-txns-inputvalues-outofrange"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange"); } if (nValueIn < tx.GetValueOut()) - return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s)", - tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())), - REJECT_INVALID, "bad-txns-in-belowout"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false, + strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut()))); // Tally transaction fees CAmount nTxFee = nValueIn - tx.GetValueOut(); if (nTxFee < 0) - return state.DoS(100, error("CheckInputs(): %s nTxFee < 0", tx.GetHash().ToString()), - REJECT_INVALID, "bad-txns-fee-negative"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); nFees += nTxFee; if (!MoneyRange(nFees)) - return state.DoS(100, error("CheckInputs(): nFees out of range"), - REJECT_INVALID, "bad-txns-fee-outofrange"); + return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); return true; } }// namespace Consensus From 66daed5e1be7932e08896794ca016ff31c71a1d4 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 10:02:12 +0200 Subject: [PATCH 5/6] Add information to errors in ConnectBlock, CheckBlock Add detailed state information to the errors, as it is no longer being logged downstream. Also add the state information to mempool rejection debug message in ProcessMessages. --- src/main.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 947bd8ef1..5d9247e4b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1777,7 +1777,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin std::vector vChecks; if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) - return false; + return error("ConnectBlock(): CheckInputs on %s failed with %s", + tx.GetHash().ToString(), FormatStateMessage(state)); control.Add(vChecks); } @@ -2604,7 +2605,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo // Check transactions BOOST_FOREACH(const CTransaction& tx, block.vtx) if (!CheckTransaction(tx, state)) - return error("CheckBlock(): CheckTransaction failed"); + return error("CheckBlock(): CheckTransaction of %s failed with %s", + tx.GetHash().ToString(), + FormatStateMessage(state)); unsigned int nSigOps = 0; BOOST_FOREACH(const CTransaction& tx, block.vtx) @@ -4341,7 +4344,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), pfrom->id, pfrom->cleanSubVer, - state.GetRejectReason()); + FormatStateMessage(state)); if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash); From 7f1f8f5edf36b0885b0f2b746e28a2f9bde8f4f0 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 10:03:11 +0200 Subject: [PATCH 6/6] Move mempool rejections to new debug category Move mempool rejections to debug category `mempoolrej`, to make it possible to show them without enabling the entire category `mempool` which is high volume. --- src/init.cpp | 2 +- src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index ef1c39db2..085e04fdf 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -373,7 +373,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1)); strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0)); } - string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, net, proxy, prune"; // Don't translate these and qt below + string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune"; // Don't translate these and qt below if (mode == HMM_BITCOIN_QT) debugCategories += ", qt"; strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + diff --git a/src/main.cpp b/src/main.cpp index 5d9247e4b..bb0ca9db5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4342,7 +4342,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int nDoS = 0; if (state.IsInvalid(nDoS)) { - LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), + LogPrint("mempoolrej", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(), pfrom->id, pfrom->cleanSubVer, FormatStateMessage(state)); if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P