f - Update ChainListener::block_connected
authorJeffrey Czyz <jkczyz@gmail.com>
Fri, 26 Jun 2020 01:07:55 +0000 (18:07 -0700)
committerJeffrey Czyz <jkczyz@gmail.com>
Tue, 4 Aug 2020 23:39:34 +0000 (16:39 -0700)
Support filtered blocks by taking a &BlockHeader and &Transaction slice
of the form &[(usize, &Transaction)] where each transaction is paired
with its position within the block.

fuzz/src/chanmon_consistency.rs
fuzz/src/full_stack.rs
fuzz/src/router.rs
lightning/src/chain/chaininterface.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/channelmonitor.rs
lightning/src/ln/functional_tests.rs
lightning/src/util/test_utils.rs

index 6d337a083e262741b2e79a947fa2316de5352715..887790f58063a0580afb1b238c4a6483076344bd 100644 (file)
@@ -10,7 +10,7 @@
 //! channel being force-closed.
 
 use bitcoin::BitcoinHash;
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
 use bitcoin::blockdata::script::{Builder, Script};
 use bitcoin::blockdata::opcodes;
@@ -306,17 +306,12 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
 
        macro_rules! confirm_txn {
                ($node: expr) => { {
-                       let mut block = Block {
-                               header: BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
-                               txdata: channel_txn.clone(),
-                       };
-                       $node.block_connected(&block, 1);
+                       let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+                       let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect();
+                       $node.block_connected(&header, &txdata, 1);
                        for i in 2..100 {
-                               block = Block {
-                                       header: BlockHeader { version: 0x20000000, prev_blockhash: block.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
-                                       txdata: vec![],
-                               };
-                               $node.block_connected(&block, i);
+                               header = BlockHeader { version: 0x20000000, prev_blockhash: header.bitcoin_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+                               $node.block_connected(&header, &[], i);
                        }
                } }
        }
index 614c6290c9e759e1657bb29e3c8ea8e0e75fd781..96588104ee1b52a653a19e065114955ee2d9489b 100644 (file)
@@ -4,7 +4,7 @@
 //! or payments to send/ways to handle events generated.
 //! This test has been very useful, though due to its complexity good starting inputs are critical.
 
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::transaction::{Transaction, TxOut};
 use bitcoin::blockdata::script::{Builder, Script};
 use bitcoin::blockdata::opcodes;
@@ -175,29 +175,28 @@ impl<'a> MoneyLossDetector<'a> {
        }
 
        fn connect_block(&mut self, all_txn: &[Transaction]) {
-               for tx in all_txn.iter() {
+               let mut txdata = Vec::with_capacity(all_txn.len());
+               for (idx, tx) in all_txn.iter().enumerate() {
                        let txid = tx.txid();
                        match self.txids_confirmed.entry(txid) {
                                hash_map::Entry::Vacant(e) => {
                                        e.insert(self.height);
+                                       txdata.push((idx + 1, tx));
                                },
                                _ => {},
                        }
                }
 
-               let block = Block {
-                       header: BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height], merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 },
-                       txdata: all_txn.to_vec(),
-               };
+               let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height], merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 };
                self.height += 1;
                self.blocks_connected += 1;
-               self.manager.block_connected(&block, self.height as u32);
-               (*self.monitor).block_connected(&block, self.height as u32);
+               self.manager.block_connected(&header, &txdata, self.height as u32);
+               (*self.monitor).block_connected(&header, &txdata, self.height as u32);
                if self.header_hashes.len() > self.height {
-                       self.header_hashes[self.height] = block.bitcoin_hash();
+                       self.header_hashes[self.height] = header.bitcoin_hash();
                } else {
                        assert_eq!(self.header_hashes.len(), self.height);
-                       self.header_hashes.push(block.bitcoin_hash());
+                       self.header_hashes.push(header.bitcoin_hash());
                }
                self.max_height = cmp::max(self.height, self.max_height);
        }
index 31e552f5906a518d883d877dc7dcec86e87de1f3..ffb5ccb8e8cf5ed2fbd5f11d94d5fe6edbfc9223 100644 (file)
@@ -1,5 +1,6 @@
 use bitcoin::blockdata::script::{Script, Builder};
-use bitcoin::blockdata::block::Block;
+use bitcoin::blockdata::block::BlockHeader;
+use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::hash_types::{Txid, BlockHash};
 
 use lightning::chain::chaininterface::{ChainError,ChainWatchInterface};
@@ -75,7 +76,7 @@ impl ChainWatchInterface for DummyChainWatcher {
        fn install_watch_tx(&self, _txid: &Txid, _script_pub_key: &Script) { }
        fn install_watch_outpoint(&self, _outpoint: (Txid, u32), _out_script: &Script) { }
        fn watch_all_txn(&self) { }
-       fn filter_block(&self, _block: &Block) -> Vec<usize> {
+       fn filter_block(&self, _header: &BlockHeader, _txdata: &[(usize, &Transaction)]) -> Vec<usize> {
                Vec::new()
        }
        fn reentered(&self) -> usize { 0 }
index 4cf4c5fb73805aa3b728675ec54ce36afb574b40..815ca270a889bb3314f5c400df7855a1da98dba1 100644 (file)
@@ -55,7 +55,7 @@ pub trait ChainWatchInterface: Sync + Send {
 
        /// Gets the list of transaction indices within a given block that the ChainWatchInterface is
        /// watching for.
-       fn filter_block(&self, block: &Block) -> Vec<usize>;
+       fn filter_block(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize>;
 
        /// Returns a usize that changes when the ChainWatchInterface's watched data is modified.
        /// 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 {
 
 /// A trait indicating a desire to listen for events from the chain
 pub trait ChainListener: Sync + Send {
-       /// Notifies a listener that a block was connected.
-       fn block_connected(&self, block: &Block, height: u32);
+       /// Notifies a listener that a block was connected. Transactions may be filtered and are given
+       /// paired with their position within the block.
+       fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32);
+
        /// Notifies a listener that a block was disconnected.
        /// Unlike block_connected, this *must* never be called twice for the same disconnect event.
        /// 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> {
        }
 
        /// Notify listeners that a block was connected.
-       pub fn block_connected<'b>(&self, block: &'b Block, height: u32) {
+       pub fn block_connected(&self, block: &Block, height: u32) {
+               let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
                let listeners = self.listeners.lock().unwrap();
                for listener in listeners.iter() {
-                       listener.block_connected(block, height);
+                       listener.block_connected(&block.header, &txdata, height);
                }
        }
 
@@ -320,13 +323,13 @@ impl ChainWatchInterface for ChainWatchInterfaceUtil {
                Err(ChainError::NotSupported)
        }
 
-       fn filter_block(&self, block: &Block) -> Vec<usize> {
+       fn filter_block(&self, _header: &BlockHeader, txdata: &[(usize, &Transaction)]) -> Vec<usize> {
                let mut matched_index = Vec::new();
                {
                        let watched = self.watched.lock().unwrap();
-                       for (index, transaction) in block.txdata.iter().enumerate() {
-                               if self.does_match_tx_unguarded(transaction, &watched) {
-                                       matched_index.push(index);
+                       for (i, transaction) in txdata.iter().enumerate() {
+                               if self.does_match_tx_unguarded(transaction.1, &watched) {
+                                       matched_index.push(i);
                                }
                        }
                }
index 26fc8dcc0e04b95a91534e34392038595171ab48..d717182b66a62a10a1340c01999b54a2f25a0acd 100644 (file)
@@ -1,4 +1,4 @@
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::script::{Script,Builder};
 use bitcoin::blockdata::transaction::{TxIn, TxOut, Transaction, SigHashType};
 use bitcoin::blockdata::opcodes;
@@ -3314,7 +3314,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
        ///
        /// May return some HTLCs (and their payment_hash) which have timed out and should be failed
        /// back.
-       pub fn block_connected(&mut self, block: &Block, height: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
+       pub fn block_connected(&mut self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage> {
                let mut timed_out_htlcs = Vec::new();
                self.holding_cell_htlc_updates.retain(|htlc_update| {
                        match htlc_update {
@@ -3328,13 +3328,13 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                        }
                });
                let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
-               if block.bitcoin_hash() != self.last_block_connected {
+               if header.bitcoin_hash() != self.last_block_connected {
                        if self.funding_tx_confirmations > 0 {
                                self.funding_tx_confirmations += 1;
                        }
                }
                if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
-                       for (index_in_block, ref tx) in block.txdata.iter().enumerate() {
+                       for &(index_in_block, tx) in txdata.iter() {
                                if tx.txid() == self.funding_txo.unwrap().txid {
                                        let txo_idx = self.funding_txo.unwrap().index as usize;
                                        if txo_idx >= tx.output.len() || tx.output[txo_idx].script_pubkey != self.get_funding_redeemscript().to_v0_p2wsh() ||
@@ -3377,9 +3377,9 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                                }
                        }
                }
-               if block.bitcoin_hash() != self.last_block_connected {
-                       self.last_block_connected = block.bitcoin_hash();
-                       self.update_time_counter = cmp::max(self.update_time_counter, block.header.time);
+               if header.bitcoin_hash() != self.last_block_connected {
+                       self.last_block_connected = header.bitcoin_hash();
+                       self.update_time_counter = cmp::max(self.update_time_counter, header.time);
                        if let Some(channel_monitor) = self.channel_monitor.as_mut() {
                                channel_monitor.last_block_hash = self.last_block_connected;
                        }
@@ -3403,7 +3403,7 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                                                // funding_tx_confirmed_in and return.
                                                false
                                        };
-                                       self.funding_tx_confirmed_in = Some(block.bitcoin_hash());
+                                       self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
 
                                        //TODO: Note that this must be a duplicate of the previous commitment point they sent us,
                                        //as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
index c595e10238eef853c4889bce5d60f2882f004e26..43e88c7c9badd31544f0a5c440eb45dd197a7a75 100644 (file)
@@ -8,8 +8,9 @@
 //! on-chain transactions (it only monitors the chain to watch for any force-closes that might
 //! imply it needs to fail HTLCs/payments/channels it manages).
 
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::constants::genesis_block;
+use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::network::constants::Network;
 use bitcoin::util::hash::BitcoinHash;
 
@@ -2977,8 +2978,8 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
         F::Target: FeeEstimator,
                                L::Target: Logger,
 {
-       fn block_connected(&self, block: &Block, height: u32) {
-               let header_hash = block.bitcoin_hash();
+       fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) {
+               let header_hash = header.bitcoin_hash();
                log_trace!(self.logger, "Block {} at height {} connected", header_hash, height);
                let _ = self.total_consistency_lock.read().unwrap();
                let mut failed_channels = Vec::new();
@@ -2989,7 +2990,7 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
                        let short_to_id = &mut channel_state.short_to_id;
                        let pending_msg_events = &mut channel_state.pending_msg_events;
                        channel_state.by_id.retain(|_, channel| {
-                               let res = channel.block_connected(block, height);
+                               let res = channel.block_connected(header, txdata, height);
                                if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
                                        for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
                                                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
@@ -3022,7 +3023,7 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
                                        return false;
                                }
                                if let Some(funding_txo) = channel.get_funding_txo() {
-                                       for tx in block.txdata.iter() {
+                                       for &(_, tx) in txdata.iter() {
                                                for inp in tx.input.iter() {
                                                        if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
                                                                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()));
@@ -3096,8 +3097,8 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send, T: Deref + Sync + Send, K:
                        // Just in case we end up in a race, we loop until we either successfully update
                        // last_node_announcement_serial or decide we don't need to.
                        let old_serial = self.last_node_announcement_serial.load(Ordering::Acquire);
-                       if old_serial >= block.header.time as usize { break; }
-                       if self.last_node_announcement_serial.compare_exchange(old_serial, block.header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
+                       if old_serial >= header.time as usize { break; }
+                       if self.last_node_announcement_serial.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
                                break;
                        }
                }
index e2ac2b8ebf6cbf18db19ad5e6878dbece8f3f45e..114c03611488d3c762e9b84a7bd1fe375c36f63a 100644 (file)
@@ -11,7 +11,7 @@
 //! security-domain-separated system design, you should consider having multiple paths for
 //! ChannelMonitors to get out of the HSM and onto monitoring devices.
 
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::transaction::{TxOut,Transaction};
 use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
 use bitcoin::blockdata::script::{Script, Builder};
@@ -183,13 +183,13 @@ impl<Key : Send + cmp::Eq + hash::Hash, ChanSigner: ChannelKeys, T: Deref + Sync
              L::Target: Logger,
         C::Target: ChainWatchInterface,
 {
-       fn block_connected(&self, block: &Block, height: u32) {
+       fn block_connected(&self, header: &BlockHeader, txdata: &[(usize, &Transaction)], height: u32) {
                let mut reentered = true;
                while reentered {
-                       let matched_indexes = self.chain_monitor.filter_block(block);
-                       let matched_txn: Vec<&Transaction> = matched_indexes.iter().map(|index| &block.txdata[*index]).collect();
+                       let matched_indexes = self.chain_monitor.filter_block(header, txdata);
+                       let matched_txn: Vec<_> = matched_indexes.iter().map(|index| txdata[*index].1).collect();
                        let last_seen = self.chain_monitor.reentered();
-                       let block_hash = block.bitcoin_hash();
+                       let block_hash = header.bitcoin_hash();
                        {
                                let mut monitors = self.monitors.lock().unwrap();
                                for monitor in monitors.values_mut() {
index c8dd8dea0554a3195982e8fcd07ce545d4846ad8..73e2c7ed873041995519062833f8ed40fed17280 100644 (file)
@@ -7244,15 +7244,12 @@ fn test_no_failure_dust_htlc_local_commitment() {
                output: vec![outp]
        };
 
-       let block = Block {
-               header: BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
-               txdata: vec![dummy_tx],
-       };
-       nodes[0].chan_monitor.simple_monitor.block_connected(&block, 1);
+       let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+       nodes[0].chan_monitor.simple_monitor.block_connected(&header, &[(0, &dummy_tx)], 1);
        assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
        assert_eq!(nodes[0].node.get_and_clear_pending_msg_events().len(), 0);
        // We broadcast a few more block to check everything is all right
-       connect_blocks(&nodes[0].block_notifier, 20, 1, true,  block.bitcoin_hash());
+       connect_blocks(&nodes[0].block_notifier, 20, 1, true, header.bitcoin_hash());
        assert_eq!(nodes[0].node.get_and_clear_pending_events().len(), 0);
        assert_eq!(nodes[0].node.get_and_clear_pending_msg_events().len(), 0);
 
@@ -8377,11 +8374,8 @@ fn test_update_err_monitor_lockdown() {
                assert!(watchtower.add_monitor(outpoint, new_monitor).is_ok());
                watchtower
        };
-       let block = Block {
-               header: BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 },
-               txdata: vec![],
-       };
-       watchtower.simple_monitor.block_connected(&block, 200);
+       let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+       watchtower.simple_monitor.block_connected(&header, &[], 200);
 
        // Try to update ChannelMonitor
        assert!(nodes[1].node.claim_funds(preimage, &None, 9_000_000));
index 33b070ee89d60e3b880147d1ce6535707ab6d615..70a37479931727216e0c445e5818c59997562ed7 100644 (file)
@@ -16,7 +16,7 @@ use bitcoin::BitcoinHash;
 use bitcoin::blockdata::constants::genesis_block;
 use bitcoin::blockdata::transaction::Transaction;
 use bitcoin::blockdata::script::{Builder, Script};
-use bitcoin::blockdata::block::Block;
+use bitcoin::blockdata::block::BlockHeader;
 use bitcoin::blockdata::opcodes;
 use bitcoin::network::constants::Network;
 use bitcoin::hash_types::{Txid, BlockHash};
@@ -399,7 +399,7 @@ impl ChainWatchInterface for TestChainWatcher {
        fn install_watch_tx(&self, _txid: &Txid, _script_pub_key: &Script) { }
        fn install_watch_outpoint(&self, _outpoint: (Txid, u32), _out_script: &Script) { }
        fn watch_all_txn(&self) { }
-       fn filter_block<'a>(&self, _block: &'a Block) -> Vec<usize> {
+       fn filter_block(&self, _header: &BlockHeader, _txdata: &[(usize, &Transaction)]) -> Vec<usize> {
                Vec::new()
        }
        fn reentered(&self) -> usize { 0 }