agave_validator/commands/run/args/
rpc_bootstrap_config.rs

1use {
2    crate::{
3        bootstrap::RpcBootstrapConfig,
4        commands::{FromClapArgMatches, Result},
5    },
6    clap::{value_t, Arg, ArgMatches},
7    solana_genesis_utils::MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
8    std::sync::LazyLock,
9};
10
11static DEFAULT_MAX_GENESIS_ARCHIVE_UNPACKED_SIZE: LazyLock<String> =
12    LazyLock::new(|| MAX_GENESIS_ARCHIVE_UNPACKED_SIZE.to_string());
13
14#[cfg(test)]
15impl Default for RpcBootstrapConfig {
16    fn default() -> Self {
17        Self {
18            no_genesis_fetch: false,
19            no_snapshot_fetch: false,
20            check_vote_account: None,
21            only_known_rpc: false,
22            max_genesis_archive_unpacked_size: 10485760,
23            incremental_snapshot_fetch: true,
24        }
25    }
26}
27
28impl FromClapArgMatches for RpcBootstrapConfig {
29    fn from_clap_arg_match(matches: &ArgMatches) -> Result<Self> {
30        let no_genesis_fetch = matches.is_present("no_genesis_fetch");
31
32        let no_snapshot_fetch = matches.is_present("no_snapshot_fetch");
33
34        let check_vote_account = matches
35            .value_of("check_vote_account")
36            .map(|url| url.to_string());
37
38        let only_known_rpc = matches.is_present("only_known_rpc");
39
40        let max_genesis_archive_unpacked_size =
41            value_t!(matches, "max_genesis_archive_unpacked_size", u64).map_err(|err| {
42                Box::<dyn std::error::Error>::from(format!(
43                    "failed to parse max_genesis_archive_unpacked_size: {err}"
44                ))
45            })?;
46
47        let no_incremental_snapshots = matches.is_present("no_incremental_snapshots");
48
49        Ok(Self {
50            no_genesis_fetch,
51            no_snapshot_fetch,
52            check_vote_account,
53            only_known_rpc,
54            max_genesis_archive_unpacked_size,
55            incremental_snapshot_fetch: !no_incremental_snapshots,
56        })
57    }
58}
59
60pub(crate) fn args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
61    vec![
62        Arg::with_name("no_genesis_fetch")
63            .long("no-genesis-fetch")
64            .takes_value(false)
65            .help("Do not fetch genesis from the cluster"),
66        Arg::with_name("no_snapshot_fetch")
67            .long("no-snapshot-fetch")
68            .takes_value(false)
69            .help(
70                "Do not attempt to fetch a snapshot from the cluster, start from a local snapshot \
71                 if present",
72            ),
73        Arg::with_name("check_vote_account")
74            .long("check-vote-account")
75            .takes_value(true)
76            .value_name("RPC_URL")
77            .requires("entrypoint")
78            .conflicts_with_all(&["no_voting"])
79            .help(
80                "Sanity check vote account state at startup. The JSON RPC endpoint at RPC_URL \
81                 must expose `--full-rpc-api`",
82            ),
83        Arg::with_name("only_known_rpc")
84            .alias("no-untrusted-rpc")
85            .long("only-known-rpc")
86            .takes_value(false)
87            .requires("known_validators")
88            .help("Use the RPC service of known validators only"),
89        Arg::with_name("max_genesis_archive_unpacked_size")
90            .long("max-genesis-archive-unpacked-size")
91            .value_name("NUMBER")
92            .takes_value(true)
93            .default_value(&DEFAULT_MAX_GENESIS_ARCHIVE_UNPACKED_SIZE)
94            .help("maximum total uncompressed file size of downloaded genesis archive"),
95        Arg::with_name("no_incremental_snapshots")
96            .long("no-incremental-snapshots")
97            .takes_value(false)
98            .help("Disable incremental snapshots"),
99    ]
100}
101
102#[cfg(test)]
103mod tests {
104    use {
105        super::*,
106        crate::commands::run::args::{
107            tests::verify_args_struct_by_command_run_with_identity_setup, RunArgs,
108        },
109        solana_pubkey::Pubkey,
110        std::{
111            collections::HashSet,
112            net::{IpAddr, Ipv4Addr, SocketAddr},
113        },
114    };
115
116    #[test]
117    fn verify_args_struct_by_command_run_with_no_genesis_fetch() {
118        // long arg
119        {
120            let default_run_args = RunArgs::default();
121            let expected_args = RunArgs {
122                rpc_bootstrap_config: RpcBootstrapConfig {
123                    no_genesis_fetch: true,
124                    ..RpcBootstrapConfig::default()
125                },
126                ..default_run_args.clone()
127            };
128            verify_args_struct_by_command_run_with_identity_setup(
129                default_run_args.clone(),
130                vec!["--no-genesis-fetch"],
131                expected_args,
132            );
133        }
134    }
135
136    #[test]
137    fn verify_args_struct_by_command_run_with_no_snapshot_fetch() {
138        // long arg
139        {
140            let default_run_args = RunArgs::default();
141            let expected_args = RunArgs {
142                rpc_bootstrap_config: RpcBootstrapConfig {
143                    no_snapshot_fetch: true,
144                    ..RpcBootstrapConfig::default()
145                },
146                ..default_run_args.clone()
147            };
148            verify_args_struct_by_command_run_with_identity_setup(
149                default_run_args.clone(),
150                vec!["--no-snapshot-fetch"],
151                expected_args,
152            );
153        }
154    }
155
156    #[test]
157    fn verify_args_struct_by_command_run_with_check_vote_account() {
158        // long arg
159        {
160            let default_run_args = RunArgs::default();
161            let expected_args = RunArgs {
162                entrypoints: vec![SocketAddr::new(
163                    IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
164                    8000,
165                )],
166                rpc_bootstrap_config: RpcBootstrapConfig {
167                    check_vote_account: Some("https://api.mainnet-beta.solana.com".to_string()),
168                    ..RpcBootstrapConfig::default()
169                },
170                ..default_run_args.clone()
171            };
172            verify_args_struct_by_command_run_with_identity_setup(
173                default_run_args,
174                vec![
175                    // required by --check-vote-account
176                    "--entrypoint",
177                    "127.0.0.1:8000",
178                    "--check-vote-account",
179                    "https://api.mainnet-beta.solana.com",
180                ],
181                expected_args,
182            );
183        }
184    }
185
186    #[test]
187    fn verify_args_struct_by_command_run_with_only_known_rpc() {
188        // long arg
189        {
190            let default_run_args = RunArgs::default();
191            let known_validators_pubkey = Pubkey::new_unique();
192            let known_validators = Some(HashSet::from([known_validators_pubkey]));
193            let expected_args = RunArgs {
194                known_validators,
195                rpc_bootstrap_config: RpcBootstrapConfig {
196                    only_known_rpc: true,
197                    ..RpcBootstrapConfig::default()
198                },
199                ..default_run_args.clone()
200            };
201            verify_args_struct_by_command_run_with_identity_setup(
202                default_run_args,
203                vec![
204                    // required by --only-known-rpc
205                    "--known-validator",
206                    &known_validators_pubkey.to_string(),
207                    "--only-known-rpc",
208                ],
209                expected_args,
210            );
211        }
212
213        // alias
214        {
215            let default_run_args = RunArgs::default();
216            let known_validators_pubkey = Pubkey::new_unique();
217            let known_validators = Some(HashSet::from([known_validators_pubkey]));
218            let expected_args = RunArgs {
219                known_validators,
220                rpc_bootstrap_config: RpcBootstrapConfig {
221                    only_known_rpc: true,
222                    ..RpcBootstrapConfig::default()
223                },
224                ..default_run_args.clone()
225            };
226            verify_args_struct_by_command_run_with_identity_setup(
227                default_run_args,
228                vec![
229                    // required by --no-untrusted-rpc
230                    "--known-validator",
231                    &known_validators_pubkey.to_string(),
232                    "--no-untrusted-rpc",
233                ],
234                expected_args,
235            );
236        }
237    }
238
239    #[test]
240    fn verify_args_struct_by_command_run_with_incremental_snapshot_fetch() {
241        // long arg
242        {
243            let default_run_args = RunArgs::default();
244            let expected_args = RunArgs {
245                rpc_bootstrap_config: RpcBootstrapConfig {
246                    incremental_snapshot_fetch: false,
247                    ..RpcBootstrapConfig::default()
248                },
249                ..default_run_args.clone()
250            };
251            verify_args_struct_by_command_run_with_identity_setup(
252                default_run_args,
253                vec!["--no-incremental-snapshots"],
254                expected_args,
255            );
256        }
257    }
258
259    #[test]
260    fn test_default_max_genesis_archive_unpacked_size_unchanged() {
261        assert_eq!(
262            *DEFAULT_MAX_GENESIS_ARCHIVE_UNPACKED_SIZE,
263            (10 * 1024 * 1024).to_string()
264        );
265    }
266}