hashiverse_lib/transport/
mem_transport.rs1use crate::tools::types::Id;
16use crate::transport::ddos::ddos::{DdosConnectionGuard, DdosProtection};
17use crate::transport::transport::{IncomingRequest, ServerState, TransportFactory, TransportServer};
18use crate::transport::transport_ownership_proof::{EmptyMarkerOwnershipProof, TransportOwnershipProof};
19use anyhow::{Result, anyhow};
20use bytes::Bytes;
21use log::info;
22use parking_lot::RwLock;
23use std::collections::HashMap;
24use crate::tools::time::DurationMillis;
25use crate::tools::time_provider::time_provider::TimeProvider;
26use std::sync::Arc;
27use tokio::sync::{mpsc, oneshot};
28use tokio_util::sync::CancellationToken;
29use tokio_util::task::TaskTracker;
30use crate::transport::bootstrap_provider::bootstrap_provider::BootstrapProvider;
31use crate::transport::bootstrap_provider::manual_bootstrap_provider::ManualBootstrapProvider;
32use crate::transport::ddos::noop_ddos::NoopDdosProtection;
33
34#[derive(Debug)]
35struct RpcMessage {
36 caller_address: String,
37 bytes: Bytes,
38 response_tx: oneshot::Sender<Result<Bytes>>,
39}
40
41struct ServerEntry {
42 command_tx: mpsc::Sender<RpcMessage>,
43}
44
45struct ServerManager {
46 servers: Arc<RwLock<HashMap<u16, Arc<ServerEntry>>>>,
47}
48
49impl ServerManager {
50 pub fn new() -> Self {
51 ServerManager {
52 servers: Arc::new(RwLock::new(HashMap::new())),
53 }
54 }
55 pub async fn remove_server(&self, port: u16) {
56 let mut servers_locked = self.servers.write();
57 servers_locked.remove(&port);
58 }
59}
60
61pub struct MemTransportServer {
72 port: u16,
73 address: String,
74 server_manager: Arc<ServerManager>,
75 command_rx: Arc<RwLock<Option<mpsc::Receiver<RpcMessage>>>>,
76 state: Arc<RwLock<ServerState>>,
77 ddos_protection: Arc<dyn DdosProtection>,
78}
79
80#[async_trait::async_trait]
81impl TransportServer for MemTransportServer {
82 fn get_address(&self) -> &String {
83 &self.address
84 }
85
86 fn get_transport_ownership_proof(&self) -> Arc<dyn TransportOwnershipProof> {
87 Arc::new(EmptyMarkerOwnershipProof)
88 }
89
90 async fn listen(&self, cancellation_token: CancellationToken, handler: mpsc::Sender<IncomingRequest>) -> Result<()> {
91 async fn process_connection(_cancellation_token: CancellationToken, handler: mpsc::Sender<IncomingRequest>, message: RpcMessage, ddos_protection: Arc<dyn DdosProtection>) -> anyhow::Result<()> {
92 let ddos_connection_guard = match DdosConnectionGuard::try_new(ddos_protection, message.caller_address.as_str()) {
96 Some(guard) => Arc::new(guard),
97 None => return Ok(()),
98 };
99 let caller_address = ddos_connection_guard.ip().to_string();
100 let (reply_tx, reply_rx) = oneshot::channel();
101 handler.send(IncomingRequest::new(caller_address, message.bytes, reply_tx, ddos_connection_guard)).await?;
102 let response = reply_rx.await?;
103 let _ = message.response_tx.send(Ok(response.to_bytes()));
104
105 Ok(())
106 }
107
108 {
110 let mut state = self.state.write();
111 match *state {
112 ServerState::Listening => {
113 anyhow::bail!("server is already listening");
114 }
115 ServerState::Shutdown => {
116 anyhow::bail!("server has been shut down");
117 }
118 ServerState::Created => {
119 *state = ServerState::Listening;
120 }
121 }
122 }
123
124 let task_tracker = TaskTracker::new();
125
126 info!("listening on address {}", self.address);
127
128 let mut receiver = match self.command_rx.write().take() {
130 Some(r) => r,
131 None => {
132 return Err(anyhow!("no receiver available on address {}", self.address));
133 }
134 };
135
136 loop {
137 tokio::select! {
138 _ = cancellation_token.cancelled() => {
139 break;
140 }
141
142 Some(msg) = receiver.recv() => {
143 task_tracker.spawn(
144 process_connection(cancellation_token.clone(), handler.clone(), msg, self.ddos_protection.clone())
145 );
146 }
147 }
148 }
149
150 info!("stopped listening on port {}", self.address);
151 self.server_manager.remove_server(self.port).await;
152
153 info!("waiting for open connections to complete");
155 task_tracker.close();
156 task_tracker.wait().await;
157
158 info!("all open connections complete");
160 *self.state.write() = ServerState::Shutdown;
161
162 Ok(())
163 }
164}
165
166#[derive(Clone)]
167pub struct MemTransportFactory {
168 server_manager: Arc<ServerManager>,
169 ddos_protection: Arc<dyn DdosProtection>,
170 bootstrap_provider: Arc<dyn BootstrapProvider>,
171 rpc_delay: Arc<RwLock<Option<(Arc<dyn TimeProvider>, DurationMillis)>>>,
173}
174
175impl MemTransportFactory {
176 pub fn new(ddos_protection: Arc<dyn DdosProtection>, bootstrap_provider: Arc<dyn BootstrapProvider>) -> Self {
177 Self {
178 server_manager: Arc::new(ServerManager::new()),
179 ddos_protection,
180 bootstrap_provider,
181 rpc_delay: Arc::new(RwLock::new(None)),
182 }
183 }
184
185 pub fn set_rpc_delay(&self, time_provider: Arc<dyn TimeProvider>, rpc_delay: DurationMillis) {
188 *self.rpc_delay.write() = Some((time_provider, rpc_delay));
189 }
190
191 pub fn clear_rpc_delay(&self) {
192 *self.rpc_delay.write() = None;
193 }
194
195 #[allow(clippy::should_implement_trait)] pub fn default() -> Arc<Self> {
197 Arc::new(Self::new(NoopDdosProtection::default(), ManualBootstrapProvider::new_mem_multiple()))
198 }
199}
200
201#[async_trait::async_trait]
202impl TransportFactory for MemTransportFactory {
203 async fn get_bootstrap_addresses(&self) -> Vec<String> {
204 self.bootstrap_provider.get_bootstrap_addresses().await
205 }
206
207 async fn create_server(&self, _base_path: &str, port: u16, force_local_network: bool) -> anyhow::Result<Arc<dyn TransportServer>> {
208 if !force_local_network {
209 return Err(anyhow!("only local network is supported"));
210 }
211
212 let mut servers_locked = self.server_manager.servers.write();
213
214 if servers_locked.contains_key(&port) {
215 return Err(anyhow!("server already exists on port {}", port));
216 }
217
218 let bound_port = match port {
220 0 => {
221 servers_locked.keys().max().unwrap_or(&0u16) + 1
222 }
223 _ => port
224 };
225
226 let address = format!("{}", bound_port);
227
228 let (tx, rx) = mpsc::channel::<RpcMessage>(256);
233
234 let mem_transport_server = Arc::new(MemTransportServer {
236 port: bound_port,
237 address,
238 server_manager: self.server_manager.clone(),
239 command_rx: Arc::new(RwLock::new(Some(rx))),
240 state: Arc::new(RwLock::new(ServerState::Created)),
241 ddos_protection: self.ddos_protection.clone(),
242 });
243
244 servers_locked.insert(bound_port, Arc::new(ServerEntry { command_tx: tx }));
246
247 Ok(mem_transport_server)
248 }
249
250 async fn rpc(&self, address: &str, bytes: Bytes) -> Result<Bytes> {
251 let rpc_delay = self.rpc_delay.read().clone();
252 if let Some((time_provider, rpc_delay)) = rpc_delay {
253 time_provider.sleep_millis(rpc_delay).await;
254 }
255
256 let port: u16 = address.parse()?;
257
258 let server_entry = {
259 let servers = self.server_manager.servers.read();
260 let server_entry = servers.get(&port).ok_or_else(|| anyhow::anyhow!("no server found with port {}", port))?;
261 server_entry.clone()
262 };
263
264 let (response_tx, response_rx) = oneshot::channel();
269
270 let message = RpcMessage { caller_address: format!("mem:{}", Id::random()), bytes, response_tx };
272
273 server_entry.command_tx.send(message).await.map_err(|e| anyhow::anyhow!("failed to send request: {}", e))?;
277
278 response_rx.await.map_err(|_| anyhow::anyhow!("server disconnected before responding"))?
280 }
281}
282
283
284#[cfg(test)]
285mod tests {
286 use crate::transport::mem_transport::MemTransportFactory;
287 use crate::transport::bootstrap_provider::manual_bootstrap_provider::ManualBootstrapProvider;
288 use crate::transport::ddos::noop_ddos::NoopDdosProtection;
289 use std::sync::Arc;
290
291 #[tokio::test]
292 async fn rpc_test() -> anyhow::Result<()> {
293 let factory: Arc<dyn crate::transport::transport::TransportFactory> = Arc::new(MemTransportFactory::new(NoopDdosProtection::default(), ManualBootstrapProvider::default()));
294 crate::transport::transport::tests::rpc_test(factory).await
295 }
296
297 #[tokio::test]
298 async fn bind_port_zero_test() -> anyhow::Result<()> {
299 let factory: Arc<dyn crate::transport::transport::TransportFactory> = Arc::new(MemTransportFactory::new(NoopDdosProtection::default(), ManualBootstrapProvider::default()));
300 crate::transport::transport::tests::bind_port_zero_test(factory).await
301 }
302
303 #[tokio::test]
306 async fn rpc_delay_is_per_call_concurrent_and_on_the_given_clock() -> anyhow::Result<()> {
307 use crate::tools::time::MILLIS_IN_SECOND;
308 use crate::tools::time_provider::time_provider::{ScaledTimeProvider, TimeProvider};
309 use crate::transport::transport::TransportFactory;
310 use bytes::Bytes;
311
312 let time_provider = Arc::new(ScaledTimeProvider::new(10.0));
315 let rpc_delay = MILLIS_IN_SECOND.const_mul(5);
316 const CONCURRENT_RPCS: usize = 5;
317
318 let factory = MemTransportFactory::new(NoopDdosProtection::default(), ManualBootstrapProvider::default());
319 let factory_clone = factory.clone();
320
321 let started = time_provider.current_time_millis();
323 assert!(factory.rpc("65000", Bytes::new()).await.is_err());
324 assert!(time_provider.current_time_millis() - started < rpc_delay);
325
326 factory_clone.set_rpc_delay(time_provider.clone(), rpc_delay);
328 let started = time_provider.current_time_millis();
329 assert!(factory.rpc("65000", Bytes::new()).await.is_err());
330 assert!(time_provider.current_time_millis() - started >= rpc_delay);
331
332 let started = time_provider.current_time_millis();
334 let results = futures::future::join_all((0..CONCURRENT_RPCS).map(|_| factory.rpc("65000", Bytes::new()))).await;
335 assert!(results.iter().all(|result| result.is_err()));
336 let elapsed = time_provider.current_time_millis() - started;
337 assert!(elapsed >= rpc_delay);
338 assert!(elapsed < rpc_delay.const_mul(2), "concurrent delayed rpcs must overlap, took {}", elapsed);
339
340 factory.clear_rpc_delay();
342 let started = time_provider.current_time_millis();
343 assert!(factory.rpc("65000", Bytes::new()).await.is_err());
344 assert!(time_provider.current_time_millis() - started < rpc_delay);
345 Ok(())
346 }
347}