From f4fe590eeaea5ccc22dd35f7e166e1b0b8b4e6e6 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Thu, 29 Jul 2021 08:32:46 -0600 Subject: [PATCH] Make Sapling Spend and Ouput count, and Orchard Action count checks be noncontextual. Sapling spend and output max element counts may be safely made noncontextual because the existing transaction size limit checks would be violated by transactions containing more than 2^16 such elements. --- src/main.cpp | 65 +++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 652d7f35c..34ba4347e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1112,34 +1112,6 @@ bool ContextualCheckTransaction( } } - // nSpendsSapling, nOutputsSapling, and nActionsOrchard MUST all be less than 2^16 - size_t max_elements = (1 << 16) - 1; - if (tx.vShieldedSpend.size() > max_elements) { - return state.DoS( - dosLevelPotentiallyRelaxing, - error("ContextualCheckTransaction(): 2^16 or more Sapling spends"), - REJECT_INVALID, "bad-tx-too-many-sapling-spends"); - } - if (tx.vShieldedOutput.size() > max_elements) { - return state.DoS( - dosLevelPotentiallyRelaxing, - error("ContextualCheckTransaction(): 2^16 or more Sapling outputs"), - REJECT_INVALID, "bad-tx-too-many-sapling-outputs"); - } - if (orchard_bundle.GetNumActions() > max_elements) { - return state.DoS( - dosLevelPotentiallyRelaxing, - error("ContextualCheckTransaction(): 2^16 or more Orchard actions"), - REJECT_INVALID, "bad-tx-too-many-orchard-actions"); - } - - if (orchard_bundle.GetNumActions() > 0 && !orchard_bundle.OutputsEnabled() && !orchard_bundle.SpendsEnabled()) { - return state.DoS( - dosLevelPotentiallyRelaxing, - error("ContextualCheckTransaction(): Orchard actions are present, but flags do not permit Orchard spends or outputs"), - REJECT_INVALID, "bad-tx-orchard-flags-disable-actions"); - } - if (tx.IsCoinBase()) { if (!orchard_bundle.CoinbaseOutputsAreValid()) { return state.DoS( @@ -1511,13 +1483,38 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio } } - auto valueBalanceOrchard = orchard_bundle.GetValueBalance(); - - // Check for non-zero valueBalanceOrchard when there are no Orchard inputs or outputs - if (!orchard_bundle.SpendsEnabled() && !orchard_bundle.OutputsEnabled() && valueBalanceOrchard != 0) { - return state.DoS(100, error("CheckTransaction(): tx.valueBalanceOrchard has no sources or sinks"), - REJECT_INVALID, "bad-txns-valuebalance-nonzero"); + // nSpendsSapling, nOutputsSapling, and nActionsOrchard MUST all be less than 2^16 + size_t max_elements = (1 << 16) - 1; + if (tx.vShieldedSpend.size() > max_elements) { + return state.DoS( + dosLevelPotentiallyRelaxing, + error("ContextualCheckTransaction(): 2^16 or more Sapling spends"), + REJECT_INVALID, "bad-tx-too-many-sapling-spends"); } + if (tx.vShieldedOutput.size() > max_elements) { + return state.DoS( + dosLevelPotentiallyRelaxing, + error("ContextualCheckTransaction(): 2^16 or more Sapling outputs"), + REJECT_INVALID, "bad-tx-too-many-sapling-outputs"); + } + if (orchard_bundle.GetNumActions() > max_elements) { + return state.DoS( + dosLevelPotentiallyRelaxing, + error("ContextualCheckTransaction(): 2^16 or more Orchard actions"), + REJECT_INVALID, "bad-tx-too-many-orchard-actions"); + } + + // Check that if neither Orchard spends nor outputs are enabled, the transaction contains + // no Orchard actions. This subsumes the check that valueBalanceOrchard must equal zero + // in the case that both spends and outputs are disabled. + if (orchard_bundle.GetNumActions() > 0 && !orchard_bundle.OutputsEnabled() && !orchard_bundle.SpendsEnabled()) { + return state.DoS( + 100, + error("ContextualCheckTransaction(): Orchard actions are present, but flags do not permit Orchard spends or outputs"), + REJECT_INVALID, "bad-tx-orchard-flags-disable-actions"); + } + + auto valueBalanceOrchard = orchard_bundle.GetValueBalance(); // Check for overflow valueBalanceOrchard if (valueBalanceOrchard > MAX_MONEY || valueBalanceOrchard < -MAX_MONEY) {