1use crate::{
2 chain_config::{check_and_update_chain_config, ChainConfig},
3 consts::{
4 TESTNET_RELAYER_DA_DEPLOY_HEIGHT, TESTNET_RELAYER_LISTENING_CONTRACT,
5 TESTNET_RELAYER_LOG_PAGE_SIZE, TESTNET_SERVICE_NAME, TESTNET_SYNC_BLOCK_STREAM_BUFFER_SIZE,
6 TESTNET_SYNC_HEADER_BATCH_SIZE,
7 },
8 run_opts::{DbType, RunOpts},
9 testnet::cmd::TestnetCmd,
10 util::{ask_user_keypair, ask_user_string, HumanReadableCommand, KeyPair},
11};
12use anyhow::Context;
13use forc_tracing::println_green;
14use std::{
15 net::IpAddr,
16 path::PathBuf,
17 process::{Child, Command},
18};
19
20pub(crate) async fn run(cmd: TestnetCmd, dry_run: bool) -> anyhow::Result<Option<Child>> {
23 check_and_update_chain_config(ChainConfig::Testnet).await?;
24 let keypair = if let (Some(peer_id), Some(secret)) = (
25 &cmd.connection_settings.peer_id,
26 &cmd.connection_settings.secret,
27 ) {
28 KeyPair {
29 peer_id: peer_id.clone(),
30 secret: secret.clone(),
31 }
32 } else {
33 ask_user_keypair()?
34 };
35
36 let relayer = cmd.connection_settings.relayer.unwrap_or_else(|| {
37 ask_user_string("Ethereum RPC (Sepolia) Endpoint:").expect("Failed to get RPC endpoint")
38 });
39
40 let opts = TestnetOpts {
41 keypair,
42 relayer,
43 ip: cmd.connection_settings.ip,
44 port: cmd.connection_settings.port,
45 peering_port: cmd.connection_settings.peering_port,
46 db_path: cmd.db_path,
47 bootstrap_node: cmd.bootstrap_node,
48 };
49 let run_opts = RunOpts::from(opts);
50 let params = run_opts.generate_params();
51 let mut fuel_core_command = Command::new("fuel-core");
52 fuel_core_command.arg("run");
53 fuel_core_command.args(params.as_slice());
54
55 println_green(&format!(
56 "{}",
57 HumanReadableCommand::from(&fuel_core_command)
58 ));
59
60 if dry_run {
61 return Ok(None);
62 }
63
64 let handle = fuel_core_command
66 .spawn()
67 .with_context(|| "Failed to spawn fuel-core process:".to_string())?;
68 Ok(Some(handle))
69}
70
71#[derive(Debug)]
72pub struct TestnetOpts {
73 keypair: KeyPair,
74 relayer: String,
75 ip: IpAddr,
76 port: u16,
77 peering_port: u16,
78 db_path: PathBuf,
79 bootstrap_node: String,
80}
81
82impl From<TestnetOpts> for RunOpts {
83 fn from(value: TestnetOpts) -> Self {
84 Self {
85 service_name: Some(TESTNET_SERVICE_NAME.to_string()),
86 db_type: DbType::RocksDb,
87 debug: false,
88 snapshot: ChainConfig::Testnet.into(),
89 keypair: Some(value.keypair.secret),
90 relayer: Some(value.relayer),
91 ip: Some(value.ip),
92 port: Some(value.port),
93 peering_port: Some(value.peering_port),
94 db_path: Some(value.db_path),
95 bootstrap_nodes: Some(value.bootstrap_node),
96 utxo_validation: true,
97 poa_instant: false,
98 enable_p2p: true,
99 sync_header_batch_size: Some(TESTNET_SYNC_HEADER_BATCH_SIZE),
100 enable_relayer: true,
101 relayer_listener: Some(TESTNET_RELAYER_LISTENING_CONTRACT.to_string()),
102 relayer_da_deploy_height: Some(TESTNET_RELAYER_DA_DEPLOY_HEIGHT),
103 relayer_log_page_size: Some(TESTNET_RELAYER_LOG_PAGE_SIZE),
104 sync_block_stream_buffer_size: Some(TESTNET_SYNC_BLOCK_STREAM_BUFFER_SIZE),
105 }
106 }
107}