Skip to main content

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