Skip to content

Commit ed2a5fd

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 5fceb0f commit ed2a5fd

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

lightning/src/ln/channel.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3670,12 +3670,15 @@ 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+
continue; // Drop
3675+
}
36733676
htlc.htlc_id.write(writer)?;
36743677
htlc.amount_msat.write(writer)?;
36753678
htlc.cltv_expiry.write(writer)?;
36763679
htlc.payment_hash.write(writer)?;
36773680
match &htlc.state {
3678-
&InboundHTLCState::RemoteAnnounced(_) => {}, // Drop
3681+
&InboundHTLCState::RemoteAnnounced(_) => unreachable!(),
36793682
&InboundHTLCState::AwaitingRemoteRevokeToAnnounce(ref htlc_state) => {
36803683
1u8.write(writer)?;
36813684
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
@@ -4,7 +4,7 @@
44
use chain::chaininterface;
55
use chain::transaction::OutPoint;
66
use chain::keysinterface::KeysInterface;
7-
use ln::channelmanager::{ChannelManager,RAACommitmentOrder, PaymentPreimage, PaymentHash};
7+
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash};
88
use ln::channelmonitor::{ChannelMonitor, ManyChannelMonitor};
99
use ln::router::{Route, Router};
1010
use ln::features::InitFeatures;
@@ -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 get the
9696
// same set of outputs to watch for on chain as we have now. Note that if we write
9797
// tests that fully close channels and remove the monitors at some point this may break.
98-
let chain_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 channel_monitor = test_utils::TestChannelMonitor::new(chain_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 deserialized_monitors = Vec::new();
102101
for (_, old_monitor) in old_monitors.iter() {
103102
let mut w = test_utils::TestVecWriter(Vec::new());
104103
old_monitor.write_for_disk(&mut w).unwrap();
105104
let (_, deserialized_monitor) = <(Sha256d, ChannelMonitor<EnforcingChannelKeys>)>::read(
106105
&mut ::std::io::Cursor::new(&w.0), Arc::clone(&self.logger) as Arc<Logger>).unwrap();
106+
deserialized_monitors.push(deserialized_monitor);
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 deserialized_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 chain_watch = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&self.logger) as Arc<Logger>));
131+
let channel_monitor = test_utils::TestChannelMonitor::new(chain_watch.clone(), self.tx_broadcaster.clone(), self.logger.clone(), feeest);
132+
for deserialized_monitor in deserialized_monitors.drain(..) {
107133
if let Err(_) = channel_monitor.add_update_monitor(deserialized_monitor.get_funding_txo().unwrap(), deserialized_monitor) {
108134
panic!();
109135
}
110136
}
111-
112137
if *chain_watch != *self.chain_monitor {
113138
panic!();
114139
}

0 commit comments

Comments
 (0)