|
1 | 1 | mod common;
|
2 |
| -use std::collections::HashMap; |
3 |
| - |
4 |
| -use bitcoin::Amount; |
| 2 | +use bitcoin::{Amount, ScriptBuf}; |
5 | 3 | use ldk_node::payment::{PaymentDirection, PaymentKind};
|
6 | 4 | use ldk_node::{Event, LightningBalance, PendingSweepBalance};
|
7 |
| -use proptest::prelude::prop; |
8 |
| -use proptest::proptest; |
| 5 | +use proptest::strategy::Strategy; |
| 6 | +use proptest::strategy::ValueTree; |
| 7 | +use proptest::{prelude::prop, proptest}; |
| 8 | +use std::collections::{HashMap, HashSet}; |
9 | 9 |
|
10 | 10 | use crate::common::{
|
11 |
| - expect_event, generate_blocks_and_wait, invalidate_blocks, new_node, open_channel, |
12 |
| - premine_and_distribute_funds, setup_bitcoind_and_electrsd, wait_for_outpoint_spend, |
13 |
| - TestChainSource, |
| 11 | + bump_fee_and_broadcast, distribute_funds_unconfirmed, expect_event, |
| 12 | + generate_block_and_insert_transactions, generate_blocks_and_wait, invalidate_blocks, new_node, |
| 13 | + open_channel, premine_and_distribute_funds, premine_blocks, prepare_rbf, |
| 14 | + setup_bitcoind_and_electrsd, wait_for_outpoint_spend, TestChainSource, |
14 | 15 | };
|
15 | 16 |
|
16 | 17 | proptest! {
|
17 | 18 | #![proptest_config(proptest::test_runner::Config::with_cases(5))]
|
| 19 | + |
18 | 20 | #[test]
|
19 | 21 | fn reorg_test(reorg_depth in 1..=6usize, force_close in prop::bool::ANY) {
|
20 | 22 | let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
|
@@ -185,4 +187,98 @@ proptest! {
|
185 | 187 | assert_eq!(node.next_event(), None);
|
186 | 188 | });
|
187 | 189 | }
|
| 190 | + |
| 191 | + #[test] |
| 192 | + fn test_reorg_rbf( |
| 193 | + reorg_depth in 2..=5usize, |
| 194 | + quantity_rbf in 2..=6usize, |
| 195 | + ) { |
| 196 | + let mut runner = proptest::test_runner::TestRunner::default(); |
| 197 | + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); |
| 198 | + |
| 199 | + let chain_source_bitcoind = TestChainSource::BitcoindRpcSync(&bitcoind); |
| 200 | + let chain_source_electrsd = TestChainSource::Electrum(&electrsd); |
| 201 | + let chain_source_esplora = TestChainSource::Esplora(&electrsd); |
| 202 | + |
| 203 | + let anchor_channels = true; |
| 204 | + let nodes = vec![ |
| 205 | + new_node(&chain_source_bitcoind, anchor_channels), |
| 206 | + new_node(&chain_source_electrsd, anchor_channels), |
| 207 | + new_node(&chain_source_esplora, anchor_channels), |
| 208 | + ]; |
| 209 | + |
| 210 | + let (bitcoind, electrs) = (&bitcoind.client, &electrsd.client); |
| 211 | + |
| 212 | + let mut amount_sat = 2_100_000; |
| 213 | + let all_addrs = |
| 214 | + nodes.iter().map(|node| node.onchain_payment().new_address().unwrap()).collect::<Vec<_>>(); |
| 215 | + let scripts_buf: HashSet<ScriptBuf> = |
| 216 | + all_addrs.iter().map(|addr| addr.script_pubkey()).collect(); |
| 217 | + |
| 218 | + premine_blocks(bitcoind, electrs); |
| 219 | + generate_blocks_and_wait(bitcoind, electrs, reorg_depth); |
| 220 | + let txid = distribute_funds_unconfirmed(bitcoind, electrs, all_addrs, Amount::from_sat(amount_sat)); |
| 221 | + |
| 222 | + let mut is_spendable = false; |
| 223 | + macro_rules! verify_wallet_balances_and_transactions { |
| 224 | + ($expected_balance_sat: expr, $expected_size_list_payments: expr) => { |
| 225 | + let spend_balance = if is_spendable { $expected_balance_sat } else { 0 }; |
| 226 | + for node in &nodes { |
| 227 | + node.sync_wallets().unwrap(); |
| 228 | + let balances = node.list_balances(); |
| 229 | + assert_eq!(balances.total_onchain_balance_sats, $expected_balance_sat); |
| 230 | + assert_eq!(balances.spendable_onchain_balance_sats, spend_balance); |
| 231 | + } |
| 232 | + }; |
| 233 | + } |
| 234 | + |
| 235 | + let mut tx_to_amount = HashMap::new(); |
| 236 | + let (mut tx, fee_output_index) = prepare_rbf(electrs, txid, &scripts_buf); |
| 237 | + tx_to_amount.insert(tx.clone(), amount_sat); |
| 238 | + generate_block_and_insert_transactions(bitcoind, electrs, &[]); |
| 239 | + verify_wallet_balances_and_transactions!(amount_sat, expected_size_list_payments); |
| 240 | + for _ in 0..quantity_rbf { |
| 241 | + let is_alterable_value = prop::bool::ANY.new_tree(&mut runner).unwrap().current(); |
| 242 | + if is_alterable_value { |
| 243 | + let value_sat = (5000..20000u64).new_tree(&mut runner).unwrap().current(); |
| 244 | + let is_acrent_value = prop::bool::ANY.new_tree(&mut runner).unwrap().current(); |
| 245 | + amount_sat = if is_acrent_value {amount_sat + value_sat} else {amount_sat - value_sat}; |
| 246 | + for output in &mut tx.output { |
| 247 | + if scripts_buf.contains(&output.script_pubkey) { |
| 248 | + output.value = Amount::from_sat(amount_sat); |
| 249 | + } |
| 250 | + } |
| 251 | + let fee_sat = Amount::from_sat(scripts_buf.len() as u64 * value_sat); |
| 252 | + if is_acrent_value { |
| 253 | + tx.output[fee_output_index].value -= fee_sat; |
| 254 | + } else { |
| 255 | + tx.output[fee_output_index].value += fee_sat; |
| 256 | + } |
| 257 | + |
| 258 | + } |
| 259 | + |
| 260 | + tx = bump_fee_and_broadcast(bitcoind, electrs, tx, fee_output_index, is_spendable); |
| 261 | + tx_to_amount.insert(tx.clone(), amount_sat); |
| 262 | + |
| 263 | + verify_wallet_balances_and_transactions!(amount_sat, expected_size_list_payments); |
| 264 | + } |
| 265 | + |
| 266 | + is_spendable = true; |
| 267 | + let index_tx_confirm = (0..tx_to_amount.len() - 1).new_tree(&mut runner).unwrap().current(); |
| 268 | + let tx_to_confirm = tx_to_amount.iter().nth(index_tx_confirm).unwrap(); |
| 269 | + generate_block_and_insert_transactions(bitcoind, electrs, &[tx_to_confirm.0.clone()]); |
| 270 | + generate_blocks_and_wait(bitcoind, electrs, reorg_depth - 1); |
| 271 | + amount_sat = *tx_to_confirm.1; |
| 272 | + verify_wallet_balances_and_transactions!(amount_sat, expected_size_list_payments); |
| 273 | + |
| 274 | + invalidate_blocks(bitcoind, reorg_depth); |
| 275 | + generate_block_and_insert_transactions(bitcoind, electrs, &[]); |
| 276 | + |
| 277 | + let index_tx_confirm = (0..tx_to_amount.len() - 1).new_tree(&mut runner).unwrap().current(); |
| 278 | + let tx_to_confirm = tx_to_amount.iter().nth(index_tx_confirm).unwrap(); |
| 279 | + generate_block_and_insert_transactions(bitcoind, electrs, &[tx_to_confirm.0.clone()]); |
| 280 | + amount_sat = *tx_to_confirm.1; |
| 281 | + generate_blocks_and_wait(bitcoind, electrs, 5); |
| 282 | + verify_wallet_balances_and_transactions!(amount_sat, expected_size_list_payments); |
| 283 | + } |
188 | 284 | }
|
0 commit comments