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:
parent
29a658be11
commit
86bbafd02d
|
@ -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:
|
/// Double-spends:
|
||||||
/// - duplicate spends that are both in this block,
|
/// - 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_unspent_utxos: &HashMap<transparent::OutPoint, transparent::Utxo>,
|
||||||
non_finalized_chain_spent_utxos: &HashSet<transparent::OutPoint>,
|
non_finalized_chain_spent_utxos: &HashSet<transparent::OutPoint>,
|
||||||
finalized_state: &FinalizedState,
|
finalized_state: &FinalizedState,
|
||||||
) -> Result<(), ValidateContextError> {
|
) -> Result<HashMap<transparent::OutPoint, transparent::Utxo>, ValidateContextError> {
|
||||||
let mut block_spends = HashSet::new();
|
let mut block_spends = HashMap::new();
|
||||||
|
|
||||||
for (spend_tx_index_in_block, transaction) in prepared.block.transactions.iter().enumerate() {
|
for (spend_tx_index_in_block, transaction) in prepared.block.transactions.iter().enumerate() {
|
||||||
let spends = transaction.inputs().iter().filter_map(|input| match input {
|
let spends = transaction.inputs().iter().filter_map(|input| match input {
|
||||||
|
@ -48,15 +52,6 @@ pub fn transparent_spend(
|
||||||
});
|
});
|
||||||
|
|
||||||
for spend in spends {
|
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(
|
let utxo = transparent_spend_chain_order(
|
||||||
*spend,
|
*spend,
|
||||||
spend_tx_index_in_block,
|
spend_tx_index_in_block,
|
||||||
|
@ -75,13 +70,23 @@ pub fn transparent_spend(
|
||||||
// We don't want to use UTXOs from invalid pending blocks,
|
// We don't want to use UTXOs from invalid pending blocks,
|
||||||
// so we check transparent coinbase maturity and shielding
|
// so we check transparent coinbase maturity and shielding
|
||||||
// using known valid UTXOs during non-finalized chain validation.
|
// using known valid UTXOs during non-finalized chain validation.
|
||||||
|
|
||||||
let spend_restriction = transaction.coinbase_spend_restriction(prepared.height);
|
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.
|
/// Check that transparent spends occur in chain order.
|
||||||
|
|
Loading…
Reference in New Issue