From 22854f79987ff02625a354566bc3f5b108cd1a85 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Tue, 29 Jun 2021 15:21:39 -0600 Subject: [PATCH] Add Orchard value balance checks. --- src/main.cpp | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a64442790..0648f39ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1455,13 +1455,13 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio } // Check for non-zero valueBalanceSapling when there are no Sapling inputs or outputs - if (tx.vShieldedSpend.empty() && tx.vShieldedOutput.empty() && tx.GetValueBalanceSapling() != 0) { // XXX value balance ffi + if (tx.vShieldedSpend.empty() && tx.vShieldedOutput.empty() && tx.GetValueBalanceSapling() != 0) { return state.DoS(100, error("CheckTransaction(): tx.valueBalanceSapling has no sources or sinks"), REJECT_INVALID, "bad-txns-valuebalance-nonzero"); } - // Check for overflow valueBalanceSapling XXX rename to sapling value balance, add orchard value balance checks - if (tx.GetValueBalanceSapling() > MAX_MONEY || tx.GetValueBalanceSapling() < -MAX_MONEY) { // XXX need value balance ffi + // Check for overflow valueBalanceSapling + if (tx.GetValueBalanceSapling() > MAX_MONEY || tx.GetValueBalanceSapling() < -MAX_MONEY) { return state.DoS(100, error("CheckTransaction(): abs(tx.valueBalanceSapling) too large"), REJECT_INVALID, "bad-txns-valuebalance-toolarge"); } @@ -1476,6 +1476,30 @@ 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"); + } + + // Check for overflow valueBalanceOrchard + if (valueBalanceOrchard > MAX_MONEY || valueBalanceOrchard < -MAX_MONEY) { + return state.DoS(100, error("CheckTransaction(): abs(tx.valueBalanceOrchard) too large"), + REJECT_INVALID, "bad-txns-valuebalance-toolarge"); + } + + if (valueBalanceOrchard <= 0) { + // NB: negative valueBalanceOrchard "takes" money from the transparent value pool just as outputs do + nValueOut += -valueBalanceOrchard; + + if (!MoneyRange(nValueOut)) { + return state.DoS(100, error("CheckTransaction(): txout total out of range"), + REJECT_INVALID, "bad-txns-txouttotal-toolarge"); + } + } + // Ensure that joinsplit values are well-formed for (const JSDescription& joinsplit : tx.vJoinSplit) { @@ -1532,12 +1556,22 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio // NB: positive valueBalanceSapling "adds" money to the transparent value pool, just as inputs do nValueIn += tx.GetValueBalanceSapling(); + if (!MoneyRange(nValueIn)) { + return state.DoS(100, error("CheckTransaction(): txin total out of range"), + REJECT_INVALID, "bad-txns-txintotal-toolarge"); + } + } + + // Also check for Orchard + if (valueBalanceOrchard >= 0) { + // NB: positive valueBalanceOrchard "adds" money to the transparent value pool, just as inputs do + nValueIn += valueBalanceOrchard; + if (!MoneyRange(nValueIn)) { return state.DoS(100, error("CheckTransaction(): txin total out of range"), REJECT_INVALID, "bad-txns-txintotal-toolarge"); } } - // XXX add orchard block, similar to sapling } // Check for duplicate inputs @@ -1578,7 +1612,6 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio vSaplingNullifiers.insert(spend_desc.nullifier); } } - // XXX similar for orchard // Check for duplicate orchard nullifiers in this transaction {