#![cfg(test)]
use core::num::NonZero;
use super::super::validate;
use super::{Config, LightPool};
#[test]
fn regular_path() {
let mut pool = LightPool::<_, _, ()>::new(Config {
blocks_capacity: 16,
finalized_block_hash: [0; 32],
transactions_capacity: 16,
});
assert_eq!(pool.missing_block_bodies().count(), 0);
let tx_id = pool.add_unvalidated(vec![0], ());
pool.add_block([1; 32], &[0; 32], ());
let set_best_block = pool.set_best_block(&[1; 32]);
assert!(set_best_block.included_transactions.is_empty());
assert!(set_best_block.retracted_transactions.is_empty());
assert_eq!(pool.missing_block_bodies().count(), 1);
let included_txs = pool
.set_block_body(&[1; 32], vec![vec![0]].into_iter())
.collect::<Vec<_>>();
assert_eq!(included_txs, vec![(tx_id, 0)]);
assert_eq!(pool.missing_block_bodies().count(), 0);
let mut non_finalized_iter = pool.set_finalized_block(&[1; 32]);
assert!(non_finalized_iter.next().is_none());
let mut iter = pool.prune_finalized_with_body();
let pruned = iter.next().unwrap();
assert_eq!(pruned.block_hash, [1; 32]);
assert_eq!(
pruned.included_transactions,
vec![super::RemovedTransaction {
id: tx_id,
index_in_block: 0,
scale_encoding: vec![0],
user_data: ()
}]
);
}
#[test]
fn included_after_set_best() {
let mut pool = LightPool::<_, _, ()>::new(Config {
blocks_capacity: 16,
finalized_block_hash: [0; 32],
transactions_capacity: 16,
});
assert_eq!(pool.missing_block_bodies().count(), 0);
let tx_id = pool.add_unvalidated(vec![0], ());
pool.add_block([1; 32], &[0; 32], ());
let included_txs = pool
.set_block_body(&[1; 32], vec![vec![0]].into_iter())
.collect::<Vec<_>>();
assert!(included_txs.is_empty());
let set_best_block = pool.set_best_block(&[1; 32]);
assert_eq!(
set_best_block.included_transactions,
vec![(tx_id, [1; 32], 0)]
);
assert!(set_best_block.retracted_transactions.is_empty());
}
#[test]
fn transaction_retracted_after_reorg() {
let mut pool = LightPool::<_, _, ()>::new(Config {
blocks_capacity: 16,
finalized_block_hash: [0; 32],
transactions_capacity: 16,
});
assert_eq!(pool.missing_block_bodies().count(), 0);
let tx_id = pool.add_unvalidated(vec![0], ());
pool.add_block([1; 32], &[0; 32], ());
pool.add_block([2; 32], &[0; 32], ());
let included_txs = pool
.set_block_body(&[1; 32], vec![vec![0]].into_iter())
.collect::<Vec<_>>();
assert!(included_txs.is_empty());
let included_txs = pool
.set_block_body(&[2; 32], Vec::<Vec<u8>>::new().into_iter())
.collect::<Vec<_>>();
assert!(included_txs.is_empty());
let set_best_block = pool.set_best_block(&[1; 32]);
assert_eq!(
set_best_block.included_transactions,
vec![(tx_id, [1; 32], 0)]
);
assert!(set_best_block.retracted_transactions.is_empty());
let set_best_block = pool.set_best_block(&[2; 32]);
assert!(set_best_block.included_transactions.is_empty());
assert_eq!(
set_best_block.retracted_transactions,
vec![(tx_id, [1; 32], 0)]
);
let set_best_block = pool.set_best_block(&[1; 32]);
assert_eq!(
set_best_block.included_transactions,
vec![(tx_id, [1; 32], 0)]
);
assert!(set_best_block.retracted_transactions.is_empty());
}
#[test]
fn longevity_works_non_finalized() {
let mut pool = LightPool::<_, _, ()>::new(Config {
blocks_capacity: 16,
finalized_block_hash: [0; 32],
transactions_capacity: 16,
});
let tx_id = pool.add_unvalidated(vec![0], ());
pool.add_block([1; 32], &[0; 32], ());
let _ = pool.set_best_block(&[1; 32]);
assert!(!pool.is_valid_against_best_block(tx_id));
assert_eq!(
pool.unvalidated_transactions()
.map(|(id, _)| id)
.collect::<Vec<_>>(),
vec![tx_id]
);
pool.set_validation_result(
tx_id,
&[1; 32],
Ok(validate::ValidTransaction {
longevity: NonZero::<u64>::new(2).unwrap(),
priority: 1,
propagate: true,
provides: Vec::new(),
requires: Vec::new(),
}),
);
assert!(pool.is_valid_against_best_block(tx_id));
assert_eq!(pool.unvalidated_transactions().count(), 0);
pool.add_block([2; 32], &[1; 32], ());
let _ = pool.set_best_block(&[2; 32]);
pool.add_block([3; 32], &[2; 32], ());
let _ = pool.set_best_block(&[3; 32]);
assert!(pool.is_valid_against_best_block(tx_id));
assert_eq!(pool.unvalidated_transactions().count(), 0);
pool.add_block([4; 32], &[3; 32], ());
let _ = pool.set_best_block(&[4; 32]);
assert!(!pool.is_valid_against_best_block(tx_id));
assert_eq!(
pool.unvalidated_transactions()
.map(|(id, _)| id)
.collect::<Vec<_>>(),
vec![tx_id]
);
}
#[test]
fn longevity_works_finalized() {
let mut pool = LightPool::<_, _, ()>::new(Config {
blocks_capacity: 16,
finalized_block_hash: [0; 32],
transactions_capacity: 16,
});
let tx_id = pool.add_unvalidated(vec![0], ());
pool.add_block([1; 32], &[0; 32], ());
let _ = pool.set_best_block(&[1; 32]);
assert!(!pool.is_valid_against_best_block(tx_id));
assert_eq!(
pool.unvalidated_transactions()
.map(|(id, _)| id)
.collect::<Vec<_>>(),
vec![tx_id]
);
pool.set_validation_result(
tx_id,
&[1; 32],
Ok(validate::ValidTransaction {
longevity: NonZero::<u64>::new(2).unwrap(),
priority: 1,
propagate: true,
provides: Vec::new(),
requires: Vec::new(),
}),
);
assert!(pool.is_valid_against_best_block(tx_id));
assert_eq!(pool.unvalidated_transactions().count(), 0);
pool.add_block([2; 32], &[1; 32], ());
let _ = pool.set_best_block(&[2; 32]);
pool.add_block([3; 32], &[2; 32], ());
let _ = pool.set_best_block(&[3; 32]);
let _ = pool.set_finalized_block(&[3; 32]);
let _ = pool.prune_finalized_with_body();
assert!(pool.is_valid_against_best_block(tx_id));
assert_eq!(pool.unvalidated_transactions().count(), 0);
pool.add_block([4; 32], &[3; 32], ());
let _ = pool.set_best_block(&[4; 32]);
assert!(!pool.is_valid_against_best_block(tx_id));
assert_eq!(
pool.unvalidated_transactions()
.map(|(id, _)| id)
.collect::<Vec<_>>(),
vec![tx_id]
);
}
#[test]
fn longevity_works_finalized_base() {
let mut pool = LightPool::<_, _, ()>::new(Config {
blocks_capacity: 16,
finalized_block_hash: [0; 32],
transactions_capacity: 16,
});
let tx_id = pool.add_unvalidated(vec![0], ());
pool.set_validation_result(
tx_id,
&[0; 32],
Ok(validate::ValidTransaction {
longevity: NonZero::<u64>::new(2).unwrap(),
priority: 1,
propagate: true,
provides: Vec::new(),
requires: Vec::new(),
}),
);
assert!(pool.is_valid_against_best_block(tx_id));
assert_eq!(pool.unvalidated_transactions().count(), 0);
pool.add_block([1; 32], &[0; 32], ());
let _ = pool.set_best_block(&[1; 32]);
pool.add_block([2; 32], &[1; 32], ());
let _ = pool.set_best_block(&[2; 32]);
let _ = pool.set_finalized_block(&[2; 32]);
let _ = pool.prune_finalized_with_body();
assert!(pool.is_valid_against_best_block(tx_id));
assert_eq!(pool.unvalidated_transactions().count(), 0);
pool.add_block([3; 32], &[2; 32], ());
let _ = pool.set_best_block(&[3; 32]);
assert!(!pool.is_valid_against_best_block(tx_id));
assert_eq!(
pool.unvalidated_transactions()
.map(|(id, _)| id)
.collect::<Vec<_>>(),
vec![tx_id]
);
}