Return valid `Utxo`s from `check::transparent_spend` (#2561)

Later PRs will use these UTXOs to check other transparent consensus rules.

Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>
This commit is contained in:
teor 2021-08-04 06:53:47 +10:00 committed by GitHub
parent 29a658be11
commit 86bbafd02d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 20 additions and 15 deletions

View File

@ -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,
@ -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 {
@ -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,
@ -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.