Skip to content

Commit

Permalink
create known_outpoint_hashes in block verifier to be shared across …
Browse files Browse the repository at this point in the history
…transaction verifier calls
  • Loading branch information
arya2 committed Oct 19, 2024
1 parent b9ec784 commit ee23d3d
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 10 deletions.
8 changes: 7 additions & 1 deletion zebra-consensus/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
//! verification, where it may be accepted or rejected.

use std::{
collections::HashSet,
future::Future,
pin::Pin,
sync::Arc,
Expand All @@ -25,7 +26,7 @@ use zebra_chain::{
amount::Amount,
block,
parameters::{subsidy::FundingStreamReceiver, Network},
transparent,
transaction, transparent,
work::equihash,
};
use zebra_state as zs;
Expand Down Expand Up @@ -232,13 +233,18 @@ where
&block,
&transaction_hashes,
));

let known_outpoint_hashes: Arc<HashSet<transaction::Hash>> =
Arc::new(known_utxos.keys().map(|outpoint| outpoint.hash).collect());

for transaction in &block.transactions {
let rsp = transaction_verifier
.ready()
.await
.expect("transaction verifier is always ready")
.call(tx::Request::Block {
transaction: transaction.clone(),
known_outpoint_hashes: known_outpoint_hashes.clone(),
known_utxos: known_utxos.clone(),
height,
time: block.header.time,
Expand Down
21 changes: 14 additions & 7 deletions zebra-consensus/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ pub enum Request {
Block {
/// The transaction itself.
transaction: Arc<Transaction>,
/// Set of transaction hashes that create new transparent outputs.
known_outpoint_hashes: Arc<HashSet<transaction::Hash>>,
/// Additional UTXOs which are known at the time of verification.
known_utxos: Arc<HashMap<transparent::OutPoint, transparent::OrderedUtxo>>,
/// The height of the block containing this transaction.
Expand Down Expand Up @@ -267,6 +269,17 @@ impl Request {
}
}

/// The set of additional known [`transparent::OutPoint`]s of unspent transaction outputs that's in this request.
pub fn known_outpoint_hashes(&self) -> Arc<HashSet<transaction::Hash>> {
match self {
Request::Block {
known_outpoint_hashes,
..
} => known_outpoint_hashes.clone(),
Request::Mempool { .. } => HashSet::new().into(),
}
}

/// The height used to select the consensus rules for verifying this transaction.
pub fn height(&self) -> block::Height {
match self {
Expand Down Expand Up @@ -635,14 +648,8 @@ where
return None;
}

// TODO: Do this transformation in the block verifier and include it in Request::Block instead?.
let known_outpoint_hashes: HashSet<transaction::Hash> = req
.known_utxos()
.keys()
.map(|outpoint| outpoint.hash)
.collect();

let mut mempool = mempool?;
let known_outpoint_hashes = req.known_outpoint_hashes();
let tx_id = req.transaction().hash();

let mempool::Response::TransactionWithDeps {
Expand Down
37 changes: 36 additions & 1 deletion zebra-consensus/src/transaction/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
//
// TODO: split fixed test vectors into a `vectors` module?

use std::{collections::HashMap, sync::Arc};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};

use chrono::{DateTime, TimeZone, Utc};
use color_eyre::eyre::Report;
Expand Down Expand Up @@ -984,6 +987,7 @@ async fn v5_transaction_is_rejected_before_nu5_activation() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: canopy
.activation_height(&network)
.expect("Canopy activation height is specified"),
Expand Down Expand Up @@ -1044,6 +1048,7 @@ fn v5_transaction_is_accepted_after_nu5_activation_for_network(network: Network)
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: expiry_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1099,6 +1104,7 @@ async fn v4_transaction_with_transparent_transfer_is_accepted() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1143,6 +1149,7 @@ async fn v4_transaction_with_last_valid_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1188,6 +1195,7 @@ async fn v4_coinbase_transaction_with_low_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1235,6 +1243,7 @@ async fn v4_transaction_with_too_low_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1285,6 +1294,7 @@ async fn v4_transaction_with_exceeding_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1338,6 +1348,7 @@ async fn v4_coinbase_transaction_with_exceeding_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1389,6 +1400,7 @@ async fn v4_coinbase_transaction_is_accepted() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1444,6 +1456,7 @@ async fn v4_transaction_with_transparent_transfer_is_rejected_by_the_script() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1499,6 +1512,7 @@ async fn v4_transaction_with_conflicting_transparent_spend_is_rejected() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1570,6 +1584,7 @@ fn v4_transaction_with_conflicting_sprout_nullifier_inside_joinsplit_is_rejected
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1646,6 +1661,7 @@ fn v4_transaction_with_conflicting_sprout_nullifier_across_joinsplits_is_rejecte
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1705,6 +1721,7 @@ async fn v5_transaction_with_transparent_transfer_is_accepted() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1751,6 +1768,7 @@ async fn v5_transaction_with_last_valid_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1796,6 +1814,7 @@ async fn v5_coinbase_transaction_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand All @@ -1817,6 +1836,7 @@ async fn v5_coinbase_transaction_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(new_transaction.clone()),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1846,6 +1866,7 @@ async fn v5_coinbase_transaction_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(new_transaction.clone()),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1877,6 +1898,7 @@ async fn v5_coinbase_transaction_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(new_transaction.clone()),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: new_expiry_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1926,6 +1948,7 @@ async fn v5_transaction_with_too_low_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -1977,6 +2000,7 @@ async fn v5_transaction_with_exceeding_expiry_height() {
.oneshot(Request::Block {
transaction: Arc::new(transaction.clone()),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2031,6 +2055,7 @@ async fn v5_coinbase_transaction_is_accepted() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2088,6 +2113,7 @@ async fn v5_transaction_with_transparent_transfer_is_rejected_by_the_script() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2145,6 +2171,7 @@ async fn v5_transaction_with_conflicting_transparent_spend_is_rejected() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height: transaction_block_height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2189,6 +2216,7 @@ fn v4_with_signed_sprout_transfer_is_accepted() {
.oneshot(Request::Block {
transaction,
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2278,6 +2306,7 @@ async fn v4_with_joinsplit_is_rejected_for_modification(
.oneshot(Request::Block {
transaction: transaction.clone(),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2324,6 +2353,7 @@ fn v4_with_sapling_spends() {
.oneshot(Request::Block {
transaction,
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2366,6 +2396,7 @@ fn v4_with_duplicate_sapling_spends() {
.oneshot(Request::Block {
transaction,
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2410,6 +2441,7 @@ fn v4_with_sapling_outputs_and_no_spends() {
.oneshot(Request::Block {
transaction,
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2458,6 +2490,7 @@ fn v5_with_sapling_spends() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2501,6 +2534,7 @@ fn v5_with_duplicate_sapling_spends() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down Expand Up @@ -2563,6 +2597,7 @@ fn v5_with_duplicate_orchard_action() {
.oneshot(Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(HashMap::new()),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: DateTime::<Utc>::MAX_UTC,
})
Expand Down
6 changes: 5 additions & 1 deletion zebra-consensus/src/transaction/tests/prop.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Randomised property tests for transaction verification.

use std::{collections::HashMap, sync::Arc};
use std::{
collections::{HashMap, HashSet},
sync::Arc,
};

use chrono::{DateTime, Duration, Utc};
use proptest::{collection::vec, prelude::*};
Expand Down Expand Up @@ -459,6 +462,7 @@ fn validate(
.oneshot(transaction::Request::Block {
transaction: Arc::new(transaction),
known_utxos: Arc::new(known_utxos),
known_outpoint_hashes: Arc::new(HashSet::new()),
height,
time: block_time,
})
Expand Down

0 comments on commit ee23d3d

Please sign in to comment.