Skip to content

Commit a805567

Browse files
Antoine RiardTheBlueMatt
Antoine Riard
authored andcommitted
Test htlc outputs shared tx claim case
1 parent ae8bd1b commit a805567

File tree

1 file changed

+69
-1
lines changed

1 file changed

+69
-1
lines changed

src/ln/channelmanager.rs

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2284,7 +2284,7 @@ mod tests {
22842284
use rand::{thread_rng,Rng};
22852285

22862286
use std::cell::RefCell;
2287-
use std::collections::HashMap;
2287+
use std::collections::{BTreeSet, HashMap};
22882288
use std::default::Default;
22892289
use std::rc::Rc;
22902290
use std::sync::{Arc, Mutex};
@@ -3494,6 +3494,74 @@ mod tests {
34943494
get_announce_close_broadcast_events(&nodes, 0, 1);
34953495
}
34963496

3497+
#[test]
3498+
fn claim_htlc_outputs_shared_tx() {
3499+
// Node revoked old state, htlcs haven't time out yet, claim them in shared justice tx
3500+
let nodes = create_network(2);
3501+
3502+
// Create some new channel:
3503+
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);
3504+
3505+
// Rebalance the network to generate htlc in the two directions
3506+
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
3507+
// node[0] is gonna to revoke an old state thus node[1] should be able to claim both offered/received HTLC outputs on top of commitment tx
3508+
let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
3509+
let _payment_preimage_2 = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000).0;
3510+
3511+
// Get the will-be-revoked local txn from node[0]
3512+
let revoked_local_txn = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone();
3513+
assert_eq!(revoked_local_txn.len(), 2); // commitment tx + 1 HTLC-Timeout tx
3514+
assert_eq!(revoked_local_txn[0].input.len(), 1);
3515+
assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_1.3.txid());
3516+
assert_eq!(revoked_local_txn[1].input.len(), 1);
3517+
assert_eq!(revoked_local_txn[1].input[0].previous_output.txid, revoked_local_txn[0].txid());
3518+
assert_eq!(revoked_local_txn[1].input[0].witness.last().unwrap().len(), 133); // HTLC-Timeout
3519+
3520+
//Revoke the old state
3521+
claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_1);
3522+
3523+
{
3524+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
3525+
3526+
nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
3527+
3528+
nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
3529+
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
3530+
assert_eq!(node_txn.len(), 4);
3531+
3532+
let mut revoked_tx_map = HashMap::new();
3533+
revoked_tx_map.insert(revoked_local_txn[0].txid(), revoked_local_txn[0].clone());
3534+
3535+
assert_eq!(node_txn[0].input.len(), 3); // Claim the revoked output + both revoked HTLC outputs
3536+
node_txn[0].verify(&revoked_tx_map).unwrap();
3537+
assert_eq!(node_txn[0], node_txn[3]); // justice tx is duplicated due to block re-scanning
3538+
3539+
let mut witness_lens = BTreeSet::new();
3540+
witness_lens.insert(node_txn[0].input[0].witness.last().unwrap().len());
3541+
witness_lens.insert(node_txn[0].input[1].witness.last().unwrap().len());
3542+
witness_lens.insert(node_txn[0].input[2].witness.last().unwrap().len());
3543+
assert_eq!(witness_lens.len(), 3);
3544+
assert_eq!(*witness_lens.iter().skip(0).next().unwrap(), 77); // revoked to_local
3545+
assert_eq!(*witness_lens.iter().skip(1).next().unwrap(), 133); // revoked offered HTLC
3546+
assert_eq!(*witness_lens.iter().skip(2).next().unwrap(), 138); // revoked received HTLC
3547+
3548+
// Next nodes[1] broadcasts its current local tx state:
3549+
assert_eq!(node_txn[1].input.len(), 1);
3550+
assert_eq!(node_txn[1].input[0].previous_output.txid, chan_1.3.txid()); //Spending funding tx unique txouput, tx broadcasted by ChannelManager
3551+
3552+
assert_eq!(node_txn[2].input.len(), 1);
3553+
let witness_script = node_txn[2].clone().input[0].witness.pop().unwrap();
3554+
assert_eq!(witness_script.len(), 133); //Spending an offered htlc output
3555+
assert_eq!(node_txn[2].input[0].previous_output.txid, node_txn[1].txid());
3556+
assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[0].previous_output.txid);
3557+
assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[1].previous_output.txid);
3558+
}
3559+
get_announce_close_broadcast_events(&nodes, 0, 1);
3560+
assert_eq!(nodes[0].node.list_channels().len(), 0);
3561+
assert_eq!(nodes[1].node.list_channels().len(), 0);
3562+
}
3563+
3564+
#[test]
34973565
fn test_htlc_ignore_latest_remote_commitment() {
34983566
// Test that HTLC transactions spending the latest remote commitment transaction are simply
34993567
// ignored if we cannot claim them. This originally tickled an invalid unwrap().

0 commit comments

Comments
 (0)