simulacrum/
epoch_state.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{collections::HashSet, sync::Arc};
6
7use anyhow::Result;
8use iota_config::{
9    transaction_deny_config::TransactionDenyConfig, verifier_signing_config::VerifierSigningConfig,
10};
11use iota_execution::Executor;
12use iota_protocol_config::{Chain, ProtocolConfig, ProtocolVersion};
13use iota_types::{
14    committee::{Committee, EpochId},
15    effects::TransactionEffects,
16    gas::IotaGasStatus,
17    inner_temporary_store::InnerTemporaryStore,
18    iota_system_state::{
19        IotaSystemState, IotaSystemStateTrait,
20        epoch_start_iota_system_state::{EpochStartSystemState, EpochStartSystemStateTrait},
21    },
22    metrics::{BytecodeVerifierMetrics, LimitsMetrics},
23    transaction::{TransactionDataAPI, VerifiedTransaction},
24};
25
26use crate::SimulatorStore;
27
28pub struct EpochState {
29    epoch_start_state: EpochStartSystemState,
30    committee: Committee,
31    protocol_config: ProtocolConfig,
32    limits_metrics: Arc<LimitsMetrics>,
33    bytecode_verifier_metrics: Arc<BytecodeVerifierMetrics>,
34    executor: Arc<dyn Executor + Send + Sync>,
35    /// A counter that advances each time we advance the clock in order to
36    /// ensure that each update txn has a unique digest. This is reset on
37    /// epoch changes
38    next_consensus_round: u64,
39}
40
41impl EpochState {
42    pub fn new(system_state: IotaSystemState) -> Self {
43        let epoch_start_state = system_state.into_epoch_start_state();
44        let committee = epoch_start_state.get_iota_committee();
45        let protocol_config =
46            ProtocolConfig::get_for_version(epoch_start_state.protocol_version(), Chain::Unknown);
47        let registry = prometheus::Registry::new();
48        let limits_metrics = Arc::new(LimitsMetrics::new(&registry));
49        let bytecode_verifier_metrics = Arc::new(BytecodeVerifierMetrics::new(&registry));
50        let executor = iota_execution::executor(&protocol_config, true, None).unwrap();
51
52        Self {
53            epoch_start_state,
54            committee,
55            protocol_config,
56            limits_metrics,
57            bytecode_verifier_metrics,
58            executor,
59            next_consensus_round: 0,
60        }
61    }
62
63    pub fn epoch(&self) -> EpochId {
64        self.epoch_start_state.epoch()
65    }
66
67    pub fn reference_gas_price(&self) -> u64 {
68        self.epoch_start_state.reference_gas_price()
69    }
70
71    pub fn next_consensus_round(&mut self) -> u64 {
72        let round = self.next_consensus_round;
73        self.next_consensus_round += 1;
74        round
75    }
76
77    pub fn committee(&self) -> &Committee {
78        &self.committee
79    }
80
81    pub fn epoch_start_state(&self) -> &EpochStartSystemState {
82        &self.epoch_start_state
83    }
84
85    pub fn protocol_version(&self) -> ProtocolVersion {
86        self.protocol_config().version
87    }
88
89    pub fn protocol_config(&self) -> &ProtocolConfig {
90        &self.protocol_config
91    }
92
93    pub fn execute_transaction(
94        &self,
95        store: &dyn SimulatorStore,
96        deny_config: &TransactionDenyConfig,
97        verifier_signing_config: &VerifierSigningConfig,
98        transaction: &VerifiedTransaction,
99    ) -> Result<(
100        InnerTemporaryStore,
101        IotaGasStatus,
102        TransactionEffects,
103        Result<(), iota_types::error::ExecutionError>,
104    )> {
105        let tx_digest = *transaction.digest();
106        let tx_data = &transaction.data().intent_message().value;
107        let input_object_kinds = tx_data.input_objects()?;
108        let receiving_object_refs = tx_data.receiving_objects();
109
110        iota_transaction_checks::deny::check_transaction_for_signing(
111            tx_data,
112            transaction.tx_signatures(),
113            &input_object_kinds,
114            &receiving_object_refs,
115            deny_config,
116            &store,
117        )?;
118
119        let (input_objects, receiving_objects) = store.read_objects_for_synchronous_execution(
120            &tx_digest,
121            &input_object_kinds,
122            &receiving_object_refs,
123        )?;
124
125        // Run the transaction input checks that would run when submitting the txn to a
126        // validator for signing
127        let (gas_status, checked_input_objects) = iota_transaction_checks::check_transaction_input(
128            &self.protocol_config,
129            self.epoch_start_state.reference_gas_price(),
130            transaction.data().transaction_data(),
131            input_objects,
132            &receiving_objects,
133            &self.bytecode_verifier_metrics,
134            verifier_signing_config,
135        )?;
136
137        let transaction_data = transaction.data().transaction_data();
138        let (kind, signer, gas) = transaction_data.execution_parts();
139        Ok(self.executor.execute_transaction_to_effects(
140            store.backing_store(),
141            &self.protocol_config,
142            self.limits_metrics.clone(),
143            false,           // enable_expensive_checks
144            &HashSet::new(), // certificate_deny_set
145            &self.epoch_start_state.epoch(),
146            self.epoch_start_state.epoch_start_timestamp_ms(),
147            checked_input_objects,
148            gas,
149            gas_status,
150            kind,
151            signer,
152            tx_digest,
153            &mut None,
154        ))
155    }
156}