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