Check that duplicate Sapling nullifiers don't exist within a transaction.
This commit is contained in:
parent
9669920f75
commit
6679855147
21
src/main.cpp
21
src/main.cpp
|
@ -1040,11 +1040,11 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
|||
}
|
||||
|
||||
// Transactions can contain empty `vin` and `vout` so long as
|
||||
// `vjoinsplit` is non-empty.
|
||||
if (tx.vin.empty() && tx.vjoinsplit.empty())
|
||||
// either `vjoinsplit` or `vShieldedSpend` are non-empty.
|
||||
if (tx.vin.empty() && tx.vjoinsplit.empty() && tx.vShieldedSpend.empty())
|
||||
return state.DoS(10, error("CheckTransaction(): vin empty"),
|
||||
REJECT_INVALID, "bad-txns-vin-empty");
|
||||
if (tx.vout.empty() && tx.vjoinsplit.empty())
|
||||
if (tx.vout.empty() && tx.vjoinsplit.empty() && tx.vShieldedSpend.empty())
|
||||
return state.DoS(10, error("CheckTransaction(): vout empty"),
|
||||
REJECT_INVALID, "bad-txns-vout-empty");
|
||||
|
||||
|
@ -1134,6 +1134,7 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
|||
}
|
||||
|
||||
// Check for duplicate joinsplit nullifiers in this transaction
|
||||
{
|
||||
set<uint256> vJoinSplitNullifiers;
|
||||
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
|
||||
{
|
||||
|
@ -1146,6 +1147,20 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
|
|||
vJoinSplitNullifiers.insert(nf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for duplicate sapling nullifiers in this transaction
|
||||
{
|
||||
set<uint256> vSaplingNullifiers;
|
||||
BOOST_FOREACH(const SpendDescription& spend_desc, tx.vShieldedSpend)
|
||||
{
|
||||
if (vSaplingNullifiers.count(spend_desc.nullifier))
|
||||
return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"),
|
||||
REJECT_INVALID, "bad-spend-description-nullifiers-duplicate");
|
||||
|
||||
vSaplingNullifiers.insert(spend_desc.nullifier);
|
||||
}
|
||||
}
|
||||
|
||||
if (tx.IsCoinBase())
|
||||
{
|
||||
|
|
|
@ -399,6 +399,34 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
|
|||
}
|
||||
}
|
||||
|
||||
void test_simple_sapling_invalidity(uint32_t consensusBranchId, CMutableTransaction tx)
|
||||
{
|
||||
{
|
||||
CMutableTransaction newTx(tx);
|
||||
CValidationState state;
|
||||
|
||||
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vin-empty");
|
||||
}
|
||||
{
|
||||
// Ensure that nullifiers are never duplicated within a transaction.
|
||||
CMutableTransaction newTx(tx);
|
||||
CValidationState state;
|
||||
|
||||
newTx.vShieldedSpend.push_back(SpendDescription());
|
||||
newTx.vShieldedSpend[0].nullifier = GetRandHash();
|
||||
newTx.vShieldedSpend.push_back(SpendDescription());
|
||||
newTx.vShieldedSpend[1].nullifier = newTx.vShieldedSpend[0].nullifier;
|
||||
|
||||
BOOST_CHECK(!CheckTransactionWithoutProofVerification(newTx, state));
|
||||
BOOST_CHECK(state.GetRejectReason() == "bad-spend-description-nullifiers-duplicate");
|
||||
|
||||
newTx.vShieldedSpend[1].nullifier = GetRandHash();
|
||||
|
||||
BOOST_CHECK(CheckTransactionWithoutProofVerification(newTx, state));
|
||||
}
|
||||
}
|
||||
|
||||
void test_simple_joinsplit_invalidity(uint32_t consensusBranchId, CMutableTransaction tx)
|
||||
{
|
||||
auto verifier = libzcash::ProofVerifier::Strict();
|
||||
|
@ -548,6 +576,14 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity_driver) {
|
|||
test_simple_joinsplit_invalidity(NetworkUpgradeInfo[Consensus::UPGRADE_OVERWINTER].nBranchId, mtx);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
|
||||
// Test Sapling things
|
||||
mtx.nVersionGroupId = SAPLING_VERSION_GROUP_ID;
|
||||
mtx.nVersion = SAPLING_TX_VERSION;
|
||||
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
|
||||
test_simple_sapling_invalidity(NetworkUpgradeInfo[Consensus::UPGRADE_SAPLING].nBranchId, mtx);
|
||||
UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT);
|
||||
|
||||
// Switch back to mainnet parameters as originally selected in test fixture
|
||||
SelectParams(CBaseChainParams::MAIN);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue