add spending tx ids for spent outpoints to non-finalized chains

This commit is contained in:
Arya 2024-09-26 21:37:37 -04:00
parent e9b39306c9
commit 5281565713
4 changed files with 21 additions and 21 deletions

View File

@ -221,7 +221,7 @@ proptest! {
.unwrap();
prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
prop_assert!(chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains_key(&expected_outpoint));
// the finalized state does not have the UTXO
prop_assert!(finalized_state.utxo(&expected_outpoint).is_none());
@ -310,14 +310,14 @@ proptest! {
if use_finalized_state_output {
// the chain has spent the UTXO from the finalized state
prop_assert!(!chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains_key(&expected_outpoint));
// the finalized state has the UTXO, but it will get deleted on commit
prop_assert!(finalized_state.utxo(&expected_outpoint).is_some());
} else {
// the chain has spent its own UTXO
prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
prop_assert!(chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains_key(&expected_outpoint));
// the finalized state does not have the UTXO
prop_assert!(finalized_state.utxo(&expected_outpoint).is_none());
}
@ -650,12 +650,12 @@ proptest! {
// the finalized state has the unspent UTXO
prop_assert!(finalized_state.utxo(&expected_outpoint).is_some());
// the non-finalized state has spent the UTXO
prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains_key(&expected_outpoint));
} else {
// the non-finalized state has created and spent the UTXO
prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
prop_assert!(chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains_key(&expected_outpoint));
// the finalized state does not have the UTXO
prop_assert!(finalized_state.utxo(&expected_outpoint).is_none());
}

View File

@ -1,9 +1,9 @@
//! Consensus rule checks for the finalized state.
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use zebra_chain::{
amount,
amount, transaction,
transparent::{self, utxos_from_ordered_utxos, CoinbaseSpendRestriction::*},
};
@ -38,7 +38,7 @@ use crate::{
pub fn transparent_spend(
semantically_verified: &SemanticallyVerifiedBlock,
non_finalized_chain_unspent_utxos: &HashMap<transparent::OutPoint, transparent::OrderedUtxo>,
non_finalized_chain_spent_utxos: &HashSet<transparent::OutPoint>,
non_finalized_chain_spent_utxos: &HashMap<transparent::OutPoint, transaction::Hash>,
finalized_state: &ZebraDb,
) -> Result<HashMap<transparent::OutPoint, transparent::OrderedUtxo>, ValidateContextError> {
let mut block_spends = HashMap::new();
@ -126,7 +126,7 @@ fn transparent_spend_chain_order(
spend_tx_index_in_block: usize,
block_new_outputs: &HashMap<transparent::OutPoint, transparent::OrderedUtxo>,
non_finalized_chain_unspent_utxos: &HashMap<transparent::OutPoint, transparent::OrderedUtxo>,
non_finalized_chain_spent_utxos: &HashSet<transparent::OutPoint>,
non_finalized_chain_spent_utxos: &HashMap<transparent::OutPoint, transaction::Hash>,
finalized_state: &ZebraDb,
) -> Result<transparent::OrderedUtxo, ValidateContextError> {
if let Some(output) = block_new_outputs.get(&spend) {
@ -146,7 +146,7 @@ fn transparent_spend_chain_order(
}
}
if non_finalized_chain_spent_utxos.contains(&spend) {
if non_finalized_chain_spent_utxos.contains_key(&spend) {
// reject the spend if its UTXO is already spent in the
// non-finalized parent chain
return Err(DuplicateTransparentSpend {

View File

@ -90,18 +90,15 @@ pub struct ChainInner {
//
// TODO: replace OutPoint with OutputLocation?
pub(crate) created_utxos: HashMap<transparent::OutPoint, transparent::OrderedUtxo>,
/// The [`transparent::OutPoint`]s spent by `blocks`,
/// The spending transaction ids by [`transparent::OutPoint`]s spent by `blocks`,
/// including those created by earlier transactions or blocks in the chain.
pub(crate) spent_utxos: HashSet<transparent::OutPoint>,
// TODO:
// - Add a field for tracking spending tx ids by spent outpoint
// - Update the field when committing blocks to non-finalized chain
// - Add a read fn for querying tx ids by spent outpoint
// - Add a db format upgrade for indexing spending tx ids (transaction locations) by
// spent outpoints (output locations) in the finalized state
// - Add ReadRequest & ReadResponse variants for querying spending tx ids by
// spent outpoints and handle them in the ReadStateService
pub(crate) spent_utxos: HashMap<transparent::OutPoint, transaction::Hash>,
// Note commitment trees
//
@ -1249,7 +1246,7 @@ impl Chain {
/// and removed from the relevant chain(s).
pub fn unspent_utxos(&self) -> HashMap<transparent::OutPoint, transparent::OrderedUtxo> {
let mut unspent_utxos = self.created_utxos.clone();
unspent_utxos.retain(|outpoint, _utxo| !self.spent_utxos.contains(outpoint));
unspent_utxos.retain(|outpoint, _utxo| !self.spent_utxos.contains_key(outpoint));
unspent_utxos
}
@ -1854,9 +1851,12 @@ impl
};
// Index the spent outpoint in the chain
let first_spend = self.spent_utxos.insert(spent_outpoint);
let was_spend_already_present = self
.spent_utxos
.insert(spent_outpoint, *spending_tx_hash)
.is_some();
assert!(
first_spend,
was_spend_already_present,
"unexpected duplicate spent output: should be checked earlier"
);
@ -1904,9 +1904,9 @@ impl
};
// Revert the spent outpoint in the chain
let spent_outpoint_was_removed = self.spent_utxos.remove(&spent_outpoint);
let was_spent_outpoint_removed = self.spent_utxos.remove(&spent_outpoint).is_some();
assert!(
spent_outpoint_was_removed,
was_spent_outpoint_removed,
"spent_utxos must be present if block was added to chain"
);

View File

@ -176,7 +176,7 @@ where
C: AsRef<Chain>,
{
match chain {
Some(chain) if chain.as_ref().spent_utxos.contains(&outpoint) => None,
Some(chain) if chain.as_ref().spent_utxos.contains_key(&outpoint) => None,
chain => utxo(chain, db, outpoint),
}
}