add spending tx ids for spent outpoints to non-finalized chains
This commit is contained in:
parent
e9b39306c9
commit
5281565713
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue