Skip to content

Commit 899fc9e

Browse files
committed
Fix serialization rt bug in Channel and test in functional_tests
Previously, when attempting to write out a channel with some RemoteAnnounced pending inbound HTLCs, we'd write out the count without them, but write out some of their fields. We should drop them as intended as they will need to be reannounced upon reconnection. This was found while attempting to simply reproduce a different bug by adding tests for ChannelManager serialization rount-trip at the end of each functional_test (in Node::drop). That test is included here to prevent some classes of similar bugs in the future.
1 parent af4c5a2 commit 899fc9e

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

lightning/src/ln/channel.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3670,12 +3670,17 @@ impl<ChanSigner: ChannelKeys + Writeable> Writeable for Channel<ChanSigner> {
36703670
}
36713671
(self.pending_inbound_htlcs.len() as u64 - dropped_inbound_htlcs).write(writer)?;
36723672
for htlc in self.pending_inbound_htlcs.iter() {
3673+
if let &InboundHTLCState::RemoteAnnounced(_) = &htlc.state {
3674+
// remove_uncommitted_htlcs_and_mark_paused drops these (as the remote never
3675+
// committed to them and will have to rebroadcast them on reconnect), so skip them.
3676+
continue;
3677+
}
36733678
htlc.htlc_id.write(writer)?;
36743679
htlc.amount_msat.write(writer)?;
36753680
htlc.cltv_expiry.write(writer)?;
36763681
htlc.payment_hash.write(writer)?;
36773682
match &htlc.state {
3678-
&InboundHTLCState::RemoteAnnounced(_) => {}, // Drop
3683+
&InboundHTLCState::RemoteAnnounced(_) => unreachable!(),
36793684
&InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_state) => {
36803685
1u8.write(writer)?;
36813686
htlc_state.write(writer)?;

lightning/src/ln/functional_test_utils.rs

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use chain::chaininterface;
55
use chain::transaction::OutPoint;
66
use chain::keysinterface::KeysInterface;
77
use ln::channelmonitor::{ChannelMonitor, ManyChannelMonitor};
8-
use ln::channelmanager::{ChannelManager,RAACommitmentOrder, PaymentPreimage, PaymentHash};
8+
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash};
99
use ln::router::{Route, Router};
1010
use ln::features::InitFeatures;
1111
use ln::msgs;
@@ -17,7 +17,7 @@ use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsPro
1717
use util::errors::APIError;
1818
use util::logger::Logger;
1919
use util::config::UserConfig;
20-
use util::ser::ReadableArgs;
20+
use util::ser::{ReadableArgs, Writeable};
2121

2222
use bitcoin::util::hash::BitcoinHash;
2323
use bitcoin::blockdata::block::BlockHeader;
@@ -37,7 +37,7 @@ use std::cell::RefCell;
3737
use std::rc::Rc;
3838
use std::sync::{Arc, Mutex};
3939
use std::mem;
40-
use std::collections::HashSet;
40+
use std::collections::{HashSet, HashMap};
4141

4242
pub const CHAN_CONFIRM_DEPTH: u32 = 100;
4343
pub fn confirm_transaction<'a, 'b: 'a>(notifier: &'a chaininterface::BlockNotifierRef<'b>, chain: &chaininterface::ChainWatchInterfaceUtil, tx: &Transaction, chan_id: u32) {
@@ -95,20 +95,45 @@ impl<'a, 'b> Drop for Node<'a, 'b> {
9595
// Check that if we serialize and then deserialize all our channel monitors we the same
9696
// set of outputs to watch for on chain as we have now. Note that if we write tests
9797
// that fully close channels and remove the monitors at some point this may break.
98-
let new_watch = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&self.logger) as Arc<Logger>));
9998
let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
100-
let new_monitor = test_utils::TestChannelMonitor::new(new_watch.clone(), self.tx_broadcaster.clone(), self.logger.clone(), feeest);
10199
let old_monitors = self.chan_monitor.simple_monitor.monitors.lock().unwrap();
100+
let mut new_monitors = Vec::new();
102101
for (_, monitor) in old_monitors.iter() {
103102
let mut w = test_utils::TestVecWriter(Vec::new());
104103
monitor.write_for_disk(&mut w).unwrap();
105104
let (_, new_mon) = <(Sha256d, ChannelMonitor<EnforcingChannelKeys>)>::read(
106105
&mut ::std::io::Cursor::new(&w.0), Arc::clone(&self.logger) as Arc<Logger>).unwrap();
106+
new_monitors.push(new_mon);
107+
}
108+
109+
// Before using all the new monitors to check the watch outpoints, use the full set of
110+
// them to ensure we can write and reload our ChannelManager.
111+
{
112+
let mut channel_monitors = HashMap::new();
113+
for monitor in new_monitors.iter_mut() {
114+
channel_monitors.insert(monitor.get_funding_txo().unwrap(), monitor);
115+
}
116+
117+
let mut w = test_utils::TestVecWriter(Vec::new());
118+
self.node.write(&mut w).unwrap();
119+
<(Sha256d, ChannelManager<EnforcingChannelKeys, &test_utils::TestChannelMonitor>)>::read(&mut ::std::io::Cursor::new(w.0), ChannelManagerReadArgs {
120+
default_config: UserConfig::default(),
121+
keys_manager: self.keys_manager.clone(),
122+
fee_estimator: Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 }),
123+
monitor: self.chan_monitor,
124+
tx_broadcaster: self.tx_broadcaster.clone(),
125+
logger: Arc::new(test_utils::TestLogger::new()),
126+
channel_monitors: &mut channel_monitors,
127+
}).unwrap();
128+
}
129+
130+
let new_watch = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&self.logger) as Arc<Logger>));
131+
let new_monitor = test_utils::TestChannelMonitor::new(new_watch.clone(), self.tx_broadcaster.clone(), self.logger.clone(), feeest);
132+
for new_mon in new_monitors.drain(..) {
107133
if let Err(_) = new_monitor.add_update_monitor(new_mon.get_funding_txo().unwrap(), new_mon) {
108134
panic!();
109135
}
110136
}
111-
112137
if *new_watch != *self.chain_monitor {
113138
panic!();
114139
}

0 commit comments

Comments
 (0)