1#![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
26pub mod logging;
28pub mod pubsub;
30pub mod server;
32mod macros;
34
35pub mod api_server;
36
37pub mod cmd;
39
40pub mod opts;
41
42#[macro_use]
43extern crate tracing;
44
45pub fn run() -> Result<()> {
47 setup()?;
48
49 let args = Anvil::parse();
50 args.global.init()?;
51
52 run_command(args)
53}
54
55pub 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
65pub 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 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 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 let api_handle =
149 api_server::spawn(&anvil_config, service, logging_manager, revert_manager, filters);
150
151 for addr in &anvil_config.host {
153 let sock_addr = SocketAddr::new(*addr, anvil_config.port);
154
155 let tcp_listener = tokio::net::TcpListener::bind(sock_addr).await?;
157
158 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 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 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}