diff --git a/src/script/script.h b/src/script/script.h index fa4dd176a5..21264b9584 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -657,6 +657,8 @@ public: * Returns whether the script is guaranteed to fail at execution, * regardless of the initial stack. This allows outputs to be pruned * instantly when entering the UTXO set. This includes fee outputs. + * + * This is consensus-critical because it is called by VerifyAmounts(). */ bool IsUnspendable() const { diff --git a/src/validation.cpp b/src/validation.cpp index 9abb28917a..95d54dfa55 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -793,6 +793,7 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve if (!MoneyRange(val.GetAmount())) return false; + // Fails if val.GetAmount() == 0 if (secp256k1_pedersen_commit(secp256k1_ctx_verify_amounts, &commit, explBlinds, val.GetAmount(), &gen) != 1) return false; } else if (val.IsCommitment()) { @@ -831,8 +832,7 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve // Null nAmount is considered explicit 0, so just check for commitment CalculateReissuanceToken(assetTokenID, entropy, issuance.nAmount.IsCommitment()); } else { - //Re-issuance - + // Re-issuance // hashAssetIdentifier doubles as the entropy on reissuance CalculateAsset(assetID, issuance.assetEntropy); CalculateReissuanceToken(assetTokenID, issuance.assetEntropy, issuance.nAmount.IsCommitment()); @@ -927,6 +927,7 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve continue; } else { // No spendable 0-value outputs + // Reason: A spendable output of 0 reissuance tokens would allow reissuance without reissuance tokens. return false; } } @@ -977,11 +978,12 @@ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::ve } } + // Surjection proofs for (size_t i = 0; i < tx.vout.size(); i++) { const CConfidentialAsset& asset = tx.vout[i].nAsset; const CTxOutWitness* ptxoutwit = tx.wit.vtxoutwit.size() <= i? NULL: &tx.wit.vtxoutwit[i]; - //No need for surjective proof + // No need for surjection proof if (asset.IsExplicit()) { if (ptxoutwit && !ptxoutwit->vchSurjectionproof.empty()) { return false; diff --git a/src/validation.h b/src/validation.h index 0a1542ccc3..61d3425b8d 100644 --- a/src/validation.h +++ b/src/validation.h @@ -399,11 +399,14 @@ bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoins /** * Verify the transaction's outputs spend exactly what its inputs provide, plus some excess amount. * + * This also checks rangeproofs, surjection proofs, and issuances of assets and re-issuance tokens. + * The function assumes that IsValidPeginWitness() returns true on all peg-in inputs. + * * @param[in] view CCoinsViewCache to find necessary outputs * @param[in] tx transaction for which we are checking totals - * @param[in] pvChecks multithreaded rangeproof and commitment checker - * @param[in] cacheStore signal if rangeproof verification should be cached - * @return True if totals are identical + * @param[in] pvChecks multithreaded rangeproof, surjection proof and commitment checker + * @param[in] cacheStore signal if rangeproof and surjection proof verification should be cached + * @return True if verification was not aborted and totals are identical */ bool VerifyAmounts(const CCoinsViewCache& cache, const CTransaction& tx, std::vector* pvChecks = NULL, const bool cacheStore = false);