anvil/server/
mod.rs

1//! This module provides the infrastructure to launch an Ethereum JSON-RPC server
2//! (via HTTP, WebSocket, and IPC) and Beacon Node REST API.
3
4use crate::{EthApi, IpcTask};
5use anvil_server::{ServerConfig, ipc::IpcEndpoint};
6use axum::Router;
7use futures::StreamExt;
8use rpc_handlers::{HttpEthRpcHandler, PubSubEthRpcHandler};
9use std::{io, net::SocketAddr, pin::pin};
10use tokio::net::TcpListener;
11
12mod beacon;
13mod rpc_handlers;
14
15/// Configures a server that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.
16///
17/// The returned future creates a new server, binding it to the given address, which returns another
18/// future that runs it.
19pub async fn serve(
20    addr: SocketAddr,
21    api: EthApi,
22    config: ServerConfig,
23) -> io::Result<impl Future<Output = io::Result<()>>> {
24    let tcp_listener = TcpListener::bind(addr).await?;
25    Ok(serve_on(tcp_listener, api, config))
26}
27
28/// Configures a server that handles [`EthApi`] related JSON-RPC calls via HTTP and WS.
29pub async fn serve_on(
30    tcp_listener: TcpListener,
31    api: EthApi,
32    config: ServerConfig,
33) -> io::Result<()> {
34    axum::serve(tcp_listener, router(api, config).into_make_service()).await
35}
36
37/// Configures an [`axum::Router`] that handles [`EthApi`] related JSON-RPC calls via HTTP and WS,
38/// and Beacon REST API calls.
39pub fn router(api: EthApi, config: ServerConfig) -> Router {
40    let http = HttpEthRpcHandler::new(api.clone());
41    let ws = PubSubEthRpcHandler::new(api.clone());
42
43    // JSON-RPC router
44    let rpc_router = anvil_server::http_ws_router(config, http, ws);
45
46    // Beacon REST API router
47    let beacon_router = beacon::router(api);
48
49    // Merge the routers
50    rpc_router.merge(beacon_router)
51}
52
53/// Launches an ipc server at the given path in a new task
54///
55/// # Panics
56///
57/// Panics if setting up the IPC connection was unsuccessful.
58#[track_caller]
59pub fn spawn_ipc(api: EthApi, path: String) -> IpcTask {
60    try_spawn_ipc(api, path).expect("failed to establish ipc connection")
61}
62
63/// Launches an ipc server at the given path in a new task.
64pub fn try_spawn_ipc(api: EthApi, path: String) -> io::Result<IpcTask> {
65    let handler = PubSubEthRpcHandler::new(api);
66    let ipc = IpcEndpoint::new(handler, path);
67    let incoming = ipc.incoming()?;
68
69    let task = tokio::task::spawn(async move {
70        let mut incoming = pin!(incoming);
71        while let Some(stream) = incoming.next().await {
72            trace!(target: "ipc", "new ipc connection");
73            tokio::task::spawn(stream);
74        }
75    });
76
77    Ok(task)
78}