use blvm_node::config::{RbfConfig, RbfMode};
use blvm_node::node::mempool::MempoolManager;
use blvm_protocol::{OutPoint, Transaction, TransactionInput, TransactionOutput, UtxoSet, UTXO};
use std::sync::Arc;
fn create_rbf_tx(input_value: u64, output_value: u64) -> Transaction {
Transaction {
version: 1,
inputs: blvm_protocol::tx_inputs![TransactionInput {
prevout: OutPoint {
hash: [1; 32],
index: 0,
},
script_sig: vec![],
sequence: 0xfffffffe, }],
outputs: blvm_protocol::tx_outputs![TransactionOutput {
value: output_value as i64,
script_pubkey: [0x76, 0xa9, 0x14, 0x00].repeat(20).into(), }],
lock_time: 0,
}
}
fn create_test_utxo_set() -> UtxoSet {
let mut utxo_set = UtxoSet::default();
utxo_set.insert(
OutPoint {
hash: [1; 32],
index: 0,
},
Arc::new(UTXO {
value: 100_000,
script_pubkey: [0x76, 0xa9, 0x14, 0x00].repeat(20).into(),
height: 0,
is_coinbase: false,
}),
);
utxo_set
}
#[test]
fn test_rbf_mode_disabled() {
let mempool = MempoolManager::new();
let rbf_config = RbfConfig::with_mode(RbfMode::Disabled);
mempool.set_rbf_config(Some(rbf_config));
let existing_tx = create_rbf_tx(100_000, 90_000); let new_tx = create_rbf_tx(100_000, 80_000);
let utxo_set = create_test_utxo_set();
let result = mempool.check_rbf_replacement(&new_tx, &existing_tx, &utxo_set, None);
assert!(result.is_ok());
assert!(!result.unwrap(), "RBF should be disabled");
}
#[test]
fn test_rbf_mode_conservative() {
let mempool = MempoolManager::new();
let rbf_config = RbfConfig::with_mode(RbfMode::Conservative);
mempool.set_rbf_config(Some(rbf_config));
let existing_tx = create_rbf_tx(100_000, 90_000); let new_tx = create_rbf_tx(100_000, 70_000);
let utxo_set = create_test_utxo_set();
let result = mempool.check_rbf_replacement(&new_tx, &existing_tx, &utxo_set, None);
assert!(result.is_ok());
}
#[test]
fn test_rbf_mode_standard() {
let mempool = MempoolManager::new();
let rbf_config = RbfConfig::with_mode(RbfMode::Standard);
mempool.set_rbf_config(Some(rbf_config));
let existing_tx = create_rbf_tx(100_000, 90_000); let new_tx = create_rbf_tx(100_000, 88_000);
let utxo_set = create_test_utxo_set();
let result = mempool.check_rbf_replacement(&new_tx, &existing_tx, &utxo_set, None);
assert!(result.is_ok());
}
#[test]
fn test_rbf_mode_aggressive() {
let mempool = MempoolManager::new();
let rbf_config = RbfConfig::with_mode(RbfMode::Aggressive);
mempool.set_rbf_config(Some(rbf_config));
let existing_tx = create_rbf_tx(100_000, 90_000); let new_tx = create_rbf_tx(100_000, 89_500);
let utxo_set = create_test_utxo_set();
let result = mempool.check_rbf_replacement(&new_tx, &existing_tx, &utxo_set, None);
assert!(result.is_ok());
}
#[test]
fn test_rbf_replacement_count_limit() {
let mut rbf_config = RbfConfig::with_mode(RbfMode::Standard);
rbf_config.max_replacements_per_tx = 2;
assert_eq!(rbf_config.max_replacements_per_tx, 2);
assert_eq!(rbf_config.mode, RbfMode::Standard);
}
#[test]
fn test_rbf_cooldown_period() {
let mut rbf_config = RbfConfig::with_mode(RbfMode::Standard);
rbf_config.cooldown_seconds = 60;
assert_eq!(rbf_config.cooldown_seconds, 60);
assert_eq!(rbf_config.mode, RbfMode::Standard);
}
#[test]
fn test_rbf_fee_rate_multiplier() {
let mempool = MempoolManager::new();
let mut rbf_config = RbfConfig::with_mode(RbfMode::Standard);
rbf_config.min_fee_rate_multiplier = 1.5; mempool.set_rbf_config(Some(rbf_config));
let existing_tx = create_rbf_tx(100_000, 90_000); let new_tx_insufficient = create_rbf_tx(100_000, 91_000); let new_tx_sufficient = create_rbf_tx(100_000, 85_000);
let utxo_set = create_test_utxo_set();
let result1 =
mempool.check_rbf_replacement(&new_tx_insufficient, &existing_tx, &utxo_set, None);
assert!(result1.is_ok());
let result2 = mempool.check_rbf_replacement(&new_tx_sufficient, &existing_tx, &utxo_set, None);
assert!(result2.is_ok());
}
#[test]
fn test_rbf_absolute_fee_bump() {
let mempool = MempoolManager::new();
let mut rbf_config = RbfConfig::with_mode(RbfMode::Standard);
rbf_config.min_fee_bump_satoshis = 5000; mempool.set_rbf_config(Some(rbf_config));
let existing_tx = create_rbf_tx(100_000, 90_000); let new_tx_insufficient = create_rbf_tx(100_000, 89_500); let new_tx_sufficient = create_rbf_tx(100_000, 84_000);
let utxo_set = create_test_utxo_set();
let result1 =
mempool.check_rbf_replacement(&new_tx_insufficient, &existing_tx, &utxo_set, None);
assert!(result1.is_ok());
let result2 = mempool.check_rbf_replacement(&new_tx_sufficient, &existing_tx, &utxo_set, None);
assert!(result2.is_ok());
}
#[test]
fn test_rbf_config_with_mode() {
let conservative = RbfConfig::with_mode(RbfMode::Conservative);
assert_eq!(conservative.mode, RbfMode::Conservative);
assert_eq!(conservative.min_fee_rate_multiplier, 2.0);
assert_eq!(conservative.min_fee_bump_satoshis, 5000);
assert_eq!(conservative.min_confirmations, 1);
let aggressive = RbfConfig::with_mode(RbfMode::Aggressive);
assert_eq!(aggressive.mode, RbfMode::Aggressive);
assert_eq!(aggressive.min_fee_rate_multiplier, 1.05);
assert_eq!(aggressive.min_fee_bump_satoshis, 500);
assert!(aggressive.allow_package_replacements);
let standard = RbfConfig::with_mode(RbfMode::Standard);
assert_eq!(standard.mode, RbfMode::Standard);
assert_eq!(standard.min_fee_rate_multiplier, 1.1);
assert_eq!(standard.min_fee_bump_satoshis, 1000);
}