diff --git a/src/main.cpp b/src/main.cpp index 510fe6f18..12b405a95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1283,6 +1283,16 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde const bool overwinterActive = nHeight >=1 ? true : false; //NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_OVERWINTER); const bool saplingActive = nHeight >=1 ? true : false; //NetworkUpgradeActive(nHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING); + // SECURITY FIX (JoinSplit inflation): reject Sprout JoinSplits at consensus. DragonX is + // Sapling-only from genesis (zero JoinSplits in its entire history, verified by the mainnet + // supply audit); a tx carrying one is illegitimate. Their zk-proof/sig/nullifier/anchor are + // never verified while vpub_new is counted as transparent value-in -> unlimited inflation. + // Coinbase/notary (IsMint) exempt. Unconditional is safe: no historical block has a JoinSplit. + if (!tx.IsMint() && !tx.vjoinsplit.empty()) { + return state.DoS(100, error("ContextualCheckTransaction(): Sprout JoinSplits are disabled (inflation vector)"), + REJECT_INVALID, "bad-txns-joinsplit-disabled"); + } + if (saplingActive) { // Reject transactions with valid version but missing overwintered flag if (tx.nVersion >= SAPLING_MIN_TX_VERSION && !tx.fOverwintered) {