1use 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
47const MESSAGE_BUFFER_CAPACITY: usize = 1024;
49
50pub struct IpcServer<RpcMiddleware = Identity> {
54 endpoint: String,
56 id_provider: Arc<dyn IdProvider>,
57 cfg: Settings,
58 rpc_middleware: RpcServiceBuilder<RpcMiddleware>,
59}
60
61impl<RpcMiddleware> IpcServer<RpcMiddleware> {
62 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 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 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 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 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 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 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(drop_on_completion);
240
241 while process_connection_awaiter.recv().await.is_some() {
244 }
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 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#[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#[derive(Debug, Clone)]
293struct ServiceData {
294 methods: Methods,
296 id_provider: Arc<dyn IdProvider>,
298 conn_id: usize,
300 conn_permit: Arc<ConnectionPermit>,
302 bounded_subscriptions: BoundedSubscriptions,
304 method_sink: MethodSink,
308 server_cfg: Settings,
310}
311
312#[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 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 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 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 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#[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 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#[derive(Debug, Clone)]
486pub struct Settings {
487 max_request_body_size: u32,
489 max_response_body_size: u32,
491 max_connections: u32,
493 max_subscriptions_per_connection: u32,
495 tokio_runtime: Option<tokio::runtime::Handle>,
497 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#[derive(Debug)]
516pub struct Builder<RpcMiddleware> {
517 settings: Settings,
518 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 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 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 pub const fn max_connections(mut self, max: u32) -> Self {
548 self.settings.max_connections = max;
549 self
550 }
551
552 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 pub fn custom_tokio_runtime(mut self, rt: tokio::runtime::Handle) -> Self {
562 self.settings.tokio_runtime = Some(rt);
563 self
564 }
565
566 pub fn set_ipc_socket_permissions(mut self, permissions: Option<String>) -> Self {
573 self.settings.ipc_socket_permissions = permissions;
574 self
575 }
576
577 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 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 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 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 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 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 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 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 Either::Left((_, _)) | Either::Right((None, _)) => break Ok(()),
757
758 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 if sink.send(notif).await.is_err() {
767 break Ok(());
768 }
769
770 closed = c;
771 }
772
773 Either::Right((Some(Err(e)), _)) => break Err(e.into()),
775 }
776 }
777 }
778
779 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 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 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 assert!(client3.call("anything", json!([])).await.is_none());
843
844 drop(client2);
846 tokio::time::sleep(std::time::Duration::from_millis(100)).await;
847
848 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 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 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 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 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 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 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 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 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}