iota_genesis_common/
lib.rs

1// Copyright (c) 2024 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{collections::HashSet, sync::Arc};
5
6use iota_execution::executor;
7use iota_protocol_config::{ProtocolConfig, ProtocolVersion};
8use iota_types::{
9    digests::ChainIdentifier,
10    effects::{TransactionEffects, TransactionEffectsAPI, TransactionEvents},
11    epoch_data::EpochData,
12    gas::IotaGasStatus,
13    in_memory_storage::InMemoryStorage,
14    messages_checkpoint::CheckpointTimestamp,
15    metrics::LimitsMetrics,
16    object::Object,
17    transaction::{CheckedInputObjects, Transaction, TransactionDataAPI, TransactionKind},
18};
19use prometheus::Registry;
20
21/// Gets a `ProtocolConfig` for genesis based on a `ProtocolVersion`.
22pub fn get_genesis_protocol_config(version: ProtocolVersion) -> ProtocolConfig {
23    // We have a circular dependency here. Protocol config depends on chain ID,
24    // which depends on genesis checkpoint (digest), which depends on genesis
25    // transaction, which depends on protocol config.
26    //
27    // ChainIdentifier::default().chain() which can be overridden by the
28    // IOTA_PROTOCOL_CONFIG_CHAIN_OVERRIDE if necessary
29    ProtocolConfig::get_for_version(version, ChainIdentifier::default().chain())
30}
31
32/// Prepares the data necessary and then invokes `execute_genesis_transaction`.
33/// The `chain_start_timestamp_ms` is used to construct a genesis `EpochData`.
34/// The `protocol_version` is used to create a `ProtocolConfig` for genesis.
35/// The `genesis_transaction` is the transaction to be executed.
36pub fn prepare_and_execute_genesis_transaction(
37    chain_start_timestamp_ms: CheckpointTimestamp,
38    protocol_version: ProtocolVersion,
39    genesis_transaction: &Transaction,
40) -> (TransactionEffects, TransactionEvents, Vec<Object>) {
41    let registry = Registry::new();
42    let metrics = Arc::new(LimitsMetrics::new(&registry));
43    let epoch_data = EpochData::new_genesis(chain_start_timestamp_ms);
44    let protocol_config = get_genesis_protocol_config(protocol_version);
45
46    execute_genesis_transaction(&epoch_data, &protocol_config, metrics, genesis_transaction)
47}
48
49/// Takes as input a transaction of kind Genesis and executes it. This can be
50/// used to obtain the `TransactionEffects`, `TransactionEvents` and
51/// `Vec<Object>` (vector of created objects) that result from the execution.
52/// Some `EpochData`, `ProtocolConfig` and `LimitsMetrics` are needed as input
53/// to be passed to the transaction executor.
54pub fn execute_genesis_transaction(
55    epoch_data: &EpochData,
56    protocol_config: &ProtocolConfig,
57    metrics: Arc<LimitsMetrics>,
58    genesis_transaction: &Transaction,
59) -> (TransactionEffects, TransactionEvents, Vec<Object>) {
60    assert!(
61        matches!(
62            genesis_transaction.transaction_data().kind(),
63            TransactionKind::Genesis(_)
64        ),
65        "wrong transaction type to execute"
66    );
67    let genesis_digest = *genesis_transaction.digest();
68    // execute txn to effects
69    let silent = true;
70
71    let executor =
72        executor(protocol_config, silent, None).expect("Creating an executor should not fail here");
73
74    let expensive_checks = false;
75    let certificate_deny_set = HashSet::new();
76    let transaction_data = &genesis_transaction.data().intent_message().value;
77    let (kind, signer, _) = transaction_data.execution_parts();
78    let input_objects = CheckedInputObjects::new_for_genesis(vec![]);
79    let (inner_temp_store, _, effects, _execution_error) = executor.execute_transaction_to_effects(
80        &InMemoryStorage::new(Vec::new()),
81        protocol_config,
82        metrics,
83        expensive_checks,
84        &certificate_deny_set,
85        &epoch_data.epoch_id(),
86        epoch_data.epoch_start_timestamp(),
87        input_objects,
88        vec![],
89        IotaGasStatus::new_unmetered(),
90        kind,
91        signer,
92        genesis_digest,
93        &mut None,
94    );
95    assert!(inner_temp_store.input_objects.is_empty());
96    assert!(inner_temp_store.mutable_inputs.is_empty());
97    assert!(effects.mutated().is_empty());
98    assert!(effects.unwrapped().is_empty());
99    assert!(effects.deleted().is_empty());
100    assert!(effects.wrapped().is_empty());
101    assert!(effects.unwrapped_then_deleted().is_empty());
102
103    let objects = inner_temp_store.written.into_values().collect();
104    (effects, inner_temp_store.events, objects)
105}