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_move_natives::{
12 NativesCostTable,
13 authentication_context::AuthenticationContext,
14 object_runtime::{self, ObjectRuntime},
15 transaction_context::TransactionContext,
16 };
17 use iota_protocol_config::ProtocolConfig;
18 use iota_types::{
19 auth_context::AuthContext,
20 base_types::*,
21 error::{ExecutionError, ExecutionErrorKind, IotaError},
22 execution_config_utils::to_binary_config,
23 metrics::{BytecodeVerifierMetrics, LimitsMetrics},
24 storage::ChildObjectResolver,
25 };
26 use iota_verifier::{
27 check_for_verifier_timeout, verifier::iota_verify_module_metered_check_timeout_only,
28 };
29 use move_binary_format::file_format::CompiledModule;
30 use move_bytecode_verifier::verify_module_with_config_metered;
31 use move_bytecode_verifier_meter::{Meter, Scope};
32 use move_core_types::account_address::AccountAddress;
33 #[cfg(feature = "tracing")]
34 use move_vm_config::runtime::VMProfilerConfig;
35 use move_vm_config::{
36 runtime::{VMConfig, VMRuntimeLimitsConfig},
37 verifier::VerifierConfig,
38 };
39 use move_vm_runtime::{
40 move_vm::MoveVM, native_extensions::NativeContextExtensions,
41 native_functions::NativeFunctionTable,
42 };
43 use tracing::instrument;
44
45 pub fn new_move_vm(
52 natives: NativeFunctionTable,
53 protocol_config: &ProtocolConfig,
54 _enable_profiler: Option<PathBuf>,
55 ) -> Result<MoveVM, IotaError> {
56 #[cfg(not(feature = "tracing"))]
57 let vm_profiler_config = None;
58 #[cfg(feature = "tracing")]
59 let vm_profiler_config = _enable_profiler.map(|path| VMProfilerConfig {
60 full_path: path,
61 track_bytecode_instructions: false,
62 use_long_function_name: false,
63 });
64 MoveVM::new_with_config(
65 natives,
66 VMConfig {
67 verifier: protocol_config.verifier_config(None),
68 max_binary_format_version: protocol_config.move_binary_format_version(),
69 runtime_limits_config: VMRuntimeLimitsConfig {
70 vector_len_max: protocol_config.max_move_vector_len(),
71 max_value_nest_depth: protocol_config.max_move_value_depth_as_option(),
72 hardened_otw_check: protocol_config.hardened_otw_check(),
73 },
74 enable_invariant_violation_check_in_swap_loc: !protocol_config
75 .disable_invariant_violation_check_in_swap_loc(),
76 check_no_extraneous_bytes_during_deserialization: protocol_config
77 .no_extraneous_module_bytes(),
78 profiler_config: vm_profiler_config,
79 error_execution_state: false,
81 binary_config: to_binary_config(protocol_config),
82 rethrow_serialization_type_layout_errors: protocol_config
83 .rethrow_serialization_type_layout_errors(),
84 max_type_to_layout_nodes: protocol_config.max_type_to_layout_nodes_as_option(),
85 variant_nodes: protocol_config.variant_nodes(),
86 },
87 )
88 .map_err(|_| IotaError::ExecutionInvariantViolation)
89 }
90
91 pub fn new_native_extensions<'r>(
99 child_resolver: &'r dyn ChildObjectResolver,
100 input_objects: BTreeMap<ObjectID, object_runtime::InputObject>,
101 is_metered: bool,
102 protocol_config: &'r ProtocolConfig,
103 metrics: Arc<LimitsMetrics>,
104 tx_context: Rc<RefCell<TxContext>>,
105 auth_context: Option<Rc<RefCell<AuthContext>>>,
106 ) -> NativeContextExtensions<'r> {
107 let current_epoch_id = tx_context.borrow().epoch();
110 let mut extensions = NativeContextExtensions::default();
111 extensions.add(ObjectRuntime::new(
112 child_resolver,
113 input_objects,
114 is_metered,
115 protocol_config,
116 metrics,
117 current_epoch_id,
118 ));
119 extensions.add(NativesCostTable::from_protocol_config(protocol_config));
120 extensions.add(TransactionContext::new(tx_context));
121 if let Some(auth_context) = auth_context {
122 extensions.add(AuthenticationContext::new(auth_context));
123 }
124 extensions
125 }
126
127 pub fn substitute_package_id(
130 modules: &mut [CompiledModule],
131 object_id: ObjectID,
132 ) -> Result<(), ExecutionError> {
133 let new_address = AccountAddress::from(object_id);
134
135 for module in modules.iter_mut() {
136 let self_handle = module.self_handle().clone();
137 let self_address_idx = self_handle.address;
138
139 let addrs = &mut module.address_identifiers;
140 let Some(address_mut) = addrs.get_mut(self_address_idx.0 as usize) else {
141 let name = module.identifier_at(self_handle.name);
142 return Err(ExecutionError::new_with_source(
143 ExecutionErrorKind::PublishErrorNonZeroAddress,
144 format!("Publishing module {name} with invalid address index"),
145 ));
146 };
147
148 if *address_mut != AccountAddress::ZERO {
149 let name = module.identifier_at(self_handle.name);
150 return Err(ExecutionError::new_with_source(
151 ExecutionErrorKind::PublishErrorNonZeroAddress,
152 format!("Publishing module {name} with non-zero address is not allowed"),
153 ));
154 };
155
156 *address_mut = new_address;
157 }
158
159 Ok(())
160 }
161
162 #[instrument(level = "trace", skip_all)]
168 pub fn run_metered_move_bytecode_verifier(
169 modules: &[CompiledModule],
170 verifier_config: &VerifierConfig,
171 meter: &mut (impl Meter + ?Sized),
172 metrics: &Arc<BytecodeVerifierMetrics>,
173 ) -> Result<(), IotaError> {
174 for module in modules.iter() {
176 let per_module_meter_verifier_timer = metrics
177 .verifier_runtime_per_module_success_latency
178 .start_timer();
179
180 if let Err(e) = verify_module_timeout_only(module, verifier_config, meter) {
181 metrics
184 .verifier_runtime_per_module_timeout_latency
185 .observe(per_module_meter_verifier_timer.stop_and_discard());
186 metrics
187 .verifier_timeout_metrics
188 .with_label_values(&[
189 BytecodeVerifierMetrics::OVERALL_TAG,
190 BytecodeVerifierMetrics::TIMEOUT_TAG,
191 ])
192 .inc();
193
194 return Err(e);
195 };
196
197 per_module_meter_verifier_timer.stop_and_record();
199 metrics
200 .verifier_timeout_metrics
201 .with_label_values(&[
202 BytecodeVerifierMetrics::OVERALL_TAG,
203 BytecodeVerifierMetrics::SUCCESS_TAG,
204 ])
205 .inc();
206 }
207
208 Ok(())
209 }
210
211 fn verify_module_timeout_only(
216 module: &CompiledModule,
217 verifier_config: &VerifierConfig,
218 meter: &mut (impl Meter + ?Sized),
219 ) -> Result<(), IotaError> {
220 meter.enter_scope(module.self_id().name().as_str(), Scope::Module);
221
222 if let Err(e) = verify_module_with_config_metered(verifier_config, module, meter) {
223 if check_for_verifier_timeout(&e.major_status()) {
225 return Err(IotaError::ModuleVerificationFailure {
226 error: format!("Verification timed out: {e}"),
227 });
228 }
229 } else if let Err(err) =
230 iota_verify_module_metered_check_timeout_only(module, &BTreeMap::new(), meter)
231 {
232 return Err(err.into());
233 }
234
235 if meter.transfer(Scope::Module, Scope::Package, 1.0).is_err() {
236 return Err(IotaError::ModuleVerificationFailure {
237 error: "Verification timed out".to_string(),
238 });
239 }
240
241 Ok(())
242 }
243}