1use std::path::PathBuf;
5use std::time::Duration;
6use std::{num::NonZeroUsize, path::Path, sync::Arc};
7
8use mysten_common::ZipDebugEqIteratorExt;
9use mysten_common::in_test_configuration;
10use rand::rngs::OsRng;
11use sui_config::ExecutionCacheConfig;
12use sui_config::genesis::{TokenAllocation, TokenDistributionScheduleBuilder};
13use sui_config::node::AuthorityOverloadConfig;
14#[cfg(msim)]
15use sui_config::node::ExecutionTimeObserverConfig;
16use sui_config::node::FundsWithdrawSchedulerType;
17use sui_config::transaction_deny_config::PeerDenySyncConfig;
18use sui_protocol_config::Chain;
19use sui_types::base_types::{AuthorityName, SuiAddress};
20use sui_types::committee::{Committee, ProtocolVersion};
21use sui_types::crypto::{
22 AccountKeyPair, AuthorityKeyPair, KeypairTraits, PublicKey, get_key_pair_from_rng,
23};
24use sui_types::object::Object;
25use sui_types::supported_protocol_versions::SupportedProtocolVersions;
26use sui_types::traffic_control::{PolicyConfig, RemoteFirewallConfig};
27
28use consensus_config::ObserverParameters;
29
30use crate::genesis_config::{AccountConfig, DEFAULT_GAS_AMOUNT, ValidatorGenesisConfigBuilder};
31use crate::genesis_config::{GenesisConfig, ValidatorGenesisConfig};
32use crate::network_config::NetworkConfig;
33use crate::node_config_builder::ValidatorConfigBuilder;
34
35pub type ValidatorObserverConfigCallback =
36 Arc<dyn Fn(usize) -> Option<ObserverParameters> + Send + Sync + 'static>;
37
38pub struct KeyPairWrapper {
39 pub account_key_pair: AccountKeyPair,
40 pub protocol_key_pair: Option<AuthorityKeyPair>,
41}
42
43impl Clone for KeyPairWrapper {
44 fn clone(&self) -> Self {
45 Self {
46 account_key_pair: self.account_key_pair.copy(),
47 protocol_key_pair: self.protocol_key_pair.as_ref().map(|k| k.copy()),
48 }
49 }
50}
51
52pub enum CommitteeConfig {
53 Size(NonZeroUsize),
54 Validators(Vec<ValidatorGenesisConfig>),
55 AccountKeys(Vec<AccountKeyPair>),
56 Deterministic((NonZeroUsize, Option<Vec<KeyPairWrapper>>)),
59}
60
61pub type SupportedProtocolVersionsCallback = Arc<
62 dyn Fn(
63 usize, Option<AuthorityName>, ) -> SupportedProtocolVersions
66 + Send
67 + Sync
68 + 'static,
69>;
70
71#[derive(Clone)]
72pub enum ProtocolVersionsConfig {
73 Default,
75 Global(SupportedProtocolVersions),
77 PerValidator(SupportedProtocolVersionsCallback),
80}
81
82pub type GlobalStateHashV2EnabledCallback = Arc<dyn Fn(usize) -> bool + Send + Sync + 'static>;
83
84#[derive(Clone)]
85pub enum GlobalStateHashV2EnabledConfig {
86 Global(bool),
87 PerValidator(GlobalStateHashV2EnabledCallback),
88}
89
90pub type FundsWithdrawSchedulerTypeCallback =
91 Arc<dyn Fn(usize) -> FundsWithdrawSchedulerType + Send + Sync + 'static>;
92
93#[derive(Clone)]
94pub enum FundsWithdrawSchedulerTypeConfig {
95 Global(FundsWithdrawSchedulerType),
96 PerValidator(FundsWithdrawSchedulerTypeCallback),
97}
98
99pub type PeerDenySyncConfigCallback =
104 Arc<dyn Fn(AuthorityName, &[AuthorityName]) -> PeerDenySyncConfig + Send + Sync + 'static>;
105
106pub struct ConfigBuilder<R = OsRng> {
107 rng: Option<R>,
108 config_directory: PathBuf,
109 supported_protocol_versions_config: Option<ProtocolVersionsConfig>,
110 chain_override: Option<Chain>,
111 committee: CommitteeConfig,
112 genesis_config: Option<GenesisConfig>,
113 reference_gas_price: Option<u64>,
114 additional_objects: Vec<Object>,
115 jwk_fetch_interval: Option<Duration>,
116 num_unpruned_validators: Option<usize>,
117 authority_overload_config: Option<AuthorityOverloadConfig>,
118 execution_cache_config: Option<ExecutionCacheConfig>,
119 data_ingestion_dir: Option<PathBuf>,
120 policy_config: Option<PolicyConfig>,
121 firewall_config: Option<RemoteFirewallConfig>,
122 global_state_hash_v2_enabled_config: Option<GlobalStateHashV2EnabledConfig>,
123 funds_withdraw_scheduler_type_config: Option<FundsWithdrawSchedulerTypeConfig>,
124 state_sync_config: Option<sui_config::p2p::StateSyncConfig>,
125 peer_deny_sync_config: Option<PeerDenySyncConfigCallback>,
126 #[cfg(msim)]
127 execution_time_observer_config: Option<ExecutionTimeObserverConfig>,
128 validator_observer_config: Option<ValidatorObserverConfigCallback>,
129}
130
131impl ConfigBuilder {
132 pub fn new<P: AsRef<Path>>(config_directory: P) -> Self {
133 let funds_withdraw_scheduler_type_config = if in_test_configuration() {
137 Some(FundsWithdrawSchedulerTypeConfig::PerValidator(Arc::new(
138 |idx| {
139 if idx % 2 == 0 {
140 FundsWithdrawSchedulerType::Eager
141 } else {
142 FundsWithdrawSchedulerType::Naive
143 }
144 },
145 )))
146 } else {
147 None
148 };
149
150 Self {
151 rng: Some(OsRng),
152 config_directory: config_directory.as_ref().into(),
153 supported_protocol_versions_config: None,
154 chain_override: None,
155 committee: CommitteeConfig::Size(NonZeroUsize::new(1).unwrap()),
158 genesis_config: None,
159 reference_gas_price: None,
160 additional_objects: vec![],
161 jwk_fetch_interval: None,
162 num_unpruned_validators: None,
163 authority_overload_config: None,
164 execution_cache_config: None,
165 data_ingestion_dir: None,
166 policy_config: None,
167 firewall_config: None,
168 global_state_hash_v2_enabled_config: None,
169 funds_withdraw_scheduler_type_config,
170 state_sync_config: None,
171 peer_deny_sync_config: None,
172 #[cfg(msim)]
173 execution_time_observer_config: None,
174 validator_observer_config: None,
175 }
176 }
177
178 pub fn new_with_temp_dir() -> Self {
179 Self::new(mysten_common::tempdir().unwrap().keep())
180 }
181}
182
183impl<R> ConfigBuilder<R> {
184 pub fn committee(mut self, committee: CommitteeConfig) -> Self {
185 self.committee = committee;
186 self
187 }
188
189 pub fn committee_size(mut self, committee_size: NonZeroUsize) -> Self {
190 self.committee = CommitteeConfig::Size(committee_size);
191 self
192 }
193
194 pub fn deterministic_committee_size(mut self, committee_size: NonZeroUsize) -> Self {
195 self.committee = CommitteeConfig::Deterministic((committee_size, None));
196 self
197 }
198
199 pub fn deterministic_committee_validators(mut self, keys: Vec<KeyPairWrapper>) -> Self {
200 self.committee = CommitteeConfig::Deterministic((
201 NonZeroUsize::new(keys.len()).expect("Validator keys should be non empty"),
202 Some(keys),
203 ));
204 self
205 }
206
207 pub fn with_validator_account_keys(mut self, keys: Vec<AccountKeyPair>) -> Self {
208 self.committee = CommitteeConfig::AccountKeys(keys);
209 self
210 }
211
212 pub fn with_validators(mut self, validators: Vec<ValidatorGenesisConfig>) -> Self {
213 self.committee = CommitteeConfig::Validators(validators);
214 self
215 }
216
217 pub fn with_genesis_config(mut self, genesis_config: GenesisConfig) -> Self {
218 assert!(self.genesis_config.is_none(), "Genesis config already set");
219 self.genesis_config = Some(genesis_config);
220 self
221 }
222
223 pub fn with_chain_override(mut self, chain: Chain) -> Self {
224 assert!(self.chain_override.is_none(), "Chain override already set");
225 self.chain_override = Some(chain);
226 self
227 }
228
229 pub fn with_num_unpruned_validators(mut self, n: usize) -> Self {
230 self.num_unpruned_validators = Some(n);
231 self
232 }
233
234 pub fn with_jwk_fetch_interval(mut self, i: Duration) -> Self {
235 self.jwk_fetch_interval = Some(i);
236 self
237 }
238
239 pub fn with_data_ingestion_dir(mut self, path: PathBuf) -> Self {
240 self.data_ingestion_dir = Some(path);
241 self
242 }
243
244 pub fn with_reference_gas_price(mut self, reference_gas_price: u64) -> Self {
245 self.reference_gas_price = Some(reference_gas_price);
246 self
247 }
248
249 pub fn with_accounts(mut self, accounts: Vec<AccountConfig>) -> Self {
250 self.get_or_init_genesis_config().accounts = accounts;
251 self
252 }
253
254 pub fn with_chain_start_timestamp_ms(mut self, chain_start_timestamp_ms: u64) -> Self {
255 self.get_or_init_genesis_config()
256 .parameters
257 .chain_start_timestamp_ms = chain_start_timestamp_ms;
258 self
259 }
260
261 pub fn with_objects<I: IntoIterator<Item = Object>>(mut self, objects: I) -> Self {
262 self.additional_objects.extend(objects);
263 self
264 }
265
266 pub fn with_epoch_duration(mut self, epoch_duration_ms: u64) -> Self {
267 self.get_or_init_genesis_config()
268 .parameters
269 .epoch_duration_ms = epoch_duration_ms;
270 self
271 }
272
273 pub fn with_protocol_version(mut self, protocol_version: ProtocolVersion) -> Self {
274 self.get_or_init_genesis_config()
275 .parameters
276 .protocol_version = protocol_version;
277 self
278 }
279
280 pub fn with_supported_protocol_versions(mut self, c: SupportedProtocolVersions) -> Self {
281 self.supported_protocol_versions_config = Some(ProtocolVersionsConfig::Global(c));
282 self
283 }
284
285 pub fn with_supported_protocol_version_callback(
286 mut self,
287 func: SupportedProtocolVersionsCallback,
288 ) -> Self {
289 self.supported_protocol_versions_config = Some(ProtocolVersionsConfig::PerValidator(func));
290 self
291 }
292
293 pub fn with_supported_protocol_versions_config(mut self, c: ProtocolVersionsConfig) -> Self {
294 self.supported_protocol_versions_config = Some(c);
295 self
296 }
297
298 pub fn with_global_state_hash_v2_enabled(mut self, enabled: bool) -> Self {
299 self.global_state_hash_v2_enabled_config =
300 Some(GlobalStateHashV2EnabledConfig::Global(enabled));
301 self
302 }
303
304 pub fn with_global_state_hash_v2_enabled_callback(
305 mut self,
306 func: GlobalStateHashV2EnabledCallback,
307 ) -> Self {
308 self.global_state_hash_v2_enabled_config =
309 Some(GlobalStateHashV2EnabledConfig::PerValidator(func));
310 self
311 }
312
313 pub fn with_global_state_hash_v2_enabled_config(
314 mut self,
315 c: GlobalStateHashV2EnabledConfig,
316 ) -> Self {
317 self.global_state_hash_v2_enabled_config = Some(c);
318 self
319 }
320
321 pub fn with_funds_withdraw_scheduler_type(
322 mut self,
323 scheduler_type: FundsWithdrawSchedulerType,
324 ) -> Self {
325 self.funds_withdraw_scheduler_type_config =
326 Some(FundsWithdrawSchedulerTypeConfig::Global(scheduler_type));
327 self
328 }
329
330 pub fn with_funds_withdraw_scheduler_type_callback(
331 mut self,
332 func: FundsWithdrawSchedulerTypeCallback,
333 ) -> Self {
334 self.funds_withdraw_scheduler_type_config =
335 Some(FundsWithdrawSchedulerTypeConfig::PerValidator(func));
336 self
337 }
338
339 pub fn with_funds_withdraw_scheduler_type_config(
340 mut self,
341 c: FundsWithdrawSchedulerTypeConfig,
342 ) -> Self {
343 self.funds_withdraw_scheduler_type_config = Some(c);
344 self
345 }
346
347 #[cfg(msim)]
348 pub fn with_execution_time_observer_config(mut self, c: ExecutionTimeObserverConfig) -> Self {
349 self.execution_time_observer_config = Some(c);
350 self
351 }
352
353 pub fn with_validator_observer_config(mut self, c: ValidatorObserverConfigCallback) -> Self {
354 self.validator_observer_config = Some(c);
355 self
356 }
357
358 pub fn with_authority_overload_config(mut self, c: AuthorityOverloadConfig) -> Self {
359 self.authority_overload_config = Some(c);
360 self
361 }
362
363 pub fn with_execution_cache_config(mut self, c: ExecutionCacheConfig) -> Self {
364 self.execution_cache_config = Some(c);
365 self
366 }
367
368 pub fn with_policy_config(mut self, config: Option<PolicyConfig>) -> Self {
369 self.policy_config = config;
370 self
371 }
372
373 pub fn with_firewall_config(mut self, config: Option<RemoteFirewallConfig>) -> Self {
374 self.firewall_config = config;
375 self
376 }
377
378 pub fn rng<N: rand::RngCore + rand::CryptoRng>(self, rng: N) -> ConfigBuilder<N> {
379 ConfigBuilder {
380 rng: Some(rng),
381 config_directory: self.config_directory,
382 supported_protocol_versions_config: self.supported_protocol_versions_config,
383 committee: self.committee,
384 genesis_config: self.genesis_config,
385 chain_override: self.chain_override,
386 reference_gas_price: self.reference_gas_price,
387 additional_objects: self.additional_objects,
388 num_unpruned_validators: self.num_unpruned_validators,
389 jwk_fetch_interval: self.jwk_fetch_interval,
390 authority_overload_config: self.authority_overload_config,
391 execution_cache_config: self.execution_cache_config,
392 data_ingestion_dir: self.data_ingestion_dir,
393 policy_config: self.policy_config,
394 firewall_config: self.firewall_config,
395 global_state_hash_v2_enabled_config: self.global_state_hash_v2_enabled_config,
396 funds_withdraw_scheduler_type_config: self.funds_withdraw_scheduler_type_config,
397 state_sync_config: self.state_sync_config,
398 peer_deny_sync_config: self.peer_deny_sync_config,
399 #[cfg(msim)]
400 execution_time_observer_config: self.execution_time_observer_config,
401 validator_observer_config: self.validator_observer_config,
402 }
403 }
404
405 pub fn with_state_sync_config(mut self, config: sui_config::p2p::StateSyncConfig) -> Self {
406 self.state_sync_config = Some(config);
407 self
408 }
409
410 pub fn with_peer_deny_sync_config_per_validator(
415 mut self,
416 f: PeerDenySyncConfigCallback,
417 ) -> Self {
418 self.peer_deny_sync_config = Some(f);
419 self
420 }
421
422 fn get_or_init_genesis_config(&mut self) -> &mut GenesisConfig {
423 if self.genesis_config.is_none() {
424 self.genesis_config = Some(GenesisConfig::for_local_testing());
425 }
426 self.genesis_config.as_mut().unwrap()
427 }
428}
429
430impl<R: rand::RngCore + rand::CryptoRng> ConfigBuilder<R> {
431 pub fn build(self) -> NetworkConfig {
433 let committee = self.committee;
434
435 let mut rng = self.rng.unwrap();
436 let validators = match committee {
437 CommitteeConfig::Size(size) => {
438 let (_, keys) = Committee::new_simple_test_committee_of_size(size.into());
443
444 keys.into_iter()
445 .map(|authority_key| {
446 let mut builder = ValidatorGenesisConfigBuilder::new()
447 .with_protocol_key_pair(authority_key);
448 if let Some(rgp) = self.reference_gas_price {
449 builder = builder.with_gas_price(rgp);
450 }
451 builder.build(&mut rng)
452 })
453 .collect::<Vec<_>>()
454 }
455
456 CommitteeConfig::Validators(v) => v,
457
458 CommitteeConfig::AccountKeys(keys) => {
459 let (_, protocol_keys) = Committee::new_simple_test_committee_of_size(keys.len());
461 keys.into_iter()
462 .zip_debug_eq(protocol_keys)
463 .map(|(account_key, protocol_key)| {
464 let mut builder = ValidatorGenesisConfigBuilder::new()
465 .with_protocol_key_pair(protocol_key)
466 .with_account_key_pair(account_key);
467 if let Some(rgp) = self.reference_gas_price {
468 builder = builder.with_gas_price(rgp);
469 }
470 builder.build(&mut rng)
471 })
472 .collect::<Vec<_>>()
473 }
474 CommitteeConfig::Deterministic((size, key_pair_wrappers)) => {
475 let keys = key_pair_wrappers.unwrap_or_else(|| {
477 (0..size.get())
478 .map(|_| KeyPairWrapper {
479 account_key_pair: get_key_pair_from_rng(&mut rng).1,
480 protocol_key_pair: None,
481 })
482 .collect()
483 });
484
485 let mut configs = vec![];
486 for (i, key) in keys.into_iter().enumerate() {
487 let port_offset = 8000 + i * 10;
488 let mut builder = ValidatorGenesisConfigBuilder::new()
489 .with_ip("127.0.0.1".to_owned())
490 .with_account_key_pair(key.account_key_pair)
491 .with_deterministic_ports(port_offset as u16);
492 if let Some(protocol_key_pair) = key.protocol_key_pair {
493 builder = builder.with_protocol_key_pair(protocol_key_pair);
494 }
495 if let Some(rgp) = self.reference_gas_price {
496 builder = builder.with_gas_price(rgp);
497 }
498 configs.push(builder.build(&mut rng));
499 }
500 configs
501 }
502 };
503
504 let genesis_config = self
505 .genesis_config
506 .unwrap_or_else(GenesisConfig::for_local_testing);
507
508 let (account_keys, allocations) = genesis_config.generate_accounts(&mut rng).unwrap();
509
510 let token_distribution_schedule = {
511 let mut builder = TokenDistributionScheduleBuilder::new();
512 for allocation in allocations {
513 builder.add_allocation(allocation);
514 }
515 for validator in &validators {
517 let account_key: PublicKey = validator.account_key_pair.public();
518 let address = SuiAddress::from(&account_key);
519 let gas_coin = TokenAllocation {
521 recipient_address: address,
522 amount_mist: DEFAULT_GAS_AMOUNT,
523 staked_with_validator: None,
524 };
525 let stake = TokenAllocation {
526 recipient_address: address,
527 amount_mist: validator.stake,
528 staked_with_validator: Some(address),
529 };
530 builder.add_allocation(gas_coin);
531 builder.add_allocation(stake);
532 }
533 builder.build()
534 };
535
536 let genesis = {
537 let mut builder = sui_genesis_builder::Builder::new()
538 .with_parameters(genesis_config.parameters)
539 .add_objects(self.additional_objects);
540
541 for (i, validator) in validators.iter().enumerate() {
542 let name = validator
543 .name
544 .clone()
545 .unwrap_or(format!("validator-{i}").to_string());
546 let validator_info = validator.to_validator_info(name);
547 builder =
548 builder.add_validator(validator_info.info, validator_info.proof_of_possession);
549 }
550
551 builder = builder.with_token_distribution_schedule(token_distribution_schedule);
552
553 for validator in &validators {
554 builder = builder.add_validator_signature(&validator.key_pair);
555 }
556
557 builder.build()
558 };
559
560 let all_authority_names: Vec<AuthorityName> = validators
561 .iter()
562 .map(|v| v.key_pair.public().into())
563 .collect();
564 let validator_configs = validators
565 .into_iter()
566 .enumerate()
567 .map(|(idx, validator)| {
568 let mut builder = ValidatorConfigBuilder::new()
569 .with_config_directory(self.config_directory.clone())
570 .with_policy_config(self.policy_config.clone())
571 .with_firewall_config(self.firewall_config.clone());
572
573 if let Some(chain) = self.chain_override {
574 builder = builder.with_chain_override(chain);
575 }
576
577 if let Some(jwk_fetch_interval) = self.jwk_fetch_interval {
578 builder = builder.with_jwk_fetch_interval(jwk_fetch_interval);
579 }
580
581 if let Some(authority_overload_config) = &self.authority_overload_config {
582 builder =
583 builder.with_authority_overload_config(authority_overload_config.clone());
584 }
585
586 if let Some(execution_cache_config) = &self.execution_cache_config {
587 builder = builder.with_execution_cache_config(execution_cache_config.clone());
588 }
589
590 if let Some(path) = &self.data_ingestion_dir {
591 builder = builder.with_data_ingestion_dir(path.clone());
592 }
593
594 if let Some(state_sync_config) = &self.state_sync_config {
595 builder = builder.with_state_sync_config(state_sync_config.clone());
596 }
597
598 #[cfg(msim)]
599 if let Some(execution_time_observer_config) = &self.execution_time_observer_config {
600 builder = builder.with_execution_time_observer_config(
601 execution_time_observer_config.clone(),
602 );
603 }
604
605 if let Some(spvc) = &self.supported_protocol_versions_config {
606 let supported_versions = match spvc {
607 ProtocolVersionsConfig::Default => {
608 SupportedProtocolVersions::SYSTEM_DEFAULT
609 }
610 ProtocolVersionsConfig::Global(v) => *v,
611 ProtocolVersionsConfig::PerValidator(func) => {
612 func(idx, Some(validator.key_pair.public().into()))
613 }
614 };
615 builder = builder.with_supported_protocol_versions(supported_versions);
616 }
617 if let Some(acc_v2_config) = &self.global_state_hash_v2_enabled_config {
618 let global_state_hash_v2_enabled: bool = match acc_v2_config {
619 GlobalStateHashV2EnabledConfig::Global(enabled) => *enabled,
620 GlobalStateHashV2EnabledConfig::PerValidator(func) => func(idx),
621 };
622 builder =
623 builder.with_global_state_hash_v2_enabled(global_state_hash_v2_enabled);
624 }
625 if let Some(scheduler_type_config) = &self.funds_withdraw_scheduler_type_config {
626 let scheduler_type = match scheduler_type_config {
627 FundsWithdrawSchedulerTypeConfig::Global(t) => *t,
628 FundsWithdrawSchedulerTypeConfig::PerValidator(func) => func(idx),
629 };
630 builder = builder.with_funds_withdraw_scheduler_type(scheduler_type);
631 }
632 if let Some(observer_config_fn) = &self.validator_observer_config
633 && let Some(observer_config) = observer_config_fn(idx)
634 {
635 builder = builder.with_observer_config(observer_config);
636 }
637 if let Some(num_unpruned_validators) = self.num_unpruned_validators
638 && idx < num_unpruned_validators
639 {
640 builder = builder.with_unpruned_checkpoints();
641 }
642 if let Some(peer_deny_sync_cb) = &self.peer_deny_sync_config {
643 let this_authority: AuthorityName = validator.key_pair.public().into();
644 builder = builder.with_peer_deny_sync_config(peer_deny_sync_cb(
645 this_authority,
646 &all_authority_names,
647 ));
648 }
649 builder.build(validator, genesis.clone())
650 })
651 .collect();
652 NetworkConfig {
653 validator_configs,
654 genesis,
655 account_keys,
656 }
657 }
658}
659
660#[cfg(test)]
661mod tests {
662 use sui_config::node::Genesis;
663
664 #[test]
665 fn serialize_genesis_config_in_place() {
666 let dir = tempfile::TempDir::new().unwrap();
667 let network_config = crate::network_config_builder::ConfigBuilder::new(&dir).build();
668 let genesis = network_config.genesis;
669
670 let g = Genesis::new(genesis);
671
672 let mut s = serde_yaml::to_string(&g).unwrap();
673 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
674 loaded_genesis
675 .genesis()
676 .unwrap()
677 .checkpoint_contents()
678 .digest(); assert_eq!(g, loaded_genesis);
680
681 s.push_str("\ngenesis-file-location: path/to/file");
683 let loaded_genesis: Genesis = serde_yaml::from_str(&s).unwrap();
684 loaded_genesis
685 .genesis()
686 .unwrap()
687 .checkpoint_contents()
688 .digest(); assert_eq!(g, loaded_genesis);
690 }
691
692 #[test]
693 fn load_genesis_config_from_file() {
694 let file = tempfile::NamedTempFile::new().unwrap();
695 let genesis_config = Genesis::new_from_file(file.path());
696
697 let dir = tempfile::TempDir::new().unwrap();
698 let network_config = crate::network_config_builder::ConfigBuilder::new(&dir).build();
699 let genesis = network_config.genesis;
700 genesis.save(file.path()).unwrap();
701
702 let loaded_genesis = genesis_config.genesis().unwrap();
703 loaded_genesis.checkpoint_contents().digest(); assert_eq!(&genesis, loaded_genesis);
705 }
706}
707
708#[cfg(test)]
709mod test {
710 use std::sync::Arc;
711 use sui_config::genesis::Genesis;
712 use sui_protocol_config::{Chain, ProtocolConfig, ProtocolVersion};
713 use sui_types::epoch_data::EpochData;
714 use sui_types::execution_params::ExecutionOrEarlyError;
715 use sui_types::gas::SuiGasStatus;
716 use sui_types::in_memory_storage::InMemoryStorage;
717 use sui_types::metrics::ExecutionMetrics;
718 use sui_types::sui_system_state::SuiSystemStateTrait;
719 use sui_types::transaction::CheckedInputObjects;
720
721 #[test]
722 fn roundtrip() {
723 let dir = tempfile::TempDir::new().unwrap();
724 let network_config = crate::network_config_builder::ConfigBuilder::new(&dir).build();
725 let genesis = network_config.genesis;
726
727 let s = serde_yaml::to_string(&genesis).unwrap();
728 let from_s: Genesis = serde_yaml::from_str(&s).unwrap();
729 from_s.checkpoint_contents().digest();
731 assert_eq!(genesis, from_s);
732 }
733
734 #[test]
735 fn genesis_transaction() {
736 let builder = crate::network_config_builder::ConfigBuilder::new_with_temp_dir();
737 let network_config = builder.build();
738 let genesis = network_config.genesis;
739 let protocol_version = ProtocolVersion::new(genesis.sui_system_object().protocol_version());
740 let protocol_config = ProtocolConfig::get_for_version(protocol_version, Chain::Unknown);
741
742 let genesis_transaction = genesis.transaction().clone();
743
744 let genesis_digest = *genesis_transaction.digest();
745
746 let silent = true;
747 let executor = sui_execution::executor(&protocol_config, silent)
748 .expect("Creating an executor should not fail here");
749
750 let registry = prometheus::Registry::new();
752 let metrics = Arc::new(ExecutionMetrics::new(®istry));
753 let expensive_checks = false;
754 let epoch = EpochData::new_test();
755 let transaction_data = &genesis_transaction.data().intent_message().value;
756 let (kind, signer, mut gas_data) = transaction_data.execution_parts();
757 gas_data.payment = vec![];
758 let input_objects = CheckedInputObjects::new_for_genesis(vec![]);
759
760 let (_inner_temp_store, _, effects, _timings, _execution_error) = executor
761 .execute_transaction_to_effects(
762 &InMemoryStorage::new(Vec::new()),
763 &protocol_config,
764 metrics,
765 expensive_checks,
766 ExecutionOrEarlyError::ok(None),
767 &epoch.epoch_id(),
768 epoch.epoch_start_timestamp(),
769 input_objects,
770 std::collections::BTreeMap::new(),
771 gas_data,
772 SuiGasStatus::new_unmetered(),
773 kind,
774 None, signer,
776 genesis_digest,
777 &mut None,
778 );
779
780 assert_eq!(&effects, genesis.effects());
781 }
782}