stratum_apps/network_helpers/
mod.rs1pub mod noise_connection;
14pub mod noise_stream;
15pub mod resolve_hostname;
16
17#[cfg(feature = "sv1")]
18pub mod sv1_connection;
19
20pub use resolve_hostname::{resolve_host, resolve_host_port, ResolveError};
21
22use async_channel::{RecvError, SendError};
23use std::{fmt, time::Duration};
24use stratum_core::{
25 binary_sv2::{Deserialize, GetSize, Serialize},
26 codec_sv2::{Error as CodecError, HandshakeRole},
27 noise_sv2::{Initiator, Responder},
28};
29use tokio::net::TcpStream;
30
31use crate::{
32 key_utils::{Secp256k1PublicKey, Secp256k1SecretKey},
33 network_helpers::noise_stream::NoiseTcpStream,
34};
35
36#[derive(Debug)]
38pub enum Error {
39 HandshakeRemoteInvalidMessage,
41 CodecError(CodecError),
43 RecvError,
45 SendError,
47 SocketClosed,
49 HandshakeTimeout,
51 InvalidKey,
53 DnsResolutionFailed(String),
55}
56
57impl fmt::Display for Error {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 match self {
60 Error::HandshakeRemoteInvalidMessage => {
61 write!(f, "Invalid handshake message received from remote peer")
62 }
63
64 Error::CodecError(e) => write!(f, "{e}"),
65
66 Error::RecvError => write!(f, "Error receiving from async channel"),
67
68 Error::SendError => write!(f, "Error sending to async channel"),
69
70 Error::SocketClosed => write!(f, "Socket was closed (likely by the peer)"),
71
72 Error::HandshakeTimeout => write!(f, "Handshake timeout"),
73
74 Error::InvalidKey => write!(f, "Invalid key provided for handshake"),
75
76 Error::DnsResolutionFailed(msg) => write!(f, "DNS resolution failed: {msg}"),
77 }
78 }
79}
80
81impl From<CodecError> for Error {
82 fn from(e: CodecError) -> Self {
83 Error::CodecError(e)
84 }
85}
86
87impl From<RecvError> for Error {
88 fn from(_: RecvError) -> Self {
89 Error::RecvError
90 }
91}
92
93impl<T> From<SendError<T>> for Error {
94 fn from(_: SendError<T>) -> Self {
95 Error::SendError
96 }
97}
98
99impl From<ResolveError> for Error {
100 fn from(e: ResolveError) -> Self {
101 Error::DnsResolutionFailed(e.to_string())
102 }
103}
104
105const NOISE_HANDSHAKE_TIMEOUT: Duration = Duration::from_secs(10);
108
109pub const TCP_CONNECT_TIMEOUT: Duration = Duration::from_secs(5);
112
113pub async fn connect_with_noise<Message>(
121 stream: TcpStream,
122 authority_pub_key: Option<Secp256k1PublicKey>,
123) -> Result<NoiseTcpStream<Message>, Error>
124where
125 Message: Serialize + Deserialize<'static> + GetSize + Send + 'static,
126{
127 let initiator = match authority_pub_key {
128 Some(key) => Initiator::from_raw_k(key.into_bytes()).map_err(|_| Error::InvalidKey)?,
129 None => Initiator::without_pk().map_err(|_| Error::InvalidKey)?,
130 };
131 let stream = noise_stream::NoiseTcpStream::new(
132 stream,
133 HandshakeRole::Initiator(initiator),
134 NOISE_HANDSHAKE_TIMEOUT,
135 )
136 .await?;
137 Ok(stream)
138}
139
140pub async fn accept_noise_connection<Message>(
148 stream: TcpStream,
149 pub_key: Secp256k1PublicKey,
150 prv_key: Secp256k1SecretKey,
151 cert_validity: u64,
152) -> Result<NoiseTcpStream<Message>, Error>
153where
154 Message: Serialize + Deserialize<'static> + GetSize + Send + 'static,
155{
156 let responder = Responder::from_authority_kp(
157 &pub_key.into_bytes(),
158 &prv_key.into_bytes(),
159 Duration::from_secs(cert_validity),
160 )
161 .map_err(|_| Error::InvalidKey)?;
162 let stream = noise_stream::NoiseTcpStream::new(
163 stream,
164 HandshakeRole::Responder(responder),
165 NOISE_HANDSHAKE_TIMEOUT,
166 )
167 .await?;
168 Ok(stream)
169}