sui_swarm_config/
network_config_builder.rs

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