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