Skip to main content

anvil_polkadot/
lib.rs

1//! Anvil is a fast local Ethereum development node.
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5use crate::{
6    api_server::{ApiHandle, filters::Filters},
7    config::AnvilNodeConfig,
8    logging::{LoggingManager, NodeLogLayer},
9    substrate_node::{genesis::GenesisConfig, revert::RevertManager, service::Service},
10};
11use clap::{CommandFactory, Parser};
12use eyre::Result;
13use foundry_cli::utils;
14use opts::{Anvil, AnvilSubcommand};
15use polkadot_sdk::{
16    sc_cli::{self, SubstrateCli, build_runtime},
17    sc_service::{self, TaskManager},
18};
19use server::try_spawn_ipc;
20use std::net::SocketAddr;
21
22pub mod substrate_node;
23
24pub mod config;
25
26/// commandline output
27pub mod logging;
28/// types for subscriptions
29pub mod pubsub;
30/// axum RPC server implementations
31pub mod server;
32//node_info
33mod macros;
34
35pub mod api_server;
36
37/// contains cli command
38pub mod cmd;
39
40pub mod opts;
41
42#[macro_use]
43extern crate tracing;
44
45/// Run the `anvil` command line interface.
46pub fn run() -> Result<()> {
47    setup()?;
48
49    let args = Anvil::parse();
50    args.global.init()?;
51
52    run_command(args)
53}
54
55/// Setup the panic handler and other utilities.
56pub fn setup() -> Result<()> {
57    utils::install_crypto_provider();
58    foundry_cli::handler::install();
59    utils::load_dotenv();
60    utils::enable_paint();
61
62    Ok(())
63}
64
65/// Run the subcommand.
66pub fn run_command(args: Anvil) -> Result<()> {
67    if let Some(cmd) = &args.cmd {
68        match cmd {
69            AnvilSubcommand::Completions { shell } => {
70                clap_complete::generate(
71                    *shell,
72                    &mut Anvil::command(),
73                    "anvil-polkadot",
74                    &mut std::io::stdout(),
75                );
76            }
77            AnvilSubcommand::GenerateFigSpec => clap_complete::generate(
78                clap_complete_fig::Fig,
79                &mut Anvil::command(),
80                "anvil-polkadot",
81                &mut std::io::stdout(),
82            ),
83        }
84        return Ok(());
85    }
86
87    let (anvil_config, substrate_config) = args.node.into_node_config()?;
88
89    let substrate_client = opts::SubstrateCli::new(GenesisConfig::from(&anvil_config));
90
91    let tokio_runtime = build_runtime()?;
92
93    let signals = tokio_runtime.block_on(async { sc_cli::Signals::capture() })?;
94    let config =
95        substrate_client.create_configuration(&substrate_config, tokio_runtime.handle().clone())?;
96    let logging_manager = if anvil_config.enable_tracing {
97        init_tracing(anvil_config.silent)
98    } else {
99        LoggingManager::default()
100    };
101
102    let runner: sc_cli::Runner<opts::SubstrateCli> =
103        sc_cli::Runner::new(config, tokio_runtime, signals)?;
104    let filters = Filters::default();
105
106    Ok(runner.run_node_until_exit(|config| async move {
107        let (_service, task_manager, ..) =
108            spawn(anvil_config, config, logging_manager, filters).await?;
109        Ok::<TaskManager, sc_cli::Error>(task_manager)
110    })?)
111}
112
113pub async fn spawn(
114    anvil_config: AnvilNodeConfig,
115    substrate_config: sc_service::Configuration,
116    logging_manager: LoggingManager,
117    filters: Filters,
118) -> Result<(Service, TaskManager, ApiHandle), sc_cli::Error> {
119    // Spawn the substrate node.
120    let (substrate_service, task_manager) =
121        substrate_node::service::new(&anvil_config, substrate_config)
122            .map_err(sc_cli::Error::Service)?;
123    let revert_manager =
124        RevertManager::new(substrate_service.client.clone(), substrate_service.backend.clone());
125
126    // Spawn the other tasks.
127    let api_handle = spawn_anvil_tasks(
128        anvil_config,
129        &substrate_service,
130        logging_manager,
131        revert_manager,
132        filters,
133    )
134    .await
135    .map_err(|err| sc_cli::Error::Application(err.into()))?;
136
137    Ok((substrate_service, task_manager, api_handle))
138}
139
140pub async fn spawn_anvil_tasks(
141    anvil_config: AnvilNodeConfig,
142    service: &Service,
143    logging_manager: LoggingManager,
144    revert_manager: RevertManager,
145    filters: Filters,
146) -> Result<ApiHandle> {
147    // Spawn the api server.
148    let api_handle =
149        api_server::spawn(&anvil_config, service, logging_manager, revert_manager, filters);
150
151    // Spawn the network servers.
152    for addr in &anvil_config.host {
153        let sock_addr = SocketAddr::new(*addr, anvil_config.port);
154
155        // Create a TCP listener.
156        let tcp_listener = tokio::net::TcpListener::bind(sock_addr).await?;
157
158        // Spawn the server future on a new task.
159        let srv =
160            server::serve_on(tcp_listener, anvil_config.server_config.clone(), api_handle.clone());
161        service
162            .spawn_handle
163            .spawn("anvil", "anvil-tcp", async move { srv.await.expect("TCP server failure") });
164    }
165
166    // If configured, spawn the IPC server.
167    anvil_config
168        .get_ipc_path()
169        .map(|path| try_spawn_ipc(&service.spawn_handle, path, api_handle.clone()))
170        .transpose()?;
171
172    anvil_config.print()?;
173
174    Ok(api_handle)
175}
176
177pub fn init_tracing(silent: bool) -> LoggingManager {
178    use tracing_subscriber::prelude::*;
179
180    let manager = LoggingManager::default();
181    manager.set_enabled(!silent);
182
183    let env_filter = if !silent && std::env::var("RUST_LOG").is_ok() {
184        tracing_subscriber::EnvFilter::from_default_env()
185    } else {
186        tracing_subscriber::EnvFilter::new("warn,node=debug")
187    };
188
189    let _ = if std::env::var("RUST_LOG").is_ok() {
190        tracing_subscriber::Registry::default()
191            .with(env_filter)
192            .with(tracing_subscriber::fmt::layer())
193            .try_init()
194    } else {
195        // Default filter: show substrate warnings/errors and our node targets
196        tracing_subscriber::Registry::default()
197            .with(env_filter)
198            .with(NodeLogLayer::new(manager.clone()))
199            .with(
200                tracing_subscriber::fmt::layer()
201                    .without_time()
202                    .with_target(false)
203                    .with_level(false),
204            )
205            .try_init()
206    };
207
208    manager
209}