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