diff --git a/consensus/src/consensus/factory.rs b/consensus/src/consensus/factory.rs index 0d66b61f2..a0b42ad65 100644 --- a/consensus/src/consensus/factory.rs +++ b/consensus/src/consensus/factory.rs @@ -11,6 +11,7 @@ use kaspa_database::{ registry::DatabaseStorePrefixes, }; +use kaspa_txscript::caches::TxScriptCacheCounters; use parking_lot::RwLock; use rocksdb::WriteBatch; use serde::{Deserialize, Serialize}; @@ -153,6 +154,7 @@ pub struct Factory { db_parallelism: usize, notification_root: Arc, counters: Arc, + tx_script_cache_counters: Arc, } impl Factory { @@ -163,6 +165,7 @@ impl Factory { db_parallelism: usize, notification_root: Arc, counters: Arc, + tx_script_cache_counters: Arc, ) -> Self { let mut config = config.clone(); #[cfg(feature = "devnet-prealloc")] @@ -175,6 +178,7 @@ impl Factory { db_parallelism, notification_root, counters, + tx_script_cache_counters, } } } @@ -208,6 +212,7 @@ impl ConsensusFactory for Factory { session_lock.clone(), self.notification_root.clone(), self.counters.clone(), + self.tx_script_cache_counters.clone(), entry.creation_timestamp, )); @@ -236,6 +241,7 @@ impl ConsensusFactory for Factory { session_lock.clone(), self.notification_root.clone(), self.counters.clone(), + self.tx_script_cache_counters.clone(), entry.creation_timestamp, )); diff --git a/consensus/src/consensus/mod.rs b/consensus/src/consensus/mod.rs index dd82c09d6..7485f5547 100644 --- a/consensus/src/consensus/mod.rs +++ b/consensus/src/consensus/mod.rs @@ -70,6 +70,7 @@ use kaspa_consensusmanager::{SessionLock, SessionReadGuard}; use kaspa_database::prelude::StoreResultExtensions; use kaspa_hashes::Hash; use kaspa_muhash::MuHash; +use kaspa_txscript::caches::TxScriptCacheCounters; use std::thread::{self, JoinHandle}; use std::{ @@ -132,6 +133,7 @@ impl Consensus { pruning_lock: SessionLock, notification_root: Arc, counters: Arc, + tx_script_cache_counters: Arc, creation_timestamp: u64, ) -> Self { let params = &config.params; @@ -147,7 +149,7 @@ impl Consensus { // Services and managers // - let services = ConsensusServices::new(db.clone(), storage.clone(), config.clone()); + let services = ConsensusServices::new(db.clone(), storage.clone(), config.clone(), tx_script_cache_counters); // // Processor channels diff --git a/consensus/src/consensus/services.rs b/consensus/src/consensus/services.rs index f0b791ba2..d76a28d5a 100644 --- a/consensus/src/consensus/services.rs +++ b/consensus/src/consensus/services.rs @@ -18,6 +18,7 @@ use crate::{ }; use itertools::Itertools; +use kaspa_txscript::caches::TxScriptCacheCounters; use std::sync::Arc; pub type DbGhostdagManager = @@ -65,7 +66,12 @@ pub struct ConsensusServices { } impl ConsensusServices { - pub fn new(db: Arc, storage: Arc, config: Arc) -> Arc { + pub fn new( + db: Arc, + storage: Arc, + config: Arc, + tx_script_cache_counters: Arc, + ) -> Arc { let params = &config.params; let statuses_service = MTStatusesService::new(storage.statuses_store.clone()); @@ -144,6 +150,7 @@ impl ConsensusServices { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + tx_script_cache_counters, ); let pruning_point_manager = PruningPointManager::new( diff --git a/consensus/src/consensus/test_consensus.rs b/consensus/src/consensus/test_consensus.rs index 620722022..10d6d5dd2 100644 --- a/consensus/src/consensus/test_consensus.rs +++ b/consensus/src/consensus/test_consensus.rs @@ -49,8 +49,17 @@ impl TestConsensus { /// Creates a test consensus instance based on `config` with the provided `db` and `notification_sender` pub fn with_db(db: Arc, config: &Config, notification_sender: Sender) -> Self { let notification_root = Arc::new(ConsensusNotificationRoot::new(notification_sender)); - let counters = Arc::new(ProcessingCounters::default()); - let consensus = Arc::new(Consensus::new(db, Arc::new(config.clone()), Default::default(), notification_root, counters, 0)); + let counters = Default::default(); + let tx_script_cache_counters = Default::default(); + let consensus = Arc::new(Consensus::new( + db, + Arc::new(config.clone()), + Default::default(), + notification_root, + counters, + tx_script_cache_counters, + 0, + )); let block_builder = TestBlockBuilder::new(consensus.virtual_processor.clone()); Self { params: config.params.clone(), consensus, block_builder, db_lifetime: Default::default() } @@ -60,8 +69,17 @@ impl TestConsensus { pub fn with_notifier(config: &Config, notification_sender: Sender) -> Self { let (db_lifetime, db) = create_temp_db!(ConnBuilder::default()); let notification_root = Arc::new(ConsensusNotificationRoot::new(notification_sender)); - let counters = Arc::new(ProcessingCounters::default()); - let consensus = Arc::new(Consensus::new(db, Arc::new(config.clone()), Default::default(), notification_root, counters, 0)); + let counters = Default::default(); + let tx_script_cache_counters = Default::default(); + let consensus = Arc::new(Consensus::new( + db, + Arc::new(config.clone()), + Default::default(), + notification_root, + counters, + tx_script_cache_counters, + 0, + )); let block_builder = TestBlockBuilder::new(consensus.virtual_processor.clone()); Self { consensus, block_builder, params: config.params.clone(), db_lifetime } @@ -72,8 +90,17 @@ impl TestConsensus { let (db_lifetime, db) = create_temp_db!(ConnBuilder::default()); let (dummy_notification_sender, _) = async_channel::unbounded(); let notification_root = Arc::new(ConsensusNotificationRoot::new(dummy_notification_sender)); - let counters = Arc::new(ProcessingCounters::default()); - let consensus = Arc::new(Consensus::new(db, Arc::new(config.clone()), Default::default(), notification_root, counters, 0)); + let counters = Default::default(); + let tx_script_cache_counters = Default::default(); + let consensus = Arc::new(Consensus::new( + db, + Arc::new(config.clone()), + Default::default(), + notification_root, + counters, + tx_script_cache_counters, + 0, + )); let block_builder = TestBlockBuilder::new(consensus.virtual_processor.clone()); Self { consensus, block_builder, params: config.params.clone(), db_lifetime } diff --git a/consensus/src/processes/transaction_validator/mod.rs b/consensus/src/processes/transaction_validator/mod.rs index 792ecb9b1..0565a89a9 100644 --- a/consensus/src/processes/transaction_validator/mod.rs +++ b/consensus/src/processes/transaction_validator/mod.rs @@ -2,9 +2,14 @@ pub mod errors; pub mod transaction_validator_populated; mod tx_validation_in_isolation; pub mod tx_validation_not_utxo_related; +use std::sync::Arc; + use crate::model::stores::ghostdag; -use kaspa_txscript::{caches::Cache, SigCacheKey}; +use kaspa_txscript::{ + caches::{Cache, TxScriptCacheCounters}, + SigCacheKey, +}; pub use tx_validation_in_isolation::*; #[derive(Clone)] @@ -28,6 +33,7 @@ impl TransactionValidator { ghostdag_k: ghostdag::KType, coinbase_payload_script_public_key_max_len: u8, coinbase_maturity: u64, + counters: Arc, ) -> Self { Self { max_tx_inputs, @@ -37,7 +43,7 @@ impl TransactionValidator { ghostdag_k, coinbase_payload_script_public_key_max_len, coinbase_maturity, - sig_cache: Cache::new(10_000), + sig_cache: Cache::new(10_000, counters), } } } diff --git a/consensus/src/processes/transaction_validator/transaction_validator_populated.rs b/consensus/src/processes/transaction_validator/transaction_validator_populated.rs index 5e0443164..b46527aca 100644 --- a/consensus/src/processes/transaction_validator/transaction_validator_populated.rs +++ b/consensus/src/processes/transaction_validator/transaction_validator_populated.rs @@ -142,6 +142,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); let prev_tx_id = TransactionId::from_str("746915c8dfc5e1550eacbe1d87625a105750cf1a65aaddd1baa60f8bcf7e953c").unwrap(); @@ -202,6 +203,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); // Taken from: 3f582463d73c77d93f278b7bf649bd890e75fe9bb8a1edd7a6854df1a2a2bfc1 @@ -263,6 +265,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); // Taken from: d839d29b549469d0f9a23e51febe68d4084967a6a477868b511a5a8d88c5ae06 @@ -324,6 +327,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); // Taken from: d839d29b549469d0f9a23e51febe68d4084967a6a477868b511a5a8d88c5ae06 @@ -386,6 +390,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); // Taken from: d839d29b549469d0f9a23e51febe68d4084967a6a477868b511a5a8d88c5ae06 @@ -448,6 +453,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); // Taken from: d839d29b549469d0f9a23e51febe68d4084967a6a477868b511a5a8d88c5ae06 @@ -510,6 +516,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); let prev_tx_id = TransactionId::from_str("1111111111111111111111111111111111111111111111111111111111111111").unwrap(); @@ -563,6 +570,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); let secp = Secp256k1::new(); diff --git a/consensus/src/processes/transaction_validator/tx_validation_in_isolation.rs b/consensus/src/processes/transaction_validator/tx_validation_in_isolation.rs index a30d0c826..88a2e63a2 100644 --- a/consensus/src/processes/transaction_validator/tx_validation_in_isolation.rs +++ b/consensus/src/processes/transaction_validator/tx_validation_in_isolation.rs @@ -173,6 +173,7 @@ mod tests { params.ghostdag_k, params.coinbase_payload_script_public_key_max_len, params.coinbase_maturity, + Default::default(), ); let valid_cb = Transaction::new( diff --git a/crypto/txscript/src/caches.rs b/crypto/txscript/src/caches.rs index 854bfd1b8..209bf6854 100644 --- a/crypto/txscript/src/caches.rs +++ b/crypto/txscript/src/caches.rs @@ -1,22 +1,37 @@ use indexmap::IndexMap; use parking_lot::RwLock; use rand::Rng; -use std::{collections::hash_map::RandomState, hash::BuildHasher, sync::Arc}; +use std::{ + collections::hash_map::RandomState, + hash::BuildHasher, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, +}; #[derive(Clone)] pub struct Cache { // We use IndexMap and not HashMap, because it makes it cheaper to remove a random element when the cache is full. map: Arc>>, size: usize, + counters: Arc, } impl Cache { - pub fn new(size: u64) -> Self { - Self { map: Arc::new(RwLock::new(IndexMap::with_capacity_and_hasher(size as usize, S::default()))), size: size as usize } + pub fn new(size: u64, counters: Arc) -> Self { + Self { + map: Arc::new(RwLock::new(IndexMap::with_capacity_and_hasher(size as usize, S::default()))), + size: size as usize, + counters, + } } pub(crate) fn get(&self, key: &TKey) -> Option { - self.map.read().get(key).cloned() + self.map.read().get(key).cloned().map(|data| { + self.counters.get_counts.fetch_add(1, Ordering::Relaxed); + data + }) } pub(crate) fn insert(&self, key: TKey, data: TData) { @@ -28,5 +43,48 @@ impl TxScriptCacheCountersSnapshot { + TxScriptCacheCountersSnapshot { + insert_counts: self.insert_counts.load(Ordering::Relaxed), + get_counts: self.get_counts.load(Ordering::Relaxed), + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct TxScriptCacheCountersSnapshot { + pub insert_counts: u64, + pub get_counts: u64, +} + +impl TxScriptCacheCountersSnapshot { + pub fn hit_ratio(&self) -> f64 { + if self.insert_counts > 0 { + self.get_counts as f64 / self.insert_counts as f64 + } else { + 0f64 + } + } +} + +impl core::ops::Sub for &TxScriptCacheCountersSnapshot { + type Output = TxScriptCacheCountersSnapshot; + + fn sub(self, rhs: Self) -> Self::Output { + Self::Output { + insert_counts: self.insert_counts.checked_sub(rhs.insert_counts).unwrap_or_default(), + get_counts: self.get_counts.checked_sub(rhs.get_counts).unwrap_or_default(), + } } } diff --git a/crypto/txscript/src/lib.rs b/crypto/txscript/src/lib.rs index 31e5dcbd4..0c941222c 100644 --- a/crypto/txscript/src/lib.rs +++ b/crypto/txscript/src/lib.rs @@ -529,7 +529,7 @@ mod tests { } fn run_test_script_cases(test_cases: Vec) { - let sig_cache = Cache::new(10_000); + let sig_cache = Cache::new(10_000, Default::default()); let mut reused_values = SigHashReusedValues::new(); for test in test_cases { diff --git a/crypto/txscript/src/opcodes/mod.rs b/crypto/txscript/src/opcodes/mod.rs index 30c893211..203045694 100644 --- a/crypto/txscript/src/opcodes/mod.rs +++ b/crypto/txscript/src/opcodes/mod.rs @@ -961,7 +961,7 @@ mod test { } fn run_test_cases(tests: Vec) { - let cache = Cache::new(10_000); + let cache = Cache::new(10_000, Default::default()); let mut reused_values = SigHashReusedValues::new(); for TestCase { init, code, dstack } in tests { let mut vm = TxScriptEngine::new(&mut reused_values, &cache); @@ -990,7 +990,7 @@ mod test { opcodes::OpRShift::empty().expect("Should accept empty"), ]; - let cache = Cache::new(10_000); + let cache = Cache::new(10_000, Default::default()); let mut reused_values = SigHashReusedValues::new(); let mut vm = TxScriptEngine::new(&mut reused_values, &cache); @@ -1013,7 +1013,7 @@ mod test { opcodes::OpReserved2::empty().expect("Should accept empty"), ]; - let cache = Cache::new(10_000); + let cache = Cache::new(10_000, Default::default()); let mut reused_values = SigHashReusedValues::new(); let mut vm = TxScriptEngine::new(&mut reused_values, &cache); @@ -1104,7 +1104,7 @@ mod test { opcodes::OpUnknown249::empty().expect("Should accept empty"), ]; - let cache = Cache::new(10_000); + let cache = Cache::new(10_000, Default::default()); let mut reused_values = SigHashReusedValues::new(); let mut vm = TxScriptEngine::new(&mut reused_values, &cache); diff --git a/crypto/txscript/src/standard/multisig.rs b/crypto/txscript/src/standard/multisig.rs index 28d9173d5..afe6ef0d9 100644 --- a/crypto/txscript/src/standard/multisig.rs +++ b/crypto/txscript/src/standard/multisig.rs @@ -183,7 +183,7 @@ mod tests { let tx = tx.as_verifiable(); let (input, entry) = tx.populated_inputs().next().unwrap(); - let cache = Cache::new(10_000); + let cache = Cache::new(10_000, Default::default()); let mut engine = TxScriptEngine::from_transaction_input(&tx, input, 0, entry, &mut reused_values, &cache).unwrap(); assert_eq!(engine.execute().is_ok(), is_ok); } diff --git a/kaspad/src/daemon.rs b/kaspad/src/daemon.rs index b279d6f15..8d37405bc 100644 --- a/kaspad/src/daemon.rs +++ b/kaspad/src/daemon.rs @@ -10,6 +10,7 @@ use kaspa_core::{core::Core, info, trace}; use kaspa_core::{kaspad_env::version, task::tick::TickService}; use kaspa_grpc_server::service::GrpcService; use kaspa_rpc_service::service::RpcCoreService; +use kaspa_txscript::caches::TxScriptCacheCounters; use kaspa_utils::networking::ContextualNetAddress; use kaspa_addressmanager::AddressManager; @@ -240,6 +241,7 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm let mining_counters = Arc::new(MiningCounters::default()); let wrpc_borsh_counters = Arc::new(WrpcServerCounters::default()); let wrpc_json_counters = Arc::new(WrpcServerCounters::default()); + let tx_script_cache_counters = Arc::new(TxScriptCacheCounters::default()); // Use `num_cpus` background threads for the consensus database as recommended by rocksdb let consensus_db_parallelism = num_cpus::get(); @@ -250,6 +252,7 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm consensus_db_parallelism, notification_root.clone(), processing_counters.clone(), + tx_script_cache_counters.clone(), )); let consensus_manager = Arc::new(ConsensusManager::new(consensus_factory)); let consensus_monitor = Arc::new(ConsensusMonitor::new(processing_counters.clone(), tick_service.clone())); @@ -285,7 +288,7 @@ do you confirm? (answer y/n or pass --yes to the Kaspad command line to confirm let cache_lifetime: Option = None; #[cfg(feature = "devnet-prealloc")] let cache_lifetime = config.block_template_cache_lifetime; - let mining_monitor = Arc::new(MiningMonitor::new(mining_counters.clone(), tick_service.clone())); + let mining_monitor = Arc::new(MiningMonitor::new(mining_counters.clone(), tx_script_cache_counters.clone(), tick_service.clone())); let mining_manager = MiningManagerProxy::new(Arc::new(MiningManager::new( config.target_time_per_block, false, diff --git a/mining/src/monitor.rs b/mining/src/monitor.rs index a79df99d1..1359286a5 100644 --- a/mining/src/monitor.rs +++ b/mining/src/monitor.rs @@ -7,6 +7,7 @@ use kaspa_core::{ }, trace, }; +use kaspa_txscript::caches::TxScriptCacheCounters; use std::{ sync::Arc, time::{Duration, Instant}, @@ -18,17 +19,24 @@ pub struct MiningMonitor { // Counters counters: Arc, + tx_script_cache_counters: Arc, + // Tick service tick_service: Arc, } impl MiningMonitor { - pub fn new(counters: Arc, tick_service: Arc) -> MiningMonitor { - MiningMonitor { counters, tick_service } + pub fn new( + counters: Arc, + tx_script_cache_counters: Arc, + tick_service: Arc, + ) -> MiningMonitor { + MiningMonitor { counters, tx_script_cache_counters, tick_service } } pub async fn worker(self: &Arc) { let mut last_snapshot = self.counters.snapshot(); + let mut last_tx_script_cache_snapshot = self.tx_script_cache_counters.snapshot(); let mut last_log_time = Instant::now(); let snapshot_interval = 10; loop { @@ -39,6 +47,9 @@ impl MiningMonitor { } let snapshot = self.counters.snapshot(); + let tx_script_cache_snapshot = self.tx_script_cache_counters.snapshot(); + let now = Instant::now(); + let elapsed = (now - last_log_time).as_secs_f64(); if snapshot == last_snapshot { // No update, avoid printing useless info last_log_time = Instant::now(); @@ -47,20 +58,35 @@ impl MiningMonitor { // Subtract the snapshots let delta = &snapshot - &last_snapshot; - let now = Instant::now(); - let elapsed = (now - last_log_time).as_secs_f64(); + let tx_script_cache_delta = &tx_script_cache_snapshot - &last_tx_script_cache_snapshot; - info!("Processed {} unique transactions in the last {:.2}s ({:.2} avg txs/s, in: {} via RPC, {} via P2P, out: {} via accepted blocks, {:.2}% e-tps)", - delta.tx_accepted_counts, - elapsed, - delta.tx_accepted_counts as f64 / elapsed, - delta.high_priority_tx_counts, - delta.low_priority_tx_counts, - delta.block_tx_counts, - delta.e_tps() * 100.0, - ); + // Avoid printing useless info if no update + if snapshot != last_snapshot { + info!("Processed {} unique transactions in the last {:.2}s ({:.2} avg txs/s, in: {} via RPC, {} via P2P, out: {} via accepted blocks, {:.2}% e-tps)", + delta.tx_accepted_counts, + elapsed, + delta.tx_accepted_counts as f64 / elapsed, + delta.high_priority_tx_counts, + delta.low_priority_tx_counts, + delta.block_tx_counts, + delta.e_tps() * 100.0, + ); + // FIXME: (wip) decide if the log level should be debug and what info should be kept or formulated differently + if tx_script_cache_snapshot != last_tx_script_cache_snapshot { + info!( + "Created {} UTXOs, spent {} in the last {:.2}s ({} signatures validated, {} cache hits, {:.2} hit ratio)", + delta.output_counts, + delta.input_counts, + elapsed, + tx_script_cache_delta.insert_counts, + tx_script_cache_delta.get_counts, + tx_script_cache_delta.hit_ratio() + ); + } + } last_snapshot = snapshot; + last_tx_script_cache_snapshot = tx_script_cache_snapshot; last_log_time = now; } diff --git a/simpa/src/main.rs b/simpa/src/main.rs index 123f21f72..0458a34ef 100644 --- a/simpa/src/main.rs +++ b/simpa/src/main.rs @@ -187,8 +187,15 @@ fn main() { }; let (dummy_notification_sender, _) = unbounded(); let notification_root = Arc::new(ConsensusNotificationRoot::new(dummy_notification_sender)); - let consensus = - Arc::new(Consensus::new(db, config.clone(), Default::default(), notification_root, Default::default(), unix_now())); + let consensus = Arc::new(Consensus::new( + db, + config.clone(), + Default::default(), + notification_root, + Default::default(), + Default::default(), + unix_now(), + )); (consensus, lifetime) } else { let until = if args.target_blocks.is_none() { config.genesis.timestamp + args.sim_time * 1000 } else { u64::MAX }; // milliseconds @@ -216,8 +223,15 @@ fn main() { let (_lifetime2, db2) = create_temp_db!(ConnBuilder::default().with_parallelism(num_cpus::get())); let (dummy_notification_sender, _) = unbounded(); let notification_root = Arc::new(ConsensusNotificationRoot::new(dummy_notification_sender)); - let consensus2 = - Arc::new(Consensus::new(db2, config.clone(), Default::default(), notification_root, Default::default(), unix_now())); + let consensus2 = Arc::new(Consensus::new( + db2, + config.clone(), + Default::default(), + notification_root, + Default::default(), + Default::default(), + unix_now(), + )); let handles2 = consensus2.run_processors(); rt.block_on(validate(&consensus, &consensus2, &config, args.delay, args.bps)); consensus2.shutdown(handles2); diff --git a/simpa/src/simulator/network.rs b/simpa/src/simulator/network.rs index 82e75178e..74fdabf69 100644 --- a/simpa/src/simulator/network.rs +++ b/simpa/src/simulator/network.rs @@ -82,6 +82,7 @@ impl KaspaNetworkSimulator { Default::default(), notification_root, Default::default(), + Default::default(), unix_now(), )); let handles = consensus.run_processors(); diff --git a/testing/integration/src/consensus_integration_tests.rs b/testing/integration/src/consensus_integration_tests.rs index 7dcf3fe84..09776015e 100644 --- a/testing/integration/src/consensus_integration_tests.rs +++ b/testing/integration/src/consensus_integration_tests.rs @@ -52,6 +52,7 @@ use kaspa_database::prelude::ConnBuilder; use kaspa_index_processor::service::IndexService; use kaspa_math::Uint256; use kaspa_muhash::MuHash; +use kaspa_txscript::caches::TxScriptCacheCounters; use kaspa_utxoindex::api::{UtxoIndexApi, UtxoIndexProxy}; use kaspa_utxoindex::UtxoIndex; use serde::{Deserialize, Serialize}; @@ -1689,8 +1690,10 @@ async fn staging_consensus_test() { let (notification_send, _notification_recv) = unbounded(); let notification_root = Arc::new(ConsensusNotificationRoot::new(notification_send)); let counters = Arc::new(ProcessingCounters::default()); + let tx_script_cache_counters = Arc::new(TxScriptCacheCounters::default()); - let consensus_factory = Arc::new(ConsensusFactory::new(meta_db, &config, consensus_db_dir, 4, notification_root, counters)); + let consensus_factory = + Arc::new(ConsensusFactory::new(meta_db, &config, consensus_db_dir, 4, notification_root, counters, tx_script_cache_counters)); let consensus_manager = Arc::new(ConsensusManager::new(consensus_factory)); let core = Arc::new(Core::new());