kyoto/db/
mod.rs

1//! Traits and structures that define the data persistence required for a node.
2//!
3//! All nodes require a [`HeaderStore`](traits::HeaderStore) and a [`PeerStore`](traits::PeerStore). Unless
4//! your application dependency tree is particularly strict, SQL-based storage will be sufficient for the majority of
5//! applications.
6
7use bitcoin::key::rand::distributions::Standard;
8use bitcoin::key::rand::prelude::Distribution;
9use bitcoin::key::rand::{thread_rng, Rng};
10use bitcoin::p2p::address::AddrV2;
11use bitcoin::p2p::ServiceFlags;
12
13use crate::chain::IndexedHeader;
14
15/// Errors a database backend may produce.
16pub mod error;
17/// Persistence traits defined with SQL Lite to store data between sessions.
18#[cfg(feature = "rusqlite")]
19pub mod sqlite;
20/// Traits that define the header and peer databases.
21pub mod traits;
22
23/// A peer that will be saved to the [`traits::PeerStore`].
24#[derive(Debug, Clone, PartialEq)]
25pub struct PersistedPeer {
26    /// Canonical IP address of this peer.
27    pub addr: AddrV2,
28    /// The port believed to be listening for connections.
29    pub port: u16,
30    /// The services this peer may offer.
31    pub services: ServiceFlags,
32    /// A new, tried, or banned status.
33    pub status: PeerStatus,
34}
35
36impl PersistedPeer {
37    /// Build a new peer with known fields
38    pub fn new(addr: AddrV2, port: u16, services: ServiceFlags, status: PeerStatus) -> Self {
39        Self {
40            addr,
41            port,
42            services,
43            status,
44        }
45    }
46
47    pub(crate) fn gossiped(addr: AddrV2, port: u16, services: ServiceFlags) -> Self {
48        Self {
49            addr,
50            port,
51            services,
52            status: PeerStatus::Gossiped,
53        }
54    }
55}
56
57impl From<PersistedPeer> for (AddrV2, u16) {
58    fn from(value: PersistedPeer) -> Self {
59        (value.addr, value.port)
60    }
61}
62
63/// The status of a peer in the database.
64#[derive(Debug, Clone, PartialEq, PartialOrd)]
65pub enum PeerStatus {
66    /// A peer was gossiped via DNS or the peer-to-peer network.
67    Gossiped,
68    /// The node successfully connected to this peer.
69    Tried,
70    /// A connected peer responded with faulty or malicious behavior.
71    Ban,
72}
73
74impl Distribution<PeerStatus> for Standard {
75    fn sample<R: bitcoin::key::rand::Rng + ?Sized>(&self, rng: &mut R) -> PeerStatus {
76        match rng.gen_range(0..=1) {
77            0 => PeerStatus::Gossiped,
78            _ => PeerStatus::Tried,
79        }
80    }
81}
82
83impl PeerStatus {
84    pub(crate) fn random() -> PeerStatus {
85        let mut rng = thread_rng();
86        rng.gen()
87    }
88}
89
90/// Changes applied to the chain of block headers.
91#[derive(Debug, Clone)]
92pub enum BlockHeaderChanges {
93    /// A block was connected to the tip of the chain.
94    Connected(IndexedHeader),
95    /// Blocks were reorganized and a new chain of most work was selected.
96    Reorganized {
97        /// Newly accepted blocks from the chain of most work.
98        accepted: Vec<IndexedHeader>,
99        /// Blocks that were removed from the chain.
100        reorganized: Vec<IndexedHeader>,
101    },
102}