send-transaction-service metrics improvement (#24816)

Use data_point report metrics periodically -- every 5 seconds for better metrics correlation and reduce noisy metrics.
This commit is contained in:
Lijun Wang 2022-05-04 17:06:21 -07:00 committed by GitHub
parent 9bca909f63
commit 3852959ac8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 242 additions and 65 deletions

View File

@ -4,9 +4,12 @@ use {
log::*, log::*,
solana_client::connection_cache, solana_client::connection_cache,
solana_measure::measure::Measure, solana_measure::measure::Measure,
solana_metrics::{datapoint_warn, inc_new_counter_info}, solana_metrics::datapoint_warn,
solana_runtime::{bank::Bank, bank_forks::BankForks}, solana_runtime::{bank::Bank, bank_forks::BankForks},
solana_sdk::{hash::Hash, nonce_account, pubkey::Pubkey, signature::Signature}, solana_sdk::{
hash::Hash, nonce_account, pubkey::Pubkey, saturating_add_assign, signature::Signature,
timing::AtomicInterval, transport::TransportError,
},
std::{ std::{
collections::{ collections::{
hash_map::{Entry, HashMap}, hash_map::{Entry, HashMap},
@ -14,7 +17,7 @@ use {
}, },
net::SocketAddr, net::SocketAddr,
sync::{ sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, AtomicU64, Ordering},
Arc, Mutex, RwLock, Arc, Mutex, RwLock,
}, },
thread::{self, sleep, Builder, JoinHandle}, thread::{self, sleep, Builder, JoinHandle},
@ -181,6 +184,150 @@ where
} }
} }
/// Metrics of the send-transaction-service.
#[derive(Default)]
struct SendTransactionServiceStats {
/// Count of the received transactions
received_transactions: AtomicU64,
/// Count of the received duplicate transactions
received_duplicate_transactions: AtomicU64,
/// Count of transactions sent in batch
sent_transactions: AtomicU64,
/// Count of transactions not being added to retry queue
/// due to queue size limit
retry_queue_overflow: AtomicU64,
/// retry queue size
retry_queue_size: AtomicU64,
/// The count of calls of sending transactions which can be in batch or single.
send_attempt_count: AtomicU64,
/// Time spent on transactions in micro seconds
send_us: AtomicU64,
/// Send failure count
send_failure_count: AtomicU64,
/// Count of nonced transactions
nonced_transactions: AtomicU64,
/// Count of rooted transactions
rooted_transactions: AtomicU64,
/// Count of expired transactions
expired_transactions: AtomicU64,
/// Count of transactions exceeding max retries
transactions_exceeding_max_retries: AtomicU64,
/// Count of retries of transactions
retries: AtomicU64,
/// Count of transactions failed
failed_transactions: AtomicU64,
}
#[derive(Default)]
struct SendTransactionServiceStatsReport {
stats: SendTransactionServiceStats,
last_report: AtomicInterval,
}
impl SendTransactionServiceStatsReport {
/// report metrics of the send transaction service
fn report(&self) {
if self
.last_report
.should_update(SEND_TRANSACTION_METRICS_REPORT_RATE_MS)
{
datapoint_info!(
"send_transaction_service",
(
"recv-tx",
self.stats.received_transactions.swap(0, Ordering::Relaxed),
i64
),
(
"recv-duplicate",
self.stats
.received_duplicate_transactions
.swap(0, Ordering::Relaxed),
i64
),
(
"sent-tx",
self.stats.sent_transactions.swap(0, Ordering::Relaxed),
i64
),
(
"retry-queue-overflow",
self.stats.retry_queue_overflow.swap(0, Ordering::Relaxed),
i64
),
(
"retry-queue-size",
self.stats.retry_queue_size.swap(0, Ordering::Relaxed),
i64
),
(
"send-us",
self.stats.send_us.swap(0, Ordering::Relaxed),
i64
),
(
"send-attempt-count",
self.stats.send_attempt_count.swap(0, Ordering::Relaxed),
i64
),
(
"send-failure-count",
self.stats.send_failure_count.swap(0, Ordering::Relaxed),
i64
),
(
"nonced-tx",
self.stats.nonced_transactions.swap(0, Ordering::Relaxed),
i64
),
(
"rooted-tx",
self.stats.rooted_transactions.swap(0, Ordering::Relaxed),
i64
),
(
"expired-tx",
self.stats.expired_transactions.swap(0, Ordering::Relaxed),
i64
),
(
"max-retries-exceeded-tx",
self.stats
.transactions_exceeding_max_retries
.swap(0, Ordering::Relaxed),
i64
),
(
"retries",
self.stats.retries.swap(0, Ordering::Relaxed),
i64
),
(
"failed-tx",
self.stats.failed_transactions.swap(0, Ordering::Relaxed),
i64
)
);
}
}
}
/// Report the send transaction memtrics for every 5 seconds.
const SEND_TRANSACTION_METRICS_REPORT_RATE_MS: u64 = 5000;
impl SendTransactionService { impl SendTransactionService {
pub fn new<T: TpuInfo + std::marker::Send + 'static>( pub fn new<T: TpuInfo + std::marker::Send + 'static>(
tpu_address: SocketAddr, tpu_address: SocketAddr,
@ -207,6 +354,8 @@ impl SendTransactionService {
receiver: Receiver<TransactionInfo>, receiver: Receiver<TransactionInfo>,
config: Config, config: Config,
) -> Self { ) -> Self {
let stats_report = Arc::new(SendTransactionServiceStatsReport::default());
let retry_transactions = Arc::new(Mutex::new(HashMap::new())); let retry_transactions = Arc::new(Mutex::new(HashMap::new()));
let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(leader_info))); let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(leader_info)));
@ -218,6 +367,7 @@ impl SendTransactionService {
leader_info_provider.clone(), leader_info_provider.clone(),
config.clone(), config.clone(),
retry_transactions.clone(), retry_transactions.clone(),
stats_report.clone(),
exit.clone(), exit.clone(),
); );
@ -227,6 +377,7 @@ impl SendTransactionService {
leader_info_provider, leader_info_provider,
config, config,
retry_transactions, retry_transactions,
stats_report,
exit.clone(), exit.clone(),
); );
Self { Self {
@ -243,6 +394,7 @@ impl SendTransactionService {
leader_info_provider: Arc<Mutex<CurrentLeaderInfo<T>>>, leader_info_provider: Arc<Mutex<CurrentLeaderInfo<T>>>,
config: Config, config: Config,
retry_transactions: Arc<Mutex<HashMap<Signature, TransactionInfo>>>, retry_transactions: Arc<Mutex<HashMap<Signature, TransactionInfo>>>,
stats_report: Arc<SendTransactionServiceStatsReport>,
exit: Arc<AtomicBool>, exit: Arc<AtomicBool>,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
let mut last_batch_sent = Instant::now(); let mut last_batch_sent = Instant::now();
@ -257,6 +409,7 @@ impl SendTransactionService {
.name("send-tx-receive".to_string()) .name("send-tx-receive".to_string())
.spawn(move || loop { .spawn(move || loop {
let recv_timeout_ms = config.batch_send_rate_ms; let recv_timeout_ms = config.batch_send_rate_ms;
let stats = &stats_report.stats;
match receiver.recv_timeout(Duration::from_millis(recv_timeout_ms)) { match receiver.recv_timeout(Duration::from_millis(recv_timeout_ms)) {
Err(RecvTimeoutError::Disconnected) => { Err(RecvTimeoutError::Disconnected) => {
info!("Terminating send-transaction-service."); info!("Terminating send-transaction-service.");
@ -265,7 +418,7 @@ impl SendTransactionService {
} }
Err(RecvTimeoutError::Timeout) => {} Err(RecvTimeoutError::Timeout) => {}
Ok(transaction_info) => { Ok(transaction_info) => {
inc_new_counter_info!("send_transaction_service-recv-tx", 1); stats.received_transactions.fetch_add(1, Ordering::Relaxed);
let entry = transactions.entry(transaction_info.signature); let entry = transactions.entry(transaction_info.signature);
let mut new_transaction = false; let mut new_transaction = false;
if let Entry::Vacant(_) = entry { if let Entry::Vacant(_) = entry {
@ -279,7 +432,9 @@ impl SendTransactionService {
} }
} }
if !new_transaction { if !new_transaction {
inc_new_counter_info!("send_transaction_service-recv-duplicate", 1); stats
.received_duplicate_transactions
.fetch_add(1, Ordering::Relaxed);
} }
} }
} }
@ -288,20 +443,22 @@ impl SendTransactionService {
&& last_batch_sent.elapsed().as_millis() as u64 >= config.batch_send_rate_ms) && last_batch_sent.elapsed().as_millis() as u64 >= config.batch_send_rate_ms)
|| transactions.len() >= config.batch_size || transactions.len() >= config.batch_size
{ {
inc_new_counter_info!( stats
"send_transaction_service-batch-size", .sent_transactions
transactions.len() .fetch_add(transactions.len() as u64, Ordering::Relaxed);
);
let _result = Self::send_transactions_in_batch( let _result = Self::send_transactions_in_batch(
&tpu_address, &tpu_address,
&mut transactions, &mut transactions,
leader_info_provider.lock().unwrap().get_leader_info(), leader_info_provider.lock().unwrap().get_leader_info(),
&config, &config,
stats,
); );
let last_sent_time = Instant::now(); let last_sent_time = Instant::now();
{ {
// take a lock of retry_transactions and move the batch to the retry set. // take a lock of retry_transactions and move the batch to the retry set.
let mut retry_transactions = retry_transactions.lock().unwrap(); let mut retry_transactions = retry_transactions.lock().unwrap();
let transactions_to_retry = transactions.len();
let mut transactions_added_to_retry: usize = 0;
for (signature, mut transaction_info) in transactions.drain() { for (signature, mut transaction_info) in transactions.drain() {
let retry_len = retry_transactions.len(); let retry_len = retry_transactions.len();
let entry = retry_transactions.entry(signature); let entry = retry_transactions.entry(signature);
@ -311,14 +468,23 @@ impl SendTransactionService {
break; break;
} else { } else {
transaction_info.last_sent_time = Some(last_sent_time); transaction_info.last_sent_time = Some(last_sent_time);
saturating_add_assign!(transactions_added_to_retry, 1);
entry.or_insert(transaction_info); entry.or_insert(transaction_info);
} }
} }
} }
stats.retry_queue_overflow.fetch_add(
transactions_to_retry.saturating_sub(transactions_added_to_retry)
as u64,
Ordering::Relaxed,
);
stats
.retry_queue_size
.store(retry_transactions.len() as u64, Ordering::Relaxed);
} }
last_batch_sent = Instant::now(); last_batch_sent = Instant::now();
} }
stats_report.report();
}) })
.unwrap() .unwrap()
} }
@ -330,6 +496,7 @@ impl SendTransactionService {
leader_info_provider: Arc<Mutex<CurrentLeaderInfo<T>>>, leader_info_provider: Arc<Mutex<CurrentLeaderInfo<T>>>,
config: Config, config: Config,
retry_transactions: Arc<Mutex<HashMap<Signature, TransactionInfo>>>, retry_transactions: Arc<Mutex<HashMap<Signature, TransactionInfo>>>,
stats_report: Arc<SendTransactionServiceStatsReport>,
exit: Arc<AtomicBool>, exit: Arc<AtomicBool>,
) -> JoinHandle<()> { ) -> JoinHandle<()> {
info!( info!(
@ -341,6 +508,7 @@ impl SendTransactionService {
.name("send-tx-retry".to_string()) .name("send-tx-retry".to_string())
.spawn(move || loop { .spawn(move || loop {
let retry_interval_ms = config.retry_rate_ms; let retry_interval_ms = config.retry_rate_ms;
let stats = &stats_report.stats;
sleep(Duration::from_millis( sleep(Duration::from_millis(
MAX_RETRY_SLEEP_MS.min(retry_interval_ms), MAX_RETRY_SLEEP_MS.min(retry_interval_ms),
)); ));
@ -349,10 +517,9 @@ impl SendTransactionService {
} }
let mut transactions = retry_transactions.lock().unwrap(); let mut transactions = retry_transactions.lock().unwrap();
if !transactions.is_empty() { if !transactions.is_empty() {
datapoint_info!( stats
"send_transaction_service-queue-size", .retry_queue_size
("len", transactions.len(), i64) .store(transactions.len() as u64, Ordering::Relaxed);
);
let (root_bank, working_bank) = { let (root_bank, working_bank) = {
let bank_forks = bank_forks.read().unwrap(); let bank_forks = bank_forks.read().unwrap();
( (
@ -368,7 +535,9 @@ impl SendTransactionService {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
stats,
); );
stats_report.report();
} }
}) })
.unwrap() .unwrap()
@ -380,9 +549,8 @@ impl SendTransactionService {
transactions: &mut HashMap<Signature, TransactionInfo>, transactions: &mut HashMap<Signature, TransactionInfo>,
leader_info: Option<&T>, leader_info: Option<&T>,
config: &Config, config: &Config,
stats: &SendTransactionServiceStats,
) { ) {
let mut measure = Measure::start("send_transactions_in_batch-us");
// Processing the transactions in batch // Processing the transactions in batch
let addresses = Self::get_tpu_addresses(tpu_address, leader_info, config); let addresses = Self::get_tpu_addresses(tpu_address, leader_info, config);
@ -392,15 +560,8 @@ impl SendTransactionService {
.collect::<Vec<&[u8]>>(); .collect::<Vec<&[u8]>>();
for address in &addresses { for address in &addresses {
Self::send_transactions(address, &wire_transactions); Self::send_transactions(address, &wire_transactions, stats);
} }
measure.stop();
inc_new_counter_info!(
"send_transactions_in_batch-us",
measure.as_us() as usize,
1000,
1000
);
} }
/// Retry transactions sent before. /// Retry transactions sent before.
@ -411,6 +572,7 @@ impl SendTransactionService {
transactions: &mut HashMap<Signature, TransactionInfo>, transactions: &mut HashMap<Signature, TransactionInfo>,
leader_info_provider: &Arc<Mutex<CurrentLeaderInfo<T>>>, leader_info_provider: &Arc<Mutex<CurrentLeaderInfo<T>>>,
config: &Config, config: &Config,
stats: &SendTransactionServiceStats,
) -> ProcessTransactionsResult { ) -> ProcessTransactionsResult {
let mut result = ProcessTransactionsResult::default(); let mut result = ProcessTransactionsResult::default();
@ -419,12 +581,12 @@ impl SendTransactionService {
transactions.retain(|signature, mut transaction_info| { transactions.retain(|signature, mut transaction_info| {
if transaction_info.durable_nonce_info.is_some() { if transaction_info.durable_nonce_info.is_some() {
inc_new_counter_info!("send_transaction_service-nonced", 1); stats.nonced_transactions.fetch_add(1, Ordering::Relaxed);
} }
if root_bank.has_signature(signature) { if root_bank.has_signature(signature) {
info!("Transaction is rooted: {}", signature); info!("Transaction is rooted: {}", signature);
result.rooted += 1; result.rooted += 1;
inc_new_counter_info!("send_transaction_service-rooted", 1); stats.rooted_transactions.fetch_add(1, Ordering::Relaxed);
return false; return false;
} }
let signature_status = working_bank.get_signature_status_slot(signature); let signature_status = working_bank.get_signature_status_slot(signature);
@ -441,14 +603,14 @@ impl SendTransactionService {
{ {
info!("Dropping expired durable-nonce transaction: {}", signature); info!("Dropping expired durable-nonce transaction: {}", signature);
result.expired += 1; result.expired += 1;
inc_new_counter_info!("send_transaction_service-expired", 1); stats.expired_transactions.fetch_add(1, Ordering::Relaxed);
return false; return false;
} }
} }
if transaction_info.last_valid_block_height < root_bank.block_height() { if transaction_info.last_valid_block_height < root_bank.block_height() {
info!("Dropping expired transaction: {}", signature); info!("Dropping expired transaction: {}", signature);
result.expired += 1; result.expired += 1;
inc_new_counter_info!("send_transaction_service-expired", 1); stats.expired_transactions.fetch_add(1, Ordering::Relaxed);
return false; return false;
} }
@ -461,7 +623,9 @@ impl SendTransactionService {
if transaction_info.retries >= max_retries { if transaction_info.retries >= max_retries {
info!("Dropping transaction due to max retries: {}", signature); info!("Dropping transaction due to max retries: {}", signature);
result.max_retries_elapsed += 1; result.max_retries_elapsed += 1;
inc_new_counter_info!("send_transaction_service-max_retries", 1); stats
.transactions_exceeding_max_retries
.fetch_add(1, Ordering::Relaxed);
return false; return false;
} }
} }
@ -481,8 +645,7 @@ impl SendTransactionService {
info!("Retrying transaction: {}", signature); info!("Retrying transaction: {}", signature);
result.retried += 1; result.retried += 1;
transaction_info.retries += 1; transaction_info.retries += 1;
stats.retries.fetch_add(1, Ordering::Relaxed);
inc_new_counter_info!("send_transaction_service-retry", 1);
} }
batched_transactions.insert(*signature); batched_transactions.insert(*signature);
@ -494,7 +657,7 @@ impl SendTransactionService {
if status.is_err() { if status.is_err() {
info!("Dropping failed transaction: {}", signature); info!("Dropping failed transaction: {}", signature);
result.failed += 1; result.failed += 1;
inc_new_counter_info!("send_transaction_service-failed", 1); stats.failed_transactions.fetch_add(1, Ordering::Relaxed);
false false
} else { } else {
result.retained += 1; result.retained += 1;
@ -519,54 +682,51 @@ impl SendTransactionService {
let addresses = Self::get_tpu_addresses(tpu_address, leader_info, config); let addresses = Self::get_tpu_addresses(tpu_address, leader_info, config);
for address in &addresses { for address in &addresses {
Self::send_transactions(address, chunk); Self::send_transactions(address, chunk, stats);
} }
} }
} }
result result
} }
fn send_transaction(tpu_address: &SocketAddr, wire_transaction: &[u8]) { fn send_transaction(
let mut measure = Measure::start("send_transaction_service-us"); tpu_address: &SocketAddr,
if let Err(err) = wire_transaction: &[u8],
connection_cache::send_wire_transaction_async(wire_transaction.to_vec(), tpu_address) ) -> Result<(), TransportError> {
{ connection_cache::send_wire_transaction_async(wire_transaction.to_vec(), tpu_address)
warn!("Failed to send transaction to {}: {:?}", tpu_address, err);
}
measure.stop();
inc_new_counter_info!(
"send_transaction_service-us",
measure.as_us() as usize,
1000,
1000
);
} }
fn send_transactions_with_metrics(tpu_address: &SocketAddr, wire_transactions: &[&[u8]]) { fn send_transactions_with_metrics(
let mut measure = Measure::start("send_transaction_service-batch-us"); tpu_address: &SocketAddr,
wire_transactions: &[&[u8]],
) -> Result<(), TransportError> {
let wire_transactions = wire_transactions.iter().map(|t| t.to_vec()).collect(); let wire_transactions = wire_transactions.iter().map(|t| t.to_vec()).collect();
let send_result = connection_cache::send_wire_transaction_batch_async(wire_transactions, tpu_address)
connection_cache::send_wire_transaction_batch_async(wire_transactions, tpu_address);
if let Err(err) = send_result {
warn!(
"Failed to send transaction batch to {}: {:?}",
tpu_address, err
);
}
measure.stop();
inc_new_counter_info!(
"send_transaction_service-batch-us",
measure.as_us() as usize
);
} }
fn send_transactions(tpu_address: &SocketAddr, wire_transactions: &[&[u8]]) { fn send_transactions(
if wire_transactions.len() == 1 { tpu_address: &SocketAddr,
wire_transactions: &[&[u8]],
stats: &SendTransactionServiceStats,
) {
let mut measure = Measure::start("send-us");
let result = if wire_transactions.len() == 1 {
Self::send_transaction(tpu_address, wire_transactions[0]) Self::send_transaction(tpu_address, wire_transactions[0])
} else { } else {
Self::send_transactions_with_metrics(tpu_address, wire_transactions) Self::send_transactions_with_metrics(tpu_address, wire_transactions)
};
if let Err(err) = result {
warn!(
"Failed to send transaction transaction to {}: {:?}",
tpu_address, err
);
stats.send_failure_count.fetch_add(1, Ordering::Relaxed);
} }
measure.stop();
stats.send_us.fetch_add(measure.as_us(), Ordering::Relaxed);
stats.send_attempt_count.fetch_add(1, Ordering::Relaxed);
} }
fn get_tpu_addresses<'a, T: TpuInfo>( fn get_tpu_addresses<'a, T: TpuInfo>(
@ -670,6 +830,7 @@ mod test {
info!("Expired transactions are dropped..."); info!("Expired transactions are dropped...");
let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(None))); let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(None)));
let stats = SendTransactionServiceStats::default();
transactions.insert( transactions.insert(
Signature::default(), Signature::default(),
TransactionInfo::new( TransactionInfo::new(
@ -688,6 +849,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -717,6 +879,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -746,6 +909,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -775,6 +939,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert_eq!(transactions.len(), 1); assert_eq!(transactions.len(), 1);
assert_eq!( assert_eq!(
@ -806,6 +971,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert_eq!(transactions.len(), 1); assert_eq!(transactions.len(), 1);
assert_eq!( assert_eq!(
@ -847,6 +1013,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert_eq!(transactions.len(), 1); assert_eq!(transactions.len(), 1);
assert_eq!( assert_eq!(
@ -864,6 +1031,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -937,6 +1105,7 @@ mod test {
), ),
); );
let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(None))); let leader_info_provider = Arc::new(Mutex::new(CurrentLeaderInfo::new(None)));
let stats = SendTransactionServiceStats::default();
let result = SendTransactionService::process_transactions::<NullTpuInfo>( let result = SendTransactionService::process_transactions::<NullTpuInfo>(
&working_bank, &working_bank,
&root_bank, &root_bank,
@ -944,6 +1113,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -972,6 +1142,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -1002,6 +1173,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -1030,6 +1202,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -1059,6 +1232,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert!(transactions.is_empty()); assert!(transactions.is_empty());
assert_eq!( assert_eq!(
@ -1088,6 +1262,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert_eq!(transactions.len(), 1); assert_eq!(transactions.len(), 1);
assert_eq!( assert_eq!(
@ -1119,6 +1294,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert_eq!(transactions.len(), 1); assert_eq!(transactions.len(), 1);
assert_eq!( assert_eq!(
@ -1147,6 +1323,7 @@ mod test {
&mut transactions, &mut transactions,
&leader_info_provider, &leader_info_provider,
&config, &config,
&stats,
); );
assert_eq!(transactions.len(), 0); assert_eq!(transactions.len(), 0);
assert_eq!( assert_eq!(