hermes_cli_components/impls/commands/bootstrap/
chain.rs1use core::marker::PhantomData;
2use std::path::PathBuf;
3
4use cgp::prelude::*;
5use hermes_error::traits::wrap::CanWrapError;
6use hermes_logging_components::traits::has_logger::HasLogger;
7use hermes_logging_components::traits::logger::CanLog;
8use hermes_logging_components::types::level::LevelInfo;
9use hermes_relayer_components::chain::traits::types::chain_id::HasChainId;
10use hermes_runtime_components::traits::fs::file_path::HasFilePathType;
11use hermes_runtime_components::traits::os::child_process::CanWaitChildProcess;
12use hermes_runtime_components::traits::runtime::HasRuntime;
13use hermes_test_components::bootstrap::traits::chain::CanBootstrapChain;
14use hermes_test_components::chain_driver::traits::chain_process::CanTakeChainProcess;
15use hermes_test_components::chain_driver::traits::config::CanUpdateConfig;
16use hermes_test_components::chain_driver::traits::types::chain::HasChain;
17
18use crate::traits::bootstrap::CanLoadBootstrap;
19use crate::traits::command::CommandRunner;
20use crate::traits::config::config_path::HasConfigPath;
21use crate::traits::config::load_config::CanLoadConfig;
22use crate::traits::config::write_config::CanWriteConfig;
23use crate::traits::output::CanProduceOutput;
24
25pub struct RunBootstrapChainCommand;
26
27impl<App, Args, Bootstrap, ChainDriver, Chain, Runtime> CommandRunner<App, Args>
28 for RunBootstrapChainCommand
29where
30 App: HasLogger
31 + CanProduceOutput<()>
32 + CanLoadBootstrap<Args, Bootstrap = Bootstrap>
33 + HasConfigPath
34 + CanLoadConfig
35 + CanWriteConfig
36 + CanRaiseError<Bootstrap::Error>
37 + CanRaiseError<Runtime::Error>
38 + CanRaiseError<ChainDriver::Error>
39 + CanWrapError<&'static str>,
40 Bootstrap: CanBootstrapChain<ChainDriver = ChainDriver>,
41 ChainDriver: HasChain<Chain = Chain>
42 + HasRuntime<Runtime = Runtime>
43 + CanTakeChainProcess
44 + CanUpdateConfig<App::Config>,
45 Chain: HasChainId,
46 Runtime: CanWaitChildProcess + HasFilePathType<FilePath = PathBuf>,
47 Args: Async + HasField<symbol!("chain_id"), Field = String>,
48 App::Logger: CanLog<LevelInfo>,
49{
50 async fn run_command(app: &App, args: &Args) -> Result<App::Output, App::Error> {
51 let logger = app.logger();
52 let chain_id = args.get_field(PhantomData);
53
54 let mut config = app.load_config().await?;
55 let bootstrap = app.load_bootstrap(args).await?;
56
57 let chain_driver = bootstrap
58 .bootstrap_chain(chain_id)
59 .await
60 .map_err(App::raise_error)?;
61
62 let chain = chain_driver.chain();
63
64 logger
65 .log(
66 &format!(
67 "Bootstrapped a new chain with chain ID: {}",
68 chain.chain_id()
69 ),
70 &LevelInfo,
71 )
72 .await;
73
74 let chain_config = chain_driver
75 .update_config(&mut config)
76 .map_err(App::raise_error)?;
77
78 app.write_config(&config).await?;
79
80 logger
81 .log(
82 &format!(
83 "Added the following chain config to the main config file:\n{}",
84 chain_config
85 ),
86 &LevelInfo,
87 )
88 .await;
89
90 let m_chain_process = chain_driver.take_chain_process().await;
91
92 if let Some(chain_process) = m_chain_process {
93 logger.log(&format!("running chain {} running in the background. Press Ctrl+C to stop then chain...", chain.chain_id()), &LevelInfo).await;
94
95 Runtime::wait_child_process(chain_process)
96 .await
97 .map_err(|e| {
98 App::wrap_error("chain process exited with error", App::raise_error(e))
99 })?;
100
101 logger
102 .log("chain process exited with no error", &LevelInfo)
103 .await;
104 }
105
106 Ok(app.produce_output(()))
107 }
108}