1pub use checked::*;
6#[iota_macros::with_checked_arithmetic]
7mod checked {
8 use std::{collections::BTreeMap, path::PathBuf, sync::Arc};
9
10 use anyhow::Result;
11 use iota_move_natives::{NativesCostTable, object_runtime, object_runtime::ObjectRuntime};
12 use iota_protocol_config::ProtocolConfig;
13 use iota_types::{
14 base_types::*,
15 error::{ExecutionError, ExecutionErrorKind, IotaError},
16 execution_config_utils::to_binary_config,
17 metrics::{BytecodeVerifierMetrics, LimitsMetrics},
18 storage::ChildObjectResolver,
19 };
20 use iota_verifier::{
21 check_for_verifier_timeout, verifier::iota_verify_module_metered_check_timeout_only,
22 };
23 use move_binary_format::file_format::CompiledModule;
24 use move_bytecode_verifier::verify_module_with_config_metered;
25 use move_bytecode_verifier_meter::{Meter, Scope};
26 use move_core_types::account_address::AccountAddress;
27 #[cfg(feature = "tracing")]
28 use move_vm_config::runtime::VMProfilerConfig;
29 use move_vm_config::{
30 runtime::{VMConfig, VMRuntimeLimitsConfig},
31 verifier::VerifierConfig,
32 };
33 use move_vm_runtime::{
34 move_vm::MoveVM, native_extensions::NativeContextExtensions,
35 native_functions::NativeFunctionTable,
36 };
37 use tracing::instrument;
38
39 pub fn new_move_vm(
46 natives: NativeFunctionTable,
47 protocol_config: &ProtocolConfig,
48 _enable_profiler: Option<PathBuf>,
49 ) -> Result<MoveVM, IotaError> {
50 #[cfg(not(feature = "tracing"))]
51 let vm_profiler_config = None;
52 #[cfg(feature = "tracing")]
53 let vm_profiler_config = _enable_profiler.clone().map(|path| VMProfilerConfig {
54 full_path: path,
55 track_bytecode_instructions: false,
56 use_long_function_name: false,
57 });
58 MoveVM::new_with_config(
59 natives,
60 VMConfig {
61 verifier: protocol_config.verifier_config(None),
62 max_binary_format_version: protocol_config.move_binary_format_version(),
63 runtime_limits_config: VMRuntimeLimitsConfig {
64 vector_len_max: protocol_config.max_move_vector_len(),
65 max_value_nest_depth: protocol_config.max_move_value_depth_as_option(),
66 hardened_otw_check: protocol_config.hardened_otw_check(),
67 },
68 enable_invariant_violation_check_in_swap_loc: !protocol_config
69 .disable_invariant_violation_check_in_swap_loc(),
70 check_no_extraneous_bytes_during_deserialization: protocol_config
71 .no_extraneous_module_bytes(),
72 profiler_config: vm_profiler_config,
73 error_execution_state: false,
75 binary_config: to_binary_config(protocol_config),
76 rethrow_serialization_type_layout_errors: protocol_config
77 .rethrow_serialization_type_layout_errors(),
78 max_type_to_layout_nodes: protocol_config.max_type_to_layout_nodes_as_option(),
79 variant_nodes: protocol_config.variant_nodes(),
80 },
81 )
82 .map_err(|_| IotaError::ExecutionInvariantViolation)
83 }
84
85 pub fn new_native_extensions<'r>(
92 child_resolver: &'r dyn ChildObjectResolver,
93 input_objects: BTreeMap<ObjectID, object_runtime::InputObject>,
94 is_metered: bool,
95 protocol_config: &'r ProtocolConfig,
96 metrics: Arc<LimitsMetrics>,
97 current_epoch_id: EpochId,
98 ) -> NativeContextExtensions<'r> {
99 let mut extensions = NativeContextExtensions::default();
100 extensions.add(ObjectRuntime::new(
101 child_resolver,
102 input_objects,
103 is_metered,
104 protocol_config,
105 metrics,
106 current_epoch_id,
107 ));
108 extensions.add(NativesCostTable::from_protocol_config(protocol_config));
109 extensions
110 }
111
112 pub fn substitute_package_id(
115 modules: &mut [CompiledModule],
116 object_id: ObjectID,
117 ) -> Result<(), ExecutionError> {
118 let new_address = AccountAddress::from(object_id);
119
120 for module in modules.iter_mut() {
121 let self_handle = module.self_handle().clone();
122 let self_address_idx = self_handle.address;
123
124 let addrs = &mut module.address_identifiers;
125 let Some(address_mut) = addrs.get_mut(self_address_idx.0 as usize) else {
126 let name = module.identifier_at(self_handle.name);
127 return Err(ExecutionError::new_with_source(
128 ExecutionErrorKind::PublishErrorNonZeroAddress,
129 format!("Publishing module {name} with invalid address index"),
130 ));
131 };
132
133 if *address_mut != AccountAddress::ZERO {
134 let name = module.identifier_at(self_handle.name);
135 return Err(ExecutionError::new_with_source(
136 ExecutionErrorKind::PublishErrorNonZeroAddress,
137 format!("Publishing module {name} with non-zero address is not allowed"),
138 ));
139 };
140
141 *address_mut = new_address;
142 }
143
144 Ok(())
145 }
146
147 #[instrument(level = "trace", skip_all)]
153 pub fn run_metered_move_bytecode_verifier(
154 modules: &[CompiledModule],
155 verifier_config: &VerifierConfig,
156 meter: &mut (impl Meter + ?Sized),
157 metrics: &Arc<BytecodeVerifierMetrics>,
158 ) -> Result<(), IotaError> {
159 for module in modules.iter() {
161 let per_module_meter_verifier_timer = metrics
162 .verifier_runtime_per_module_success_latency
163 .start_timer();
164
165 if let Err(e) = verify_module_timeout_only(module, verifier_config, meter) {
166 metrics
169 .verifier_runtime_per_module_timeout_latency
170 .observe(per_module_meter_verifier_timer.stop_and_discard());
171 metrics
172 .verifier_timeout_metrics
173 .with_label_values(&[
174 BytecodeVerifierMetrics::OVERALL_TAG,
175 BytecodeVerifierMetrics::TIMEOUT_TAG,
176 ])
177 .inc();
178
179 return Err(e);
180 };
181
182 per_module_meter_verifier_timer.stop_and_record();
184 metrics
185 .verifier_timeout_metrics
186 .with_label_values(&[
187 BytecodeVerifierMetrics::OVERALL_TAG,
188 BytecodeVerifierMetrics::SUCCESS_TAG,
189 ])
190 .inc();
191 }
192
193 Ok(())
194 }
195
196 fn verify_module_timeout_only(
201 module: &CompiledModule,
202 verifier_config: &VerifierConfig,
203 meter: &mut (impl Meter + ?Sized),
204 ) -> Result<(), IotaError> {
205 meter.enter_scope(module.self_id().name().as_str(), Scope::Module);
206
207 if let Err(e) = verify_module_with_config_metered(verifier_config, module, meter) {
208 if check_for_verifier_timeout(&e.major_status()) {
210 return Err(IotaError::ModuleVerificationFailure {
211 error: format!("Verification timed out: {}", e),
212 });
213 }
214 } else if let Err(err) =
215 iota_verify_module_metered_check_timeout_only(module, &BTreeMap::new(), meter)
216 {
217 return Err(err.into());
218 }
219
220 if meter.transfer(Scope::Module, Scope::Package, 1.0).is_err() {
221 return Err(IotaError::ModuleVerificationFailure {
222 error: "Verification timed out".to_string(),
223 });
224 }
225
226 Ok(())
227 }
228}