Skip to content

Commit 73dce20

Browse files
committed
Track the full list of outpoints a chanmon wants monitoring for.
Upon deserialization/reload we need to be able to register each outpoint which spends the commitment txo which a channelmonitor believes to be on chain. While our other internal tracking is likely sufficient to regenerate these, its much easier to simply track all outpouts we've ever generated, so we do that here.
1 parent 473f611 commit 73dce20

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

lightning/src/ln/channelmonitor.rs

Lines changed: 57 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
@@ -2589,6 +2624,9 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
25892624
}
25902625
}
25912626
self.last_block_hash = block_hash.clone();
2627+
for &(ref txid, ref output_scripts) in watch_outputs.iter() {
2628+
self.outputs_to_watch.insert(txid.clone(), output_scripts.iter().map(|o| o.script_pubkey.clone()).collect());
2629+
}
25922630
(watch_outputs, spendable_outputs, htlc_updated)
25932631
}
25942632

@@ -3241,6 +3279,20 @@ impl<R: ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R,
32413279
onchain_events_waiting_threshold_conf.insert(height_target, events);
32423280
}
32433281

3282+
let outputs_to_watch_len: u64 = Readable::read(reader)?;
3283+
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>>())));
3284+
for _ in 0..outputs_to_watch_len {
3285+
let txid = Readable::read(reader)?;
3286+
let outputs_len: u64 = Readable::read(reader)?;
3287+
let mut outputs = Vec::with_capacity(cmp::min(outputs_len as usize, MAX_ALLOC_SIZE / mem::size_of::<Script>()));
3288+
for _ in 0..outputs_len {
3289+
outputs.push(Readable::read(reader)?);
3290+
}
3291+
if let Some(_) = outputs_to_watch.insert(txid, outputs) {
3292+
return Err(DecodeError::InvalidValue);
3293+
}
3294+
}
3295+
32443296
Ok((last_block_hash.clone(), ChannelMonitor {
32453297
commitment_transaction_number_obscure_factor,
32463298

@@ -3273,6 +3325,7 @@ impl<R: ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>> ReadableArgs<R,
32733325
claimable_outpoints,
32743326

32753327
onchain_events_waiting_threshold_conf,
3328+
outputs_to_watch,
32763329

32773330
last_block_hash,
32783331
secp_ctx,

0 commit comments

Comments
 (0)