Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return valid Utxos from check::transparent_spend #2561

Merged
merged 2 commits into from
Aug 3, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions zebra-state/src/service/check/utxo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ use crate::{
},
};

/// Reject invalid spends of transparent outputs.
/// Lookup all the [`transparent::Utxo`]s spent by a [`PreparedBlock`].
/// If any of the spends are invalid, return an error.
/// Otherwise, return the looked up UTXOs.
///
/// Checks for the following kinds of invalid spends:
///
/// Double-spends:
/// - duplicate spends that are both in this block,
Expand All @@ -36,8 +40,8 @@ pub fn transparent_spend(
non_finalized_chain_unspent_utxos: &HashMap<transparent::OutPoint, transparent::Utxo>,
non_finalized_chain_spent_utxos: &HashSet<transparent::OutPoint>,
finalized_state: &FinalizedState,
) -> Result<(), ValidateContextError> {
let mut block_spends = HashSet::new();
) -> Result<HashMap<transparent::OutPoint, transparent::Utxo>, ValidateContextError> {
let mut block_spends = HashMap::new();

for (spend_tx_index_in_block, transaction) in prepared.block.transactions.iter().enumerate() {
let spends = transaction.inputs().iter().filter_map(|input| match input {
Expand All @@ -48,15 +52,6 @@ pub fn transparent_spend(
});

for spend in spends {
// see `transparent_spend_chain_order` for the consensus rule
if !block_spends.insert(*spend) {
// reject in-block duplicate spends
return Err(DuplicateTransparentSpend {
outpoint: *spend,
location: "the same block",
});
}

let utxo = transparent_spend_chain_order(
*spend,
spend_tx_index_in_block,
Expand All @@ -75,13 +70,23 @@ pub fn transparent_spend(
// We don't want to use UTXOs from invalid pending blocks,
// so we check transparent coinbase maturity and shielding
// using known valid UTXOs during non-finalized chain validation.

let spend_restriction = transaction.coinbase_spend_restriction(prepared.height);
transparent_coinbase_spend(*spend, spend_restriction, utxo)?;
let utxo = transparent_coinbase_spend(*spend, spend_restriction, utxo)?;

// We don't delete the UTXOs until the block is committed,
// so we need to check for duplicate spends within the same block.
//
// See `transparent_spend_chain_order` for the relevant consensus rule.
if block_spends.insert(*spend, utxo).is_some() {
return Err(DuplicateTransparentSpend {
outpoint: *spend,
location: "the same block",
});
}
}
}

Ok(())
Ok(block_spends)
}

/// Check that transparent spends occur in chain order.
Expand Down