1pub use checked::*;
5#[sui_macros::with_checked_arithmetic]
6mod checked {
7 use move_vm_runtime::natives::extensions::NativeExtensions;
8 use move_vm_runtime::natives::functions::{NativeFunctionTable, NativeFunctions};
9 use move_vm_runtime::runtime::MoveRuntime;
10 use std::cell::RefCell;
11 use std::rc::Rc;
12 use std::{collections::BTreeMap, sync::Arc};
13
14 use anyhow::Result;
15 use move_binary_format::file_format::CompiledModule;
16 use move_bytecode_verifier::verify_module_with_config_metered;
17 use move_bytecode_verifier_meter::{Meter, Scope};
18 use move_core_types::account_address::AccountAddress;
19 use move_vm_config::{
20 runtime::{VMConfig, VMRuntimeLimitsConfig},
21 verifier::VerifierConfig,
22 };
23 use mysten_common::debug_fatal;
24 use sui_move_natives::{object_runtime, transaction_context::TransactionContext};
25 use sui_types::error::SuiErrorKind;
26 use sui_types::metrics::BytecodeVerifierMetrics;
27 use sui_verifier::check_for_verifier_timeout;
28 use tracing::instrument;
29
30 use sui_move_natives::{NativesCostTable, object_runtime::ObjectRuntime};
31 use sui_protocol_config::ProtocolConfig;
32 use sui_types::{
33 base_types::*,
34 error::{ExecutionError, SuiError},
35 execution_status::ExecutionErrorKind,
36 metrics::LimitsMetrics,
37 storage::ChildObjectResolver,
38 };
39 use sui_verifier::verifier::sui_verify_module_metered_check_timeout_only;
40
41 pub fn new_move_runtime(
42 natives: NativeFunctionTable,
43 protocol_config: &ProtocolConfig,
44 ) -> Result<MoveRuntime, SuiError> {
45 let native_functions =
46 NativeFunctions::new(natives).map_err(|_| SuiErrorKind::ExecutionInvariantViolation)?;
47 Ok(MoveRuntime::new(
48 native_functions,
49 vm_config(protocol_config),
50 ))
51 }
52
53 pub fn vm_config(protocol_config: &ProtocolConfig) -> VMConfig {
54 VMConfig {
55 verifier: protocol_config.verifier_config(None),
56 max_binary_format_version: protocol_config.move_binary_format_version(),
57 runtime_limits_config: VMRuntimeLimitsConfig {
58 vector_len_max: protocol_config.max_move_vector_len(),
59 max_value_nest_depth: protocol_config.max_move_value_depth_as_option(),
60 hardened_otw_check: protocol_config.hardened_otw_check(),
61 },
62 enable_invariant_violation_check_in_swap_loc: !protocol_config
63 .disable_invariant_violation_check_in_swap_loc(),
64 check_no_extraneous_bytes_during_deserialization: protocol_config
65 .no_extraneous_module_bytes(),
66 error_execution_state: false,
68 binary_config: protocol_config.binary_config(None),
69 rethrow_serialization_type_layout_errors: protocol_config
70 .rethrow_serialization_type_layout_errors(),
71 max_type_to_layout_nodes: protocol_config.max_type_to_layout_nodes_as_option(),
72 variant_nodes: protocol_config.variant_nodes(),
73 deprecate_global_storage_ops_during_deserialization: protocol_config
74 .deprecate_global_storage_ops_during_deserialization(),
75 normalize_depth_formula: protocol_config.normalize_depth_formula(),
76 }
77 }
78
79 pub fn new_native_extensions<'r>(
80 child_resolver: &'r dyn ChildObjectResolver,
81 input_objects: BTreeMap<ObjectID, object_runtime::InputObject>,
82 is_metered: bool,
83 protocol_config: &'r ProtocolConfig,
84 metrics: Arc<LimitsMetrics>,
85 tx_context: Rc<RefCell<TxContext>>,
86 ) -> Result<NativeExtensions<'r>, ExecutionError> {
87 let current_epoch_id: EpochId = tx_context.borrow().epoch();
88 let extensions = NativeExtensions::default();
89 let mut exts = extensions.try_borrow_mut().map_err(|_| {
90 make_invariant_violation!(
91 "Failed to mutably borrow native extensions to populate them right after creating them"
92 )
93 })?;
94 exts.add(ObjectRuntime::new(
95 child_resolver,
96 input_objects,
97 is_metered,
98 protocol_config,
99 metrics,
100 current_epoch_id,
101 ));
102 exts.add(NativesCostTable::from_protocol_config(protocol_config));
103 exts.add(TransactionContext::new(tx_context));
104 drop(exts);
105 Ok(extensions)
106 }
107
108 pub fn substitute_package_id(
111 modules: &mut [CompiledModule],
112 object_id: ObjectID,
113 ) -> Result<(), ExecutionError> {
114 let new_address = AccountAddress::from(object_id);
115
116 for module in modules.iter_mut() {
117 let self_handle = module.self_handle().clone();
118 let self_address_idx = self_handle.address;
119
120 let addrs = &mut module.address_identifiers;
121 let Some(address_mut) = addrs.get_mut(self_address_idx.0 as usize) else {
122 let name = module.identifier_at(self_handle.name);
123 return Err(ExecutionError::new_with_source(
124 ExecutionErrorKind::PublishErrorNonZeroAddress,
125 format!("Publishing module {name} with invalid address index"),
126 ));
127 };
128
129 if *address_mut != AccountAddress::ZERO {
130 let name = module.identifier_at(self_handle.name);
131 return Err(ExecutionError::new_with_source(
132 ExecutionErrorKind::PublishErrorNonZeroAddress,
133 format!("Publishing module {name} with non-zero address is not allowed"),
134 ));
135 };
136
137 *address_mut = new_address;
138 }
139
140 Ok(())
141 }
142
143 pub fn missing_unwrapped_msg(id: &ObjectID) -> String {
144 format!(
145 "Unable to unwrap object {}. Was unable to retrieve last known version in the parent sync",
146 id
147 )
148 }
149
150 #[instrument(level = "trace", skip_all)]
156 pub fn run_metered_move_bytecode_verifier(
157 modules: &[CompiledModule],
158 verifier_config: &VerifierConfig,
159 meter: &mut (impl Meter + ?Sized),
160 metrics: &Arc<BytecodeVerifierMetrics>,
161 ) -> Result<(), SuiError> {
162 for module in modules.iter() {
164 let per_module_meter_verifier_timer = metrics
165 .verifier_runtime_per_module_success_latency
166 .start_timer();
167
168 if let Err(e) = verify_module_timeout_only(module, verifier_config, meter) {
169 metrics
172 .verifier_runtime_per_module_timeout_latency
173 .observe(per_module_meter_verifier_timer.stop_and_discard());
174 metrics
175 .verifier_timeout_metrics
176 .with_label_values(&[
177 BytecodeVerifierMetrics::OVERALL_TAG,
178 BytecodeVerifierMetrics::TIMEOUT_TAG,
179 ])
180 .inc();
181
182 return Err(e);
183 };
184
185 per_module_meter_verifier_timer.stop_and_record();
187 metrics
188 .verifier_timeout_metrics
189 .with_label_values(&[
190 BytecodeVerifierMetrics::OVERALL_TAG,
191 BytecodeVerifierMetrics::SUCCESS_TAG,
192 ])
193 .inc();
194 }
195
196 Ok(())
197 }
198
199 fn verify_module_timeout_only(
203 module: &CompiledModule,
204 verifier_config: &VerifierConfig,
205 meter: &mut (impl Meter + ?Sized),
206 ) -> Result<(), SuiError> {
207 meter.enter_scope(module.self_id().name().as_str(), Scope::Module);
208
209 if let Err(e) = verify_module_with_config_metered(verifier_config, module, meter) {
210 if check_for_verifier_timeout(&e.major_status()) {
212 if e.major_status()
213 == move_core_types::vm_status::StatusCode::REFERENCE_SAFETY_INCONSISTENT
214 {
215 let mut bytes = vec![];
216 let _ = module.serialize_with_version(
217 move_binary_format::file_format_common::VERSION_MAX,
218 &mut bytes,
219 );
220 debug_fatal!(
221 "Reference safety inconsistency detected in module: {:?}",
222 bytes
223 );
224 }
225 return Err(SuiErrorKind::ModuleVerificationFailure {
226 error: format!("Verification timed out: {}", e),
227 }
228 .into());
229 }
230 } else if let Err(err) = sui_verify_module_metered_check_timeout_only(
231 module,
232 &BTreeMap::new(),
233 meter,
234 verifier_config,
235 ) {
236 return Err(err.into());
237 }
238
239 if meter.transfer(Scope::Module, Scope::Package, 1.0).is_err() {
240 return Err(SuiErrorKind::ModuleVerificationFailure {
241 error: "Verification timed out".to_string(),
242 }
243 .into());
244 }
245
246 Ok(())
247 }
248}