iota_swarm_config/
network_config_builder.rs

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