Add ChainPoller implementation of Poll trait
[rust-lightning] / lightning-block-sync / src / lib.rs
1 //! A lightweight client for keeping in sync with chain activity.
2 //!
3 //! Defines a [`BlockSource`] trait, which is an asynchronous interface for retrieving block headers
4 //! and data.
5 //!
6 //! Enabling feature `rest-client` or `rpc-client` allows configuring the client to fetch blocks
7 //! using Bitcoin Core's REST or RPC interface, respectively.
8 //!
9 //! Both features support either blocking I/O using `std::net::TcpStream` or, with feature `tokio`,
10 //! non-blocking I/O using `tokio::net::TcpStream` from inside a Tokio runtime.
11 //!
12 //! [`BlockSource`]: trait.BlockSource.html
13
14 #[cfg(any(feature = "rest-client", feature = "rpc-client"))]
15 pub mod http;
16
17 pub mod poll;
18
19 #[cfg(feature = "rest-client")]
20 pub mod rest;
21
22 #[cfg(feature = "rpc-client")]
23 pub mod rpc;
24
25 #[cfg(any(feature = "rest-client", feature = "rpc-client"))]
26 mod convert;
27
28 #[cfg(test)]
29 mod test_utils;
30
31 #[cfg(any(feature = "rest-client", feature = "rpc-client"))]
32 mod utils;
33
34 use bitcoin::blockdata::block::{Block, BlockHeader};
35 use bitcoin::hash_types::BlockHash;
36 use bitcoin::util::uint::Uint256;
37
38 use std::future::Future;
39 use std::pin::Pin;
40
41 /// Abstract type for retrieving block headers and data.
42 pub trait BlockSource : Sync + Send {
43         /// Returns the header for a given hash. A height hint may be provided in case a block source
44         /// cannot easily find headers based on a hash. This is merely a hint and thus the returned
45         /// header must have the same hash as was requested. Otherwise, an error must be returned.
46         ///
47         /// Implementations that cannot find headers based on the hash should return a `Transient` error
48         /// when `height_hint` is `None`.
49         fn get_header<'a>(&'a mut self, header_hash: &'a BlockHash, height_hint: Option<u32>) -> AsyncBlockSourceResult<'a, BlockHeaderData>;
50
51         /// Returns the block for a given hash. A headers-only block source should return a `Transient`
52         /// error.
53         fn get_block<'a>(&'a mut self, header_hash: &'a BlockHash) -> AsyncBlockSourceResult<'a, Block>;
54
55         // TODO: Phrase in terms of `Poll` once added.
56         /// Returns the hash of the best block and, optionally, its height. When polling a block source,
57         /// the height is passed to `get_header` to allow for a more efficient lookup.
58         fn get_best_block<'a>(&'a mut self) -> AsyncBlockSourceResult<(BlockHash, Option<u32>)>;
59 }
60
61 /// Result type for `BlockSource` requests.
62 type BlockSourceResult<T> = Result<T, BlockSourceError>;
63
64 // TODO: Replace with BlockSourceResult once `async` trait functions are supported. For details,
65 // see: https://areweasyncyet.rs.
66 /// Result type for asynchronous `BlockSource` requests.
67 type AsyncBlockSourceResult<'a, T> = Pin<Box<dyn Future<Output = BlockSourceResult<T>> + 'a + Send>>;
68
69 /// Error type for `BlockSource` requests.
70 ///
71 /// Transient errors may be resolved when re-polling, but no attempt will be made to re-poll on
72 /// persistent errors.
73 #[derive(Debug)]
74 pub struct BlockSourceError {
75         kind: BlockSourceErrorKind,
76         error: Box<dyn std::error::Error + Send + Sync>,
77 }
78
79 /// The kind of `BlockSourceError`, either persistent or transient.
80 #[derive(Clone, Copy, Debug, PartialEq)]
81 pub enum BlockSourceErrorKind {
82         /// Indicates an error that won't resolve when retrying a request (e.g., invalid data).
83         Persistent,
84
85         /// Indicates an error that may resolve when retrying a request (e.g., unresponsive).
86         Transient,
87 }
88
89 impl BlockSourceError {
90         /// Creates a new persistent error originated from the given error.
91         pub fn persistent<E>(error: E) -> Self
92         where E: Into<Box<dyn std::error::Error + Send + Sync>> {
93                 Self {
94                         kind: BlockSourceErrorKind::Persistent,
95                         error: error.into(),
96                 }
97         }
98
99         /// Creates a new transient error originated from the given error.
100         pub fn transient<E>(error: E) -> Self
101         where E: Into<Box<dyn std::error::Error + Send + Sync>> {
102                 Self {
103                         kind: BlockSourceErrorKind::Transient,
104                         error: error.into(),
105                 }
106         }
107
108         /// Returns the kind of error.
109         pub fn kind(&self) -> BlockSourceErrorKind {
110                 self.kind
111         }
112
113         /// Converts the error into the underlying error.
114         pub fn into_inner(self) -> Box<dyn std::error::Error + Send + Sync> {
115                 self.error
116         }
117 }
118
119 /// A block header and some associated data. This information should be available from most block
120 /// sources (and, notably, is available in Bitcoin Core's RPC and REST interfaces).
121 #[derive(Clone, Copy, Debug, PartialEq)]
122 pub struct BlockHeaderData {
123         /// The block header itself.
124         pub header: BlockHeader,
125
126         /// The block height where the genesis block has height 0.
127         pub height: u32,
128
129         /// The total chain work in expected number of double-SHA256 hashes required to build a chain
130         /// of equivalent weight.
131         pub chainwork: Uint256,
132 }