Browse Source

Check that duplicate Sapling nullifiers don't exist within a transaction.

pull/4/head
Sean Bowe 6 years ago
parent
commit
6679855147
No known key found for this signature in database GPG Key ID: 95684257D8F8B031
  1. 33
      src/main.cpp
  2. 36
      src/test/transaction_tests.cpp

33
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,16 +1134,31 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio
}
// Check for duplicate joinsplit nullifiers in this transaction
set<uint256> vJoinSplitNullifiers;
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
{
BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers)
set<uint256> vJoinSplitNullifiers;
BOOST_FOREACH(const JSDescription& joinsplit, tx.vjoinsplit)
{
BOOST_FOREACH(const uint256& nf, joinsplit.nullifiers)
{
if (vJoinSplitNullifiers.count(nf))
return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"),
REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate");
vJoinSplitNullifiers.insert(nf);
}
}
}
// Check for duplicate sapling nullifiers in this transaction
{
set<uint256> vSaplingNullifiers;
BOOST_FOREACH(const SpendDescription& spend_desc, tx.vShieldedSpend)
{
if (vJoinSplitNullifiers.count(nf))
if (vSaplingNullifiers.count(spend_desc.nullifier))
return state.DoS(100, error("CheckTransaction(): duplicate nullifiers"),
REJECT_INVALID, "bad-joinsplits-nullifiers-duplicate");
REJECT_INVALID, "bad-spend-description-nullifiers-duplicate");
vJoinSplitNullifiers.insert(nf);
vSaplingNullifiers.insert(spend_desc.nullifier);
}
}

36
src/test/transaction_tests.cpp

@ -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…
Cancel
Save