use blvm_node::network::package_relay::{
PackageError, PackageId, PackageRejectReason, PackageRelay, PackageStatus, PackageValidator,
TransactionPackage,
};
use blvm_protocol::{Transaction, TransactionInput, TransactionOutput};
fn create_minimal_tx() -> Transaction {
Transaction {
version: 1,
inputs: blvm_protocol::tx_inputs![],
outputs: blvm_protocol::tx_outputs![TransactionOutput {
value: 1000,
script_pubkey: vec![0x51], }],
lock_time: 0,
}
}
fn create_tx_with_input(prevout_hash: [u8; 32], prevout_index: u32) -> Transaction {
Transaction {
version: 1,
inputs: blvm_protocol::tx_inputs![TransactionInput {
prevout: blvm_protocol::OutPoint {
hash: prevout_hash,
index: prevout_index,
},
script_sig: vec![],
sequence: 0xffffffff,
}],
outputs: blvm_protocol::tx_outputs![TransactionOutput {
value: 500,
script_pubkey: vec![0x51],
}],
lock_time: 0,
}
}
#[test]
fn test_package_relay_creation() {
let _relay = PackageRelay::new();
assert!(true);
}
#[test]
fn test_package_relay_default() {
let _relay = PackageRelay::default();
assert!(true);
}
#[test]
fn test_package_validator_default() {
let validator = PackageValidator::default();
assert_eq!(validator.max_package_size, 25);
assert_eq!(validator.max_package_weight, 404_000);
assert_eq!(validator.min_fee_rate, 1000);
}
#[test]
fn test_package_id_from_transactions() {
let tx1 = create_minimal_tx();
let tx2 = create_minimal_tx();
let package_id1 = PackageId::from_transactions(&[tx1.clone()], None);
let _package_id2 = PackageId::from_transactions(&[tx2.clone()], None);
let package_id3 = PackageId::from_transactions(&[tx1.clone(), tx2.clone()], None);
let package_id1_again = PackageId::from_transactions(&[tx1.clone()], None);
assert_eq!(package_id1, package_id1_again);
assert_ne!(package_id1, package_id3);
}
#[test]
fn test_transaction_package_empty() {
let result = TransactionPackage::new(vec![]);
assert!(result.is_err());
match result.unwrap_err() {
PackageError::EmptyPackage => assert!(true),
_ => panic!("Expected EmptyPackage error"),
}
}
#[test]
fn test_transaction_package_single_tx() {
let tx = create_minimal_tx();
let result = TransactionPackage::new(vec![tx]);
assert!(result.is_ok());
let package = result.unwrap();
assert_eq!(package.transactions.len(), 1);
assert!(package.combined_weight > 0);
}
#[test]
fn test_transaction_package_multiple_txs() {
let tx1 = create_minimal_tx();
let tx2 = create_minimal_tx();
let result = TransactionPackage::new(vec![tx1, tx2]);
assert!(result.is_ok());
let package = result.unwrap();
assert_eq!(package.transactions.len(), 2);
}
#[test]
fn test_transaction_package_ordering_valid() {
let parent_tx = create_minimal_tx();
let parent_txid = blvm_protocol::block::calculate_tx_id(&parent_tx);
let child_tx = create_tx_with_input(parent_txid, 0);
let result = TransactionPackage::new(vec![parent_tx, child_tx]);
assert!(result.is_ok());
}
#[test]
fn test_transaction_package_ordering_invalid() {
let parent_tx = create_minimal_tx();
let parent_txid = blvm_protocol::block::calculate_tx_id(&parent_tx);
let child_tx = create_tx_with_input(parent_txid, 0);
let result = TransactionPackage::new(vec![child_tx, parent_tx]);
assert!(result.is_err());
match result.unwrap_err() {
PackageError::InvalidOrder => assert!(true),
_ => panic!("Expected InvalidOrder error"),
}
}
#[test]
fn test_package_fee_rate() {
let tx = create_minimal_tx();
let package = TransactionPackage::new(vec![tx]).unwrap();
let fee_rate = package.fee_rate();
assert!(fee_rate >= 0.0);
}
#[test]
fn test_package_relay_create_package() {
let relay = PackageRelay::new();
let tx = create_minimal_tx();
let result = relay.create_package(vec![tx]);
assert!(result.is_ok());
}
#[test]
fn test_package_relay_validate_package_size() {
let relay = PackageRelay::new();
let mut txs = Vec::new();
for _ in 0..26 {
txs.push(create_minimal_tx());
}
let package = TransactionPackage::new(txs).unwrap();
let result = relay.validate_package(&package);
assert!(result.is_err());
match result.unwrap_err() {
PackageRejectReason::TooManyTransactions => assert!(true),
_ => panic!("Expected TooManyTransactions"),
}
}
#[test]
fn test_package_relay_validate_package_duplicates() {
let relay = PackageRelay::new();
let tx = create_minimal_tx();
let package = TransactionPackage::new(vec![tx.clone(), tx]).unwrap();
let result = relay.validate_package(&package);
assert!(result.is_err());
match result.unwrap_err() {
PackageRejectReason::DuplicateTransactions => assert!(true),
_ => panic!("Expected DuplicateTransactions"),
}
}
#[test]
fn test_package_relay_validate_package_valid() {
let relay = PackageRelay::new();
let tx1 = create_minimal_tx();
let tx2 = create_minimal_tx();
let package = TransactionPackage::new(vec![tx1, tx2]).unwrap();
let result = relay.validate_package(&package);
if result.is_err() {
let err = result.unwrap_err();
assert!(matches!(
err,
PackageRejectReason::InvalidOrder | PackageRejectReason::DuplicateTransactions
));
} else {
assert!(result.is_ok());
}
}
#[test]
fn test_package_relay_register_package() {
let mut relay = PackageRelay::new();
let tx = create_minimal_tx();
let package = TransactionPackage::new(vec![tx]).unwrap();
let result = relay.register_package(package);
assert!(result.is_ok());
let package_id = result.unwrap();
let retrieved = relay.get_package(&package_id);
assert!(retrieved.is_some());
}
#[test]
fn test_package_relay_get_package_nonexistent() {
let relay = PackageRelay::new();
let fake_id = PackageId([0u8; 32]);
let result = relay.get_package(&fake_id);
assert!(result.is_none());
}
#[test]
fn test_package_relay_mark_accepted() {
let mut relay = PackageRelay::new();
let tx = create_minimal_tx();
let package = TransactionPackage::new(vec![tx]).unwrap();
let package_id = relay.register_package(package).unwrap();
relay.mark_accepted(&package_id);
let retrieved = relay.get_package(&package_id);
assert!(retrieved.is_some());
}
#[test]
fn test_package_relay_mark_rejected() {
let mut relay = PackageRelay::new();
let tx = create_minimal_tx();
let package = TransactionPackage::new(vec![tx]).unwrap();
let package_id = relay.register_package(package).unwrap();
relay.mark_rejected(&package_id, PackageRejectReason::FeeRateTooLow);
let retrieved = relay.get_package(&package_id);
assert!(retrieved.is_some());
}
#[test]
fn test_package_relay_cleanup_old_packages() {
let mut relay = PackageRelay::new();
let tx = create_minimal_tx();
let package = TransactionPackage::new(vec![tx]).unwrap();
let package_id = relay.register_package(package).unwrap();
assert!(relay.get_package(&package_id).is_some());
std::thread::sleep(std::time::Duration::from_secs(2));
relay.cleanup_old_packages(1);
assert!(relay.get_package(&package_id).is_none());
}
#[test]
fn test_package_status_variants() {
let statuses = vec![
PackageStatus::Pending,
PackageStatus::Accepted,
PackageStatus::Rejected {
reason: PackageRejectReason::TooManyTransactions,
},
];
for status in statuses {
match status {
PackageStatus::Pending => assert!(true),
PackageStatus::Accepted => assert!(true),
PackageStatus::Rejected { reason } => {
assert_eq!(reason, PackageRejectReason::TooManyTransactions);
}
}
}
}
#[test]
fn test_package_reject_reason_variants() {
let reasons = vec![
PackageRejectReason::TooManyTransactions,
PackageRejectReason::WeightExceedsLimit,
PackageRejectReason::FeeRateTooLow,
PackageRejectReason::InvalidOrder,
PackageRejectReason::DuplicateTransactions,
PackageRejectReason::InvalidStructure,
];
for reason in reasons {
match reason {
PackageRejectReason::TooManyTransactions => assert!(true),
PackageRejectReason::WeightExceedsLimit => assert!(true),
PackageRejectReason::FeeRateTooLow => assert!(true),
PackageRejectReason::InvalidOrder => assert!(true),
PackageRejectReason::DuplicateTransactions => assert!(true),
PackageRejectReason::InvalidStructure => assert!(true),
}
}
}
#[test]
fn test_package_id_equality() {
let tx = create_minimal_tx();
let id1 = PackageId::from_transactions(&[tx.clone()], None);
let id2 = PackageId::from_transactions(&[tx], None);
assert_eq!(id1, id2);
assert_eq!(id1.0, id2.0);
}
#[test]
fn test_package_id_hash() {
use std::collections::HashSet;
let tx1 = create_minimal_tx();
let tx2 = create_minimal_tx();
let id1 = PackageId::from_transactions(&[tx1.clone()], None);
let id2 = PackageId::from_transactions(&[tx2.clone()], None);
let mut set = HashSet::new();
set.insert(id1);
set.insert(id2);
assert!(!set.is_empty());
assert!(set.len() <= 2);
let id1_again = PackageId::from_transactions(&[tx1], None);
set.insert(id1_again);
assert!(!set.is_empty());
assert!(set.len() <= 2);
}