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