Function zebra_state::service::check::nullifier::add_to_non_finalized_chain_unique
source · pub(crate) fn add_to_non_finalized_chain_unique<'block, NullifierT>(
chain_nullifiers: &mut HashSet<NullifierT>,
shielded_data_nullifiers: impl IntoIterator<Item = &'block NullifierT>,
) -> Result<(), ValidateContextError>
Expand description
Reject double-spends of nullifers:
- both within the same
JoinSplit
(sprout only), - from different
JoinSplit
s,sapling::Spend
s ororchard::Action
s in thisTransaction
’s shielded data, or - one from this shielded data, and another from:
(Duplicate finalized nullifiers are rejected during service contextual validation,
see no_duplicates_in_finalized_chain
for details.)
§Consensus
A nullifier MUST NOT repeat either within a transaction, or across transactions in a valid blockchain. Sprout and Sapling and Orchard nullifiers are considered disjoint, even if they have the same bit pattern.
https://zips.z.cash/protocol/protocol.pdf#nullifierset
We comply with the “disjoint” rule by storing the nullifiers for each pool in separate sets (also with different types), so that even if different pools have nullifiers with same bit pattern, they won’t be considered the same when determining uniqueness. This is enforced by the callers of this function.