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