Skip to main content

chia_peer/
config.rs

1//! [`ChiaPeerConfig`] — how a [`ChiaLightClient`](crate::ChiaLightClient) is pointed at a Chia
2//! network and, optionally, at the operator's own trusted full node.
3
4use std::net::SocketAddr;
5use std::time::Duration;
6
7use chia_protocol::Bytes32;
8use chia_wallet_sdk::types::{MAINNET_CONSTANTS, TESTNET11_CONSTANTS};
9
10/// The Chia network a client speaks to.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum ChiaNetwork {
13    /// Chia mainnet.
14    Mainnet,
15    /// The current public testnet (testnet11).
16    Testnet11,
17}
18
19const MAINNET_PORT: u16 = 8444;
20const TESTNET11_PORT: u16 = 58444;
21
22impl ChiaNetwork {
23    /// The wallet-protocol `network_id` handshake string for this network.
24    pub fn network_id(self) -> &'static str {
25        match self {
26            ChiaNetwork::Mainnet => "mainnet",
27            ChiaNetwork::Testnet11 => "testnet11",
28        }
29    }
30
31    /// The default full-node port peers listen on for this network.
32    pub fn default_port(self) -> u16 {
33        match self {
34            ChiaNetwork::Mainnet => MAINNET_PORT,
35            ChiaNetwork::Testnet11 => TESTNET11_PORT,
36        }
37    }
38
39    /// The genesis challenge, used as the `header_hash` when querying coin state from height 0
40    /// (`Bytes32::default()` is rejected by the peer protocol).
41    pub fn genesis_challenge(self) -> Bytes32 {
42        match self {
43            ChiaNetwork::Mainnet => MAINNET_CONSTANTS.genesis_challenge,
44            ChiaNetwork::Testnet11 => TESTNET11_CONSTANTS.genesis_challenge,
45        }
46    }
47}
48
49/// Connection + trust configuration for a [`ChiaLightClient`](crate::ChiaLightClient).
50///
51/// When [`endpoint`](Self::endpoint) names the operator's own node (`trusted == true`), the derived
52/// provider is a [`LocalNode`](dig_chainsource_interface::ProviderKind::LocalNode); otherwise peers
53/// are discovered from the network's DNS introducers and the provider is
54/// [`Custom`](dig_chainsource_interface::ProviderKind::Custom).
55#[derive(Debug, Clone)]
56pub struct ChiaPeerConfig {
57    /// The network to connect to.
58    pub network: ChiaNetwork,
59    /// An explicit peer to dial (the operator's own node). `None` = discover via DNS introducers.
60    pub endpoint: Option<SocketAddr>,
61    /// Whether [`endpoint`](Self::endpoint) is the operator's own trusted node. Governs the derived
62    /// [`ProviderKind`](dig_chainsource_interface::ProviderKind).
63    pub trusted: bool,
64    /// Per-attempt connection timeout.
65    pub connect_timeout: Duration,
66    /// Per-request response timeout.
67    pub request_timeout: Duration,
68    /// Filesystem path to the client TLS certificate (PEM).
69    pub tls_cert_path: Option<String>,
70    /// Filesystem path to the client TLS key (PEM).
71    pub tls_key_path: Option<String>,
72}
73
74impl ChiaPeerConfig {
75    /// A mainnet config that discovers public peers via DNS introducers.
76    pub fn mainnet() -> Self {
77        Self::discovering(ChiaNetwork::Mainnet)
78    }
79
80    /// A testnet11 config that discovers public peers via DNS introducers.
81    pub fn testnet11() -> Self {
82        Self::discovering(ChiaNetwork::Testnet11)
83    }
84
85    /// A config that discovers untrusted public peers for `network` via DNS introducers.
86    pub fn discovering(network: ChiaNetwork) -> Self {
87        Self {
88            network,
89            endpoint: None,
90            trusted: false,
91            connect_timeout: Duration::from_secs(5),
92            request_timeout: Duration::from_secs(15),
93            tls_cert_path: None,
94            tls_key_path: None,
95        }
96    }
97
98    /// Points the client at the operator's OWN trusted node at `endpoint` (e.g. a local full node),
99    /// deriving a [`LocalNode`](dig_chainsource_interface::ProviderKind::LocalNode) provider.
100    pub fn with_trusted_endpoint(mut self, endpoint: SocketAddr) -> Self {
101        self.endpoint = Some(endpoint);
102        self.trusted = true;
103        self
104    }
105
106    /// Sets the client TLS certificate + key paths (PEM).
107    pub fn with_tls(mut self, cert_path: impl Into<String>, key_path: impl Into<String>) -> Self {
108        self.tls_cert_path = Some(cert_path.into());
109        self.tls_key_path = Some(key_path.into());
110        self
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117    use std::net::{IpAddr, Ipv4Addr};
118
119    #[test]
120    fn network_ids_and_ports_are_canonical() {
121        assert_eq!(ChiaNetwork::Mainnet.network_id(), "mainnet");
122        assert_eq!(ChiaNetwork::Testnet11.network_id(), "testnet11");
123        assert_eq!(ChiaNetwork::Mainnet.default_port(), 8444);
124        assert_eq!(ChiaNetwork::Testnet11.default_port(), 58444);
125    }
126
127    #[test]
128    fn genesis_challenge_differs_per_network() {
129        assert_ne!(
130            ChiaNetwork::Mainnet.genesis_challenge(),
131            ChiaNetwork::Testnet11.genesis_challenge()
132        );
133    }
134
135    #[test]
136    fn discovering_config_is_untrusted_with_no_endpoint() {
137        let cfg = ChiaPeerConfig::mainnet();
138        assert!(!cfg.trusted);
139        assert!(cfg.endpoint.is_none());
140    }
141
142    #[test]
143    fn trusted_endpoint_marks_config_trusted() {
144        let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8444);
145        let cfg = ChiaPeerConfig::testnet11().with_trusted_endpoint(addr);
146        assert!(cfg.trusted);
147        assert_eq!(cfg.endpoint, Some(addr));
148    }
149
150    #[test]
151    fn with_tls_sets_both_paths() {
152        let cfg = ChiaPeerConfig::mainnet().with_tls("cert.pem", "key.pem");
153        assert_eq!(cfg.tls_cert_path.as_deref(), Some("cert.pem"));
154        assert_eq!(cfg.tls_key_path.as_deref(), Some("key.pem"));
155    }
156}