From aa97bd1c608a70315f249c92f7f04a22ed6de1d2 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 6 Aug 2015 09:51:36 +0200 Subject: [PATCH] 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. (cherry picked from commit bitcoin/bitcoin@dc58258adf1fb1e05002c3057045f113aa214cb7) --- 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 48ace24c3..bf3fb3bc2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1778,7 +1778,7 @@ bool AcceptToMemoryPool( // 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 for (unsigned int i = 0; i < tx.vin.size(); i++) @@ -1787,7 +1787,7 @@ bool AcceptToMemoryPool( if (pool.mapNextTx.count(outpoint)) { // Disable replacement feature for now - return false; + return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict"); } } for (const JSDescription &joinsplit : tx.vJoinSplit) { @@ -1813,7 +1813,7 @@ bool AcceptToMemoryPool( // 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), @@ -1822,7 +1822,7 @@ bool AcceptToMemoryPool( 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() } } @@ -1853,7 +1853,7 @@ bool AcceptToMemoryPool( // Check for non-standard pay-to-script-hash in inputs if (chainparams.RequireStandard() && !AreInputsStandard(tx, view, consensusBranchId)) - 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 @@ -2415,7 +2415,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) @@ -6779,8 +6779,9 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string 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); } @@ -6882,6 +6883,7 @@ bool static ProcessMessage(const CChainParams& chainparams, CNode* pfrom, string ProcessNewBlock(state, chainparams, 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 f4b3f8cbd..ab0859ee0 100644 --- a/src/main.h +++ b/src/main.h @@ -549,8 +549,17 @@ 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; uint64_t CalculateCurrentUsage();