Skip to content

Commit 0ab393f

Browse files
committed
f - Update ChainListener::block_connected
Support partial blocks by taking a &BlockHeader and &Transaction slice of the form &[(usize, &Transaction)] where each transaction is paired with its position within the block.
1 parent 7ee34ba commit 0ab393f

9 files changed

+57
-64
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! channel being force-closed.
1111
1212
use bitcoin::BitcoinHash;
13-
use bitcoin::blockdata::block::{Block, BlockHeader};
13+
use bitcoin::blockdata::block::BlockHeader;
1414
use bitcoin::blockdata::transaction::{Transaction, TxOut};
1515
use bitcoin::blockdata::script::{Builder, Script};
1616
use bitcoin::blockdata::opcodes;
@@ -306,17 +306,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
306306

307307
macro_rules! confirm_txn {
308308
($node: expr) => { {
309-
let mut block = Block {
310-
header: BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
311-
txdata: channel_txn.clone(),
312-
};
313-
$node.block_connected(&block, 1);
309+
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
310+
let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect();
311+
$node.block_connected(&header, &txdata, 1);
314312
for i in 2..100 {
315-
block = Block {
316-
header: BlockHeader { version: 0x20000000, prev_blockhash: block.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
317-
txdata: vec![],
318-
};
319-
$node.block_connected(&block, i);
313+
header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
314+
$node.block_connected(&header, &[], i);
320315
}
321316
} }
322317
}

fuzz/src/full_stack.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! or payments to send/ways to handle events generated.
55
//! This test has been very useful, though due to its complexity good starting inputs are critical.
66
7-
use bitcoin::blockdata::block::{Block, BlockHeader};
7+
use bitcoin::blockdata::block::BlockHeader;
88
use bitcoin::blockdata::transaction::{Transaction, TxOut};
99
use bitcoin::blockdata::script::{Builder, Script};
1010
use bitcoin::blockdata::opcodes;
@@ -175,29 +175,28 @@ impl<'a> MoneyLossDetector<'a> {
175175
}
176176

177177
fn connect_block(&mut self, all_txn: &[Transaction]) {
178-
for tx in all_txn.iter() {
178+
let mut txdata = Vec::with_capacity(all_txn.len());
179+
for (idx, tx) in all_txn.iter().enumerate() {
179180
let txid = tx.txid();
180181
match self.txids_confirmed.entry(txid) {
181182
hash_map::Entry::Vacant(e) => {
182183
e.insert(self.height);
184+
txdata.push((idx + 1, tx));
183185
},
184186
_ => {},
185187
}
186188
}
187189

188-
let block = Block {
189-
header: BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height], merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 },
190-
txdata: all_txn.to_vec(),
191-
};
190+
let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height], merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 };
192191
self.height += 1;
193192
self.blocks_connected += 1;
194-
self.manager.block_connected(&block, self.height as u32);
195-
(*self.monitor).block_connected(&block, self.height as u32);
193+
self.manager.block_connected(&header, &txdata, self.height as u32);
194+
(*self.monitor).block_connected(&header, &txdata, self.height as u32);
196195
if self.header_hashes.len() > self.height {
197-
self.header_hashes[self.height] = block.bitcoin_hash();
196+
self.header_hashes[self.height] = header.bitcoin_hash();
198197
} else {
199198
assert_eq!(self.header_hashes.len(), self.height);
200-
self.header_hashes.push(block.bitcoin_hash());
199+
self.header_hashes.push(header.bitcoin_hash());
201200
}
202201
self.max_height = cmp::max(self.height, self.max_height);
203202
}

fuzz/src/router.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use bitcoin::blockdata::script::{Script, Builder};
2-
use bitcoin::blockdata::block::Block;
2+
use bitcoin::blockdata::block::BlockHeader;
3+
use bitcoin::blockdata::transaction::Transaction;
34
use bitcoin::hash_types::{Txid, BlockHash};
45

56
use lightning::chain::chaininterface::{ChainError,ChainWatchInterface};
@@ -75,7 +76,7 @@ impl ChainWatchInterface for DummyChainWatcher {
7576
fn install_watch_tx(&self, _txid: &Txid, _script_pub_key: &Script) { }
7677
fn install_watch_outpoint(&self, _outpoint: (Txid, u32), _out_script: &Script) { }
7778
fn watch_all_txn(&self) { }
78-
fn filter_block(&self, _block: &Block) -> Vec<usize> {
79+
fn filter_block(&self, _header: &BlockHeader, _txdata: &[(usize, &Transaction)]) -> Vec<usize> {
7980
Vec::new()
8081
}
8182
fn reentered(&self) -> usize { 0 }

lightning/src/chain/chaininterface.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ pub trait ChainWatchInterface: Sync + Send {
5555

5656
/// Gets the list of transaction indices within a given block that the ChainWatchInterface is
5757
/// watching for.
58-
fn filter_block(&self, block: &Block) -> Vec<usize>;
58+
fn filter_block(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize>;
5959

6060
/// Returns a usize that changes when the ChainWatchInterface's watched data is modified.
6161
/// Users of `filter_block` should pre-save a copy of `reentered`'s return value and use it to
@@ -71,8 +71,10 @@ pub trait BroadcasterInterface: Sync + Send {
7171

7272
/// A trait indicating a desire to listen for events from the chain
7373
pub trait ChainListener: Sync + Send {
74-
/// Notifies a listener that a block was connected.
75-
fn block_connected(&self, block: &Block, height: u32);
74+
/// Notifies a listener that a block was connected. Transactions may be filtered and are given
75+
/// paired with their position within the block.
76+
fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32);
77+
7678
/// Notifies a listener that a block was disconnected.
7779
/// Unlike block_connected, this *must* never be called twice for the same disconnect event.
7880
/// Height must be the one of the block which was disconnected (not new height of the best chain)
@@ -254,10 +256,11 @@ impl<'a, CL: Deref<Target = ChainListener + 'a> + 'a> BlockNotifier<'a, CL> {
254256
}
255257

256258
/// Notify listeners that a block was connected.
257-
pub fn block_connected<'b>(&self, block: &'b Block, height: u32) {
259+
pub fn block_connected(&self, block: &Block, height: u32) {
260+
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
258261
let listeners = self.listeners.lock().unwrap();
259262
for listener in listeners.iter() {
260-
listener.block_connected(block, height);
263+
listener.block_connected(&block.header, &txdata, height);
261264
}
262265
}
263266

@@ -320,11 +323,11 @@ impl ChainWatchInterface for ChainWatchInterfaceUtil {
320323
Err(ChainError::NotSupported)
321324
}
322325

323-
fn filter_block(&self, block: &Block) -> Vec<usize> {
326+
fn filter_block(&self, _header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize> {
324327
let mut matched_index = Vec::new();
325328
{
326329
let watched = self.watched.lock().unwrap();
327-
for (index, transaction) in block.txdata.iter().enumerate() {
330+
for &(index, transaction) in txdata.iter() {
328331
if self.does_match_tx_unguarded(transaction, &watched) {
329332
matched_index.push(index);
330333
}

lightning/src/ln/channel.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bitcoin::blockdata::block::{Block, BlockHeader};
1+
use bitcoin::blockdata::block::BlockHeader;
22
use bitcoin::blockdata::script::{Script,Builder};
33
use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
44
use bitcoin::blockdata::opcodes;
@@ -3299,7 +3299,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
32993299
///
33003300
/// May return some HTLCs (and their payment_hash) which have timed out and should be failed
33013301
/// back.
3302-
pub fn block_connected(&mut self, block: &Block, height: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
3302+
pub fn block_connected(&mut self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
33033303
let mut timed_out_htlcs = Vec::new();
33043304
self.holding_cell_htlc_updates.retain(|htlc_update| {
33053305
match htlc_update {
@@ -3313,13 +3313,13 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
33133313
}
33143314
});
33153315
let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
3316-
if block.bitcoin_hash() != self.last_block_connected {
3316+
if header.bitcoin_hash() != self.last_block_connected {
33173317
if self.funding_tx_confirmations > 0 {
33183318
self.funding_tx_confirmations += 1;
33193319
}
33203320
}
33213321
if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
3322-
for (index_in_block, ref tx) in block.txdata.iter().enumerate() {
3322+
for &(index_in_block, tx) in txdata.iter() {
33233323
if tx.txid() == self.funding_txo.unwrap().txid {
33243324
let txo_idx = self.funding_txo.unwrap().index as usize;
33253325
if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() ||
@@ -3362,9 +3362,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
33623362
}
33633363
}
33643364
}
3365-
if block.bitcoin_hash() != self.last_block_connected {
3366-
self.last_block_connected = block.bitcoin_hash();
3367-
self.update_time_counter = cmp::max(self.update_time_counter, block.header.time);
3365+
if header.bitcoin_hash() != self.last_block_connected {
3366+
self.last_block_connected = header.bitcoin_hash();
3367+
self.update_time_counter = cmp::max(self.update_time_counter, header.time);
33683368
if let Some(channel_monitor) = self.channel_monitor.as_mut() {
33693369
channel_monitor.last_block_hash = self.last_block_connected;
33703370
}
@@ -3388,7 +3388,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
33883388
// funding_tx_confirmed_in and return.
33893389
false
33903390
};
3391-
self.funding_tx_confirmed_in = Some(block.bitcoin_hash());
3391+
self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
33923392

33933393
//TODO: Note that this must be a duplicate of the previous commitment point they sent us,
33943394
//as otherwise we will have a commitment transaction that they can't revoke (well, kinda,

lightning/src/ln/channelmanager.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
//! on-chain transactions (it only monitors the chain to watch for any force-closes that might
99
//! imply it needs to fail HTLCs/payments/channels it manages).
1010
11-
use bitcoin::blockdata::block::{Block, BlockHeader};
11+
use bitcoin::blockdata::block::BlockHeader;
1212
use bitcoin::blockdata::constants::genesis_block;
13+
use bitcoin::blockdata::transaction::Transaction;
1314
use bitcoin::network::constants::Network;
1415
use bitcoin::util::hash::BitcoinHash;
1516

@@ -2962,8 +2963,8 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
29622963
F::Target: FeeEstimator,
29632964
L::Target: Logger,
29642965
{
2965-
fn block_connected(&self, block: &Block, height: u32) {
2966-
let header_hash = block.bitcoin_hash();
2966+
fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) {
2967+
let header_hash = header.bitcoin_hash();
29672968
log_trace!(self.logger, "Block {} at height {} connected", header_hash, height);
29682969
let _ = self.total_consistency_lock.read().unwrap();
29692970
let mut failed_channels = Vec::new();
@@ -2974,7 +2975,7 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
29742975
let short_to_id = &mut channel_state.short_to_id;
29752976
let pending_msg_events = &mut channel_state.pending_msg_events;
29762977
channel_state.by_id.retain(|_, channel| {
2977-
let res = channel.block_connected(block, height);
2978+
let res = channel.block_connected(header, txdata, height);
29782979
if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
29792980
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
29802981
let chan_update = self.get_channel_update(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
@@ -3007,7 +3008,7 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
30073008
return false;
30083009
}
30093010
if let Some(funding_txo) = channel.get_funding_txo() {
3010-
for tx in block.txdata.iter() {
3011+
for &(_, tx) in txdata.iter() {
30113012
for inp in tx.input.iter() {
30123013
if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
30133014
log_trace!(self.logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(channel.channel_id()));
@@ -3081,8 +3082,8 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
30813082
// Just in case we end up in a race, we loop until we either successfully update
30823083
// last_node_announcement_serial or decide we don't need to.
30833084
let old_serial = self.last_node_announcement_serial.load(Ordering::Acquire);
3084-
if old_serial >= block.header.time as usize { break; }
3085-
if self.last_node_announcement_serial.compare_exchange(old_serial, block.header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
3085+
if old_serial >= header.time as usize { break; }
3086+
if self.last_node_announcement_serial.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
30863087
break;
30873088
}
30883089
}

lightning/src/ln/channelmonitor.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! security-domain-separated system design, you should consider having multiple paths for
1212
//! ChannelMonitors to get out of the HSM and onto monitoring devices.
1313
14-
use bitcoin::blockdata::block::{Block, BlockHeader};
14+
use bitcoin::blockdata::block::BlockHeader;
1515
use bitcoin::blockdata::transaction::{TxOut,Transaction};
1616
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
1717
use bitcoin::blockdata::script::{Script, Builder};
@@ -39,7 +39,7 @@ use util::logger::Logger;
3939
use util::ser::{Readable, MaybeReadable, Writer, Writeable, U48};
4040
use util::{byte_utils, events};
4141

42-
use std::collections::{HashMap, hash_map};
42+
use std::collections::{HashMap, HashSet, hash_map};
4343
use std::sync::Mutex;
4444
use std::{hash,cmp, mem};
4545
use std::ops::Deref;
@@ -183,13 +183,13 @@ impl<Key : Send + cmp::Eq + hash::Hash, ChanSigner: ChannelKeys, T: Deref + Sync
183183
L::Target: Logger,
184184
C::Target: ChainWatchInterface,
185185
{
186-
fn block_connected(&self, block: &Block, height: u32) {
186+
fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) {
187187
let mut reentered = true;
188188
while reentered {
189-
let matched_indexes = self.chain_monitor.filter_block(block);
190-
let matched_txn: Vec<&Transaction> = matched_indexes.iter().map(|index| &block.txdata[*index]).collect();
189+
let matched_indexes: HashSet<_> = self.chain_monitor.filter_block(header, txdata).into_iter().collect();
190+
let matched_txn: Vec<_> = txdata.iter().filter(|&&(index, _)| matched_indexes.contains(&index)).map(|&(_, tx)| tx).collect();
191191
let last_seen = self.chain_monitor.reentered();
192-
let block_hash = block.bitcoin_hash();
192+
let block_hash = header.bitcoin_hash();
193193
{
194194
let mut monitors = self.monitors.lock().unwrap();
195195
for monitor in monitors.values_mut() {

lightning/src/ln/functional_tests.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7067,15 +7067,12 @@ fn test_no_failure_dust_htlc_local_commitment() {
70677067
output: vec![outp]
70687068
};
70697069

7070-
let block = Block {
7071-
header: BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
7072-
txdata: vec![dummy_tx],
7073-
};
7074-
nodes[0].chan_monitor.simple_monitor.block_connected(&block, 1);
7070+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
7071+
nodes[0].chan_monitor.simple_monitor.block_connected(&header, &[(0, &dummy_tx)], 1);
70757072
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
70767073
assert_eq!(nodes[0].node.get_and_clear_pending_msg_events().len(), 0);
70777074
// We broadcast a few more block to check everything is all right
7078-
connect_blocks(&nodes[0].block_notifier, 20, 1, true, block.bitcoin_hash());
7075+
connect_blocks(&nodes[0].block_notifier, 20, 1, true, header.bitcoin_hash());
70797076
assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
70807077
assert_eq!(nodes[0].node.get_and_clear_pending_msg_events().len(), 0);
70817078

@@ -8199,11 +8196,8 @@ fn test_update_err_monitor_lockdown() {
81998196
assert!(watchtower.add_monitor(outpoint, new_monitor).is_ok());
82008197
watchtower
82018198
};
8202-
let block = Block {
8203-
header: BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
8204-
txdata: vec![],
8205-
};
8206-
watchtower.simple_monitor.block_connected(&block, 200);
8199+
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
8200+
watchtower.simple_monitor.block_connected(&header, &[], 200);
82078201

82088202
// Try to update ChannelMonitor
82098203
assert!(nodes[1].node.claim_funds(preimage, &None, 9_000_000));

lightning/src/util/test_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bitcoin::BitcoinHash;
1515
use bitcoin::blockdata::constants::genesis_block;
1616
use bitcoin::blockdata::transaction::Transaction;
1717
use bitcoin::blockdata::script::{Builder, Script};
18-
use bitcoin::blockdata::block::Block;
18+
use bitcoin::blockdata::block::BlockHeader;
1919
use bitcoin::blockdata::opcodes;
2020
use bitcoin::network::constants::Network;
2121
use bitcoin::hash_types::{Txid, BlockHash};
@@ -371,7 +371,7 @@ impl ChainWatchInterface for TestChainWatcher {
371371
fn install_watch_tx(&self, _txid: &Txid, _script_pub_key: &Script) { }
372372
fn install_watch_outpoint(&self, _outpoint: (Txid, u32), _out_script: &Script) { }
373373
fn watch_all_txn(&self) { }
374-
fn filter_block<'a>(&self, _block: &'a Block) -> Vec<usize> {
374+
fn filter_block(&self, _header: &BlockHeader, _txdata: &[(usize, &Transaction)]) -> Vec<usize> {
375375
Vec::new()
376376
}
377377
fn reentered(&self) -> usize { 0 }

0 commit comments

Comments
 (0)