Skip to content

Commit dc58258

Browse files
committed
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.
1 parent fbf44e6 commit dc58258

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

src/main.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
811811
// is it already in the memory pool?
812812
uint256 hash = tx.GetHash();
813813
if (pool.exists(hash))
814-
return false;
814+
return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool");
815815

816816
// Check for conflicts with in-memory transactions
817817
{
@@ -822,7 +822,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
822822
if (pool.mapNextTx.count(outpoint))
823823
{
824824
// Disable replacement feature for now
825-
return false;
825+
return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
826826
}
827827
}
828828
}
@@ -839,7 +839,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
839839

840840
// do we already have it?
841841
if (view.HaveCoins(hash))
842-
return false;
842+
return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known");
843843

844844
// do all inputs exist?
845845
// 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
848848
if (!view.HaveCoins(txin.prevout.hash)) {
849849
if (pfMissingInputs)
850850
*pfMissingInputs = true;
851-
return false;
851+
return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid()
852852
}
853853
}
854854

@@ -868,7 +868,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
868868

869869
// Check for non-standard pay-to-script-hash in inputs
870870
if (fRequireStandard && !AreInputsStandard(tx, view))
871-
return error("AcceptToMemoryPool: nonstandard transaction input");
871+
return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
872872

873873
// Check that the transaction doesn't have an excessive number of
874874
// sigops, making it impossible to mine. Since the coinbase transaction
@@ -1239,7 +1239,7 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
12391239
if (state.IsInvalid(nDoS)) {
12401240
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
12411241
if (it != mapBlockSource.end() && State(it->second)) {
1242-
assert(state.GetRejectCode() < 0x100);
1242+
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
12431243
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
12441244
State(it->second)->rejects.push_back(reject);
12451245
if (nDoS > 0)
@@ -4358,8 +4358,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
43584358
LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(),
43594359
pfrom->id, pfrom->cleanSubVer,
43604360
state.GetRejectReason());
4361-
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
4362-
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
4361+
if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
4362+
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
4363+
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
43634364
if (nDoS > 0)
43644365
Misbehaving(pfrom->GetId(), nDoS);
43654366
}
@@ -4439,6 +4440,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
44394440
ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL);
44404441
int nDoS;
44414442
if (state.IsInvalid(nDoS)) {
4443+
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
44424444
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
44434445
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
44444446
if (nDoS > 0) {

src/main.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,16 @@ extern CBlockTreeDB *pblocktree;
455455
*/
456456
int GetSpendHeight(const CCoinsViewCache& inputs);
457457

458-
/** local "reject" message codes for RPC which can not be triggered by p2p trasactions */
458+
/** Reject codes greater or equal to this can be returned by AcceptToMemPool
459+
* for transactions, to signal internal conditions. They cannot and should not
460+
* be sent over the P2P network.
461+
*/
462+
static const unsigned int REJECT_INTERNAL = 0x100;
463+
/** Too high fee. Can not be triggered by P2P transactions */
459464
static const unsigned int REJECT_HIGHFEE = 0x100;
465+
/** Transaction is already known (either in mempool or blockchain) */
466+
static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
467+
/** Transaction conflicts with a transaction already known */
468+
static const unsigned int REJECT_CONFLICT = 0x102;
460469

461470
#endif // BITCOIN_MAIN_H

0 commit comments

Comments
 (0)