1use 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 base_types::ObjectID,
15 committee::{Committee, EpochId},
16 digests::TransactionDigest,
17 effects::{TransactionEffects, TransactionEffectsAPI},
18 error::IotaResult,
19 gas::IotaGasStatus,
20 gas_coin::NANOS_PER_IOTA,
21 inner_temporary_store::InnerTemporaryStore,
22 iota_system_state::{
23 IotaSystemState, IotaSystemStateTrait,
24 epoch_start_iota_system_state::{EpochStartSystemState, EpochStartSystemStateTrait},
25 },
26 metrics::{BytecodeVerifierMetrics, LimitsMetrics},
27 object::{MoveObject, Object, Owner},
28 transaction::{ObjectReadResult, TransactionData, TransactionDataAPI, VerifiedTransaction},
29 transaction_executor::{SimulateTransactionResult, VmChecks},
30};
31
32use crate::SimulatorStore;
33
34pub struct EpochState {
35 epoch_start_state: EpochStartSystemState,
36 committee: Committee,
37 protocol_config: ProtocolConfig,
38 limits_metrics: Arc<LimitsMetrics>,
39 bytecode_verifier_metrics: Arc<BytecodeVerifierMetrics>,
40 executor: Arc<dyn Executor + Send + Sync>,
41 next_consensus_round: u64,
45}
46
47impl EpochState {
48 pub fn new(system_state: IotaSystemState) -> Self {
49 let epoch_start_state = system_state.into_epoch_start_state();
50 let committee = epoch_start_state.get_iota_committee();
51 let protocol_config =
52 ProtocolConfig::get_for_version(epoch_start_state.protocol_version(), Chain::Unknown);
53 let registry = prometheus::Registry::new();
54 let limits_metrics = Arc::new(LimitsMetrics::new(®istry));
55 let bytecode_verifier_metrics = Arc::new(BytecodeVerifierMetrics::new(®istry));
56 let executor = iota_execution::executor(&protocol_config, true, None).unwrap();
57
58 Self {
59 epoch_start_state,
60 committee,
61 protocol_config,
62 limits_metrics,
63 bytecode_verifier_metrics,
64 executor,
65 next_consensus_round: 0,
66 }
67 }
68
69 pub fn epoch(&self) -> EpochId {
70 self.epoch_start_state.epoch()
71 }
72
73 pub fn reference_gas_price(&self) -> u64 {
74 self.epoch_start_state.reference_gas_price()
75 }
76
77 pub fn next_consensus_round(&mut self) -> u64 {
78 let round = self.next_consensus_round;
79 self.next_consensus_round += 1;
80 round
81 }
82
83 pub fn committee(&self) -> &Committee {
84 &self.committee
85 }
86
87 pub fn epoch_start_state(&self) -> EpochStartSystemState {
88 self.epoch_start_state.clone()
89 }
90
91 pub fn protocol_version(&self) -> ProtocolVersion {
92 self.protocol_config().version
93 }
94
95 pub fn protocol_config(&self) -> &ProtocolConfig {
96 &self.protocol_config
97 }
98
99 pub fn execute_transaction(
100 &self,
101 store: &dyn SimulatorStore,
102 deny_config: &TransactionDenyConfig,
103 verifier_signing_config: &VerifierSigningConfig,
104 transaction: &VerifiedTransaction,
105 ) -> Result<(
106 InnerTemporaryStore,
107 IotaGasStatus,
108 TransactionEffects,
109 Result<(), iota_types::error::ExecutionError>,
110 )> {
111 let tx_digest = *transaction.digest();
112 let tx_data = &transaction.data().intent_message().value;
113 let input_object_kinds = tx_data.input_objects()?;
114 let receiving_object_refs = tx_data.receiving_objects();
115
116 iota_transaction_checks::deny::check_transaction_for_signing(
117 tx_data,
118 transaction.tx_signatures(),
119 &input_object_kinds,
120 &receiving_object_refs,
121 deny_config,
122 &store,
123 )?;
124
125 let (input_objects, receiving_objects) = store.read_objects_for_synchronous_execution(
126 &tx_digest,
127 &input_object_kinds,
128 &receiving_object_refs,
129 )?;
130
131 let authenticator_gas_budget = 0;
134
135 let (gas_status, checked_input_objects) = iota_transaction_checks::check_transaction_input(
138 &self.protocol_config,
139 self.epoch_start_state.reference_gas_price(),
140 transaction.data().transaction_data(),
141 input_objects,
142 &receiving_objects,
143 &self.bytecode_verifier_metrics,
144 verifier_signing_config,
145 authenticator_gas_budget,
146 )?;
147
148 let transaction_data = transaction.data().transaction_data();
149 let (kind, signer, gas_data) = transaction_data.execution_parts();
150 Ok(self.executor.execute_transaction_to_effects(
151 store.backing_store(),
152 &self.protocol_config,
153 self.limits_metrics.clone(),
154 false, &HashSet::new(), &self.epoch_start_state.epoch(),
157 self.epoch_start_state.epoch_start_timestamp_ms(),
158 checked_input_objects,
159 gas_data,
160 gas_status,
161 kind,
162 signer,
163 tx_digest,
164 &mut None,
165 ))
166 }
167
168 pub fn simulate_transaction(
176 &self,
177 store: &dyn SimulatorStore,
178 deny_config: &TransactionDenyConfig,
179 verifier_signing_config: &VerifierSigningConfig,
180 mut transaction: TransactionData,
181 checks: VmChecks,
182 ) -> IotaResult<SimulateTransactionResult> {
183 transaction.validity_check_no_gas_check(&self.protocol_config)?;
185
186 let input_object_kinds = transaction.input_objects()?;
187 let receiving_object_refs = transaction.receiving_objects();
188
189 iota_transaction_checks::deny::check_transaction_for_signing(
191 &transaction,
192 &[],
193 &input_object_kinds,
194 &receiving_object_refs,
195 deny_config,
196 store,
197 )?;
198
199 let (mut input_objects, receiving_objects) = store.read_objects_for_synchronous_execution(
201 &transaction.digest(),
202 &input_object_kinds,
203 &receiving_object_refs,
204 )?;
205
206 const SIMULATION_GAS_COIN_VALUE: u64 = 1_000_000_000 * NANOS_PER_IOTA; let mock_gas_id = if transaction.gas().is_empty() {
209 let mock_gas_object = Object::new_move(
210 MoveObject::new_gas_coin(1.into(), ObjectID::MAX, SIMULATION_GAS_COIN_VALUE),
211 Owner::AddressOwner(transaction.gas_data().owner),
212 TransactionDigest::genesis_marker(),
213 );
214 let mock_gas_object_ref = mock_gas_object.compute_object_reference();
215 transaction.gas_data_mut().payment = vec![mock_gas_object_ref];
216 input_objects.push(ObjectReadResult::new_from_gas_object(&mock_gas_object));
217 Some(mock_gas_object.id())
218 } else {
219 None
220 };
221
222 let authenticator_gas_budget = 0;
225
226 let (gas_status, checked_input_objects) = if checks.enabled() {
229 iota_transaction_checks::check_transaction_input(
230 &self.protocol_config,
231 self.epoch_start_state.reference_gas_price(),
232 &transaction,
233 input_objects,
234 &receiving_objects,
235 &self.bytecode_verifier_metrics,
236 verifier_signing_config,
237 authenticator_gas_budget,
238 )?
239 } else {
240 let checked_input_objects = iota_transaction_checks::check_dev_inspect_input(
241 &self.protocol_config,
242 transaction.kind(),
243 input_objects,
244 receiving_objects,
245 )?;
246 let gas_status = IotaGasStatus::new(
247 transaction.gas_budget(),
248 transaction.gas_price(),
249 self.epoch_start_state.reference_gas_price(),
250 &self.protocol_config,
251 )?;
252
253 (gas_status, checked_input_objects)
254 };
255
256 let (kind, signer, gas_data) = transaction.execution_parts();
258 let (inner_temp_store, _, effects, execution_result) =
259 self.executor.dev_inspect_transaction(
260 store.backing_store(),
261 &self.protocol_config,
262 self.limits_metrics.clone(),
263 false, &HashSet::new(), &self.epoch_start_state.epoch(),
266 self.epoch_start_state.epoch_start_timestamp_ms(),
267 checked_input_objects,
268 gas_data,
269 gas_status,
270 kind,
271 signer,
272 transaction.digest(),
273 checks.disabled(),
274 );
275
276 Ok(SimulateTransactionResult {
277 input_objects: inner_temp_store.input_objects,
278 output_objects: inner_temp_store.written,
279 events: effects.events_digest().map(|_| inner_temp_store.events),
280 effects,
281 execution_result,
282 mock_gas_id,
283 suggested_gas_price: None,
284 })
285 }
286}