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