diff --git a/chainstate/src/detail/chainstateref/in_memory_reorg.rs b/chainstate/src/detail/chainstateref/in_memory_reorg.rs index 107e32c6d..04c02acbf 100644 --- a/chainstate/src/detail/chainstateref/in_memory_reorg.rs +++ b/chainstate/src/detail/chainstateref/in_memory_reorg.rs @@ -160,6 +160,7 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat TransactionVerifier::new, &tx_verifier, self.chain_config, + &cur_index, &block.into(), )? .consume()?; diff --git a/chainstate/src/detail/chainstateref/mod.rs b/chainstate/src/detail/chainstateref/mod.rs index c72b10b81..c9e9803b4 100644 --- a/chainstate/src/detail/chainstateref/mod.rs +++ b/chainstate/src/detail/chainstateref/mod.rs @@ -1206,11 +1206,16 @@ impl ChainstateRe } #[log_error] - fn disconnect_transactions(&mut self, block: &WithId) -> Result<(), BlockError> { + fn disconnect_transactions( + &mut self, + block_index: &BlockIndex, + block: &WithId, + ) -> Result<(), BlockError> { let cached_inputs = self.tx_verification_strategy.disconnect_block( TransactionVerifier::new, &*self, self.chain_config, + block_index, block, )?; let cached_inputs = cached_inputs.consume()?; @@ -1302,7 +1307,7 @@ impl ChainstateRe .expect("Best block index not present in the database"); let block = self.get_block_from_index(&block_index)?.expect("Inconsistent DB"); // Disconnect transactions - self.disconnect_transactions(&block.into())?; + self.disconnect_transactions(&block_index, &block.into())?; self.db_tx.set_best_block_id(block_index.prev_block_id())?; // Disconnect block self.db_tx.del_block_id_at_height(&block_index.block_height())?; diff --git a/chainstate/src/detail/tx_verification_strategy/default_strategy.rs b/chainstate/src/detail/tx_verification_strategy/default_strategy.rs index 3c3da64f6..edda6b78c 100644 --- a/chainstate/src/detail/tx_verification_strategy/default_strategy.rs +++ b/chainstate/src/detail/tx_verification_strategy/default_strategy.rs @@ -24,12 +24,9 @@ use constraints_value_accumulator::AccumulatedFee; use orders_accounting::OrdersAccountingView; use pos_accounting::PoSAccountingView; use tokens_accounting::TokensAccountingView; -use tx_verifier::{ - transaction_verifier::{ - error::ConnectTransactionError, storage::TransactionVerifierStorageRef, - TransactionSourceForConnect, TransactionVerifier, - }, - TransactionSource, +use tx_verifier::transaction_verifier::{ + error::ConnectTransactionError, storage::TransactionVerifierStorageRef, + TransactionSourceWithHeight, TransactionVerifier, }; use utils::{shallow_clone::ShallowClone, tap_log::TapLog}; use utxo::UtxosView; @@ -76,7 +73,7 @@ impl TransactionVerificationStrategy for DefaultTransactionVerificationStrategy .try_fold(AccumulatedFee::new(), |total, tx| { let fee = tx_verifier .connect_transaction( - &TransactionSourceForConnect::Chain { + &TransactionSourceWithHeight::Chain { new_block_index: block_index, }, tx, @@ -120,6 +117,7 @@ impl TransactionVerificationStrategy for DefaultTransactionVerificationStrategy tx_verifier_maker: M, storage_backend: S, chain_config: C, + block_index: &BlockIndex, block: &WithId, ) -> Result, ConnectTransactionError> where @@ -141,7 +139,12 @@ impl TransactionVerificationStrategy for DefaultTransactionVerificationStrategy .iter() .rev() .try_for_each(|tx| { - tx_verifier.disconnect_transaction(&TransactionSource::Chain(block.get_id()), tx) + tx_verifier.disconnect_transaction( + &TransactionSourceWithHeight::Chain { + new_block_index: block_index, + }, + tx, + ) }) .log_err()?; diff --git a/chainstate/src/detail/tx_verification_strategy/mod.rs b/chainstate/src/detail/tx_verification_strategy/mod.rs index c793a9dcf..8174b9589 100644 --- a/chainstate/src/detail/tx_verification_strategy/mod.rs +++ b/chainstate/src/detail/tx_verification_strategy/mod.rs @@ -84,6 +84,7 @@ pub trait TransactionVerificationStrategy: Sized + Send { tx_verifier_maker: M, storage_backend: S, chain_config: C, + block_index: &BlockIndex, block: &WithId, ) -> Result, ConnectTransactionError> where diff --git a/chainstate/test-framework/src/tx_verification_strategy/disposable_strategy.rs b/chainstate/test-framework/src/tx_verification_strategy/disposable_strategy.rs index b6e1be89f..0c548d541 100644 --- a/chainstate/test-framework/src/tx_verification_strategy/disposable_strategy.rs +++ b/chainstate/test-framework/src/tx_verification_strategy/disposable_strategy.rs @@ -25,12 +25,9 @@ use constraints_value_accumulator::AccumulatedFee; use orders_accounting::OrdersAccountingView; use pos_accounting::PoSAccountingView; use tokens_accounting::TokensAccountingView; -use tx_verifier::{ - transaction_verifier::{ - error::ConnectTransactionError, flush::flush_to_storage, - storage::TransactionVerifierStorageRef, TransactionSourceForConnect, TransactionVerifier, - }, - TransactionSource, +use tx_verifier::transaction_verifier::{ + error::ConnectTransactionError, flush::flush_to_storage, + storage::TransactionVerifierStorageRef, TransactionSourceWithHeight, TransactionVerifier, }; use utils::{shallow_clone::ShallowClone, tap_log::TapLog}; use utxo::UtxosView; @@ -81,7 +78,7 @@ impl TransactionVerificationStrategy for DisposableTransactionVerificationStrate let mut tx_verifier = base_tx_verifier.derive_child(); let fee = tx_verifier .connect_transaction( - &TransactionSourceForConnect::Chain { + &TransactionSourceWithHeight::Chain { new_block_index: block_index, }, tx, @@ -128,6 +125,7 @@ impl TransactionVerificationStrategy for DisposableTransactionVerificationStrate tx_verifier_maker: M, storage_backend: S, chain_config: C, + block_index: &BlockIndex, block: &WithId, ) -> Result, ConnectTransactionError> where @@ -155,7 +153,12 @@ impl TransactionVerificationStrategy for DisposableTransactionVerificationStrate let mut tx_verifier = base_tx_verifier.derive_child(); tx_verifier - .disconnect_transaction(&TransactionSource::Chain(block.get_id()), tx) + .disconnect_transaction( + &TransactionSourceWithHeight::Chain { + new_block_index: block_index, + }, + tx, + ) .log_err()?; let consumed_cache = tx_verifier.consume()?; diff --git a/chainstate/test-framework/src/tx_verification_strategy/randomized_strategy.rs b/chainstate/test-framework/src/tx_verification_strategy/randomized_strategy.rs index 6c71cd0ed..1bdf70f9e 100644 --- a/chainstate/test-framework/src/tx_verification_strategy/randomized_strategy.rs +++ b/chainstate/test-framework/src/tx_verification_strategy/randomized_strategy.rs @@ -27,13 +27,10 @@ use pos_accounting::PoSAccountingView; use randomness::{Rng, RngCore}; use test_utils::random::{make_seedable_rng, Seed}; use tokens_accounting::TokensAccountingView; -use tx_verifier::{ - transaction_verifier::{ - error::ConnectTransactionError, flush::flush_to_storage, - storage::TransactionVerifierStorageRef, TransactionSourceForConnect, TransactionVerifier, - TransactionVerifierDelta, - }, - TransactionSource, +use tx_verifier::transaction_verifier::{ + error::ConnectTransactionError, flush::flush_to_storage, + storage::TransactionVerifierStorageRef, TransactionSourceWithHeight, TransactionVerifier, + TransactionVerifierDelta, }; use utils::{shallow_clone::ShallowClone, tap_log::TapLog}; use utxo::UtxosView; @@ -105,6 +102,7 @@ impl TransactionVerificationStrategy for RandomizedTransactionVerificationStrate tx_verifier_maker: M, storage_backend: S, chain_config: C, + block_index: &BlockIndex, block: &WithId, ) -> Result, ConnectTransactionError> where @@ -117,8 +115,13 @@ impl TransactionVerificationStrategy for RandomizedTransactionVerificationStrate M: TransactionVerifierMakerFn, ::Error: From, { - let mut tx_verifier = - self.disconnect_with_base(tx_verifier_maker, storage_backend, chain_config, block)?; + let mut tx_verifier = self.disconnect_with_base( + tx_verifier_maker, + storage_backend, + chain_config, + block_index, + block, + )?; tx_verifier.set_best_block(block.prev_block_id()); @@ -173,7 +176,7 @@ impl RandomizedTransactionVerificationStrategy { // connect transactable using current verifier let fee = tx_verifier.connect_transaction( - &TransactionSourceForConnect::Chain { + &TransactionSourceWithHeight::Chain { new_block_index: block_index, }, &block.transactions()[tx_num], @@ -239,7 +242,7 @@ impl RandomizedTransactionVerificationStrategy { } else { // connect transactable using current verifier let fee = tx_verifier.connect_transaction( - &TransactionSourceForConnect::Chain { + &TransactionSourceWithHeight::Chain { new_block_index: block_index, }, &block.transactions()[tx_num], @@ -261,6 +264,7 @@ impl RandomizedTransactionVerificationStrategy { tx_verifier_maker: M, storage_backend: S, chain_config: C, + block_index: &BlockIndex, block: &WithId, ) -> Result, ConnectTransactionError> where @@ -282,7 +286,7 @@ impl RandomizedTransactionVerificationStrategy { if self.rng.lock().unwrap().gen::() { // derive a new cache let (consumed_cache, new_tx_index) = - self.disconnect_with_derived(&tx_verifier, block, tx_num)?; + self.disconnect_with_derived(&tx_verifier, block_index, block, tx_num)?; flush_to_storage(&mut tx_verifier, consumed_cache) .map_err(ConnectTransactionError::from)?; @@ -291,7 +295,9 @@ impl RandomizedTransactionVerificationStrategy { // disconnect transactable using current verifier tx_verifier .disconnect_transaction( - &TransactionSource::Chain(block.get_id()), + &TransactionSourceWithHeight::Chain { + new_block_index: block_index, + }, &block.transactions()[tx_num as usize], ) .log_err()?; @@ -305,6 +311,7 @@ impl RandomizedTransactionVerificationStrategy { fn disconnect_with_derived( &self, base_tx_verifier: &TransactionVerifier, + block_index: &BlockIndex, block: &WithId, mut tx_num: i32, ) -> Result<(TransactionVerifierDelta, i32), ConnectTransactionError> @@ -325,7 +332,9 @@ impl RandomizedTransactionVerificationStrategy { } else { // disconnect transactable using current verifier tx_verifier.disconnect_transaction( - &TransactionSource::Chain(block.get_id()), + &TransactionSourceWithHeight::Chain { + new_block_index: block_index, + }, &block.transactions()[tx_num as usize], )?; tx_num -= 1; diff --git a/chainstate/test-suite/src/tests/mempool_output_timelock.rs b/chainstate/test-suite/src/tests/mempool_output_timelock.rs index c9120a562..868e5e477 100644 --- a/chainstate/test-suite/src/tests/mempool_output_timelock.rs +++ b/chainstate/test-suite/src/tests/mempool_output_timelock.rs @@ -30,7 +30,7 @@ use rstest::rstest; use test_utils::random::{make_seedable_rng, Seed}; use tx_verifier::{ error::{InputCheckError, ScriptError, TimelockError}, - transaction_verifier::{TransactionSourceForConnect, TransactionVerifier}, + transaction_verifier::{TransactionSourceWithHeight, TransactionVerifier}, }; fn setup(rng: &mut (impl Rng + CryptoRng)) -> (ChainConfig, InMemoryStorageWrapper, TestFramework) { @@ -73,7 +73,7 @@ fn output_lock_until_height(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); assert_eq!( verifier.connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &BlockTimestamp::from_time(tf.current_time()), ), @@ -97,7 +97,7 @@ fn output_lock_until_height(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); verifier .connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &BlockTimestamp::from_time(tf.current_time()), ) @@ -138,7 +138,7 @@ fn output_lock_for_block_count(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); assert_eq!( verifier.connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &BlockTimestamp::from_time(tf.current_time()), ), @@ -165,7 +165,7 @@ fn output_lock_for_block_count(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); verifier .connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &BlockTimestamp::from_time(tf.current_time()), ) @@ -226,7 +226,7 @@ fn output_lock_until_time(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); assert_eq!( verifier.connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &mtp, ), @@ -254,7 +254,7 @@ fn output_lock_until_time(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); verifier .connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &BlockTimestamp::from_time(tf.current_time()), ) @@ -316,7 +316,7 @@ fn output_lock_for_seconds(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); assert_eq!( verifier.connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &mtp, ), @@ -349,7 +349,7 @@ fn output_lock_for_seconds(#[case] seed: Seed) { let best_block_index = tf.best_block_index(); verifier .connect_transaction( - &TransactionSourceForConnect::for_mempool(&best_block_index), + &TransactionSourceWithHeight::for_mempool(&best_block_index), &spend_locked_tx, &BlockTimestamp::from_time(time::get_time()), ) diff --git a/chainstate/test-suite/src/tests/tx_fee.rs b/chainstate/test-suite/src/tests/tx_fee.rs index 5eeddc452..bc92eef27 100644 --- a/chainstate/test-suite/src/tests/tx_fee.rs +++ b/chainstate/test-suite/src/tests/tx_fee.rs @@ -37,7 +37,7 @@ use common::{ use crypto::vrf::{VRFKeyKind, VRFPrivateKey}; use randomness::CryptoRng; use test_utils::random_ascii_alphanumeric_string; -use tx_verifier::transaction_verifier::{TransactionSourceForConnect, TransactionVerifier}; +use tx_verifier::transaction_verifier::{TransactionSourceWithHeight, TransactionVerifier}; use crate::tests::helpers::chainstate_upgrade_builder::ChainstateUpgradeBuilder; @@ -89,7 +89,7 @@ fn simple_fee_from_coin_transfer(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; @@ -161,7 +161,7 @@ fn transfer_lock_and_burn_outputs_fee(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; @@ -232,7 +232,7 @@ fn locked_outputs_can_go_to_fee(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(2), }; @@ -284,7 +284,7 @@ fn create_stake_pool(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; @@ -371,7 +371,7 @@ fn delegate_staking(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; @@ -451,7 +451,7 @@ fn fee_from_decommissioning_stake_pool(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(2), }; @@ -541,7 +541,7 @@ fn fee_from_spending_delegation_share(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(2), }; @@ -611,7 +611,7 @@ fn issue_fungible_token_v0(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, tf.chain_config().as_ref()); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; @@ -659,7 +659,7 @@ fn issue_fungible_token_v1(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; @@ -748,7 +748,7 @@ fn tokens_cannot_be_used_in_fee(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); - let tx_source = TransactionSourceForConnect::Mempool { + let tx_source = TransactionSourceWithHeight::Mempool { current_best: &tf.best_block_index(), effective_height: BlockHeight::new(1), }; diff --git a/chainstate/test-suite/src/tests/tx_verifier_disconnect.rs b/chainstate/test-suite/src/tests/tx_verifier_disconnect.rs index 722e16be0..bb7c7be1f 100644 --- a/chainstate/test-suite/src/tests/tx_verifier_disconnect.rs +++ b/chainstate/test-suite/src/tests/tx_verifier_disconnect.rs @@ -31,7 +31,7 @@ use randomness::CryptoRng; use tx_verifier::{ flush_to_storage, - transaction_verifier::{TransactionSource, TransactionSourceForConnect, TransactionVerifier}, + transaction_verifier::{TransactionSource, TransactionSourceWithHeight, TransactionVerifier}, }; fn setup(rng: &mut (impl Rng + CryptoRng)) -> (ChainConfig, InMemoryStorageWrapper, TestFramework) { @@ -63,6 +63,7 @@ fn attempt_to_disconnect_tx_mainchain(#[case] seed: Seed, #[case] num_blocks: us GenBlockId::Block(id) => id, }; let block = tf.block(block_id); + let block_index = tf.block_index(&block_id); let tx = block.transactions().first().unwrap(); let tx_id = tx.transaction().get_id(); @@ -74,7 +75,12 @@ fn attempt_to_disconnect_tx_mainchain(#[case] seed: Seed, #[case] num_blocks: us // try to disconnect anyway let mut tmp_verifier = verifier.derive_child(); assert_eq!( - tmp_verifier.disconnect_transaction(&TransactionSource::Chain(block_id), tx), + tmp_verifier.disconnect_transaction( + &TransactionSourceWithHeight::Chain { + new_block_index: &block_index + }, + tx + ), Err(ConnectTransactionError::UtxoError(utxo::Error::NoUtxoFound)) ); } @@ -85,6 +91,7 @@ fn attempt_to_disconnect_tx_mainchain(#[case] seed: Seed, #[case] num_blocks: us GenBlockId::Block(id) => id, }; let block = tf.block(block_id); + let block_index = tf.block_index(&block_id); let tx = block.transactions().first().unwrap(); let tx_id = tx.transaction().get_id(); @@ -92,7 +99,12 @@ fn attempt_to_disconnect_tx_mainchain(#[case] seed: Seed, #[case] num_blocks: us .can_disconnect_transaction(&TransactionSource::Chain(block_id), &tx_id) .unwrap()); verifier - .disconnect_transaction(&TransactionSource::Chain(block_id), tx) + .disconnect_transaction( + &TransactionSourceWithHeight::Chain { + new_block_index: &block_index, + }, + tx, + ) .unwrap(); }); } @@ -130,7 +142,7 @@ fn connect_disconnect_tx_mempool(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); let best_block_idx = best_block.into(); - let tx_source = TransactionSourceForConnect::for_mempool(&best_block_idx); + let tx_source = TransactionSourceWithHeight::for_mempool(&best_block_idx); // create and connect a tx from mempool based on best block let tx1 = TransactionBuilder::new() @@ -172,18 +184,22 @@ fn connect_disconnect_tx_mempool(#[case] seed: Seed) { .can_disconnect_transaction(&TransactionSource::Mempool, &tx2.transaction().get_id()) .unwrap()); + let source = TransactionSourceWithHeight::Mempool { + current_best: &best_block_idx, + effective_height: best_block_idx.block_height(), + }; assert_eq!( - verifier.disconnect_transaction(&TransactionSource::Mempool, &tx1), + verifier.disconnect_transaction(&source, &tx1), Err(ConnectTransactionError::UtxoBlockUndoError( utxo::UtxosBlockUndoError::TxUndoWithDependency(tx1.transaction().get_id()) )) ); - verifier.disconnect_transaction(&TransactionSource::Mempool, &tx2).unwrap(); + verifier.disconnect_transaction(&source, &tx2).unwrap(); assert!(verifier .can_disconnect_transaction(&TransactionSource::Mempool, &tx1.transaction().get_id()) .unwrap()); - verifier.disconnect_transaction(&TransactionSource::Mempool, &tx1).unwrap(); + verifier.disconnect_transaction(&source, &tx1).unwrap(); }); } @@ -220,7 +236,7 @@ fn connect_disconnect_tx_mempool_derived(#[case] seed: Seed) { let mut verifier = TransactionVerifier::new(&storage, &chain_config); let best_block_idx = best_block.into(); - let tx_source = TransactionSourceForConnect::for_mempool(&best_block_idx); + let tx_source = TransactionSourceWithHeight::for_mempool(&best_block_idx); // create and connect a tx from mempool based on best block let tx1 = TransactionBuilder::new() @@ -265,14 +281,12 @@ fn connect_disconnect_tx_mempool_derived(#[case] seed: Seed) { .unwrap()); assert_eq!( - child_verifier.disconnect_transaction(&TransactionSource::Mempool, &tx1), + child_verifier.disconnect_transaction(&tx_source, &tx1), Err(ConnectTransactionError::UtxoBlockUndoError( utxo::UtxosBlockUndoError::TxUndoWithDependency(tx1.transaction().get_id()) )) ); - child_verifier - .disconnect_transaction(&TransactionSource::Mempool, &tx2) - .unwrap(); + child_verifier.disconnect_transaction(&tx_source, &tx2).unwrap(); let consumed = child_verifier.consume().unwrap(); flush_to_storage(&mut verifier, consumed).unwrap(); @@ -282,9 +296,7 @@ fn connect_disconnect_tx_mempool_derived(#[case] seed: Seed) { assert!(child_verifier .can_disconnect_transaction(&TransactionSource::Mempool, &tx1.transaction().get_id()) .unwrap()); - child_verifier - .disconnect_transaction(&TransactionSource::Mempool, &tx1) - .unwrap(); + child_verifier.disconnect_transaction(&tx_source, &tx1).unwrap(); let consumed = child_verifier.consume().unwrap(); flush_to_storage(&mut verifier, consumed).unwrap(); diff --git a/chainstate/tx-verifier/src/transaction_verifier/input_check/mod.rs b/chainstate/tx-verifier/src/transaction_verifier/input_check/mod.rs index a34b4e65b..cc3de7b41 100644 --- a/chainstate/tx-verifier/src/transaction_verifier/input_check/mod.rs +++ b/chainstate/tx-verifier/src/transaction_verifier/input_check/mod.rs @@ -32,7 +32,7 @@ use mintscript::{ use crate::TransactionVerifierStorageRef; -use super::TransactionSourceForConnect; +use super::TransactionSourceWithHeight; pub mod signature_only_check; @@ -339,15 +339,15 @@ impl<'a, S> VerifyContextTimelock<'a, S> { fn for_verifier( chain_config: &'a ChainConfig, storage: &'a S, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, spending_time: BlockTimestamp, core_ctx: &'a CoreContext<'a>, ) -> Self { let tip = match tx_source { - TransactionSourceForConnect::Chain { new_block_index } => { + TransactionSourceWithHeight::Chain { new_block_index } => { (*new_block_index.block_id()).into() } - TransactionSourceForConnect::Mempool { + TransactionSourceWithHeight::Mempool { current_best, effective_height: _, } => current_best.block_id(), @@ -535,7 +535,7 @@ pub fn verify_full( tokens_accounting: &TV, orders_accounting: &OV, storage: &S, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, spending_time: BlockTimestamp, ) -> Result<(), InputCheckError> where diff --git a/chainstate/tx-verifier/src/transaction_verifier/mod.rs b/chainstate/tx-verifier/src/transaction_verifier/mod.rs index 40ddf10fc..85d8483dc 100644 --- a/chainstate/tx-verifier/src/transaction_verifier/mod.rs +++ b/chainstate/tx-verifier/src/transaction_verifier/mod.rs @@ -39,7 +39,7 @@ use tokens_accounting::{ TokenAccountingUndo, TokensAccountingCache, TokensAccountingDB, TokensAccountingDeltaData, TokensAccountingOperations, TokensAccountingStorageRead, TokensAccountingView, }; -pub use tx_source::{TransactionSource, TransactionSourceForConnect}; +pub use tx_source::{TransactionSource, TransactionSourceWithHeight}; mod cached_operation; pub use cached_operation::CachedOperation; @@ -343,7 +343,7 @@ where fn connect_pos_accounting_outputs( &mut self, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, tx: &Transaction, ) -> Result<(), ConnectTransactionError> { let mut check_delegation: Option = None; @@ -488,7 +488,7 @@ where fn disconnect_accounting_outputs( &mut self, - tx_source: TransactionSource, + tx_source: &TransactionSourceWithHeight, tx: &Transaction, ) -> Result<(), ConnectTransactionError> { // decrement nonce if disconnected input spent from an account @@ -498,12 +498,38 @@ where TxInput::Account(outpoint) => { self.unspend_input_from_account(outpoint.account().clone().into())?; } - TxInput::AccountCommand(_, cmd) => { - self.unspend_input_from_account(cmd.clone().into())?; - } + TxInput::AccountCommand(_, cmd) => match cmd { + AccountCommand::MintTokens(..) + | AccountCommand::UnmintTokens(..) + | AccountCommand::LockTokenSupply(..) + | AccountCommand::FreezeToken(..) + | AccountCommand::UnfreezeToken(..) + | AccountCommand::ChangeTokenAuthority(..) + | AccountCommand::ConcludeOrder(..) + | AccountCommand::ChangeTokenMetadataUri(..) => { + self.unspend_input_from_account(cmd.clone().into())?; + } + AccountCommand::FillOrder(..) => { + let orders_version = self + .chain_config + .as_ref() + .chainstate_upgrades() + .version_at_height(tx_source.expected_block_height()) + .1 + .orders_version(); + match orders_version { + OrdersVersion::V0 => { + self.unspend_input_from_account(cmd.clone().into())?; + } + OrdersVersion::V1 => { /* ignore nonce */ } + } + } + }, }; } + let tx_source = tx_source.into(); + self.disconnect_pos_accounting_outputs(tx_source, tx)?; self.disconnect_tokens_accounting_outputs(tx_source, tx)?; @@ -540,7 +566,7 @@ where fn connect_tokens_outputs( &mut self, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, tx: &Transaction, ) -> Result<(), ConnectTransactionError> { self.check_operations_with_frozen_tokens(tx, tx_source.expected_block_height())?; @@ -813,7 +839,7 @@ where fn connect_orders_outputs( &mut self, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, tx: &Transaction, ) -> Result<(), ConnectTransactionError> { let input_undos = tx @@ -941,7 +967,7 @@ where pub fn connect_transaction( &mut self, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, tx: &SignedTransaction, median_time_past: &BlockTimestamp, ) -> Result { @@ -1004,7 +1030,7 @@ where ) -> Result<(), ConnectTransactionError> { // TODO: test spending block rewards from chains outside the mainchain if reward_transactable.inputs().is_some() { - let tx_source = TransactionSourceForConnect::for_chain(block_index); + let tx_source = TransactionSourceWithHeight::for_chain(block_index); self.verify_inputs(&reward_transactable, &tx_source, median_time_past)?; } @@ -1114,7 +1140,7 @@ where pub fn disconnect_transaction( &mut self, - tx_source: &TransactionSource, + tx_source: &TransactionSourceWithHeight, tx: &SignedTransaction, ) -> Result<(), ConnectTransactionError> { let block_undo_fetcher = |tx_source: TransactionSource| { @@ -1123,12 +1149,12 @@ where .map_err(|_| ConnectTransactionError::UndoFetchFailure) }; let tx_undo = self.utxo_block_undo.take_tx_undo( - tx_source, + &TransactionSource::from(tx_source), &tx.transaction().get_id(), block_undo_fetcher, )?; - self.disconnect_accounting_outputs(*tx_source, tx.transaction())?; + self.disconnect_accounting_outputs(tx_source, tx.transaction())?; self.utxo_cache.disconnect_transaction(tx.transaction(), tx_undo)?; @@ -1192,7 +1218,7 @@ where pub fn verify_inputs( &self, tx: &Tx, - tx_source: &TransactionSourceForConnect, + tx_source: &TransactionSourceWithHeight, median_time_past: BlockTimestamp, ) -> Result<(), input_check::InputCheckError> where diff --git a/chainstate/tx-verifier/src/transaction_verifier/tx_source.rs b/chainstate/tx-verifier/src/transaction_verifier/tx_source.rs index accda837c..0bbca1b96 100644 --- a/chainstate/tx-verifier/src/transaction_verifier/tx_source.rs +++ b/chainstate/tx-verifier/src/transaction_verifier/tx_source.rs @@ -26,13 +26,13 @@ pub enum TransactionSource { Mempool, } -impl From<&TransactionSourceForConnect<'_>> for TransactionSource { - fn from(t: &TransactionSourceForConnect) -> Self { +impl From<&TransactionSourceWithHeight<'_>> for TransactionSource { + fn from(t: &TransactionSourceWithHeight) -> Self { match t { - TransactionSourceForConnect::Chain { new_block_index } => { + TransactionSourceWithHeight::Chain { new_block_index } => { TransactionSource::Chain(*new_block_index.block_id()) } - TransactionSourceForConnect::Mempool { + TransactionSourceWithHeight::Mempool { current_best: _, effective_height: _, } => TransactionSource::Mempool, @@ -45,7 +45,7 @@ impl From<&TransactionSourceForConnect<'_>> for TransactionSource { /// it's more complicated because it may either be for the possible next block, /// or it might have some required tolerance for calculating the height, due /// to timelocks depending on timestamps of blocks that haven't yet been created. -pub enum TransactionSourceForConnect<'a> { +pub enum TransactionSourceWithHeight<'a> { Chain { new_block_index: &'a BlockIndex, }, @@ -57,7 +57,7 @@ pub enum TransactionSourceForConnect<'a> { }, } -impl<'a> TransactionSourceForConnect<'a> { +impl<'a> TransactionSourceWithHeight<'a> { pub fn for_chain(new_block_index: &'a BlockIndex) -> Self { Self::Chain { new_block_index } } @@ -92,10 +92,10 @@ impl<'a> TransactionSourceForConnect<'a> { /// * For the chain, it's for the block being connected pub fn expected_block_height(&self) -> BlockHeight { match self { - TransactionSourceForConnect::Chain { new_block_index } => { + TransactionSourceWithHeight::Chain { new_block_index } => { new_block_index.block_height() } - TransactionSourceForConnect::Mempool { + TransactionSourceWithHeight::Mempool { current_best: _, effective_height, } => *effective_height, @@ -104,8 +104,8 @@ impl<'a> TransactionSourceForConnect<'a> { pub fn chain_block_index(&self) -> Option<&BlockIndex> { match self { - TransactionSourceForConnect::Chain { new_block_index } => Some(new_block_index), - TransactionSourceForConnect::Mempool { + TransactionSourceWithHeight::Chain { new_block_index } => Some(new_block_index), + TransactionSourceWithHeight::Mempool { current_best: _, effective_height: _, } => None, diff --git a/mempool/src/pool/tx_pool/collect_txs.rs b/mempool/src/pool/tx_pool/collect_txs.rs index 0cd96aec0..7b2c63ddd 100644 --- a/mempool/src/pool/tx_pool/collect_txs.rs +++ b/mempool/src/pool/tx_pool/collect_txs.rs @@ -25,7 +25,7 @@ use std::{ ops::Deref, }; -use chainstate::tx_verifier::transaction_verifier::TransactionSourceForConnect; +use chainstate::tx_verifier::transaction_verifier::TransactionSourceWithHeight; use common::{ chain::transaction::Transaction, primitives::{Id, Idable}, @@ -97,7 +97,7 @@ pub fn collect_txs( .blocking_chainstate_handle() .call(|c| c.get_best_block_index())? .expect("best index to exist"); - let tx_source = TransactionSourceForConnect::for_mempool(&best_index); + let tx_source = TransactionSourceWithHeight::for_mempool(&best_index); // Use transactions already in the Accumulator to check for uniqueness and to update the // verifier state to update UTXOs they consume / provide. diff --git a/mempool/src/pool/tx_pool/mod.rs b/mempool/src/pool/tx_pool/mod.rs index 09f223f94..bafc8f4d6 100644 --- a/mempool/src/pool/tx_pool/mod.rs +++ b/mempool/src/pool/tx_pool/mod.rs @@ -32,11 +32,8 @@ use utxo::UtxosStorageRead; use chainstate::{ chainstate_interface::ChainstateInterface, - tx_verifier::{ - transaction_verifier::{TransactionSourceForConnect, TransactionVerifierDelta}, - TransactionSource, - }, - ConnectTransactionError, + tx_verifier::transaction_verifier::{TransactionSourceWithHeight, TransactionVerifierDelta}, + ConnectTransactionError, GenBlockIndex, }; use common::{ chain::{ @@ -541,7 +538,7 @@ impl TxPool { let tx_id = *entry.tx_id(); self.store.add_transaction(entry)?; - self.remove_expired_transactions(); + self.remove_expired_transactions()?; ensure!( self.store.contains(&tx_id), MempoolPolicyError::DescendantOfExpiredTransaction @@ -576,7 +573,7 @@ impl TxPool { Ok(()) } - fn remove_expired_transactions(&mut self) { + fn remove_expired_transactions(&mut self) -> Result<(), Error> { let expired_ids: Vec<_> = self .store .txs_by_creation_time @@ -598,13 +595,45 @@ impl TxPool { .map(|entry| *entry.tx_id()) .collect(); + let current_best = self.current_best_block_index()?; + let effective_height = (current_best.block_height() + + config::FUTURE_TIMELOCK_TOLERANCE_BLOCKS) + .expect("Block height overflow"); + let source = + TransactionSourceWithHeight::for_mempool_with_height(¤t_best, effective_height); + for tx_id in expired_ids.iter() { - self.remove_tx_and_descendants(tx_id, MempoolRemovalReason::Expiry); + self.remove_tx_and_descendants(tx_id, &source, MempoolRemovalReason::Expiry); } + + Ok(()) + } + + fn current_best_block_index(&self) -> Result { + let chainstate_handle = self.blocking_chainstate_handle(); + let current_best = chainstate_handle + .call(|chainstate| { + let tip = chainstate.get_best_block_id()?; + let tip_index = chainstate + .get_gen_block_index_for_persisted_block(&tip)? + .expect("tip block index to exist"); + Ok::<_, chainstate::ChainstateError>(tip_index) + }) + .map_err(|e| Error::Validity(TxValidationError::CallError(e)))? + .map_err(|e| Error::Validity(TxValidationError::ChainstateError(e)))?; + Ok(current_best) } - fn trim(&mut self) -> Result, MempoolPolicyError> { + fn trim(&mut self) -> Result, Error> { let mut removed_fees = Vec::new(); + + let current_best = self.current_best_block_index()?; + let effective_height = (current_best.block_height() + + config::FUTURE_TIMELOCK_TOLERANCE_BLOCKS) + .expect("Block height overflow"); + let source = + TransactionSourceWithHeight::for_mempool_with_height(¤t_best, effective_height); + while !self.store.is_empty() && self.memory_usage() > self.max_size.as_bytes() { // TODO sort by descendant score, not by fee let removed_id = self @@ -623,14 +652,17 @@ impl TxPool { removed.size() ); removed_fees.push(FeeRate::from_total_tx_fee(removed.fee(), removed.size())?); - self.remove_tx_and_descendants(&removed_id, MempoolRemovalReason::SizeLimit); + self.remove_tx_and_descendants(&removed_id, &source, MempoolRemovalReason::SizeLimit); } Ok(removed_fees) } - fn remove_tx_and_descendants(&mut self, tx_id: &Id, reason: MempoolRemovalReason) { - let source = TransactionSource::Mempool; - + fn remove_tx_and_descendants( + &mut self, + tx_id: &Id, + source: &TransactionSourceWithHeight, + reason: MempoolRemovalReason, + ) { let result = self.store.drop_tx_and_descendants(tx_id, reason).try_for_each(|entry| { self.tx_verifier .disconnect_transaction(&source, entry.transaction()) @@ -823,7 +855,7 @@ impl TxPool { .expect("Block height overflow"); let connect_result = tx_verifier.connect_transaction( - &TransactionSourceForConnect::for_mempool_with_height(¤t_best, effective_height), + &TransactionSourceWithHeight::for_mempool_with_height(¤t_best, effective_height), transaction.transaction(), &BlockTimestamp::from_time(verifier_time), );