From 764c4663a09e8b0f96778b9b0798b5940584e5f7 Mon Sep 17 00:00:00 2001 From: Boog900 <54e72d8a-345f-4599-bd90-c6b9bc7d0ec5@aleeas.com> Date: Sun, 5 Jan 2025 01:07:20 +0000 Subject: [PATCH] cross block bp(+) batch verification --- consensus/src/block/batch_prepare.rs | 21 ++++++++++++++++++--- consensus/src/transactions.rs | 15 ++++++++++++++- consensus/src/transactions/free.rs | 17 +++++++++++++++-- storage/txpool/src/types.rs | 1 + types/src/transaction_verification_data.rs | 2 ++ 5 files changed, 50 insertions(+), 6 deletions(-) diff --git a/consensus/src/block/batch_prepare.rs b/consensus/src/block/batch_prepare.rs index ef384f5..3aee6eb 100644 --- a/consensus/src/block/batch_prepare.rs +++ b/consensus/src/block/batch_prepare.rs @@ -20,6 +20,8 @@ use crate::{ BlockChainContextRequest, BlockChainContextResponse, ExtendedConsensusError, VerifyBlockResponse, }; +use crate::batch_verifier::MultiThreadedBatchVerifier; +use crate::transactions::verify_tx_semantic; /// Batch prepares a list of blocks for verification. #[instrument(level = "debug", name = "batch_prep_blocks", skip_all, fields(amt = blocks.len()))] @@ -168,7 +170,9 @@ where tracing::debug!("Calculating PoW and prepping transaction"); let blocks = rayon_spawn_async(move || { - blocks + let batch_verifier = MultiThreadedBatchVerifier::new(rayon::current_num_threads()); + + let res = blocks .into_par_iter() .zip(difficulties) .zip(txs) @@ -183,11 +187,16 @@ where // Check the PoW check_block_pow(&block.pow_hash, difficultly).map_err(ConsensusError::Block)?; + let hf = block.hf_version; + // Now setup the txs. let txs = txs .into_par_iter() .map(|tx| { - let tx = new_tx_verification_data(tx)?; + let mut tx = new_tx_verification_data(tx)?; + + verify_tx_semantic(&mut tx, hf, &batch_verifier)?; + Ok::<_, ConsensusError>((tx.tx_hash, tx)) }) .collect::, _>>()?; @@ -201,7 +210,13 @@ where Ok((block, ordered_txs)) }) - .collect::, ExtendedConsensusError>>() + .collect::, ExtendedConsensusError>>()?; + + if !batch_verifier.verify() { + return Err(ExtendedConsensusError::OneOrMoreBatchVerificationStatementsInvalid); + } + + Ok(res) }) .await?; diff --git a/consensus/src/transactions.rs b/consensus/src/transactions.rs index f29c852..246718b 100644 --- a/consensus/src/transactions.rs +++ b/consensus/src/transactions.rs @@ -38,7 +38,7 @@ use crate::{ pub mod contextual_data; mod free; -pub use free::new_tx_verification_data; +pub use free::{new_tx_verification_data, verify_tx_semantic}; /// A struct representing the type of validation that needs to be completed for this transaction. #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -333,6 +333,19 @@ fn transactions_needing_verification( .push((Arc::clone(tx), VerificationNeeded::SemanticAndContextual)); continue; } + CachedVerificationState::SemanticallyValidAtHF(hf) => { + if current_hf != *hf { + drop(guard); + full_validation_transactions + .push((Arc::clone(tx), VerificationNeeded::SemanticAndContextual)); + continue; + } + + drop(guard); + full_validation_transactions + .push((Arc::clone(tx), VerificationNeeded::Contextual)); + continue; + } CachedVerificationState::ValidAtHashAndHF { block_hash, hf } => { if current_hf != *hf { drop(guard); diff --git a/consensus/src/transactions/free.rs b/consensus/src/transactions/free.rs index 3613f29..35e4228 100644 --- a/consensus/src/transactions/free.rs +++ b/consensus/src/transactions/free.rs @@ -1,4 +1,4 @@ -use std::sync::Mutex as StdMutex; +use std::sync::{Arc, Mutex as StdMutex}; use monero_serai::{ ringct::{bulletproofs::Bulletproof, RctType}, @@ -6,7 +6,8 @@ use monero_serai::{ }; use cuprate_consensus_rules::{transactions::TransactionError, ConsensusError}; -use cuprate_types::{CachedVerificationState, TransactionVerificationData, TxVersion}; +use cuprate_types::{CachedVerificationState, HardFork, TransactionVerificationData, TxVersion}; +use crate::batch_verifier::MultiThreadedBatchVerifier; /// Creates a new [`TransactionVerificationData`] from a [`Transaction`]. /// @@ -36,6 +37,18 @@ pub fn new_tx_verification_data( }) } +pub fn verify_tx_semantic( + tx: &mut TransactionVerificationData, + hf: HardFork, + multi_threaded_batch_verifier: &MultiThreadedBatchVerifier, +) -> Result<(), ConsensusError> { + cuprate_consensus_rules::transactions::check_transaction_semantic(&tx.tx, tx.tx_blob.len(), tx.tx_weight, &tx.tx_hash, hf, multi_threaded_batch_verifier)?; + + *tx.cached_verification_state.get_mut().unwrap() = CachedVerificationState::SemanticallyValidAtHF(hf); + + Ok(()) +} + /// Calculates the weight of a [`Transaction`]. /// /// This is more efficient that [`Transaction::weight`] if you already have the transaction blob. diff --git a/storage/txpool/src/types.rs b/storage/txpool/src/types.rs index 2acb819..5cf1738 100644 --- a/storage/txpool/src/types.rs +++ b/storage/txpool/src/types.rs @@ -103,6 +103,7 @@ impl From for RawCachedVerificationState { raw_hf: 0, raw_valid_past_timestamp: [0; 8], }, + CachedVerificationState::SemanticallyValidAtHF(hf) => todo!(), CachedVerificationState::ValidAtHashAndHF { block_hash, hf } => Self { raw_valid_at_hash: block_hash, raw_hf: hf.as_u8(), diff --git a/types/src/transaction_verification_data.rs b/types/src/transaction_verification_data.rs index 3dfe5fd..8a02da0 100644 --- a/types/src/transaction_verification_data.rs +++ b/types/src/transaction_verification_data.rs @@ -37,6 +37,7 @@ impl TxVersion { pub enum CachedVerificationState { /// The transaction has not been validated. NotVerified, + SemanticallyValidAtHF(HardFork), /// The transaction is valid* if the block represented by this hash is in the blockchain and the [`HardFork`] /// is the same. /// @@ -68,6 +69,7 @@ impl CachedVerificationState { pub const fn verified_at_block_hash(&self) -> Option<[u8; 32]> { match self { Self::NotVerified => None, + Self::SemanticallyValidAtHF(_) => None, Self::ValidAtHashAndHF { block_hash, .. } | Self::ValidAtHashAndHFWithTimeBasedLock { block_hash, .. } => Some(*block_hash), }