Skip to content

Fix + test funding tx confirmation while peer is disconnected #210

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

Merged
Merged
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
7 changes: 4 additions & 3 deletions src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ enum ChannelState {
ShutdownComplete = 2048,
}
const BOTH_SIDES_SHUTDOWN_MASK: u32 = (ChannelState::LocalShutdownSent as u32 | ChannelState::RemoteShutdownSent as u32);
const MULTI_STATE_FLAGS: u32 = (BOTH_SIDES_SHUTDOWN_MASK | ChannelState::PeerDisconnected as u32);

const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;

Expand Down Expand Up @@ -2560,7 +2561,7 @@ impl Channel {
/// apply - no calls may be made except those explicitly stated to be allowed post-shutdown.
/// Only returns an ErrorAction of DisconnectPeer, if Err.
pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, HandleError> {
let non_shutdown_state = self.channel_state & (!BOTH_SIDES_SHUTDOWN_MASK);
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
if self.funding_tx_confirmations > 0 {
if header.bitcoin_hash() != self.last_block_connected {
self.last_block_connected = header.bitcoin_hash();
Expand All @@ -2570,10 +2571,10 @@ impl Channel {
self.channel_state |= ChannelState::OurFundingLocked as u32;
true
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & BOTH_SIDES_SHUTDOWN_MASK);
self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
self.channel_update_count += 1;
true
} else if self.channel_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
} else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
// We got a reorg but not enough to trigger a force close, just update
// funding_tx_confirmed_in and return.
false
Expand Down
59 changes: 55 additions & 4 deletions src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2574,7 +2574,7 @@ mod tests {
(announcement, as_update, bs_update, channel_id, tx)
}

fn create_chan_between_nodes_with_value_a(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32], Transaction) {
fn create_chan_between_nodes_with_value_init(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> Transaction {
node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42).unwrap();

let events_1 = node_a.node.get_and_clear_pending_events();
Expand Down Expand Up @@ -2647,7 +2647,11 @@ mod tests {
_ => panic!("Unexpected event"),
};

confirm_transaction(&node_b.chain_monitor, &tx, chan_id);
tx
}

fn create_chan_between_nodes_with_value_confirm(node_a: &Node, node_b: &Node, tx: &Transaction) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32]) {
confirm_transaction(&node_b.chain_monitor, &tx, tx.version);
let events_5 = node_b.node.get_and_clear_pending_events();
assert_eq!(events_5.len(), 1);
match events_5[0] {
Expand All @@ -2661,7 +2665,7 @@ mod tests {

let channel_id;

confirm_transaction(&node_a.chain_monitor, &tx, chan_id);
confirm_transaction(&node_a.chain_monitor, &tx, tx.version);
let events_6 = node_a.node.get_and_clear_pending_events();
assert_eq!(events_6.len(), 1);
(match events_6[0] {
Expand All @@ -2671,7 +2675,13 @@ mod tests {
(msg.clone(), announcement_sigs.clone().unwrap())
},
_ => panic!("Unexpected event"),
}, channel_id, tx)
}, channel_id)
}

fn create_chan_between_nodes_with_value_a(node_a: &Node, node_b: &Node, channel_value: u64, push_msat: u64) -> ((msgs::FundingLocked, msgs::AnnouncementSignatures), [u8; 32], Transaction) {
let tx = create_chan_between_nodes_with_value_init(node_a, node_b, channel_value, push_msat);
let (msgs, chan_id) = create_chan_between_nodes_with_value_confirm(node_a, node_b, &tx);
(msgs, chan_id, tx)
}

fn create_chan_between_nodes_with_value_b(node_a: &Node, node_b: &Node, as_funding_msgs: &(msgs::FundingLocked, msgs::AnnouncementSignatures)) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate) {
Expand Down Expand Up @@ -5038,6 +5048,47 @@ mod tests {
do_test_drop_messages_peer_disconnect(5);
}

#[test]
fn test_funding_peer_disconnect() {
// Test that we can lock in our funding tx while disconnected
let nodes = create_network(2);
let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001);

nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);

confirm_transaction(&nodes[0].chain_monitor, &tx, tx.version);
let events_1 = nodes[0].node.get_and_clear_pending_events();
assert_eq!(events_1.len(), 1);
match events_1[0] {
Event::SendFundingLocked { ref node_id, msg: _, ref announcement_sigs } => {
assert_eq!(*node_id, nodes[1].node.get_our_node_id());
assert!(announcement_sigs.is_none());
},
_ => panic!("Unexpected event"),
}

confirm_transaction(&nodes[1].chain_monitor, &tx, tx.version);
let events_2 = nodes[1].node.get_and_clear_pending_events();
assert_eq!(events_2.len(), 1);
match events_2[0] {
Event::SendFundingLocked { ref node_id, msg: _, ref announcement_sigs } => {
assert_eq!(*node_id, nodes[0].node.get_our_node_id());
assert!(announcement_sigs.is_none());
},
_ => panic!("Unexpected event"),
}

reconnect_nodes(&nodes[0], &nodes[1], true, (0, 0), (0, 0), (0, 0), (0, 0), (false, false));

// TODO: We shouldn't need to manually pass list_usable_chanels here once we support
// rebroadcasting announcement_signatures upon reconnect.

let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), Some(&nodes[0].node.list_usable_channels()), &Vec::new(), 1000000, TEST_FINAL_CLTV).unwrap();
let (payment_preimage, _) = send_along_route(&nodes[0], route, &[&nodes[1]], 1000000);
claim_payment(&nodes[0], &[&nodes[1]], payment_preimage);
}

#[test]
fn test_invalid_channel_announcement() {
//Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs
Expand Down