Fix unused warning for un-accessed enum variant field in net-tokio
[rust-lightning] / lightning-block-sync / src / lib.rs
index 8854aa3e8e4bf8186b6cc119451e62ddc6710fae..4a01d4673b31e91d56c3cb350d995c1b7a3d7403 100644 (file)
@@ -13,7 +13,9 @@
 //! Both features support either blocking I/O using `std::net::TcpStream` or, with feature `tokio`,
 //! non-blocking I/O using `tokio::net::TcpStream` from inside a Tokio runtime.
 
-#![deny(broken_intra_doc_links)]
+#![deny(rustdoc::broken_intra_doc_links)]
+#![deny(rustdoc::private_intra_doc_links)]
+
 #![deny(missing_docs)]
 #![deny(unsafe_code)]
 
@@ -25,6 +27,8 @@ pub mod http;
 pub mod init;
 pub mod poll;
 
+pub mod gossip;
+
 #[cfg(feature = "rest-client")]
 pub mod rest;
 
@@ -42,9 +46,9 @@ mod utils;
 
 use crate::poll::{ChainTip, Poll, ValidatedBlockHeader};
 
-use bitcoin::blockdata::block::{Block, BlockHeader};
+use bitcoin::blockdata::block::{Block, Header};
 use bitcoin::hash_types::BlockHash;
-use bitcoin::util::uint::Uint256;
+use bitcoin::pow::Work;
 
 use lightning::chain;
 use lightning::chain::Listen;
@@ -61,11 +65,11 @@ pub trait BlockSource : Sync + Send {
        ///
        /// Implementations that cannot find headers based on the hash should return a `Transient` error
        /// when `height_hint` is `None`.
-       fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData>;
+       fn get_header<'a>(&'a self, header_hash: &'a BlockHash, height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData>;
 
        /// Returns the block for a given hash. A headers-only block source should return a `Transient`
        /// error.
-       fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>;
+       fn get_block<'a>(&'a self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, BlockData>;
 
        /// Returns the hash of the best block and, optionally, its height.
        ///
@@ -73,7 +77,7 @@ pub trait BlockSource : Sync + Send {
        /// to allow for a more efficient lookup.
        ///
        /// [`get_header`]: Self::get_header
-       fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<(BlockHash, Option<u32>)>;
+       fn get_best_block<'a>(&'a self) -> AsyncBlockSourceResult<(BlockHash, Option<u32>)>;
 }
 
 /// Result type for `BlockSource` requests.
@@ -95,7 +99,7 @@ pub struct BlockSourceError {
 }
 
 /// The kind of `BlockSourceError`, either persistent or transient.
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum BlockSourceErrorKind {
        /// Indicates an error that won't resolve when retrying a request (e.g., invalid data).
        Persistent,
@@ -129,6 +133,9 @@ impl BlockSourceError {
        }
 
        /// Converts the error into the underlying error.
+       ///
+       /// May contain an [`std::io::Error`] from the [`BlockSource`]. See implementations for further
+       /// details, if any.
        pub fn into_inner(self) -> Box<dyn std::error::Error + Send + Sync> {
                self.error
        }
@@ -136,17 +143,28 @@ impl BlockSourceError {
 
 /// A block header and some associated data. This information should be available from most block
 /// sources (and, notably, is available in Bitcoin Core's RPC and REST interfaces).
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub struct BlockHeaderData {
        /// The block header itself.
-       pub header: BlockHeader,
+       pub header: Header,
 
        /// The block height where the genesis block has height 0.
        pub height: u32,
 
-       /// The total chain work in expected number of double-SHA256 hashes required to build a chain
-       /// of equivalent weight.
-       pub chainwork: Uint256,
+       /// The total chain work required to build a chain of equivalent weight.
+       pub chainwork: Work,
+}
+
+/// A block including either all its transactions or only the block header.
+///
+/// [`BlockSource`] may be implemented to either always return full blocks or, in the case of
+/// compact block filters (BIP 157/158), return header-only blocks when no pertinent transactions
+/// match. See [`chain::Filter`] for details on how to notify a source of such transactions.
+pub enum BlockData {
+       /// A block containing all its transactions.
+       FullBlock(Block),
+       /// A block header for when the block does not contain any pertinent transactions.
+       HeaderOnly(Header),
 }
 
 /// A lightweight client for keeping a listener in sync with the chain, allowing for Simplified
@@ -393,13 +411,22 @@ impl<'a, C: Cache, L: Deref> ChainNotifier<'a, C, L> where L::Target: chain::Lis
                chain_poller: &mut P,
        ) -> Result<(), (BlockSourceError, Option<ValidatedBlockHeader>)> {
                for header in connected_blocks.drain(..).rev() {
-                       let block = chain_poller
+                       let height = header.height;
+                       let block_data = chain_poller
                                .fetch_block(&header).await
-                               .or_else(|e| Err((e, Some(new_tip))))?;
-                       debug_assert_eq!(block.block_hash, header.block_hash);
+                               .map_err(|e| (e, Some(new_tip)))?;
+                       debug_assert_eq!(block_data.block_hash, header.block_hash);
+
+                       match block_data.deref() {
+                               BlockData::FullBlock(block) => {
+                                       self.chain_listener.block_connected(block, height);
+                               },
+                               BlockData::HeaderOnly(header) => {
+                                       self.chain_listener.filtered_block_connected(header, &[], height);
+                               },
+                       }
 
                        self.header_cache.block_connected(header.block_hash, header);
-                       self.chain_listener.block_connected(&block, header.height);
                        new_tip = header;
                }
 
@@ -704,4 +731,25 @@ mod chain_notifier_tests {
                        Ok(_) => panic!("Expected error"),
                }
        }
+
+       #[tokio::test]
+       async fn sync_from_chain_with_filtered_blocks() {
+               let mut chain = Blockchain::default().with_height(3).filtered_blocks();
+
+               let new_tip = chain.tip();
+               let old_tip = chain.at_height(1);
+               let chain_listener = &MockChainListener::new()
+                       .expect_filtered_block_connected(*chain.at_height(2))
+                       .expect_filtered_block_connected(*new_tip);
+               let mut notifier = ChainNotifier {
+                       header_cache: &mut chain.header_cache(0..=1),
+                       chain_listener,
+               };
+               let mut poller = poll::ChainPoller::new(&mut chain, Network::Testnet);
+               match notifier.synchronize_listener(new_tip, &old_tip, &mut poller).await {
+                       Err((e, _)) => panic!("Unexpected error: {:?}", e),
+                       Ok(_) => {},
+               }
+       }
+
 }