Skip to main content

reth_ipc/server/
mod.rs

1//! JSON-RPC IPC server implementation
2
3use crate::{
4    server::connection::{IpcConn, IpcConnDriver, JsonRpcStream},
5    stream_codec::StreamCodec,
6};
7use futures_util::future::Either;
8use interprocess::local_socket::{
9    tokio::prelude::{LocalSocketListener, LocalSocketStream},
10    traits::tokio::{Listener, Stream},
11    GenericFilePath, ListenerOptions, ToFsName,
12};
13use jsonrpsee::{
14    core::{server::ConnectionId, TEN_MB_SIZE_BYTES},
15    server::{
16        accept_error_backoff, handle_rpc_call, middleware::rpc::RpcServiceT, stop_channel,
17        BatchRequestConfig, ConnectionGuard, ConnectionPermit, IdProvider, RandomIntegerIdProvider,
18        ServerHandle, StopHandle,
19    },
20    types::{error::reject_too_big_request, Id},
21    BoundedSubscriptions, MethodResponse, MethodSink, Methods,
22};
23use std::{
24    future::Future,
25    io,
26    pin::{pin, Pin},
27    sync::Arc,
28    task::{Context, Poll},
29};
30use tokio::{
31    io::{AsyncRead, AsyncWrite, AsyncWriteExt},
32    sync::{mpsc, oneshot},
33};
34use tokio_util::task::AbortOnDropHandle;
35use tower::{layer::util::Identity, Layer, Service};
36use tracing::{instrument, trace, warn, Instrument};
37
38#[cfg(unix)]
39use interprocess::os::unix::local_socket::ListenerOptionsExt;
40#[cfg(unix)]
41use std::os::unix::fs::PermissionsExt;
42
43pub use jsonrpsee::server::middleware::rpc::{RpcService, RpcServiceBuilder};
44
45mod connection;
46
47/// Number of messages a connection buffers before backpressure kicks in.
48const MESSAGE_BUFFER_CAPACITY: usize = 1024;
49
50/// Ipc Server implementation
51///
52/// This is an adapted `jsonrpsee` Server, but for `Ipc` connections.
53pub struct IpcServer<RpcMiddleware = Identity> {
54    /// The endpoint we listen for incoming transactions
55    endpoint: String,
56    id_provider: Arc<dyn IdProvider>,
57    cfg: Settings,
58    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
59}
60
61impl<RpcMiddleware> IpcServer<RpcMiddleware> {
62    /// Returns the configured endpoint
63    pub fn endpoint(&self) -> String {
64        self.endpoint.clone()
65    }
66}
67
68impl<RpcMiddleware> IpcServer<RpcMiddleware>
69where
70    RpcMiddleware: Layer<RpcService> + Clone + Send + 'static,
71    RpcMiddleware::Service: RpcServiceT + Send + Sync + 'static,
72{
73    /// Start responding to connections requests.
74    ///
75    /// This will run on the tokio runtime until the server is stopped or the `ServerHandle` is
76    /// dropped.
77    ///
78    /// Returns an error if the endpoint cannot be opened or the requested Unix socket permissions
79    /// cannot be parsed or applied before serving requests.
80    ///
81    /// ```
82    /// use jsonrpsee::RpcModule;
83    /// use reth_ipc::server::Builder;
84    /// async fn run_server() -> Result<(), Box<dyn core::error::Error + Send + Sync>> {
85    ///     let server = Builder::default().build("/tmp/my-uds".into());
86    ///     let mut module = RpcModule::new(());
87    ///     module.register_method("say_hello", |_, _| "lo")?;
88    ///     let handle = server.start(module).await?;
89    ///
90    ///     // In this example we don't care about doing shutdown so let's it run forever.
91    ///     // You may use the `ServerHandle` to shut it down or manage it yourself.
92    ///     let server = tokio::spawn(handle.stopped());
93    ///     server.await.unwrap();
94    ///     Ok(())
95    /// }
96    /// ```
97    pub async fn start(
98        mut self,
99        methods: impl Into<Methods>,
100    ) -> Result<ServerHandle, IpcServerStartError> {
101        let methods = methods.into();
102
103        let (stop_handle, server_handle) = stop_channel();
104
105        // use a signal channel to wait until we're ready to accept connections
106        let (tx, rx) = oneshot::channel();
107
108        match self.cfg.tokio_runtime.take() {
109            Some(rt) => rt.spawn(self.start_inner(methods, stop_handle, tx)),
110            None => tokio::spawn(self.start_inner(methods, stop_handle, tx)),
111        };
112        rx.await.expect("channel is open")?;
113
114        Ok(server_handle)
115    }
116
117    async fn start_inner(
118        self,
119        methods: Methods,
120        stop_handle: StopHandle,
121        on_ready: oneshot::Sender<Result<(), IpcServerStartError>>,
122    ) {
123        trace!(endpoint = ?self.endpoint, "starting ipc server");
124
125        let listener =
126            match self.endpoint.as_str().to_fs_name::<GenericFilePath>().and_then(|name| {
127                // Unlinks an existing endpoint only after binding to it fails, so earlier errors
128                // such as an unsupported mode leave it in place.
129                let options = ListenerOptions::new().name(name).try_overwrite(true);
130
131                #[cfg(unix)]
132                let mode = self
133                    .cfg
134                    .ipc_socket_permissions
135                    .as_deref()
136                    .map(|permissions| {
137                        let mode = u32::from_str_radix(
138                            permissions.strip_prefix("0o").unwrap_or(permissions),
139                            8,
140                        )
141                        .map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?;
142                        if mode > 0o7777 {
143                            return Err(io::Error::new(
144                                io::ErrorKind::InvalidInput,
145                                format!("IPC socket permissions `{permissions}` exceed 0o7777"),
146                            ));
147                        }
148                        Ok(mode)
149                    })
150                    .transpose()?;
151
152                #[cfg(unix)]
153                let options = if let Some(mode) = mode {
154                    // Set the mode before bind/listen so connections cannot bypass it during
155                    // startup. The range check keeps the cast lossless where `mode_t` is `u16`.
156                    options.mode(mode as _)
157                } else {
158                    options
159                };
160
161                let listener = options.create_tokio()?;
162
163                #[cfg(unix)]
164                if let Some(mode) = mode {
165                    // Binding can further restrict the requested mode through the process umask.
166                    std::fs::set_permissions(
167                        &self.endpoint,
168                        std::fs::Permissions::from_mode(mode),
169                    )?;
170                }
171
172                Ok(listener)
173            }) {
174                Ok(listener) => listener,
175                Err(err) => {
176                    on_ready
177                        .send(Err(IpcServerStartError {
178                            endpoint: self.endpoint.clone(),
179                            source: err,
180                        }))
181                        .ok();
182                    return;
183                }
184            };
185
186        // signal that we're ready to accept connections
187        on_ready.send(Ok(())).ok();
188
189        let connection_guard = ConnectionGuard::new(self.cfg.max_connections as usize);
190
191        let stopped = stop_handle.clone().shutdown();
192        let mut stopped = pin!(stopped);
193
194        let (drop_on_completion, mut process_connection_awaiter) = mpsc::channel::<()>(1);
195
196        trace!("accepting ipc connections");
197        loop {
198            match try_accept_conn(&listener, stopped).await {
199                AcceptConnection::Established { local_socket_stream, stop } => {
200                    let Some(conn_permit) = connection_guard.try_acquire() else {
201                        let (_reader, mut writer) = local_socket_stream.split();
202                        let _ = writer
203                            .write_all(b"Too many connections. Please try again later.")
204                            .await;
205                        stopped = stop;
206                        continue;
207                    };
208
209                    let max_conns = connection_guard.max_connections();
210                    let curr_conns = max_conns - connection_guard.available_connections();
211                    trace!("Accepting new connection {}/{}", curr_conns, max_conns);
212
213                    process_connection(ProcessConnection {
214                        rpc_middleware: self.rpc_middleware.clone(),
215                        conn_permit: Arc::new(conn_permit),
216                        conn_id: ConnectionId::next_unique().0,
217                        server_cfg: self.cfg.clone(),
218                        stop_handle: stop_handle.clone(),
219                        drop_on_completion: drop_on_completion.clone(),
220                        methods: methods.clone(),
221                        id_provider: self.id_provider.clone(),
222                        local_socket_stream,
223                    });
224
225                    stopped = stop;
226                }
227                AcceptConnection::Shutdown => {
228                    break;
229                }
230                AcceptConnection::Err((err, stop)) => {
231                    tracing::error!(%err, "Failed accepting a new IPC connection");
232                    let Some(stop) = accept_error_backoff(&err, stop).await else { break };
233                    stopped = stop;
234                }
235            }
236        }
237
238        // Drop the last Sender
239        drop(drop_on_completion);
240
241        // Once this channel is closed it is safe to assume that all connections have been
242        // gracefully shutdown
243        while process_connection_awaiter.recv().await.is_some() {
244            // Generally, messages should not be sent across this channel,
245            // but we'll loop here to wait for `None` just to be on the safe side
246        }
247    }
248}
249
250enum AcceptConnection<S> {
251    Shutdown,
252    Established { local_socket_stream: LocalSocketStream, stop: S },
253    Err((io::Error, S)),
254}
255
256async fn try_accept_conn<S>(listener: &LocalSocketListener, stopped: S) -> AcceptConnection<S>
257where
258    S: Future + Unpin,
259{
260    // `select` polls its first argument first and returns as soon as that one is ready, so the
261    // stop signal has to come first: with `accept` first, a listener that keeps returning without
262    // ever pending starves the stop signal and the server can no longer be stopped.
263    match futures_util::future::select(stopped, pin!(listener.accept())).await {
264        Either::Left(_) => AcceptConnection::Shutdown,
265        Either::Right((res, stop)) => match res {
266            Ok(local_socket_stream) => AcceptConnection::Established { local_socket_stream, stop },
267            Err(e) => AcceptConnection::Err((e, stop)),
268        },
269    }
270}
271
272impl<RpcMiddleware> std::fmt::Debug for IpcServer<RpcMiddleware> {
273    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274        f.debug_struct("IpcServer")
275            .field("endpoint", &self.endpoint)
276            .field("cfg", &self.cfg)
277            .field("id_provider", &self.id_provider)
278            .finish()
279    }
280}
281
282/// Error thrown when server couldn't be started.
283#[derive(Debug, thiserror::Error)]
284#[error("failed to listen on ipc endpoint `{endpoint}`: {source}")]
285pub struct IpcServerStartError {
286    endpoint: String,
287    #[source]
288    source: io::Error,
289}
290
291/// Data required by the server to handle requests received via an IPC connection
292#[derive(Debug, Clone)]
293struct ServiceData {
294    /// Registered server methods.
295    methods: Methods,
296    /// Subscription ID provider.
297    id_provider: Arc<dyn IdProvider>,
298    /// Connection ID
299    conn_id: usize,
300    /// Connection Permit.
301    conn_permit: Arc<ConnectionPermit>,
302    /// Limits the number of subscriptions for this connection
303    bounded_subscriptions: BoundedSubscriptions,
304    /// Sink that is used to send back responses to the connection.
305    ///
306    /// This is used for subscriptions.
307    method_sink: MethodSink,
308    /// `ServerConfig`
309    server_cfg: Settings,
310}
311
312/// Turns raw IPC messages into serialized JSON-RPC responses.
313#[derive(Debug, Clone)]
314struct TowerServiceNoHttp<L> {
315    inner: ServiceData,
316    rpc_middleware: RpcServiceBuilder<L>,
317}
318
319impl<RpcMiddleware> Service<String> for TowerServiceNoHttp<RpcMiddleware>
320where
321    RpcMiddleware: Layer<RpcService>,
322    RpcMiddleware::Service: RpcServiceT + Send + Sync + 'static,
323{
324    /// The response of a handled RPC call
325    ///
326    /// This is an `Option` because subscriptions and call responses are handled differently.
327    /// This will be `Some` for calls, and `None` for subscriptions and notifications, because the
328    /// subscription response will be emitted via the `method_sink`.
329    type Response = Option<String>;
330
331    type Error = Box<dyn core::error::Error + Send + Sync + 'static>;
332
333    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
334
335    /// Opens door for back pressure implementation.
336    fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
337        Poll::Ready(Ok(()))
338    }
339
340    fn call(&mut self, request: String) -> Self::Future {
341        trace!(request_bytes = request.len(), "Received IPC request");
342
343        let max_request_body_size = self.inner.server_cfg.max_request_body_size;
344        let conn = self.inner.conn_permit.clone();
345        let rpc_service = self.rpc_middleware.service(RpcService::new(
346            self.inner.methods.clone(),
347            self.inner.server_cfg.max_response_body_size as usize,
348            self.inner.conn_id.into(),
349            self.inner.bounded_subscriptions.clone(),
350            self.inner.method_sink.clone(),
351            self.inner.id_provider.clone(),
352        ));
353        // an ipc connection needs to handle read+write concurrently
354        // even if the underlying rpc handler spawns the actual work or is does a lot of async any
355        // additional overhead performed by `handle_request` can result in I/O latencies, for
356        // example tracing calls are relatively CPU expensive on serde::serialize alone, moving this
357        // work to a separate task takes the pressure off the connection so all concurrent responses
358        // are also serialized concurrently and the connection can focus on read+write
359        //
360        // The connection drops its pending calls when it closes, so the call must not outlive the
361        // returned future, otherwise it keeps running without anyone waiting for the response.
362        let f = AbortOnDropHandle::new(tokio::task::spawn(async move {
363            let rp = if request.len() > max_request_body_size as usize {
364                MethodResponse::error(Id::Null, reject_too_big_request(max_request_body_size))
365            } else {
366                let is_single = request.chars().find_map(|c| match c {
367                    '{' => Some(true),
368                    '[' => Some(false),
369                    _ => None,
370                });
371                handle_rpc_call(
372                    request.as_bytes(),
373                    is_single.unwrap_or(true),
374                    BatchRequestConfig::Unlimited,
375                    &rpc_service,
376                )
377                .await
378            };
379            drop(conn);
380
381            (rp.is_method_call() || rp.is_batch()).then(|| rp.into_json())
382        }));
383
384        Box::pin(async move {
385            // Call panics are answered by the call itself. Anything left here has no request id to
386            // respond to, and the connection writes errors verbatim, which would corrupt the
387            // stream.
388            Ok(f.await.unwrap_or_else(|err| {
389                warn!(%err, "IPC call task failed");
390                None
391            }))
392        })
393    }
394}
395
396struct ProcessConnection<RpcMiddleware> {
397    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
398    conn_permit: Arc<ConnectionPermit>,
399    conn_id: usize,
400    server_cfg: Settings,
401    stop_handle: StopHandle,
402    drop_on_completion: mpsc::Sender<()>,
403    methods: Methods,
404    id_provider: Arc<dyn IdProvider>,
405    local_socket_stream: LocalSocketStream,
406}
407
408/// Spawns the IPC connection onto a new task
409#[instrument(name = "connection", skip_all, fields(conn_id = %params.conn_id), level = "TRACE")]
410fn process_connection<RpcMiddleware>(params: ProcessConnection<RpcMiddleware>)
411where
412    RpcMiddleware: Layer<RpcService> + Send + 'static,
413    RpcMiddleware::Service: RpcServiceT + Send + Sync + 'static,
414{
415    let ProcessConnection {
416        rpc_middleware,
417        conn_permit,
418        conn_id,
419        server_cfg,
420        stop_handle,
421        drop_on_completion,
422        id_provider,
423        methods,
424        local_socket_stream,
425    } = params;
426
427    let codec =
428        StreamCodec::stream_incoming().with_max_length(server_cfg.max_request_body_size as usize);
429    let ipc = IpcConn(tokio_util::codec::Decoder::framed(codec, local_socket_stream));
430
431    let (tx, rx) = mpsc::channel::<String>(MESSAGE_BUFFER_CAPACITY);
432    let method_sink = MethodSink::new_with_limit(tx, server_cfg.max_response_body_size);
433    let service = TowerServiceNoHttp {
434        inner: ServiceData {
435            methods,
436            id_provider,
437            conn_id,
438            conn_permit,
439            bounded_subscriptions: BoundedSubscriptions::new(
440                server_cfg.max_subscriptions_per_connection,
441            ),
442            method_sink,
443            server_cfg,
444        },
445        rpc_middleware,
446    };
447
448    // `#[instrument]` only spans this function, so the connection span is carried into the task.
449    tokio::spawn(
450        async {
451            to_ipc_service(ipc, service, stop_handle, rx).await;
452            drop(drop_on_completion)
453        }
454        .in_current_span(),
455    );
456}
457
458async fn to_ipc_service<S, T>(
459    ipc: IpcConn<JsonRpcStream<T>>,
460    service: S,
461    stop_handle: StopHandle,
462    rx: mpsc::Receiver<String>,
463) where
464    S: Service<String, Response = Option<String>> + Send + 'static,
465    S::Error: Into<Box<dyn core::error::Error + Send + Sync>>,
466    S::Future: Send + Unpin,
467    T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
468{
469    let conn = IpcConnDriver {
470        conn: ipc,
471        service,
472        pending_calls: Default::default(),
473        items: Default::default(),
474        messages: rx,
475    };
476    let stopped = stop_handle.shutdown();
477
478    tokio::select! {
479        _ = conn => {}
480        _ = stopped => {}
481    }
482}
483
484/// JSON-RPC IPC server settings.
485#[derive(Debug, Clone)]
486pub struct Settings {
487    /// Maximum size in bytes of a request.
488    max_request_body_size: u32,
489    /// Maximum size in bytes of a response.
490    max_response_body_size: u32,
491    /// Maximum number of incoming connections allowed.
492    max_connections: u32,
493    /// Maximum number of subscriptions per connection.
494    max_subscriptions_per_connection: u32,
495    /// Custom tokio runtime to run the server on.
496    tokio_runtime: Option<tokio::runtime::Handle>,
497    /// The permissions to create the IPC socket with.
498    ipc_socket_permissions: Option<String>,
499}
500
501impl Default for Settings {
502    fn default() -> Self {
503        Self {
504            max_request_body_size: TEN_MB_SIZE_BYTES,
505            max_response_body_size: TEN_MB_SIZE_BYTES,
506            max_connections: 100,
507            max_subscriptions_per_connection: 1024,
508            tokio_runtime: None,
509            ipc_socket_permissions: None,
510        }
511    }
512}
513
514/// Builder to configure and create a JSON-RPC server
515#[derive(Debug)]
516pub struct Builder<RpcMiddleware> {
517    settings: Settings,
518    /// Subscription ID provider.
519    id_provider: Arc<dyn IdProvider>,
520    rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
521}
522
523impl Default for Builder<Identity> {
524    fn default() -> Self {
525        Self {
526            settings: Settings::default(),
527            id_provider: Arc::new(RandomIntegerIdProvider),
528            rpc_middleware: RpcServiceBuilder::new(),
529        }
530    }
531}
532
533impl<RpcMiddleware> Builder<RpcMiddleware> {
534    /// Set the maximum size of a request body in bytes. Default is 10 MiB.
535    pub const fn max_request_body_size(mut self, size: u32) -> Self {
536        self.settings.max_request_body_size = size;
537        self
538    }
539
540    /// Set the maximum size of a response body in bytes. Default is 10 MiB.
541    pub const fn max_response_body_size(mut self, size: u32) -> Self {
542        self.settings.max_response_body_size = size;
543        self
544    }
545
546    /// Set the maximum number of connections allowed. Default is 100.
547    pub const fn max_connections(mut self, max: u32) -> Self {
548        self.settings.max_connections = max;
549        self
550    }
551
552    /// Set the maximum number of subscriptions per connection. Default is 1024.
553    pub const fn max_subscriptions_per_connection(mut self, max: u32) -> Self {
554        self.settings.max_subscriptions_per_connection = max;
555        self
556    }
557
558    /// Configure a custom [`tokio::runtime::Handle`] to run the server on.
559    ///
560    /// Default: [`tokio::spawn`]
561    pub fn custom_tokio_runtime(mut self, rt: tokio::runtime::Handle) -> Self {
562        self.settings.tokio_runtime = Some(rt);
563        self
564    }
565
566    /// Sets the permissions for the IPC socket file.
567    ///
568    /// On Unix, accepts an octal mode up to `0o7777` with an optional `0o` prefix. Invalid modes or
569    /// failures to apply them cause [`IpcServer::start`] to return an error. This includes
570    /// platforms that do not support setting socket permissions before binding. `None` uses the
571    /// system's umask. Ignored on non-Unix platforms.
572    pub fn set_ipc_socket_permissions(mut self, permissions: Option<String>) -> Self {
573        self.settings.ipc_socket_permissions = permissions;
574        self
575    }
576
577    /// Configure custom `subscription ID` provider for the server to use
578    /// to when getting new subscription calls.
579    ///
580    /// You may choose static dispatch or dynamic dispatch because
581    /// `IdProvider` is implemented for `Box<T>`.
582    ///
583    /// Default: [`RandomIntegerIdProvider`].
584    ///
585    /// # Examples
586    ///
587    /// ```rust
588    /// use jsonrpsee::server::RandomStringIdProvider;
589    /// use reth_ipc::server::Builder;
590    ///
591    /// // static dispatch
592    /// let builder1 = Builder::default().set_id_provider(RandomStringIdProvider::new(16));
593    ///
594    /// // or dynamic dispatch
595    /// let builder2 = Builder::default().set_id_provider(Box::new(RandomStringIdProvider::new(16)));
596    /// ```
597    pub fn set_id_provider<I: IdProvider + 'static>(mut self, id_provider: I) -> Self {
598        self.id_provider = Arc::new(id_provider);
599        self
600    }
601
602    /// Enable middleware that is invoked on every JSON-RPC call.
603    ///
604    /// The middleware itself is very similar to the `tower middleware` but
605    /// it has a different service trait which takes &self instead &mut self
606    /// which means that you can't use built-in middleware from tower.
607    ///
608    /// Another consequence of `&self` is that you must wrap any of the middleware state in
609    /// a type which is Send and provides interior mutability such `Arc<Mutex>`.
610    ///
611    /// The builder itself exposes a similar API as the [`tower::ServiceBuilder`]
612    /// where it is possible to compose layers to the middleware.
613    pub fn set_rpc_middleware<T>(self, rpc_middleware: RpcServiceBuilder<T>) -> Builder<T> {
614        Builder { settings: self.settings, id_provider: self.id_provider, rpc_middleware }
615    }
616
617    /// Finalize the configuration of the server. Consumes the [`Builder`].
618    pub fn build(self, endpoint: String) -> IpcServer<RpcMiddleware> {
619        IpcServer {
620            endpoint,
621            cfg: self.settings,
622            id_provider: self.id_provider,
623            rpc_middleware: self.rpc_middleware,
624        }
625    }
626}
627
628#[cfg(test)]
629#[expect(missing_docs)]
630pub fn dummy_name() -> String {
631    use rand::Rng;
632    let num: u64 = rand::rng().random();
633    format!(r"/tmp/my-uds-{num}")
634}
635
636#[cfg(test)]
637mod tests {
638    use super::*;
639    use futures::{future::select, StreamExt};
640    use interprocess::local_socket::tokio::{RecvHalf, SendHalf};
641    use jsonrpsee::{
642        core::{
643            middleware::{Batch, BatchEntry, Notification},
644            server::PendingSubscriptionAcceptError,
645        },
646        types::{
647            error::{OVERSIZED_RESPONSE_CODE, OVERSIZED_RESPONSE_MSG, TOO_MANY_SUBSCRIPTIONS_CODE},
648            ErrorCode, Request,
649        },
650        PendingSubscriptionSink, RpcModule, SubscriptionMessage,
651    };
652    use reth_tracing::init_test_tracing;
653    use serde_json::{json, Value};
654    use std::{
655        pin::pin,
656        sync::atomic::{AtomicUsize, Ordering},
657        time::Duration,
658    };
659    use tokio::sync::{broadcast, mpsc};
660    use tokio_stream::wrappers::BroadcastStream;
661    use tokio_util::codec::FramedRead;
662
663    /// Raw JSON-RPC client that talks to the server over the IPC socket.
664    struct TestClient {
665        send: SendHalf,
666        recv: FramedRead<RecvHalf, StreamCodec>,
667        next_id: u64,
668    }
669
670    impl TestClient {
671        async fn connect(endpoint: &str) -> Self {
672            let name = endpoint.to_fs_name::<GenericFilePath>().unwrap();
673            let (recv, send) = LocalSocketStream::connect(name).await.unwrap().split();
674            Self { send, recv: FramedRead::new(recv, StreamCodec::stream_incoming()), next_id: 0 }
675        }
676
677        /// Sends a call and returns its response, or `None` if the server closed the
678        /// connection.
679        async fn call(&mut self, method: &str, params: Value) -> Option<Value> {
680            let request = self.request(method, params);
681            self.send(request).await.ok()?;
682            self.recv().await
683        }
684
685        /// Returns the request object for a call with a fresh id.
686        fn request(&mut self, method: &str, params: Value) -> Value {
687            self.next_id += 1;
688            json!({"jsonrpc": "2.0", "id": self.next_id, "method": method, "params": params})
689        }
690
691        async fn send(&mut self, msg: Value) -> io::Result<()> {
692            self.send.write_all(msg.to_string().as_bytes()).await
693        }
694
695        /// Returns the next message from the server, or `None` if the connection is closed.
696        async fn recv(&mut self) -> Option<Value> {
697            let msg = self.recv.next().await?.ok()?;
698            Some(serde_json::from_str(&msg).unwrap())
699        }
700    }
701
702    /// Returns the error code of a response, or `None` if it succeeded.
703    fn error_code(response: &Value) -> Option<i64> {
704        response.get("error").map(|err| err["code"].as_i64().unwrap())
705    }
706
707    #[cfg(unix)]
708    use std::{os::unix::net::UnixListener, path::Path};
709
710    #[tokio::test]
711    #[cfg(unix)]
712    async fn test_ipc_socket_permissions() {
713        for (permissions, mode) in
714            [("0777", 0o777), ("600", 0o600), ("0600", 0o600), ("0o600", 0o600)]
715        {
716            let endpoint = dummy_name();
717            let server = Builder::default()
718                .set_ipc_socket_permissions(Some(permissions.to_string()))
719                .build(endpoint.clone());
720            match server.start(RpcModule::new(())).await {
721                Ok(handle) if !cfg!(target_os = "macos") => {
722                    let actual = std::fs::metadata(&endpoint).unwrap().permissions().mode();
723                    assert_eq!(actual & 0o777, mode);
724                    handle.stop().unwrap();
725                    tokio::time::timeout(Duration::from_secs(5), handle.stopped()).await.unwrap();
726                }
727                Err(error)
728                    if !cfg!(any(
729                        target_os = "linux",
730                        target_os = "android",
731                        target_os = "openbsd"
732                    )) =>
733                {
734                    assert_eq!(error.source.kind(), io::ErrorKind::Unsupported, "{mode:o}");
735                    assert_eq!(error.endpoint, endpoint);
736                    assert!(!Path::new(&endpoint).exists());
737                }
738                result => panic!("Unexpected IPC startup result: {result:?}"),
739            }
740        }
741    }
742
743    async fn pipe_from_stream_with_bounded_buffer(
744        pending: PendingSubscriptionSink,
745        stream: BroadcastStream<usize>,
746    ) -> Result<(), Box<dyn core::error::Error + Send + Sync>> {
747        let sink = pending.accept().await.unwrap();
748        let closed = sink.closed();
749
750        let mut closed = pin!(closed);
751        let mut stream = pin!(stream);
752
753        loop {
754            match select(closed, stream.next()).await {
755                // subscription closed or stream is closed.
756                Either::Left((_, _)) | Either::Right((None, _)) => break Ok(()),
757
758                // received new item from the stream.
759                Either::Right((Some(Ok(item)), c)) => {
760                    let raw_value = serde_json::value::to_raw_value(&item)?;
761                    let notif = SubscriptionMessage::from(raw_value);
762
763                    // NOTE: this will block until there a spot in the queue
764                    // and you might want to do something smarter if it's
765                    // critical that "the most recent item" must be sent when it is produced.
766                    if sink.send(notif).await.is_err() {
767                        break Ok(());
768                    }
769
770                    closed = c;
771                }
772
773                // Send back the error.
774                Either::Right((Some(Err(e)), _)) => break Err(e.into()),
775            }
776        }
777    }
778
779    // Naive example that broadcasts the produced values to all active subscribers.
780    fn produce_items(tx: broadcast::Sender<usize>) {
781        for c in 1..=100 {
782            std::thread::sleep(std::time::Duration::from_millis(1));
783            let _ = tx.send(c);
784        }
785    }
786
787    #[tokio::test]
788    async fn can_set_the_max_response_body_size() {
789        // init_test_tracing();
790        let endpoint = &dummy_name();
791        let server = Builder::default().max_response_body_size(100).build(endpoint.clone());
792        let mut module = RpcModule::new(());
793        module.register_method("anything", |_, _| "a".repeat(101)).unwrap();
794        let handle = server.start(module).await.unwrap();
795        tokio::spawn(handle.stopped());
796
797        let mut client = TestClient::connect(endpoint).await;
798        let response = client.call("anything", json!([])).await.unwrap();
799        assert!(response["error"]["data"].as_str().unwrap().contains("Exceeded max limit of"));
800    }
801
802    #[tokio::test]
803    async fn can_set_the_max_request_body_size() {
804        init_test_tracing();
805        let endpoint = &dummy_name();
806        let server = Builder::default().max_request_body_size(100).build(endpoint.clone());
807        let mut module = RpcModule::new(());
808        module.register_method("anything", |_, _| "succeed").unwrap();
809        let handle = server.start(module).await.unwrap();
810        tokio::spawn(handle.stopped());
811
812        let mut client = TestClient::connect(endpoint).await;
813        let response = client.call("anything", json!(["a".repeat(101)])).await;
814        assert!(response.is_none_or(|response| error_code(&response).is_some()));
815
816        // The batch is more than 100 bytes.
817        let mut client = TestClient::connect(endpoint).await;
818        let batch = (0..3).map(|_| client.request("anything", json!([]))).collect();
819        client.send(Value::Array(batch)).await.unwrap();
820        let response = client.recv().await;
821        assert!(response.is_none_or(|response| error_code(&response).is_some()));
822    }
823
824    #[tokio::test]
825    async fn can_set_max_connections() {
826        init_test_tracing();
827
828        let endpoint = &dummy_name();
829        let server = Builder::default().max_connections(2).build(endpoint.clone());
830        let mut module = RpcModule::new(());
831        module.register_method("anything", |_, _| "succeed").unwrap();
832        let handle = server.start(module).await.unwrap();
833        tokio::spawn(handle.stopped());
834
835        let mut client1 = TestClient::connect(endpoint).await;
836        let mut client2 = TestClient::connect(endpoint).await;
837        let mut client3 = TestClient::connect(endpoint).await;
838
839        assert_eq!(client1.call("anything", json!([])).await.unwrap()["result"], "succeed");
840        assert_eq!(client2.call("anything", json!([])).await.unwrap()["result"], "succeed");
841        // Third connection is rejected
842        assert!(client3.call("anything", json!([])).await.is_none());
843
844        // Decrement connection count
845        drop(client2);
846        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
847
848        // Can connect again
849        let mut client4 = TestClient::connect(endpoint).await;
850        assert_eq!(client4.call("anything", json!([])).await.unwrap()["result"], "succeed");
851    }
852
853    #[tokio::test(flavor = "multi_thread")]
854    async fn test_pending_call_aborted_on_disconnect() {
855        init_test_tracing();
856
857        let endpoint = &dummy_name();
858        let server = Builder::default().build(endpoint.clone());
859        let (started_tx, started_rx) = oneshot::channel::<()>();
860        let (dropped_tx, dropped_rx) = oneshot::channel::<()>();
861        let mut module = RpcModule::new(std::sync::Mutex::new(Some((started_tx, dropped_tx))));
862        module
863            .register_async_method("hang", |_, ctx| async move {
864                // `dropped_tx` is dropped together with the call
865                let (started_tx, _dropped_tx) = ctx.lock().unwrap().take().unwrap();
866                let _ = started_tx.send(());
867                std::future::pending::<()>().await;
868                "unreachable"
869            })
870            .unwrap();
871        let handle = server.start(module).await.unwrap();
872        tokio::spawn(handle.stopped());
873
874        let mut client = TestClient::connect(endpoint).await;
875        tokio::select! {
876            _ = client.call("hang", json!([])) => panic!("call completed"),
877            _ = started_rx => {}
878        }
879        drop(client);
880
881        let dropped = tokio::time::timeout(std::time::Duration::from_secs(5), dropped_rx).await;
882        assert!(dropped.is_ok(), "call kept running after the connection closed");
883    }
884
885    #[tokio::test]
886    async fn test_panicking_call_returns_internal_error() {
887        init_test_tracing();
888
889        let endpoint = &dummy_name();
890        let server = Builder::default().build(endpoint.clone());
891        let mut module = RpcModule::new(());
892        module
893            .register_async_method("maybe_panic", |params, _| async move {
894                assert!(!params.one::<bool>().unwrap(), "requested panic");
895                "ok"
896            })
897            .unwrap();
898        let handle = server.start(module).await.unwrap();
899        tokio::spawn(handle.stopped());
900
901        let mut client = TestClient::connect(endpoint).await;
902        let response = client.call("maybe_panic", json!([true])).await.unwrap();
903        assert_eq!(
904            error_code(&response),
905            Some(ErrorCode::InternalError.code().into()),
906            "{response}"
907        );
908
909        let batch = vec![
910            client.request("maybe_panic", json!([true])),
911            client.request("maybe_panic", json!([false])),
912        ];
913        client.send(Value::Array(batch)).await.unwrap();
914        let responses = client.recv().await.unwrap();
915        assert_eq!(error_code(&responses[0]), Some(ErrorCode::InternalError.code().into()));
916        assert_eq!(responses[1]["result"], "ok");
917    }
918
919    #[tokio::test]
920    async fn test_invalid_id_is_not_a_notification() {
921        let endpoint = &dummy_name();
922        let server = Builder::default().build(endpoint.clone());
923        let mut module = RpcModule::new(());
924        module.register_method("anything", |_, _| "ok").unwrap();
925        let handle = server.start(module).await.unwrap();
926        tokio::spawn(handle.stopped());
927
928        let mut client = TestClient::connect(endpoint).await;
929        client.send(json!({"jsonrpc": "2.0", "method": "anything", "id": {}})).await.unwrap();
930        // The message used to be treated as a notification and left unanswered.
931        let response = tokio::time::timeout(std::time::Duration::from_secs(5), client.recv())
932            .await
933            .expect("message with an invalid id was not answered")
934            .unwrap();
935        assert_eq!(
936            response,
937            json!({
938                "jsonrpc": "2.0",
939                "id": null,
940                "error": {"code": ErrorCode::InvalidRequest.code(), "message": "Invalid request"},
941            })
942        );
943    }
944
945    #[tokio::test]
946    async fn test_rpc_request() {
947        init_test_tracing();
948        let endpoint = &dummy_name();
949        let server = Builder::default().build(endpoint.clone());
950        let mut module = RpcModule::new(());
951        let msg = r#"{"jsonrpc":"2.0","id":83,"result":"0x7a69"}"#;
952        module.register_method("eth_chainId", move |_, _| msg).unwrap();
953        let handle = server.start(module).await.unwrap();
954        tokio::spawn(handle.stopped());
955
956        let mut client = TestClient::connect(endpoint).await;
957        let response = client.call("eth_chainId", json!([])).await.unwrap();
958        assert_eq!(response["result"], msg);
959    }
960
961    #[tokio::test]
962    async fn test_batch_request() {
963        let endpoint = &dummy_name();
964        let server = Builder::default().build(endpoint.clone());
965        let mut module = RpcModule::new(());
966        module.register_method("anything", |_, _| "ok").unwrap();
967        let handle = server.start(module).await.unwrap();
968        tokio::spawn(handle.stopped());
969
970        let mut client = TestClient::connect(endpoint).await;
971        let batch = (0..3).map(|_| client.request("anything", json!([]))).collect();
972        client.send(Value::Array(batch)).await.unwrap();
973        let responses = client.recv().await.unwrap();
974        let results =
975            responses.as_array().unwrap().iter().map(|r| &r["result"]).collect::<Vec<_>>();
976        assert_eq!(results, vec!["ok", "ok", "ok"]);
977    }
978
979    #[tokio::test]
980    async fn test_ipc_modules() {
981        reth_tracing::init_test_tracing();
982        let endpoint = &dummy_name();
983        let server = Builder::default().build(endpoint.clone());
984        let mut module = RpcModule::new(());
985        let msg = r#"{"admin":"1.0","debug":"1.0","engine":"1.0","eth":"1.0","ethash":"1.0","miner":"1.0","net":"1.0","rpc":"1.0","txpool":"1.0","web3":"1.0"}"#;
986        module.register_method("rpc_modules", move |_, _| msg).unwrap();
987        let handle = server.start(module).await.unwrap();
988        tokio::spawn(handle.stopped());
989
990        let mut client = TestClient::connect(endpoint).await;
991        let response = client.call("rpc_modules", json!([])).await.unwrap();
992        assert_eq!(response["result"], msg);
993    }
994
995    #[tokio::test(flavor = "multi_thread")]
996    async fn test_rpc_subscription() {
997        let endpoint = &dummy_name();
998        let server = Builder::default().build(endpoint.clone());
999        let (tx, _rx) = broadcast::channel::<usize>(16);
1000
1001        let mut module = RpcModule::new(tx.clone());
1002        std::thread::spawn(move || produce_items(tx));
1003
1004        module
1005            .register_subscription(
1006                "subscribe_hello",
1007                "s_hello",
1008                "unsubscribe_hello",
1009                |_, pending, tx| async move {
1010                    let rx = tx.subscribe();
1011                    let stream = BroadcastStream::new(rx);
1012                    pipe_from_stream_with_bounded_buffer(pending, stream).await?;
1013                    Ok(())
1014                },
1015            )
1016            .unwrap();
1017
1018        let handle = server.start(module).await.unwrap();
1019        tokio::spawn(handle.stopped());
1020
1021        let mut client = TestClient::connect(endpoint).await;
1022        let response = client.call("subscribe_hello", json!([])).await.unwrap();
1023        let sub_id = response["result"].clone();
1024
1025        for _ in 0..16 {
1026            let notification = client.recv().await.unwrap();
1027            assert_eq!(notification["method"], "s_hello");
1028            assert_eq!(notification["params"]["subscription"], sub_id);
1029            assert!(notification["params"]["result"].is_u64());
1030        }
1031    }
1032
1033    #[tokio::test(flavor = "multi_thread")]
1034    async fn test_unread_subscription_is_bounded() {
1035        let endpoint = &dummy_name();
1036        let server = Builder::default().build(endpoint.clone());
1037        let sent = Arc::new(AtomicUsize::new(0));
1038        let mut module = RpcModule::new(sent.clone());
1039        module
1040            .register_subscription(
1041                "subscribe_flood",
1042                "s_flood",
1043                "unsubscribe_flood",
1044                |_, pending, sent| async move {
1045                    let sink = pending.accept().await?;
1046                    let msg = serde_json::value::to_raw_value(&"x".repeat(1024)).unwrap();
1047                    while sink.send(msg.clone()).await.is_ok() {
1048                        sent.fetch_add(1, Ordering::Relaxed);
1049                    }
1050                    Ok(())
1051                },
1052            )
1053            .unwrap();
1054        let handle = server.start(module).await.unwrap();
1055        tokio::spawn(handle.stopped());
1056
1057        let mut client = TestClient::connect(endpoint).await;
1058        client.call("subscribe_flood", json!([])).await.unwrap();
1059
1060        // The client doesn't read, so the connection's queues fill up and the subscription stalls.
1061        tokio::time::sleep(Duration::from_millis(500)).await;
1062        let stalled = sent.load(Ordering::Relaxed);
1063        tokio::time::sleep(Duration::from_millis(200)).await;
1064        assert_eq!(sent.load(Ordering::Relaxed), stalled);
1065        assert!(stalled < 3 * MESSAGE_BUFFER_CAPACITY, "{stalled} messages queued");
1066
1067        // Reading again lets the subscription continue.
1068        tokio::time::timeout(Duration::from_secs(10), async {
1069            while sent.load(Ordering::Relaxed) == stalled {
1070                assert_eq!(client.recv().await.unwrap()["method"], "s_flood");
1071            }
1072        })
1073        .await
1074        .unwrap();
1075    }
1076
1077    #[tokio::test(flavor = "multi_thread")]
1078    async fn test_max_subscriptions_per_connection() {
1079        let endpoint = &dummy_name();
1080        let server = Builder::default().max_subscriptions_per_connection(1).build(endpoint.clone());
1081        let mut module = RpcModule::new(());
1082        module
1083            .register_subscription(
1084                "subscribe_hello",
1085                "s_hello",
1086                "unsubscribe_hello",
1087                |_, pending, _| async move {
1088                    let Ok(sink) = pending.accept().await else { return };
1089                    sink.closed().await;
1090                },
1091            )
1092            .unwrap();
1093        let handle = server.start(module).await.unwrap();
1094        tokio::spawn(handle.stopped());
1095
1096        let mut client = TestClient::connect(endpoint).await;
1097        let response = client.call("subscribe_hello", json!([])).await.unwrap();
1098        assert_eq!(error_code(&response), None, "{response}");
1099        let response = client.call("subscribe_hello", json!([])).await.unwrap();
1100        assert_eq!(error_code(&response), Some(TOO_MANY_SUBSCRIPTIONS_CODE.into()), "{response}");
1101    }
1102
1103    #[tokio::test(flavor = "multi_thread")]
1104    async fn test_oversized_subscription_response_returns_error() {
1105        let endpoint = &dummy_name();
1106        let server = Builder::default()
1107            .max_response_body_size(100)
1108            .max_subscriptions_per_connection(1)
1109            .build(endpoint.clone());
1110        let (tx, mut accepted) = mpsc::unbounded_channel();
1111        let mut module = RpcModule::new(tx);
1112        module
1113            .register_subscription(
1114                "subscribe_hello",
1115                "s_hello",
1116                "unsubscribe_hello",
1117                |_, pending, ctx| async move {
1118                    match pending.accept().await {
1119                        Ok(sink) => {
1120                            ctx.send(Ok(())).unwrap();
1121                            sink.closed().await;
1122                        }
1123                        Err(err) => ctx.send(Err(err)).unwrap(),
1124                    }
1125                },
1126            )
1127            .unwrap();
1128        let handle = server.start(module).await.unwrap();
1129        tokio::spawn(handle.stopped());
1130
1131        let mut client = TestClient::connect(endpoint).await;
1132        // The subscribe acknowledgement echoes the request id, so it does not fit into 100 bytes.
1133        let id = "a".repeat(100);
1134        client
1135            .send(json!({"jsonrpc": "2.0", "id": id, "method": "subscribe_hello", "params": []}))
1136            .await
1137            .unwrap();
1138        let response = client.recv().await.unwrap();
1139        assert_eq!(
1140            response,
1141            json!({
1142                "jsonrpc": "2.0",
1143                "id": id,
1144                "error": {
1145                    "code": OVERSIZED_RESPONSE_CODE,
1146                    "message": OVERSIZED_RESPONSE_MSG,
1147                    "data": "Exceeded max limit of 100",
1148                },
1149            })
1150        );
1151        let result = tokio::time::timeout(Duration::from_secs(5), accepted.recv()).await.unwrap();
1152        assert!(matches!(result, Some(Err(PendingSubscriptionAcceptError))), "{result:?}");
1153
1154        // The failed subscription must not keep the connection's only subscription slot.
1155        let response = client.call("subscribe_hello", json!([])).await.unwrap();
1156        assert_eq!(error_code(&response), None, "{response}");
1157        let result = tokio::time::timeout(Duration::from_secs(5), accepted.recv()).await.unwrap();
1158        assert!(matches!(result, Some(Ok(()))), "{result:?}");
1159    }
1160
1161    #[tokio::test]
1162    async fn test_rpc_middleware() {
1163        #[derive(Clone)]
1164        struct ModifyRequestIf<S>(S);
1165
1166        impl<S> RpcServiceT for ModifyRequestIf<S>
1167        where
1168            S: Send + Sync + RpcServiceT,
1169        {
1170            fn call<'a>(
1171                &self,
1172                mut req: Request<'a>,
1173            ) -> impl Future<Output = MethodResponse> + Send + 'a {
1174                // Re-direct all calls that isn't `say_hello` to `say_goodbye`
1175                if req.method == "say_hello" {
1176                    req.method = "say_goodbye".into();
1177                } else if req.method == "say_goodbye" {
1178                    req.method = "say_hello".into();
1179                }
1180
1181                self.0.call(req)
1182            }
1183
1184            fn batch<'a>(
1185                &self,
1186                mut batch: Batch<'a>,
1187            ) -> impl Future<Output = MethodResponse> + Send + 'a {
1188                for call in batch.iter_mut() {
1189                    match call {
1190                        Ok(BatchEntry::Call(req)) => {
1191                            if req.method == "say_hello" {
1192                                req.method = "say_goodbye".into();
1193                            } else if req.method == "say_goodbye" {
1194                                req.method = "say_hello".into();
1195                            }
1196                        }
1197                        Ok(BatchEntry::Notification(n)) => {
1198                            if n.method == "say_hello" {
1199                                n.method = "say_goodbye".into();
1200                            } else if n.method == "say_goodbye" {
1201                                n.method = "say_hello".into();
1202                            }
1203                        }
1204                        // Invalid request, we don't care about it.
1205                        Err(_err) => {}
1206                    }
1207                }
1208
1209                self.0.batch(batch)
1210            }
1211
1212            fn notification<'a>(
1213                &self,
1214                mut n: Notification<'a>,
1215            ) -> impl Future<Output = MethodResponse> + Send + 'a {
1216                if n.method == "say_hello" {
1217                    n.method = "say_goodbye".into();
1218                } else if n.method == "say_goodbye" {
1219                    n.method = "say_hello".into();
1220                }
1221                self.0.notification(n)
1222            }
1223        }
1224
1225        reth_tracing::init_test_tracing();
1226        let endpoint = &dummy_name();
1227
1228        let rpc_middleware = RpcServiceBuilder::new().layer_fn(ModifyRequestIf);
1229        let server = Builder::default().set_rpc_middleware(rpc_middleware).build(endpoint.clone());
1230
1231        let mut module = RpcModule::new(());
1232        let goodbye_msg = r#"{"jsonrpc":"2.0","id":1,"result":"goodbye"}"#;
1233        let hello_msg = r#"{"jsonrpc":"2.0","id":2,"result":"hello"}"#;
1234        module.register_method("say_hello", move |_, _| hello_msg).unwrap();
1235        module.register_method("say_goodbye", move |_, _| goodbye_msg).unwrap();
1236        let handle = server.start(module).await.unwrap();
1237        tokio::spawn(handle.stopped());
1238
1239        let mut client = TestClient::connect(endpoint).await;
1240        let say_hello_response = client.call("say_hello", json!([])).await.unwrap();
1241        let say_goodbye_response = client.call("say_goodbye", json!([])).await.unwrap();
1242
1243        assert_eq!(say_hello_response["result"], goodbye_msg);
1244        assert_eq!(say_goodbye_response["result"], hello_msg);
1245    }
1246
1247    #[tokio::test]
1248    #[cfg(unix)]
1249    async fn invalid_ipc_socket_permissions() {
1250        for permissions in
1251            ["not-octal", "", "0o", "888", "0o0o600", "60o00", "100000000000", "10000"]
1252        {
1253            let endpoint = dummy_name();
1254            let server = Builder::default()
1255                .set_ipc_socket_permissions(Some(permissions.to_string()))
1256                .build(endpoint.clone());
1257
1258            let error = server.start(RpcModule::new(())).await.unwrap_err();
1259            assert_eq!(error.source.kind(), io::ErrorKind::InvalidInput, "{permissions}");
1260            assert_eq!(error.endpoint, endpoint);
1261            assert!(!Path::new(&endpoint).exists());
1262        }
1263    }
1264
1265    #[tokio::test]
1266    #[cfg(unix)]
1267    async fn invalid_ipc_permissions_preserve_existing_endpoint() {
1268        for (permissions, kind) in [
1269            ("not-octal", io::ErrorKind::InvalidInput),
1270            #[cfg(target_os = "macos")]
1271            ("0600", io::ErrorKind::Unsupported),
1272        ] {
1273            let endpoint = dummy_name();
1274            let _listener = ListenerOptions::new()
1275                .name(endpoint.as_str().to_fs_name::<GenericFilePath>().unwrap())
1276                .create_tokio()
1277                .unwrap();
1278            let server = Builder::default()
1279                .set_ipc_socket_permissions(Some(permissions.to_string()))
1280                .build(endpoint.clone());
1281
1282            let error = server.start(RpcModule::new(())).await.unwrap_err();
1283            assert_eq!(error.source.kind(), kind, "{permissions}");
1284            assert_eq!(error.endpoint, endpoint);
1285            assert!(Path::new(&endpoint).exists());
1286        }
1287    }
1288
1289    #[tokio::test]
1290    #[cfg(unix)]
1291    async fn replaces_stale_ipc_endpoint() {
1292        let endpoint = dummy_name();
1293        drop(UnixListener::bind(&endpoint).unwrap());
1294        assert!(Path::new(&endpoint).exists());
1295
1296        let handle =
1297            Builder::default().build(endpoint.clone()).start(RpcModule::new(())).await.unwrap();
1298        handle.stop().unwrap();
1299        tokio::time::timeout(Duration::from_secs(5), handle.stopped()).await.unwrap();
1300    }
1301}