Skip to content

Commit 29d14dd

Browse files
authored
Merge pull request #455 from TheBlueMatt/2020-01-monitor-reload-watch
Track the full list of outpoints a chanmon wants monitoring for
2 parents 473f611 + 5fceb0f commit 29d14dd

File tree

3 files changed

+97
-4
lines changed

3 files changed

+97
-4
lines changed

lightning/src/chain/chaininterface.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ pub trait FeeEstimator: Sync + Send {
126126
pub const MIN_RELAY_FEE_SAT_PER_1000_WEIGHT: u64 = 4000;
127127

128128
/// Utility for tracking registered txn/outpoints and checking for matches
129+
#[cfg_attr(test, derive(PartialEq))]
129130
pub struct ChainWatchedUtil {
130131
watch_all: bool,
131132

@@ -305,6 +306,17 @@ pub struct ChainWatchInterfaceUtil {
305306
logger: Arc<Logger>,
306307
}
307308

309+
// We only expose PartialEq in test since its somewhat unclear exactly what it should do and we're
310+
// only comparing a subset of fields (essentially just checking that the set of things we're
311+
// watching is the same).
312+
#[cfg(test)]
313+
impl PartialEq for ChainWatchInterfaceUtil {
314+
fn eq(&self, o: &Self) -> bool {
315+
self.network == o.network &&
316+
*self.watched.lock().unwrap() == *o.watched.lock().unwrap()
317+
}
318+
}
319+
308320
/// Register listener
309321
impl ChainWatchInterface for ChainWatchInterfaceUtil {
310322
fn install_watch_tx(&self, txid: &Sha256dHash, script_pub_key: &Script) {

lightning/src/ln/channelmonitor.rs

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,16 @@ pub struct HTLCUpdate {
117117
pub trait ManyChannelMonitor<ChanSigner: ChannelKeys>: Send + Sync {
118118
/// Adds or updates a monitor for the given `funding_txo`.
119119
///
120-
/// Implementor must also ensure that the funding_txo outpoint is registered with any relevant
121-
/// ChainWatchInterfaces such that the provided monitor receives block_connected callbacks with
122-
/// any spends of it.
120+
/// Implementer must also ensure that the funding_txo txid *and* outpoint are registered with
121+
/// any relevant ChainWatchInterfaces such that the provided monitor receives block_connected
122+
/// callbacks with the funding transaction, or any spends of it.
123+
///
124+
/// Further, the implementer must also ensure that each output returned in
125+
/// monitor.get_outputs_to_watch() is registered to ensure that the provided monitor learns about
126+
/// any spends of any of the outputs.
127+
///
128+
/// Any spends of outputs which should have been registered which aren't passed to
129+
/// ChannelMonitors via block_connected may result in funds loss.
123130
fn add_update_monitor(&self, funding_txo: OutPoint, monitor: ChannelMonitor<ChanSigner>) -> Result<(), ChannelMonitorUpdateErr>;
124131

125132
/// Used by ChannelManager to get list of HTLC resolved onchain and which needed to be updated
@@ -259,6 +266,11 @@ impl<Key : Send + cmp::Eq + hash::Hash + 'static, ChanSigner: ChannelKeys> Simpl
259266
self.chain_monitor.watch_all_txn();
260267
}
261268
}
269+
for (txid, outputs) in monitor.get_outputs_to_watch().iter() {
270+
for (idx, script) in outputs.iter().enumerate() {
271+
self.chain_monitor.install_watch_outpoint((*txid, idx as u32), script);
272+
}
273+
}
262274
monitors.insert(key, monitor);
263275
Ok(())
264276
}
@@ -666,6 +678,12 @@ pub struct ChannelMonitor<ChanSigner: ChannelKeys> {
666678
// actions when we receive a block with given height. Actions depend on OnchainEvent type.
667679
onchain_events_waiting_threshold_conf: HashMap<u32, Vec<OnchainEvent>>,
668680

681+
// If we get serialized out and re-read, we need to make sure that the chain monitoring
682+
// interface knows about the TXOs that we want to be notified of spends of. We could probably
683+
// be smart and derive them from the above storage fields, but its much simpler and more
684+
// Obviously Correct (tm) if we just keep track of them explicitly.
685+
outputs_to_watch: HashMap<Sha256dHash, Vec<Script>>,
686+
669687
// We simply modify last_block_hash in Channel's block_connected so that serialization is
670688
// consistent but hopefully the users' copy handles block_connected in a consistent way.
671689
// (we do *not*, however, update them in insert_combine to ensure any local user copies keep
@@ -736,7 +754,8 @@ impl<ChanSigner: ChannelKeys> PartialEq for ChannelMonitor<ChanSigner> {
736754
self.to_remote_rescue != other.to_remote_rescue ||
737755
self.pending_claim_requests != other.pending_claim_requests ||
738756
self.claimable_outpoints != other.claimable_outpoints ||
739-
self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf
757+
self.onchain_events_waiting_threshold_conf != other.onchain_events_waiting_threshold_conf ||
758+
self.outputs_to_watch != other.outputs_to_watch
740759
{
741760
false
742761
} else {
@@ -966,6 +985,15 @@ impl<ChanSigner: ChannelKeys + Writeable> ChannelMonitor<ChanSigner> {
966985
}
967986
}
968987

988+
(self.outputs_to_watch.len() as u64).write(writer)?;
989+
for (txid, output_scripts) in self.outputs_to_watch.iter() {
990+
txid.write(writer)?;
991+
(output_scripts.len() as u64).write(writer)?;
992+
for script in output_scripts.iter() {
993+
script.write(writer)?;
994+
}
995+
}
996+
969997
Ok(())
970998
}
971999

@@ -1036,6 +1064,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
10361064
claimable_outpoints: HashMap::new(),
10371065

10381066
onchain_events_waiting_threshold_conf: HashMap::new(),
1067+
outputs_to_watch: HashMap::new(),
10391068

10401069
last_block_hash: Default::default(),
10411070
secp_ctx: Secp256k1::new(),
@@ -1370,6 +1399,12 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
13701399
}
13711400
}
13721401

1402+
/// Gets a list of txids, with their output scripts (in the order they appear in the
1403+
/// transaction), which we must learn about spends of via block_connected().
1404+
pub fn get_outputs_to_watch(&self) -> &HashMap<Sha256dHash, Vec<Script>> {
1405+
&self.outputs_to_watch
1406+
}
1407+
13731408
/// Gets the sets of all outpoints which this ChannelMonitor expects to hear about spends of.
13741409
/// Generally useful when deserializing as during normal operation the return values of
13751410
/// block_connected are sufficient to ensure all relevant outpoints are being monitored (note
@@ -2362,6 +2397,11 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
23622397
}
23632398
}
23642399

2400+
/// Called by SimpleManyChannelMonitor::block_connected, which implements
2401+
/// ChainListener::block_connected.
2402+
/// Eventually this should be pub and, roughly, implement ChainListener, however this requires
2403+
/// &mut self, as well as returns new spendable outputs and outpoints to watch for spending of
2404+
/// on-chain.
23652405
fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &Sha256dHash, broadcaster: &BroadcasterInterface, fee_estimator: &FeeEstimator)-> (Vec<(Sha256dHash, Vec<TxOut>)>, Vec<SpendableOutputDescriptor>, Vec<(HTLCSource, Option<PaymentPreimage>, PaymentHash)>) {
23662406
for tx in txn_matched {
23672407
let mut output_val = 0;
@@ -2589,6 +2629,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
25892629
}
25902630
}
25912631
self.last_block_hash = block_hash.clone();
2632+
for &(ref txid, ref output_scripts) in watch_outputs.iter() {
2633+
self.outputs_to_watch.insert(txid.clone(), output_scripts.iter().map(|o| o.script_pubkey.clone()).collect());
2634+
}
25922635
(watch_outputs, spendable_outputs, htlc_updated)
25932636
}
25942637

@@ -3241,6 +3284,20 @@ impl<R: ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R,
32413284
onchain_events_waiting_threshold_conf.insert(height_target, events);
32423285
}
32433286

3287+
let outputs_to_watch_len: u64 = Readable::read(reader)?;
3288+
let mut outputs_to_watch = HashMap::with_capacity(cmp::min(outputs_to_watch_len as usize, MAX_ALLOC_SIZE / (mem::size_of::<Sha256dHash>() + mem::size_of::<Vec<Script>>())));
3289+
for _ in 0..outputs_to_watch_len {
3290+
let txid = Readable::read(reader)?;
3291+
let outputs_len: u64 = Readable::read(reader)?;
3292+
let mut outputs = Vec::with_capacity(cmp::min(outputs_len as usize, MAX_ALLOC_SIZE / mem::size_of::<Script>()));
3293+
for _ in 0..outputs_len {
3294+
outputs.push(Readable::read(reader)?);
3295+
}
3296+
if let Some(_) = outputs_to_watch.insert(txid, outputs) {
3297+
return Err(DecodeError::InvalidValue);
3298+
}
3299+
}
3300+
32443301
Ok((last_block_hash.clone(), ChannelMonitor {
32453302
commitment_transaction_number_obscure_factor,
32463303

@@ -3273,6 +3330,7 @@ impl<R: ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R,
32733330
claimable_outpoints,
32743331

32753332
onchain_events_waiting_threshold_conf,
3333+
outputs_to_watch,
32763334

32773335
last_block_hash,
32783336
secp_ctx,

lightning/src/ln/functional_test_utils.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use chain::chaininterface;
55
use chain::transaction::OutPoint;
66
use chain::keysinterface::KeysInterface;
77
use ln::channelmanager::{ChannelManager,RAACommitmentOrder, PaymentPreimage, PaymentHash};
8+
use ln::channelmonitor::{ChannelMonitor, ManyChannelMonitor};
89
use ln::router::{Route, Router};
910
use ln::features::InitFeatures;
1011
use ln::msgs;
@@ -16,6 +17,7 @@ use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsPro
1617
use util::errors::APIError;
1718
use util::logger::Logger;
1819
use util::config::UserConfig;
20+
use util::ser::ReadableArgs;
1921

2022
use bitcoin::util::hash::BitcoinHash;
2123
use bitcoin::blockdata::block::BlockHeader;
@@ -89,6 +91,27 @@ impl<'a, 'b> Drop for Node<'a, 'b> {
8991
assert!(self.node.get_and_clear_pending_msg_events().is_empty());
9092
assert!(self.node.get_and_clear_pending_events().is_empty());
9193
assert!(self.chan_monitor.added_monitors.lock().unwrap().is_empty());
94+
95+
// Check that if we serialize and then deserialize all our channel monitors we get the
96+
// same set of outputs to watch for on chain as we have now. Note that if we write
97+
// 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>));
99+
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);
101+
let old_monitors = self.chan_monitor.simple_monitor.monitors.lock().unwrap();
102+
for (_, old_monitor) in old_monitors.iter() {
103+
let mut w = test_utils::TestVecWriter(Vec::new());
104+
old_monitor.write_for_disk(&mut w).unwrap();
105+
let (_, deserialized_monitor) = <(Sha256d, ChannelMonitor<EnforcingChannelKeys>)>::read(
106+
&mut ::std::io::Cursor::new(&w.0), Arc::clone(&self.logger) as Arc<Logger>).unwrap();
107+
if let Err(_) = channel_monitor.add_update_monitor(deserialized_monitor.get_funding_txo().unwrap(), deserialized_monitor) {
108+
panic!();
109+
}
110+
}
111+
112+
if *chain_watch != *self.chain_monitor {
113+
panic!();
114+
}
92115
}
93116
}
94117
}

0 commit comments

Comments
 (0)