|
8 | 8 | // licenses.
|
9 | 9 |
|
10 | 10 | use crate::chain::chaininterface::FEERATE_FLOOR_SATS_PER_KW;
|
11 |
| -use crate::chain::channelmonitor::ANTI_REORG_DELAY; |
| 11 | +use crate::chain::channelmonitor::{ANTI_REORG_DELAY, LATENCY_GRACE_PERIOD_BLOCKS}; |
12 | 12 | use crate::events::bump_transaction::sync::WalletSourceSync;
|
13 |
| -use crate::events::Event; |
| 13 | +use crate::events::{ClosureReason, Event, HTLCHandlingFailureType}; |
14 | 14 | use crate::ln::chan_utils;
|
15 | 15 | use crate::ln::functional_test_utils::*;
|
16 | 16 | use crate::ln::funding::{FundingTxInput, SpliceContribution};
|
@@ -395,3 +395,168 @@ fn test_splice_out() {
|
395 | 395 | assert!(htlc_limit_msat < initial_channel_value_sat / 2 * 1000);
|
396 | 396 | let _ = send_payment(&nodes[0], &[&nodes[1]], htlc_limit_msat);
|
397 | 397 | }
|
| 398 | + |
| 399 | +#[derive(PartialEq)] |
| 400 | +enum SpliceStatus { |
| 401 | + Unconfirmed, |
| 402 | + Confirmed, |
| 403 | + Locked, |
| 404 | +} |
| 405 | + |
| 406 | +#[test] |
| 407 | +fn test_splice_commitment_broadcast() { |
| 408 | + do_test_splice_commitment_broadcast(SpliceStatus::Unconfirmed, false); |
| 409 | + do_test_splice_commitment_broadcast(SpliceStatus::Unconfirmed, true); |
| 410 | + do_test_splice_commitment_broadcast(SpliceStatus::Confirmed, false); |
| 411 | + do_test_splice_commitment_broadcast(SpliceStatus::Confirmed, true); |
| 412 | + do_test_splice_commitment_broadcast(SpliceStatus::Locked, false); |
| 413 | + do_test_splice_commitment_broadcast(SpliceStatus::Locked, true); |
| 414 | +} |
| 415 | + |
| 416 | +fn do_test_splice_commitment_broadcast(splice_status: SpliceStatus, claim_htlcs: bool) { |
| 417 | + // Tests that we're able to enforce HTLCs onchain during the different stages of a splice. |
| 418 | + let chanmon_cfgs = create_chanmon_cfgs(2); |
| 419 | + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); |
| 420 | + let config = test_default_anchors_channel_config(); |
| 421 | + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config.clone()), Some(config)]); |
| 422 | + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); |
| 423 | + |
| 424 | + let node_id_0 = nodes[0].node.get_our_node_id(); |
| 425 | + let node_id_1 = nodes[1].node.get_our_node_id(); |
| 426 | + |
| 427 | + let initial_channel_capacity = 100_000; |
| 428 | + let (_, _, channel_id, initial_funding_tx) = |
| 429 | + create_announced_chan_between_nodes_with_value(&nodes, 0, 1, initial_channel_capacity, 0); |
| 430 | + |
| 431 | + let coinbase_tx = provide_anchor_reserves(&nodes); |
| 432 | + |
| 433 | + // We want to have two HTLCs pending to make sure we can claim those sent before and after a |
| 434 | + // splice negotiation. |
| 435 | + let payment_amount = 1_000_000; |
| 436 | + let (preimage1, payment_hash1, ..) = route_payment(&nodes[0], &[&nodes[1]], payment_amount); |
| 437 | + let splice_in_amount = initial_channel_capacity / 2; |
| 438 | + let initiator_contribution = SpliceContribution::SpliceIn { |
| 439 | + value: Amount::from_sat(splice_in_amount), |
| 440 | + inputs: vec![FundingTxInput::new_p2wpkh(coinbase_tx.clone(), 0).unwrap()], |
| 441 | + change_script: Some(nodes[0].wallet_source.get_change_script().unwrap()), |
| 442 | + }; |
| 443 | + let splice_tx = splice_channel(&nodes[0], &nodes[1], channel_id, initiator_contribution); |
| 444 | + let (preimage2, payment_hash2, ..) = route_payment(&nodes[0], &[&nodes[1]], payment_amount); |
| 445 | + let htlc_expiry = nodes[0].best_block_info().1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS; |
| 446 | + |
| 447 | + if splice_status == SpliceStatus::Confirmed || splice_status == SpliceStatus::Locked { |
| 448 | + mine_transaction(&nodes[0], &splice_tx); |
| 449 | + mine_transaction(&nodes[1], &splice_tx); |
| 450 | + } |
| 451 | + if splice_status == SpliceStatus::Locked { |
| 452 | + lock_splice_after_blocks(&nodes[0], &nodes[1], channel_id, ANTI_REORG_DELAY - 1); |
| 453 | + } |
| 454 | + |
| 455 | + if claim_htlcs { |
| 456 | + // Claim both HTLCs, but don't do anything with the update message sent since we want to |
| 457 | + // resolve the HTLCs onchain instead with a single transaction (thanks to anchors). |
| 458 | + nodes[1].node.claim_funds(preimage1); |
| 459 | + expect_payment_claimed!(&nodes[1], payment_hash1, payment_amount); |
| 460 | + nodes[1].node.claim_funds(preimage2); |
| 461 | + expect_payment_claimed!(&nodes[1], payment_hash2, payment_amount); |
| 462 | + check_added_monitors(&nodes[1], 2); |
| 463 | + let _ = get_htlc_update_msgs(&nodes[1], &node_id_0); |
| 464 | + } |
| 465 | + |
| 466 | + // Force close the channel. This should broadcast the appropriate commitment transaction based |
| 467 | + // on the currently confirmed funding. |
| 468 | + nodes[0] |
| 469 | + .node |
| 470 | + .force_close_broadcasting_latest_txn(&channel_id, &node_id_1, "test".to_owned()) |
| 471 | + .unwrap(); |
| 472 | + handle_bump_events(&nodes[0], true, 0); |
| 473 | + let commitment_tx = { |
| 474 | + let mut txn = nodes[0].tx_broadcaster.txn_broadcast(); |
| 475 | + assert_eq!(txn.len(), 1); |
| 476 | + let commitment_tx = txn.remove(0); |
| 477 | + match splice_status { |
| 478 | + SpliceStatus::Unconfirmed => check_spends!(&commitment_tx, &initial_funding_tx), |
| 479 | + SpliceStatus::Confirmed | SpliceStatus::Locked => { |
| 480 | + check_spends!(&commitment_tx, &splice_tx) |
| 481 | + }, |
| 482 | + } |
| 483 | + commitment_tx |
| 484 | + }; |
| 485 | + |
| 486 | + mine_transaction(&nodes[0], &commitment_tx); |
| 487 | + mine_transaction(&nodes[1], &commitment_tx); |
| 488 | + |
| 489 | + let closure_reason = ClosureReason::HolderForceClosed { |
| 490 | + broadcasted_latest_txn: Some(true), |
| 491 | + message: "test".to_owned(), |
| 492 | + }; |
| 493 | + let closed_channel_capacity = if splice_status == SpliceStatus::Locked { |
| 494 | + initial_channel_capacity + splice_in_amount |
| 495 | + } else { |
| 496 | + initial_channel_capacity |
| 497 | + }; |
| 498 | + check_closed_event(&nodes[0], 1, closure_reason, false, &[node_id_1], closed_channel_capacity); |
| 499 | + check_closed_broadcast(&nodes[0], 1, true); |
| 500 | + check_added_monitors(&nodes[0], 1); |
| 501 | + |
| 502 | + let closure_reason = ClosureReason::CommitmentTxConfirmed; |
| 503 | + check_closed_event(&nodes[1], 1, closure_reason, false, &[node_id_0], closed_channel_capacity); |
| 504 | + check_closed_broadcast(&nodes[1], 1, true); |
| 505 | + check_added_monitors(&nodes[1], 1); |
| 506 | + |
| 507 | + if !claim_htlcs { |
| 508 | + // If we're supposed to time out the HTLCs, mine enough blocks until the expiration. |
| 509 | + connect_blocks(&nodes[0], htlc_expiry - nodes[0].best_block_info().1); |
| 510 | + connect_blocks(&nodes[1], htlc_expiry - nodes[1].best_block_info().1); |
| 511 | + expect_htlc_handling_failed_destinations!( |
| 512 | + nodes[1].node.get_and_clear_pending_events(), |
| 513 | + &[ |
| 514 | + HTLCHandlingFailureType::Receive { payment_hash: payment_hash1 }, |
| 515 | + HTLCHandlingFailureType::Receive { payment_hash: payment_hash2 } |
| 516 | + ] |
| 517 | + ); |
| 518 | + } |
| 519 | + |
| 520 | + // We should see either an aggregated HTLC timeout or success transaction spending the valid |
| 521 | + // commitment transaction we mined earlier. |
| 522 | + let htlc_claim_tx = if claim_htlcs { |
| 523 | + let mut txn = nodes[1].tx_broadcaster.txn_broadcast(); |
| 524 | + assert_eq!(txn.len(), 1); |
| 525 | + let htlc_success_tx = txn.remove(0); |
| 526 | + assert_eq!(htlc_success_tx.input.len(), 2); |
| 527 | + check_spends!(&htlc_success_tx, &commitment_tx); |
| 528 | + htlc_success_tx |
| 529 | + } else { |
| 530 | + handle_bump_htlc_event(&nodes[0], 1); |
| 531 | + let mut txn = nodes[0].tx_broadcaster.txn_broadcast(); |
| 532 | + assert_eq!(txn.len(), 1); |
| 533 | + let htlc_timeout_tx = txn.remove(0); |
| 534 | + // The inputs spent correspond to the fee bump input and the two HTLCs from the commitment |
| 535 | + // transaction. |
| 536 | + assert_eq!(htlc_timeout_tx.input.len(), 3); |
| 537 | + let tx_with_fee_bump_utxo = |
| 538 | + if splice_status == SpliceStatus::Unconfirmed { &coinbase_tx } else { &splice_tx }; |
| 539 | + check_spends!(&htlc_timeout_tx, &commitment_tx, tx_with_fee_bump_utxo); |
| 540 | + htlc_timeout_tx |
| 541 | + }; |
| 542 | + |
| 543 | + mine_transaction(&nodes[0], &htlc_claim_tx); |
| 544 | + mine_transaction(&nodes[1], &htlc_claim_tx); |
| 545 | + connect_blocks(&nodes[0], ANTI_REORG_DELAY - 1); |
| 546 | + connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1); |
| 547 | + |
| 548 | + let events = nodes[0].node.get_and_clear_pending_events(); |
| 549 | + if claim_htlcs { |
| 550 | + assert_eq!(events.iter().filter(|e| matches!(e, Event::PaymentSent { .. })).count(), 2); |
| 551 | + assert_eq!( |
| 552 | + events.iter().filter(|e| matches!(e, Event::PaymentPathSuccessful { .. })).count(), |
| 553 | + 2 |
| 554 | + ); |
| 555 | + } else { |
| 556 | + assert_eq!(events.iter().filter(|e| matches!(e, Event::PaymentFailed { .. })).count(), 2,); |
| 557 | + assert_eq!( |
| 558 | + events.iter().filter(|e| matches!(e, Event::PaymentPathFailed { .. })).count(), |
| 559 | + 2 |
| 560 | + ); |
| 561 | + } |
| 562 | +} |
0 commit comments