1pub use checked::*;
6#[iota_macros::with_checked_arithmetic]
7mod checked {
8 use std::{cell::RefCell, collections::BTreeMap, path::PathBuf, rc::Rc, sync::Arc};
9
10 use anyhow::Result;
11 use iota_common::debug_fatal;
12 use iota_move_natives::{
13 NativesCostTable,
14 authentication_context::AuthenticationContext,
15 object_runtime::{self, ObjectRuntime},
16 transaction_context::TransactionContext,
17 };
18 use iota_protocol_config::ProtocolConfig;
19 use iota_sdk_types::ObjectId;
20 use iota_types::{
21 auth_context::AuthContext,
22 base_types::*,
23 error::{ExecutionError, ExecutionErrorKind, IotaError},
24 execution_config_utils::to_binary_config,
25 metrics::{BytecodeVerifierMetrics, LimitsMetrics},
26 move_package::ProtocolBuildConfig,
27 storage::ChildObjectResolver,
28 };
29 use iota_verifier::{
30 check_for_verifier_timeout, verifier::iota_verify_module_metered_check_timeout_only,
31 };
32 use move_binary_format::file_format::CompiledModule;
33 use move_bytecode_verifier::verify_module_with_config_metered;
34 use move_bytecode_verifier_meter::{Meter, Scope};
35 use move_core_types::account_address::AccountAddress;
36 #[cfg(feature = "tracing")]
37 use move_vm_config::runtime::VMProfilerConfig;
38 use move_vm_config::{
39 runtime::{VMConfig, VMRuntimeLimitsConfig},
40 verifier::VerifierConfig,
41 };
42 use move_vm_runtime::{
43 move_vm::MoveVM, native_extensions::NativeContextExtensions,
44 native_functions::NativeFunctionTable,
45 };
46 use tracing::instrument;
47
48 pub fn new_move_vm(
55 natives: NativeFunctionTable,
56 protocol_config: &ProtocolConfig,
57 _enable_profiler: Option<PathBuf>,
58 ) -> Result<MoveVM, IotaError> {
59 #[cfg(not(feature = "tracing"))]
60 let vm_profiler_config = None;
61 #[cfg(feature = "tracing")]
62 let vm_profiler_config = _enable_profiler.map(|path| VMProfilerConfig {
63 full_path: path,
64 track_bytecode_instructions: false,
65 use_long_function_name: false,
66 });
67 MoveVM::new_with_config(
68 natives,
69 VMConfig {
70 verifier: protocol_config.verifier_config(None),
71 max_binary_format_version: protocol_config.move_binary_format_version(),
72 runtime_limits_config: VMRuntimeLimitsConfig {
73 vector_len_max: protocol_config.max_move_vector_len(),
74 max_value_nest_depth: protocol_config.max_move_value_depth_as_option(),
75 hardened_otw_check: protocol_config.hardened_otw_check(),
76 },
77 enable_invariant_violation_check_in_swap_loc: !protocol_config
78 .disable_invariant_violation_check_in_swap_loc(),
79 check_no_extraneous_bytes_during_deserialization: protocol_config
80 .no_extraneous_module_bytes(),
81 profiler_config: vm_profiler_config,
82 error_execution_state: false,
84 binary_config: to_binary_config(protocol_config),
85 rethrow_serialization_type_layout_errors: protocol_config
86 .rethrow_serialization_type_layout_errors(),
87 max_type_to_layout_nodes: protocol_config.max_type_to_layout_nodes_as_option(),
88 variant_nodes: protocol_config.variant_nodes(),
89 },
90 )
91 .map_err(|_| IotaError::ExecutionInvariantViolation)
92 }
93
94 pub fn new_native_extensions<'r>(
102 child_resolver: &'r dyn ChildObjectResolver,
103 input_objects: BTreeMap<ObjectId, object_runtime::InputObject>,
104 is_metered: bool,
105 protocol_config: &'r ProtocolConfig,
106 metrics: Arc<LimitsMetrics>,
107 tx_context: Rc<RefCell<TxContext>>,
108 auth_context: Option<Rc<RefCell<AuthContext>>>,
109 ) -> NativeContextExtensions<'r> {
110 let current_epoch_id = tx_context.borrow().epoch();
113 let mut extensions = NativeContextExtensions::default();
114 extensions.add(ObjectRuntime::new(
115 child_resolver,
116 input_objects,
117 is_metered,
118 protocol_config,
119 metrics,
120 current_epoch_id,
121 ));
122 extensions.add(NativesCostTable::from_protocol_config(protocol_config));
123 extensions.add(TransactionContext::new(tx_context));
124 if let Some(auth_context) = auth_context {
125 extensions.add(AuthenticationContext::new(auth_context));
126 }
127 extensions
128 }
129
130 pub fn substitute_package_id(
133 modules: &mut [CompiledModule],
134 object_id: ObjectId,
135 ) -> Result<(), ExecutionError> {
136 let new_address = AccountAddress::new(object_id.into_bytes());
137
138 for module in modules.iter_mut() {
139 let self_handle = module.self_handle().clone();
140 let self_address_idx = self_handle.address;
141
142 let addrs = &mut module.address_identifiers;
143 let Some(address_mut) = addrs.get_mut(self_address_idx.0 as usize) else {
144 let name = module.identifier_at(self_handle.name);
145 return Err(ExecutionError::new_with_source(
146 ExecutionErrorKind::PublishErrorNonZeroAddress,
147 format!("Publishing module {name} with invalid address index"),
148 ));
149 };
150
151 if *address_mut != AccountAddress::ZERO {
152 let name = module.identifier_at(self_handle.name);
153 return Err(ExecutionError::new_with_source(
154 ExecutionErrorKind::PublishErrorNonZeroAddress,
155 format!("Publishing module {name} with non-zero address is not allowed"),
156 ));
157 };
158
159 *address_mut = new_address;
160 }
161
162 Ok(())
163 }
164
165 #[instrument(level = "trace", skip_all)]
171 pub fn run_metered_move_bytecode_verifier(
172 modules: &[CompiledModule],
173 verifier_config: &VerifierConfig,
174 meter: &mut (impl Meter + ?Sized),
175 metrics: &Arc<BytecodeVerifierMetrics>,
176 protocol_build_config: &ProtocolBuildConfig,
177 ) -> Result<(), IotaError> {
178 for module in modules.iter() {
180 let per_module_meter_verifier_timer = metrics
181 .verifier_runtime_per_module_success_latency
182 .start_timer();
183
184 if let Err(e) =
185 verify_module_timeout_only(module, verifier_config, meter, protocol_build_config)
186 {
187 metrics
190 .verifier_runtime_per_module_timeout_latency
191 .observe(per_module_meter_verifier_timer.stop_and_discard());
192 metrics
193 .verifier_timeout_metrics
194 .with_label_values(&[
195 BytecodeVerifierMetrics::OVERALL_TAG,
196 BytecodeVerifierMetrics::TIMEOUT_TAG,
197 ])
198 .inc();
199
200 return Err(e);
201 };
202
203 per_module_meter_verifier_timer.stop_and_record();
205 metrics
206 .verifier_timeout_metrics
207 .with_label_values(&[
208 BytecodeVerifierMetrics::OVERALL_TAG,
209 BytecodeVerifierMetrics::SUCCESS_TAG,
210 ])
211 .inc();
212 }
213
214 Ok(())
215 }
216
217 fn verify_module_timeout_only(
222 module: &CompiledModule,
223 verifier_config: &VerifierConfig,
224 meter: &mut (impl Meter + ?Sized),
225 protocol_build_config: &ProtocolBuildConfig,
226 ) -> Result<(), IotaError> {
227 meter.enter_scope(module.self_id().name().as_str(), Scope::Module);
228
229 if let Err(e) = verify_module_with_config_metered(verifier_config, module, meter) {
230 if check_for_verifier_timeout(&e.major_status()) {
232 if e.major_status()
233 == move_core_types::vm_status::StatusCode::REFERENCE_SAFETY_INCONSISTENT
234 {
235 let mut bytes = vec![];
236 let _ = module.serialize_with_version(
237 move_binary_format::file_format_common::VERSION_MAX,
238 &mut bytes,
239 );
240 debug_fatal!(
241 "Reference safety inconsistency detected in module: {:?}",
242 bytes
243 );
244 }
245 return Err(IotaError::ModuleVerificationFailure {
246 error: format!("Verification timed out: {e}"),
247 });
248 }
249 } else if let Err(err) = iota_verify_module_metered_check_timeout_only(
250 module,
251 &BTreeMap::new(),
252 meter,
253 protocol_build_config,
254 ) {
255 return Err(err.into());
256 }
257
258 if meter.transfer(Scope::Module, Scope::Package, 1.0).is_err() {
259 return Err(IotaError::ModuleVerificationFailure {
260 error: "Verification timed out".to_string(),
261 });
262 }
263
264 Ok(())
265 }
266}