Skip to content

Commit 56513f2

Browse files
committed
Track last_block_hash in ChannelMonitor and expose it on deser
Also make block_connected take a &mut self to ensure serialized state will always be self-consistent.
1 parent 612e280 commit 56513f2

File tree

4 files changed

+45
-11
lines changed

4 files changed

+45
-11
lines changed

fuzz/fuzz_targets/chanmon_deser_target.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
// This file is auto-generated by gen_target.sh based on msg_target_template.txt
22
// To modify it, modify msg_target_template.txt and run gen_target.sh instead.
33

4+
extern crate bitcoin;
45
extern crate lightning;
56

7+
use bitcoin::util::hash::Sha256dHash;
8+
69
use lightning::ln::channelmonitor;
710
use lightning::util::reset_rng_state;
811
use lightning::util::ser::{ReadableArgs, Writer};
@@ -28,10 +31,12 @@ impl Writer for VecWriter {
2831
pub fn do_test(data: &[u8]) {
2932
reset_rng_state();
3033
let logger = Arc::new(test_logger::TestLogger{});
31-
if let Ok(monitor) = channelmonitor::ChannelMonitor::read(&mut Cursor::new(data), logger.clone()) {
34+
if let Ok((latest_block_hash, monitor)) = <(Sha256dHash, channelmonitor::ChannelMonitor)>::read(&mut Cursor::new(data), logger.clone()) {
3235
let mut w = VecWriter(Vec::new());
3336
monitor.write_for_disk(&mut w).unwrap();
34-
assert!(channelmonitor::ChannelMonitor::read(&mut Cursor::new(&w.0), logger.clone()).unwrap() == monitor);
37+
let deserialized_copy = <(Sha256dHash, channelmonitor::ChannelMonitor)>::read(&mut Cursor::new(&w.0), logger.clone()).unwrap();
38+
assert!(latest_block_hash == deserialized_copy.0);
39+
assert!(monitor == deserialized_copy.1);
3540
w.0.clear();
3641
monitor.write_for_watchtower(&mut w).unwrap();
3742
}

src/ln/channel.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2674,6 +2674,7 @@ impl Channel {
26742674
if self.funding_tx_confirmations > 0 {
26752675
if header.bitcoin_hash() != self.last_block_connected {
26762676
self.last_block_connected = header.bitcoin_hash();
2677+
self.channel_monitor.last_block_hash = self.last_block_connected;
26772678
self.funding_tx_confirmations += 1;
26782679
if self.funding_tx_confirmations == Channel::derive_minimum_depth(self.channel_value_satoshis*1000, self.value_to_self_msat) as u64 {
26792680
let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {

src/ln/channelmonitor.rs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use bitcoin::blockdata::transaction::{TxIn,TxOut,SigHashType,Transaction};
1616
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
1717
use bitcoin::blockdata::script::Script;
1818
use bitcoin::network::serialize;
19+
use bitcoin::network::serialize::BitcoinHash;
1920
use bitcoin::network::encodable::{ConsensusDecodable, ConsensusEncodable};
2021
use bitcoin::util::hash::Sha256dHash;
2122
use bitcoin::util::bip143;
@@ -114,12 +115,13 @@ pub struct SimpleManyChannelMonitor<Key> {
114115
}
115116

116117
impl<Key : Send + cmp::Eq + hash::Hash> ChainListener for SimpleManyChannelMonitor<Key> {
117-
fn block_connected(&self, _header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[u32]) {
118+
fn block_connected(&self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], _indexes_of_txn_matched: &[u32]) {
119+
let block_hash = header.bitcoin_hash();
118120
let mut new_events: Vec<events::Event> = Vec::with_capacity(0);
119121
{
120-
let monitors = self.monitors.lock().unwrap();
121-
for monitor in monitors.values() {
122-
let (txn_outputs, spendable_outputs) = monitor.block_connected(txn_matched, height, &*self.broadcaster);
122+
let mut monitors = self.monitors.lock().unwrap();
123+
for monitor in monitors.values_mut() {
124+
let (txn_outputs, spendable_outputs) = monitor.block_connected(txn_matched, height, &block_hash, &*self.broadcaster);
123125
if spendable_outputs.len() > 0 {
124126
new_events.push(events::Event::SpendableOutputs {
125127
outputs: spendable_outputs,
@@ -279,6 +281,12 @@ pub struct ChannelMonitor {
279281

280282
destination_script: Script,
281283

284+
// We simply modify last_block_hash in Channel's block_connected so that serialization is
285+
// consistent but hopefully the users' copy handles block_connected in a consistent way.
286+
// (we do *not*, however, update them in insert_combine to ensure any local user copies keep
287+
// their last_block_hash from its state and not based on updated copies that didn't run through
288+
// the full block_connected).
289+
pub(crate) last_block_hash: Sha256dHash,
282290
secp_ctx: Secp256k1<secp256k1::All>, //TODO: dedup this a bit...
283291
logger: Arc<Logger>,
284292
}
@@ -307,6 +315,7 @@ impl Clone for ChannelMonitor {
307315
payment_preimages: self.payment_preimages.clone(),
308316

309317
destination_script: self.destination_script.clone(),
318+
last_block_hash: self.last_block_hash.clone(),
310319
secp_ctx: self.secp_ctx.clone(),
311320
logger: self.logger.clone(),
312321
}
@@ -378,6 +387,7 @@ impl ChannelMonitor {
378387
payment_preimages: HashMap::new(),
379388
destination_script: destination_script,
380389

390+
last_block_hash: Default::default(),
381391
secp_ctx: Secp256k1::new(),
382392
logger,
383393
}
@@ -759,17 +769,30 @@ impl ChannelMonitor {
759769
writer.write_all(payment_preimage)?;
760770
}
761771

772+
self.last_block_hash.write(writer)?;
762773
self.destination_script.write(writer)?;
763774

764775
Ok(())
765776
}
766777

767778
/// Writes this monitor into the given writer, suitable for writing to disk.
779+
///
780+
/// Note that the deserializer is only implemented for (Sha256dHash, ChannelMonitor), which
781+
/// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along
782+
/// the "reorg path" (ie not just starting at the same height but starting at the highest
783+
/// common block that appears on your best chain as well as on the chain which contains the
784+
/// last block hash returned) upon deserializing the object!
768785
pub fn write_for_disk<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
769786
self.write(writer, true)
770787
}
771788

772789
/// Encodes this monitor into the given writer, suitable for sending to a remote watchtower
790+
///
791+
/// Note that the deserializer is only implemented for (Sha256dHash, ChannelMonitor), which
792+
/// tells you the last block hash which was block_connect()ed. You MUST rescan any blocks along
793+
/// the "reorg path" (ie not just starting at the same height but starting at the highest
794+
/// common block that appears on your best chain as well as on the chain which contains the
795+
/// last block hash returned) upon deserializing the object!
773796
pub fn write_for_watchtower<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
774797
self.write(writer, false)
775798
}
@@ -1283,7 +1306,7 @@ impl ChannelMonitor {
12831306
(Vec::new(), Vec::new())
12841307
}
12851308

1286-
fn block_connected(&self, txn_matched: &[&Transaction], height: u32, broadcaster: &BroadcasterInterface)-> (Vec<(Sha256dHash, Vec<TxOut>)>, Vec<SpendableOutputDescriptor>) {
1309+
fn block_connected(&mut self, txn_matched: &[&Transaction], height: u32, block_hash: &Sha256dHash, broadcaster: &BroadcasterInterface)-> (Vec<(Sha256dHash, Vec<TxOut>)>, Vec<SpendableOutputDescriptor>) {
12871310
let mut watch_outputs = Vec::new();
12881311
let mut spendable_outputs = Vec::new();
12891312
for tx in txn_matched {
@@ -1344,6 +1367,7 @@ impl ChannelMonitor {
13441367
}
13451368
}
13461369
}
1370+
self.last_block_hash = block_hash.clone();
13471371
(watch_outputs, spendable_outputs)
13481372
}
13491373

@@ -1382,7 +1406,7 @@ impl ChannelMonitor {
13821406

13831407
const MAX_ALLOC_SIZE: usize = 64*1024;
13841408

1385-
impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for ChannelMonitor {
1409+
impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for (Sha256dHash, ChannelMonitor) {
13861410
fn read(reader: &mut R, logger: Arc<Logger>) -> Result<Self, DecodeError> {
13871411
let secp_ctx = Secp256k1::new();
13881412
macro_rules! unwrap_obj {
@@ -1578,9 +1602,10 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for ChannelMonitor {
15781602
}
15791603
}
15801604

1605+
let last_block_hash: Sha256dHash = Readable::read(reader)?;
15811606
let destination_script = Readable::read(reader)?;
15821607

1583-
Ok(ChannelMonitor {
1608+
Ok((last_block_hash.clone(), ChannelMonitor {
15841609
funding_txo,
15851610
commitment_transaction_number_obscure_factor,
15861611

@@ -1603,9 +1628,10 @@ impl<R: ::std::io::Read> ReadableArgs<R, Arc<Logger>> for ChannelMonitor {
16031628
payment_preimages,
16041629

16051630
destination_script,
1631+
last_block_hash,
16061632
secp_ctx,
16071633
logger,
1608-
})
1634+
}))
16091635
}
16101636

16111637
}

src/util/test_utils.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use util::logger::{Logger, Level, Record};
99
use util::ser::{ReadableArgs, Writer};
1010

1111
use bitcoin::blockdata::transaction::Transaction;
12+
use bitcoin::util::hash::Sha256dHash;
1213

1314
use secp256k1::PublicKey;
1415

@@ -55,7 +56,8 @@ impl channelmonitor::ManyChannelMonitor for TestChannelMonitor {
5556
// to a watchtower and disk...
5657
let mut w = VecWriter(Vec::new());
5758
monitor.write_for_disk(&mut w).unwrap();
58-
assert!(channelmonitor::ChannelMonitor::read(&mut ::std::io::Cursor::new(&w.0), Arc::new(TestLogger::new())).unwrap() == monitor);
59+
assert!(<(Sha256dHash, channelmonitor::ChannelMonitor)>::read(
60+
&mut ::std::io::Cursor::new(&w.0), Arc::new(TestLogger::new())).unwrap().1 == monitor);
5961
w.0.clear();
6062
monitor.write_for_watchtower(&mut w).unwrap(); // This at least shouldn't crash...
6163
self.added_monitors.lock().unwrap().push((funding_txo, monitor.clone()));

0 commit comments

Comments
 (0)