diff --git a/src/consensus/validation.h b/src/consensus/validation.h index 8ae53c89a..f3d7b3b31 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -29,6 +29,8 @@ static const unsigned char REJECT_MALFORMED = 0x01; static const unsigned char REJECT_INVALID = 0x10; static const unsigned char REJECT_OBSOLETE = 0x11; static const unsigned char REJECT_DUPLICATE = 0x12; +static const unsigned char REJECT_DUPLICATE_OUTPUT_PROOF = 0x13; +static const unsigned char REJECT_DUPLICATE_SPEND_PROOF = 0x14; static const unsigned char REJECT_NONSTANDARD = 0x40; static const unsigned char REJECT_DUST = 0x41; static const unsigned char REJECT_INSUFFICIENTFEE = 0x42; diff --git a/src/main.cpp b/src/main.cpp index 55b26b70b..0d132f952 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1751,7 +1751,31 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa { return error("AcceptToMemoryPool: CheckTransaction failed"); } - + + // Reject duplicate output proofs in a single ztx in mempool + // Migrate this to CheckTransaction() to make it a consensus requirement + { + set vSaplingOutputProof; + BOOST_FOREACH(const OutputDescription& output, tx.vShieldedOutput) + { + if (vSaplingOutputProof.count(output.zkproof)) + return state.Invalid(error("AcceptToMemoryPool: duplicate output proof"),REJECT_DUPLICATE_OUTPUT_PROOF, "bad-txns-duplicate-output-proof"); + vSaplingOutputProof.insert(output.zkproof); + } + } + + // Reject duplicate spend proofs in a single ztx in mempool + // Migrate this to CheckTransaction() to make it a consensus requirement + { + set vSaplingSpendProof; + BOOST_FOREACH(const SpendDescription& spend, tx.vShieldedSpend) + { + if (vSaplingSpendProof.count(spend.zkproof)) + return state.Invalid(error("AcceptToMemoryPool: duplicate spend proof"),REJECT_DUPLICATE_SPEND_PROOF, "bad-txns-duplicate-spend-proof"); + vSaplingSpendProof.insert(spend.zkproof); + } + } + // DoS level set to 10 to be more forgiving. // Check transaction contextually against the set of consensus rules which apply in the next block to be mined. if (!ContextualCheckTransaction(0,0,0,tx, state, nextBlockHeight, (dosLevel == -1) ? 10 : dosLevel))