Skip to content

Add channel_monitor_claim_revoked_commitment_tx test #184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3426,6 +3426,146 @@ mod tests {
assert_eq!(nodes[1].node.list_channels().len(), 0);
}

#[test]
fn claim_htlc_outputs_shared_tx() {
// Node revoked old state, htlcs haven't time out yet, claim them in shared justice tx

let nodes = create_network(2);

// Create some new channel:
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);

// Rebalance the network to generate htlc in the two directions
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
// 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
let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let _payment_preimage_2 = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000).0;

// Get the will-be-revoked local txn from node[0]
let revoked_local_txn = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone();

//Revoke the old state
claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_1);

{
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };

nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);

nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 4);

let mut revoked_tx_map = HashMap::new();
revoked_tx_map.insert(revoked_local_txn[0].txid(), revoked_local_txn[0].clone());

assert_eq!(node_txn[0].input.len(), 2);
node_txn[0].verify(&revoked_tx_map).unwrap();

assert_eq!(node_txn[3].input.len(), 2);
node_txn[3].verify(&revoked_tx_map).unwrap();

assert_eq!(node_txn[0], node_txn[3]); // justice tx is duplicated due to block re-scanning

let witness_script_1 = node_txn[0].clone().input[0].witness.pop().unwrap();
let witness_script_2 = node_txn[0].clone().input[1].witness.pop().unwrap();
if witness_script_1.len() > 133 {
assert_eq!(witness_script_1.len(), 138);
Copy link
Author

@ariard ariard Sep 20, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to get accepted HTLC script of 138 bytes instead of BOLT 3 139 bytes ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be 139 in prod but because the block height being used as locktime here is < 2^15 (but more than 2^7) its 138.

assert_eq!(witness_script_2.len(), 133);
} else {
assert_eq!(witness_script_1.len(), 133);
assert_eq!(witness_script_2.len(), 138);
}

assert_eq!(node_txn[1].input.len(), 1);
assert_eq!(node_txn[1].input[0].previous_output.txid, chan_1.3.txid()); //Spending funding tx unique txouput, tx broadcasted by ChannelManager

assert_eq!(node_txn[2].input.len(), 1);
let witness_script = node_txn[2].clone().input[0].witness.pop().unwrap();
assert_eq!(witness_script.len(), 133); //Spending an offered htlc output
assert_eq!(node_txn[2].input[0].previous_output.txid, node_txn[1].txid());
assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[0].previous_output.txid);
assert_ne!(node_txn[2].input[0].previous_output.txid, node_txn[0].input[1].previous_output.txid);

}
get_announce_close_broadcast_events(&nodes, 0, 1);
assert_eq!(nodes[0].node.list_channels().len(), 0);
assert_eq!(nodes[1].node.list_channels().len(), 0);
}

#[test]
fn claim_htlc_outputs_single_tx() {
// Node revoked old state, htlcs have timed out, claim each of them in separated justice tx

let nodes = create_network(2);

let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1);

// Rebalance the network to generate htlc in the two directions
send_payment(&nodes[0], &vec!(&nodes[1])[..], 8000000);
// 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, but this
// time as two different claim transactions as we're gonna to timeout htlc with given a high current height
let payment_preimage_1 = route_payment(&nodes[0], &vec!(&nodes[1])[..], 3000000).0;
let _payment_preimage_2 = route_payment(&nodes[1], &vec!(&nodes[0])[..], 3000000).0;

// Get the will-be-revoked local txn from node[0]
let revoked_local_txn = nodes[0].node.channel_state.lock().unwrap().by_id.get(&chan_1.2).unwrap().last_local_commitment_txn.clone();

//Revoke the old state
claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage_1);

{
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };

nodes[0].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 200);

nodes[1].chain_monitor.block_connected_with_filtering(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 200);
let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
assert_eq!(node_txn.len(), 10); // ChannelManager : 2, ChannelMontitor: 8 (2 revocation htlc tx, 1 local commitment tx + 1 htlc timeout tx) * 2 (block-rescan)

assert_eq!(node_txn[0], node_txn[6]);
assert_eq!(node_txn[1], node_txn[7]);
assert_eq!(node_txn[2], node_txn[8]);
assert_eq!(node_txn[3], node_txn[9]);
assert_eq!(node_txn[2], node_txn[4]); //local commitment tx + htlc timeout tx broadcated by ChannelManger
assert_eq!(node_txn[3], node_txn[5]);

assert_eq!(node_txn[0].input.len(), 1);
assert_eq!(node_txn[1].input.len(), 1);

let mut revoked_tx_map = HashMap::new();
revoked_tx_map.insert(revoked_local_txn[0].txid(), revoked_local_txn[0].clone());
node_txn[0].verify(&revoked_tx_map).unwrap();
node_txn[1].verify(&revoked_tx_map).unwrap();

let witness_script_1 = node_txn[0].clone().input[0].witness.pop().unwrap();
let witness_script_2 = node_txn[1].clone().input[0].witness.pop().unwrap();
if witness_script_1.len() > 133 {
assert_eq!(witness_script_1.len(), 138);
assert_eq!(witness_script_2.len(), 133);
} else {
assert_eq!(witness_script_1.len(), 133);
assert_eq!(witness_script_2.len(), 138);
}

let mut funding_tx_map = HashMap::new();
funding_tx_map.insert(chan_1.3.txid(), chan_1.3.clone());
node_txn[2].verify(&funding_tx_map).unwrap();
assert_eq!(node_txn[2].input.len(), 1);

assert_eq!(node_txn[3].input.len(), 1);
let witness_script = node_txn[3].clone().input[0].witness.pop().unwrap();
assert_eq!(witness_script.len(), 133); //Spending an offered htlc output
assert_eq!(node_txn[3].input[0].previous_output.txid, node_txn[2].txid());
assert_ne!(node_txn[3].input[0].previous_output.txid, node_txn[0].input[0].previous_output.txid);
assert_ne!(node_txn[3].input[0].previous_output.txid, node_txn[1].input[0].previous_output.txid);

}
get_announce_close_broadcast_events(&nodes, 0, 1);
assert_eq!(nodes[0].node.list_channels().len(), 0);
assert_eq!(nodes[1].node.list_channels().len(), 0);
}

#[test]
fn test_htlc_ignore_latest_remote_commitment() {
// Test that HTLC transactions spending the latest remote commitment transaction are simply
Expand Down
2 changes: 1 addition & 1 deletion src/ln/channelmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ impl ChannelMonitor {
};
let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
sign_input!(sighash_parts, single_htlc_tx.input[0], Some(idx), htlc.amount_msat / 1000);
txn_to_broadcast.push(single_htlc_tx); // TODO: This is not yet tested in ChannelManager!
txn_to_broadcast.push(single_htlc_tx);
}
}
}
Expand Down