kyoto/db/
traits.rs

1use std::fmt::Debug;
2use std::ops::RangeBounds;
3use std::{collections::BTreeMap, fmt::Display};
4
5use bitcoin::{block::Header, BlockHash};
6
7use crate::prelude::FutureResult;
8
9use super::{BlockHeaderChanges, PersistedPeer};
10
11/// Methods required to persist the chain of block headers.
12pub trait HeaderStore: Debug + Send + Sync {
13    /// Errors that may occur within a [`HeaderStore`].
14    type Error: Debug + Display;
15    /// Load the headers of the canonical chain for the specified range.
16    fn load<'a>(
17        &'a mut self,
18        range: impl RangeBounds<u32> + Send + Sync + 'a,
19    ) -> FutureResult<'a, BTreeMap<u32, Header>, Self::Error>;
20
21    /// Stage changes to the chain to be written in the future.
22    fn stage(&mut self, changes: BlockHeaderChanges);
23
24    /// Commit the changes by writing them to disk.
25    fn write(&mut self) -> FutureResult<'_, (), Self::Error>;
26
27    /// Return the height of a block hash in the database, if it exists.
28    fn height_of<'a>(
29        &'a mut self,
30        hash: &'a BlockHash,
31    ) -> FutureResult<'a, Option<u32>, Self::Error>;
32
33    /// Return the hash at the height in the database, if it exists.
34    fn hash_at(&mut self, height: u32) -> FutureResult<'_, Option<BlockHash>, Self::Error>;
35
36    /// Return the header at the height in the database, if it exists.
37    fn header_at(&mut self, height: u32) -> FutureResult<'_, Option<Header>, Self::Error>;
38}
39
40/// Methods that define a list of peers on the Bitcoin P2P network.
41pub trait PeerStore: Debug + Send + Sync {
42    /// Errors that may occur within a [`PeerStore`].
43    type Error: Debug + Display;
44    /// Add a peer to the database, defining if it should be replaced or not.
45    fn update(&mut self, peer: PersistedPeer) -> FutureResult<'_, (), Self::Error>;
46
47    /// Get any peer from the database, selected at random. If no peers exist, an error is thrown.
48    fn random(&mut self) -> FutureResult<'_, PersistedPeer, Self::Error>;
49
50    /// The number of peers in the database that are not marked as banned.
51    fn num_unbanned(&mut self) -> FutureResult<'_, u32, Self::Error>;
52}
53
54#[cfg(test)]
55mod test {
56    use super::*;
57    use std::convert::Infallible;
58
59    /// Errors for the [`PeerStore`](crate) of unit type.
60    #[derive(Debug)]
61    pub enum UnitPeerStoreError {
62        /// There were no peers found.
63        NoPeers,
64    }
65
66    impl core::fmt::Display for UnitPeerStoreError {
67        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68            match self {
69                UnitPeerStoreError::NoPeers => write!(f, "no peers in unit database."),
70            }
71        }
72    }
73
74    impl PeerStore for () {
75        type Error = UnitPeerStoreError;
76        fn update(&mut self, _peer: PersistedPeer) -> FutureResult<'_, (), Self::Error> {
77            async fn do_update() -> Result<(), UnitPeerStoreError> {
78                Ok(())
79            }
80            Box::pin(do_update())
81        }
82
83        fn random(&mut self) -> FutureResult<'_, PersistedPeer, Self::Error> {
84            async fn do_random() -> Result<PersistedPeer, UnitPeerStoreError> {
85                Err(UnitPeerStoreError::NoPeers)
86            }
87            Box::pin(do_random())
88        }
89
90        fn num_unbanned(&mut self) -> FutureResult<'_, u32, Self::Error> {
91            async fn do_num_unbanned() -> Result<u32, UnitPeerStoreError> {
92                Ok(0)
93            }
94            Box::pin(do_num_unbanned())
95        }
96    }
97
98    impl HeaderStore for () {
99        type Error = Infallible;
100        fn load<'a>(
101            &'a mut self,
102            _range: impl RangeBounds<u32> + Send + Sync + 'a,
103        ) -> FutureResult<'a, BTreeMap<u32, Header>, Self::Error> {
104            async fn do_load() -> Result<BTreeMap<u32, Header>, Infallible> {
105                Ok(BTreeMap::new())
106            }
107            Box::pin(do_load())
108        }
109
110        fn stage(&mut self, _changes: BlockHeaderChanges) {}
111
112        fn write(&mut self) -> FutureResult<'_, (), Self::Error> {
113            async fn do_write() -> Result<(), Infallible> {
114                Ok(())
115            }
116            Box::pin(do_write())
117        }
118
119        fn height_of<'a>(
120            &'a mut self,
121            _block_hash: &'a BlockHash,
122        ) -> FutureResult<'a, Option<u32>, Self::Error> {
123            async fn do_height_of() -> Result<Option<u32>, Infallible> {
124                Ok(None)
125            }
126            Box::pin(do_height_of())
127        }
128
129        fn hash_at(&mut self, _height: u32) -> FutureResult<'_, Option<BlockHash>, Self::Error> {
130            async fn do_hast_at() -> Result<Option<BlockHash>, Infallible> {
131                Ok(None)
132            }
133            Box::pin(do_hast_at())
134        }
135
136        fn header_at(&mut self, _height: u32) -> FutureResult<'_, Option<Header>, Self::Error> {
137            async fn do_header_at() -> Result<Option<Header>, Infallible> {
138                Ok(None)
139            }
140            Box::pin(do_header_at())
141        }
142    }
143}