Skip to main content

sui_swarm_config/
node_config_builder.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::net::SocketAddr;
5use std::path::PathBuf;
6use std::time::Duration;
7
8use consensus_config::{ObserverParameters, Parameters as ConsensusParameters};
9use fastcrypto::encoding::{Encoding, Hex};
10use fastcrypto::traits::KeyPair;
11use sui_config::node::{
12    AuthorityKeyPairWithPath, AuthorityOverloadConfig, AuthorityStorePruningConfig,
13    CheckpointExecutorConfig, DBCheckpointConfig, DEFAULT_GRPC_CONCURRENCY_LIMIT,
14    ExecutionCacheConfig, ExecutionTimeObserverConfig, ExpensiveSafetyCheckConfig,
15    FundsWithdrawSchedulerType, Genesis, KeyPairWithPath, StateSnapshotConfig,
16    default_enable_index_processing, default_end_of_epoch_broadcast_channel_capacity,
17};
18use sui_config::node::{RunWithRange, TransactionDriverConfig, default_zklogin_oauth_providers};
19use sui_config::p2p::{P2pConfig, SeedPeer, StateSyncConfig};
20use sui_config::transaction_deny_config::PeerDenySyncConfig;
21use sui_config::verifier_signing_config::VerifierSigningConfig;
22use sui_config::{
23    AUTHORITIES_DB_NAME, CONSENSUS_DB_NAME, ConsensusConfig, FULL_NODE_DB_PATH, NodeConfig,
24    local_ip_utils,
25};
26use sui_protocol_config::Chain;
27use sui_types::crypto::{AuthorityKeyPair, AuthorityPublicKeyBytes, NetworkKeyPair, SuiKeyPair};
28use sui_types::multiaddr::Multiaddr;
29use sui_types::node_role::FullNodeSyncMode;
30use sui_types::supported_protocol_versions::SupportedProtocolVersions;
31use sui_types::traffic_control::{PolicyConfig, RemoteFirewallConfig};
32
33use crate::genesis_config::{ValidatorGenesisConfig, ValidatorGenesisConfigBuilder};
34use crate::network_config::NetworkConfig;
35
36/// This builder contains information that's not included in ValidatorGenesisConfig for building
37/// a validator NodeConfig. It can be used to build either a genesis validator or a new validator.
38#[derive(Clone, Default)]
39pub struct ValidatorConfigBuilder {
40    config_directory: Option<PathBuf>,
41    supported_protocol_versions: Option<SupportedProtocolVersions>,
42    force_unpruned_checkpoints: bool,
43    jwk_fetch_interval: Option<Duration>,
44    authority_overload_config: Option<AuthorityOverloadConfig>,
45    execution_cache_config: Option<ExecutionCacheConfig>,
46    data_ingestion_dir: Option<PathBuf>,
47    policy_config: Option<PolicyConfig>,
48    firewall_config: Option<RemoteFirewallConfig>,
49    global_state_hash_v2: bool,
50    funds_withdraw_scheduler_type: FundsWithdrawSchedulerType,
51    execution_time_observer_config: Option<ExecutionTimeObserverConfig>,
52    chain_override: Option<Chain>,
53    state_sync_config: Option<StateSyncConfig>,
54    observer_config: Option<ObserverParameters>,
55    peer_deny_sync_config: Option<PeerDenySyncConfig>,
56}
57
58impl ValidatorConfigBuilder {
59    pub fn new() -> Self {
60        Self {
61            global_state_hash_v2: true,
62            ..Default::default()
63        }
64    }
65
66    pub fn with_chain_override(mut self, chain: Chain) -> Self {
67        assert!(self.chain_override.is_none(), "Chain override already set");
68        self.chain_override = Some(chain);
69        self
70    }
71
72    pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
73        assert!(self.config_directory.is_none());
74        self.config_directory = Some(config_directory);
75        self
76    }
77
78    pub fn with_supported_protocol_versions(
79        mut self,
80        supported_protocol_versions: SupportedProtocolVersions,
81    ) -> Self {
82        assert!(self.supported_protocol_versions.is_none());
83        self.supported_protocol_versions = Some(supported_protocol_versions);
84        self
85    }
86
87    pub fn with_unpruned_checkpoints(mut self) -> Self {
88        self.force_unpruned_checkpoints = true;
89        self
90    }
91
92    pub fn with_jwk_fetch_interval(mut self, i: Duration) -> Self {
93        self.jwk_fetch_interval = Some(i);
94        self
95    }
96
97    pub fn with_authority_overload_config(mut self, config: AuthorityOverloadConfig) -> Self {
98        self.authority_overload_config = Some(config);
99        self
100    }
101
102    pub fn with_execution_cache_config(mut self, config: ExecutionCacheConfig) -> Self {
103        self.execution_cache_config = Some(config);
104        self
105    }
106
107    pub fn with_data_ingestion_dir(mut self, path: PathBuf) -> Self {
108        self.data_ingestion_dir = Some(path);
109        self
110    }
111
112    pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
113        self.policy_config = config;
114        self
115    }
116
117    pub fn with_firewall_config(mut self, config: Option<RemoteFirewallConfig>) -> Self {
118        self.firewall_config = config;
119        self
120    }
121
122    pub fn with_global_state_hash_v2_enabled(mut self, enabled: bool) -> Self {
123        self.global_state_hash_v2 = enabled;
124        self
125    }
126
127    pub fn with_funds_withdraw_scheduler_type(
128        mut self,
129        scheduler_type: FundsWithdrawSchedulerType,
130    ) -> Self {
131        self.funds_withdraw_scheduler_type = scheduler_type;
132        self
133    }
134
135    pub fn with_execution_time_observer_config(
136        mut self,
137        config: ExecutionTimeObserverConfig,
138    ) -> Self {
139        self.execution_time_observer_config = Some(config);
140        self
141    }
142
143    pub fn with_state_sync_config(mut self, config: StateSyncConfig) -> Self {
144        self.state_sync_config = Some(config);
145        self
146    }
147
148    pub fn with_observer_config(mut self, config: ObserverParameters) -> Self {
149        self.observer_config = Some(config);
150        self
151    }
152
153    pub fn with_peer_deny_sync_config(mut self, config: PeerDenySyncConfig) -> Self {
154        self.peer_deny_sync_config = Some(config);
155        self
156    }
157
158    pub fn build(
159        self,
160        validator: ValidatorGenesisConfig,
161        genesis: sui_config::genesis::Genesis,
162    ) -> NodeConfig {
163        let key_path = get_key_path(&validator.key_pair);
164        let config_directory = self
165            .config_directory
166            .unwrap_or_else(|| mysten_common::tempdir().unwrap().keep());
167        let db_path = config_directory
168            .join(AUTHORITIES_DB_NAME)
169            .join(key_path.clone());
170
171        let network_address = validator.network_address;
172        let consensus_db_path = config_directory.join(CONSENSUS_DB_NAME).join(key_path);
173        let localhost = local_ip_utils::localhost_for_testing();
174        let parameters = self
175            .observer_config
176            .map(|observer_config| ConsensusParameters {
177                observer: ObserverParameters {
178                    server_port: observer_config
179                        .server_port
180                        .or_else(|| Some(local_ip_utils::get_available_port(&localhost))),
181                    allowlist: observer_config.allowlist,
182                    peers: observer_config.peers,
183                },
184                ..Default::default()
185            });
186        let consensus_config = ConsensusConfig {
187            db_path: consensus_db_path,
188            db_retention_epochs: None,
189            db_pruner_period_secs: None,
190            max_pending_transactions: None,
191            parameters,
192            listen_address: None,
193            external_address: None,
194        };
195
196        let p2p_config = P2pConfig {
197            listen_address: validator.p2p_listen_address.unwrap_or_else(|| {
198                validator
199                    .p2p_address
200                    .udp_multiaddr_to_listen_address()
201                    .unwrap()
202            }),
203            external_address: Some(validator.p2p_address),
204            // Set a shorter timeout for checkpoint content download in tests, since
205            // checkpoint pruning also happens much faster, and network is local.
206            state_sync: Some(if let Some(mut config) = self.state_sync_config {
207                if config.checkpoint_content_timeout_ms.is_none() {
208                    config.checkpoint_content_timeout_ms = Some(10_000);
209                }
210                config
211            } else {
212                StateSyncConfig {
213                    checkpoint_content_timeout_ms: Some(10_000),
214                    ..Default::default()
215                }
216            }),
217            ..Default::default()
218        };
219
220        let mut pruning_config = AuthorityStorePruningConfig::default();
221        if self.force_unpruned_checkpoints {
222            pruning_config.set_num_epochs_to_retain_for_checkpoints(None);
223        }
224        let pruning_config = pruning_config;
225        let checkpoint_executor_config = CheckpointExecutorConfig {
226            data_ingestion_dir: self.data_ingestion_dir,
227            ..Default::default()
228        };
229
230        NodeConfig {
231            recent_submission_dedup_window_ms: None,
232            address_prober: None,
233            protocol_key_pair: AuthorityKeyPairWithPath::new(validator.key_pair),
234            network_key_pair: KeyPairWithPath::new(SuiKeyPair::Ed25519(validator.network_key_pair)),
235            account_key_pair: KeyPairWithPath::new(validator.account_key_pair),
236            worker_key_pair: KeyPairWithPath::new(SuiKeyPair::Ed25519(validator.worker_key_pair)),
237            db_path,
238            network_address,
239            metrics_address: validator.metrics_address,
240            admin_interface_port: local_ip_utils::get_available_port(&localhost),
241            json_rpc_address: local_ip_utils::new_tcp_address_for_testing(&localhost)
242                .to_socket_addr()
243                .unwrap(),
244            consensus_config: Some(consensus_config),
245            fullnode_sync_mode: None,
246            remove_deprecated_tables: false,
247            enable_index_processing: default_enable_index_processing(),
248            sync_post_process_one_tx: false,
249            genesis: sui_config::node::Genesis::new(genesis),
250            grpc_load_shed: None,
251            grpc_concurrency_limit: Some(DEFAULT_GRPC_CONCURRENCY_LIMIT),
252            p2p_config,
253            authority_store_pruning_config: pruning_config,
254            end_of_epoch_broadcast_channel_capacity:
255                default_end_of_epoch_broadcast_channel_capacity(),
256            checkpoint_executor_config,
257            metrics: None,
258            supported_protocol_versions: self.supported_protocol_versions,
259            db_checkpoint_config: Default::default(),
260            // By default, expensive checks will be enabled in debug build, but not in release build.
261            expensive_safety_check_config: ExpensiveSafetyCheckConfig::default(),
262            name_service_package_address: None,
263            name_service_registry_id: None,
264            name_service_reverse_registry_id: None,
265            transaction_deny_config: Default::default(),
266            peer_deny_sync_config: self.peer_deny_sync_config.unwrap_or_default(),
267            dev_inspect_disabled: false,
268            certificate_deny_config: Default::default(),
269            state_debug_dump_config: Default::default(),
270            state_archive_read_config: vec![],
271            state_snapshot_write_config: StateSnapshotConfig::default(),
272            indexer_max_subscriptions: Default::default(),
273            transaction_kv_store_read_config: Default::default(),
274            transaction_kv_store_write_config: None,
275            rpc: Some(sui_rpc_api::Config {
276                ..Default::default()
277            }),
278            jwk_fetch_interval_seconds: self
279                .jwk_fetch_interval
280                .map(|i| i.as_secs())
281                .unwrap_or(3600),
282            zklogin_oauth_providers: default_zklogin_oauth_providers(),
283            authority_overload_config: self.authority_overload_config.unwrap_or_default(),
284            execution_cache: self.execution_cache_config.unwrap_or_default(),
285            run_with_range: None,
286            jsonrpc_server_type: None,
287            disable_json_rpc: false,
288            policy_config: self.policy_config,
289            firewall_config: self.firewall_config,
290            state_accumulator_v2: self.global_state_hash_v2,
291            funds_withdraw_scheduler_type: self.funds_withdraw_scheduler_type,
292            enable_soft_bundle: true,
293            verifier_signing_config: VerifierSigningConfig::default(),
294            enable_db_write_stall: None,
295            enable_db_sync_to_disk: None,
296            execution_time_observer_config: self.execution_time_observer_config,
297            chain_override_for_testing: self.chain_override,
298            validator_client_monitor_config: None,
299            fork_recovery: None,
300            transaction_driver_config: Some(TransactionDriverConfig::default()),
301            congestion_log: None,
302        }
303    }
304
305    pub fn build_new_validator<R: rand::RngCore + rand::CryptoRng>(
306        self,
307        rng: &mut R,
308        network_config: &NetworkConfig,
309    ) -> NodeConfig {
310        let validator_config = ValidatorGenesisConfigBuilder::new().build(rng);
311        self.build(validator_config, network_config.genesis.clone())
312    }
313}
314
315#[derive(Clone, Debug, Default)]
316pub struct FullnodeConfigBuilder {
317    config_directory: Option<PathBuf>,
318    // port for json rpc api
319    rpc_port: Option<u16>,
320    rpc_addr: Option<SocketAddr>,
321    supported_protocol_versions: Option<SupportedProtocolVersions>,
322    db_checkpoint_config: Option<DBCheckpointConfig>,
323    expensive_safety_check_config: Option<ExpensiveSafetyCheckConfig>,
324    db_path: Option<PathBuf>,
325    network_address: Option<Multiaddr>,
326    json_rpc_address: Option<SocketAddr>,
327    metrics_address: Option<SocketAddr>,
328    admin_interface_port: Option<u16>,
329    genesis: Option<Genesis>,
330    p2p_external_address: Option<Multiaddr>,
331    p2p_listen_address: Option<SocketAddr>,
332    network_key_pair: Option<KeyPairWithPath>,
333    run_with_range: Option<RunWithRange>,
334    policy_config: Option<PolicyConfig>,
335    fw_config: Option<RemoteFirewallConfig>,
336    data_ingestion_dir: Option<PathBuf>,
337    disable_pruning: bool,
338    disable_json_rpc: bool,
339    sync_post_process_one_tx: bool,
340    chain_override: Option<Chain>,
341    transaction_driver_config: Option<TransactionDriverConfig>,
342    rpc_config: Option<sui_config::RpcConfig>,
343    state_sync_config: Option<StateSyncConfig>,
344    observer_config: Option<ObserverParameters>,
345}
346
347impl FullnodeConfigBuilder {
348    pub fn new() -> Self {
349        Self::default()
350    }
351
352    pub fn with_chain_override(mut self, chain: Chain) -> Self {
353        assert!(self.chain_override.is_none(), "Chain override already set");
354        self.chain_override = Some(chain);
355        self
356    }
357
358    pub fn with_config_directory(mut self, config_directory: PathBuf) -> Self {
359        self.config_directory = Some(config_directory);
360        self
361    }
362
363    pub fn with_rpc_port(mut self, port: u16) -> Self {
364        assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
365        self.rpc_port = Some(port);
366        self
367    }
368
369    pub fn with_rpc_addr(mut self, addr: SocketAddr) -> Self {
370        assert!(self.rpc_addr.is_none() && self.rpc_port.is_none());
371        self.rpc_addr = Some(addr);
372        self
373    }
374
375    pub fn with_rpc_config(mut self, rpc_config: sui_config::RpcConfig) -> Self {
376        self.rpc_config = Some(rpc_config);
377        self
378    }
379
380    pub fn with_supported_protocol_versions(mut self, versions: SupportedProtocolVersions) -> Self {
381        self.supported_protocol_versions = Some(versions);
382        self
383    }
384
385    pub fn with_db_checkpoint_config(mut self, db_checkpoint_config: DBCheckpointConfig) -> Self {
386        self.db_checkpoint_config = Some(db_checkpoint_config);
387        self
388    }
389
390    pub fn with_disable_pruning(mut self, disable_pruning: bool) -> Self {
391        self.disable_pruning = disable_pruning;
392        self
393    }
394
395    pub fn with_disable_json_rpc(mut self, disable_json_rpc: bool) -> Self {
396        self.disable_json_rpc = disable_json_rpc;
397        self
398    }
399
400    pub fn with_expensive_safety_check_config(
401        mut self,
402        expensive_safety_check_config: ExpensiveSafetyCheckConfig,
403    ) -> Self {
404        self.expensive_safety_check_config = Some(expensive_safety_check_config);
405        self
406    }
407
408    pub fn with_sync_post_process_one_tx(mut self, sync: bool) -> Self {
409        self.sync_post_process_one_tx = sync;
410        self
411    }
412
413    pub fn with_db_path(mut self, db_path: PathBuf) -> Self {
414        self.db_path = Some(db_path);
415        self
416    }
417
418    pub fn with_network_address(mut self, network_address: Multiaddr) -> Self {
419        self.network_address = Some(network_address);
420        self
421    }
422
423    pub fn with_json_rpc_address(mut self, json_rpc_address: SocketAddr) -> Self {
424        self.json_rpc_address = Some(json_rpc_address);
425        self
426    }
427
428    pub fn with_metrics_address(mut self, metrics_address: SocketAddr) -> Self {
429        self.metrics_address = Some(metrics_address);
430        self
431    }
432
433    pub fn with_admin_interface_port(mut self, admin_interface_port: u16) -> Self {
434        self.admin_interface_port = Some(admin_interface_port);
435        self
436    }
437
438    pub fn with_genesis(mut self, genesis: Genesis) -> Self {
439        self.genesis = Some(genesis);
440        self
441    }
442
443    pub fn with_p2p_external_address(mut self, p2p_external_address: Multiaddr) -> Self {
444        self.p2p_external_address = Some(p2p_external_address);
445        self
446    }
447
448    pub fn with_p2p_listen_address(mut self, p2p_listen_address: SocketAddr) -> Self {
449        self.p2p_listen_address = Some(p2p_listen_address);
450        self
451    }
452
453    pub fn with_network_key_pair(mut self, network_key_pair: Option<NetworkKeyPair>) -> Self {
454        if let Some(network_key_pair) = network_key_pair {
455            self.network_key_pair =
456                Some(KeyPairWithPath::new(SuiKeyPair::Ed25519(network_key_pair)));
457        }
458        self
459    }
460
461    pub fn with_run_with_range(mut self, run_with_range: Option<RunWithRange>) -> Self {
462        if let Some(run_with_range) = run_with_range {
463            self.run_with_range = Some(run_with_range);
464        }
465        self
466    }
467
468    pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
469        self.policy_config = config;
470        self
471    }
472
473    pub fn with_fw_config(mut self, config: Option<RemoteFirewallConfig>) -> Self {
474        self.fw_config = config;
475        self
476    }
477
478    pub fn with_data_ingestion_dir(mut self, path: Option<PathBuf>) -> Self {
479        self.data_ingestion_dir = path;
480        self
481    }
482
483    pub fn with_transaction_driver_config(
484        mut self,
485        config: Option<TransactionDriverConfig>,
486    ) -> Self {
487        self.transaction_driver_config = config;
488        self
489    }
490
491    pub fn with_state_sync_config(mut self, config: StateSyncConfig) -> Self {
492        self.state_sync_config = Some(config);
493        self
494    }
495
496    pub fn with_observer_config(mut self, config: ObserverParameters) -> Self {
497        self.observer_config = Some(config);
498        self
499    }
500
501    pub fn build<R: rand::RngCore + rand::CryptoRng>(
502        self,
503        rng: &mut R,
504        network_config: &NetworkConfig,
505    ) -> NodeConfig {
506        // Take advantage of ValidatorGenesisConfigBuilder to build the keypairs and addresses,
507        // even though this is a fullnode.
508        let validator_config = ValidatorGenesisConfigBuilder::new().build(rng);
509        let ip = validator_config
510            .network_address
511            .to_socket_addr()
512            .unwrap()
513            .ip()
514            .to_string();
515
516        let key_path = get_key_path(&validator_config.key_pair);
517        let config_directory = self
518            .config_directory
519            .unwrap_or_else(|| mysten_common::tempdir().unwrap().keep());
520
521        let consensus_db_path = config_directory.join(CONSENSUS_DB_NAME).join(&key_path);
522
523        let fullnode_sync_mode = self
524            .observer_config
525            .as_ref()
526            .filter(|c| !c.peers.is_empty())
527            .map(|_| FullNodeSyncMode::ConsensusObserver);
528
529        // Create consensus config, if observer config is provided.
530        let consensus_config = self.observer_config.map(|observer_config| ConsensusConfig {
531            db_path: consensus_db_path,
532            db_retention_epochs: None,
533            db_pruner_period_secs: None,
534            max_pending_transactions: None,
535            parameters: Some(ConsensusParameters {
536                observer: ObserverParameters {
537                    server_port: observer_config
538                        .server_port
539                        .or_else(|| Some(local_ip_utils::get_available_port(&ip))),
540                    allowlist: observer_config.allowlist,
541                    peers: observer_config.peers,
542                },
543                ..Default::default()
544            }),
545            listen_address: None,
546            external_address: None,
547        });
548
549        let p2p_config = {
550            let seed_peers = network_config
551                .validator_configs
552                .iter()
553                .map(|config| SeedPeer {
554                    peer_id: Some(anemo::PeerId(
555                        config.network_key_pair().public().0.to_bytes(),
556                    )),
557                    address: config.p2p_config.external_address.clone().unwrap(),
558                })
559                .collect();
560
561            P2pConfig {
562                listen_address: self.p2p_listen_address.unwrap_or_else(|| {
563                    validator_config.p2p_listen_address.unwrap_or_else(|| {
564                        validator_config
565                            .p2p_address
566                            .udp_multiaddr_to_listen_address()
567                            .unwrap()
568                    })
569                }),
570                external_address: self
571                    .p2p_external_address
572                    .or(Some(validator_config.p2p_address.clone())),
573                seed_peers,
574                // Set a shorter timeout for checkpoint content download in tests, since
575                // checkpoint pruning also happens much faster, and network is local.
576                state_sync: Some(if let Some(mut config) = self.state_sync_config {
577                    if config.checkpoint_content_timeout_ms.is_none() {
578                        config.checkpoint_content_timeout_ms = Some(10_000);
579                    }
580                    config
581                } else {
582                    StateSyncConfig {
583                        checkpoint_content_timeout_ms: Some(10_000),
584                        ..Default::default()
585                    }
586                }),
587                ..Default::default()
588            }
589        };
590
591        let localhost = local_ip_utils::localhost_for_testing();
592        let json_rpc_address = self.rpc_addr.unwrap_or_else(|| {
593            let rpc_port = self
594                .rpc_port
595                .unwrap_or_else(|| local_ip_utils::get_available_port(&ip));
596            format!("{}:{}", ip, rpc_port).parse().unwrap()
597        });
598
599        let checkpoint_executor_config = CheckpointExecutorConfig {
600            data_ingestion_dir: self.data_ingestion_dir,
601            ..Default::default()
602        };
603
604        let mut pruning_config = AuthorityStorePruningConfig::default();
605        if self.disable_pruning {
606            pruning_config.set_num_epochs_to_retain_for_checkpoints(None);
607            pruning_config.set_num_epochs_to_retain(u64::MAX);
608        };
609
610        NodeConfig {
611            recent_submission_dedup_window_ms: None,
612            address_prober: None,
613            protocol_key_pair: AuthorityKeyPairWithPath::new(validator_config.key_pair),
614            account_key_pair: KeyPairWithPath::new(validator_config.account_key_pair),
615            worker_key_pair: KeyPairWithPath::new(SuiKeyPair::Ed25519(
616                validator_config.worker_key_pair,
617            )),
618            network_key_pair: self.network_key_pair.unwrap_or(KeyPairWithPath::new(
619                SuiKeyPair::Ed25519(validator_config.network_key_pair),
620            )),
621            db_path: self
622                .db_path
623                .unwrap_or(config_directory.join(FULL_NODE_DB_PATH).join(key_path)),
624            network_address: self
625                .network_address
626                .unwrap_or(validator_config.network_address),
627            metrics_address: self
628                .metrics_address
629                .unwrap_or(local_ip_utils::new_local_tcp_socket_for_testing()),
630            admin_interface_port: self
631                .admin_interface_port
632                .unwrap_or(local_ip_utils::get_available_port(&localhost)),
633            json_rpc_address: self.json_rpc_address.unwrap_or(json_rpc_address),
634            fullnode_sync_mode,
635            consensus_config,
636            remove_deprecated_tables: false,
637            enable_index_processing: default_enable_index_processing(),
638            sync_post_process_one_tx: self.sync_post_process_one_tx,
639            genesis: self.genesis.unwrap_or(sui_config::node::Genesis::new(
640                network_config.genesis.clone(),
641            )),
642            grpc_load_shed: None,
643            grpc_concurrency_limit: None,
644            p2p_config,
645            authority_store_pruning_config: pruning_config,
646            end_of_epoch_broadcast_channel_capacity:
647                default_end_of_epoch_broadcast_channel_capacity(),
648            checkpoint_executor_config,
649            metrics: None,
650            supported_protocol_versions: self.supported_protocol_versions,
651            db_checkpoint_config: self.db_checkpoint_config.unwrap_or_default(),
652            expensive_safety_check_config: self
653                .expensive_safety_check_config
654                .unwrap_or_else(ExpensiveSafetyCheckConfig::new_enable_all),
655            name_service_package_address: None,
656            name_service_registry_id: None,
657            name_service_reverse_registry_id: None,
658            transaction_deny_config: Default::default(),
659            peer_deny_sync_config: Default::default(),
660            dev_inspect_disabled: false,
661            certificate_deny_config: Default::default(),
662            state_debug_dump_config: Default::default(),
663            state_archive_read_config: vec![],
664            state_snapshot_write_config: StateSnapshotConfig::default(),
665            indexer_max_subscriptions: Default::default(),
666            transaction_kv_store_read_config: Default::default(),
667            transaction_kv_store_write_config: Default::default(),
668            rpc: self.rpc_config.or_else(|| {
669                Some(sui_rpc_api::Config {
670                    enable_indexing: Some(true),
671                    ..Default::default()
672                })
673            }),
674            // note: not used by fullnodes.
675            jwk_fetch_interval_seconds: 3600,
676            zklogin_oauth_providers: default_zklogin_oauth_providers(),
677            authority_overload_config: Default::default(),
678            run_with_range: self.run_with_range,
679            jsonrpc_server_type: None,
680            disable_json_rpc: self.disable_json_rpc,
681            policy_config: self.policy_config,
682            firewall_config: self.fw_config,
683            execution_cache: ExecutionCacheConfig::default(),
684            state_accumulator_v2: true,
685            funds_withdraw_scheduler_type: FundsWithdrawSchedulerType::default(),
686            enable_soft_bundle: true,
687            verifier_signing_config: VerifierSigningConfig::default(),
688            enable_db_write_stall: None,
689            enable_db_sync_to_disk: None,
690            execution_time_observer_config: None,
691            chain_override_for_testing: self.chain_override,
692            validator_client_monitor_config: None,
693            fork_recovery: None,
694            transaction_driver_config: self
695                .transaction_driver_config
696                .or(Some(TransactionDriverConfig::default())),
697            congestion_log: None,
698        }
699    }
700}
701
702/// Given a validator keypair, return a path that can be used to identify the validator.
703fn get_key_path(key_pair: &AuthorityKeyPair) -> String {
704    let public_key: AuthorityPublicKeyBytes = key_pair.public().into();
705    let mut key_path = Hex::encode(public_key);
706    // 12 is rather arbitrary here but it's a nice balance between being short and being unique.
707    key_path.truncate(12);
708    key_path
709}