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,
36 error::{ExecutionErrorKind, SuiError},
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 }
73 }
74
75 pub fn new_native_extensions<'r>(
76 child_resolver: &'r dyn ChildObjectResolver,
77 input_objects: BTreeMap<ObjectID, object_runtime::InputObject>,
78 is_metered: bool,
79 protocol_config: &'r ProtocolConfig,
80 metrics: Arc<LimitsMetrics>,
81 tx_context: Rc<RefCell<TxContext>>,
82 ) -> NativeContextExtensions<'r> {
83 let current_epoch_id: EpochId = tx_context.borrow().epoch();
84 let mut extensions = NativeContextExtensions::default();
85 extensions.add(ObjectRuntime::new(
86 child_resolver,
87 input_objects,
88 is_metered,
89 protocol_config,
90 metrics,
91 current_epoch_id,
92 ));
93 extensions.add(NativesCostTable::from_protocol_config(protocol_config));
94 extensions.add(TransactionContext::new(tx_context));
95 extensions
96 }
97
98 pub fn substitute_package_id(
101 modules: &mut [CompiledModule],
102 object_id: ObjectID,
103 ) -> Result<(), ExecutionError> {
104 let new_address = AccountAddress::from(object_id);
105
106 for module in modules.iter_mut() {
107 let self_handle = module.self_handle().clone();
108 let self_address_idx = self_handle.address;
109
110 let addrs = &mut module.address_identifiers;
111 let Some(address_mut) = addrs.get_mut(self_address_idx.0 as usize) else {
112 let name = module.identifier_at(self_handle.name);
113 return Err(ExecutionError::new_with_source(
114 ExecutionErrorKind::PublishErrorNonZeroAddress,
115 format!("Publishing module {name} with invalid address index"),
116 ));
117 };
118
119 if *address_mut != AccountAddress::ZERO {
120 let name = module.identifier_at(self_handle.name);
121 return Err(ExecutionError::new_with_source(
122 ExecutionErrorKind::PublishErrorNonZeroAddress,
123 format!("Publishing module {name} with non-zero address is not allowed"),
124 ));
125 };
126
127 *address_mut = new_address;
128 }
129
130 Ok(())
131 }
132
133 pub fn missing_unwrapped_msg(id: &ObjectID) -> String {
134 format!(
135 "Unable to unwrap object {}. Was unable to retrieve last known version in the parent sync",
136 id
137 )
138 }
139
140 #[instrument(level = "trace", skip_all)]
146 pub fn run_metered_move_bytecode_verifier(
147 modules: &[CompiledModule],
148 verifier_config: &VerifierConfig,
149 meter: &mut (impl Meter + ?Sized),
150 metrics: &Arc<BytecodeVerifierMetrics>,
151 ) -> Result<(), SuiError> {
152 for module in modules.iter() {
154 let per_module_meter_verifier_timer = metrics
155 .verifier_runtime_per_module_success_latency
156 .start_timer();
157
158 if let Err(e) = verify_module_timeout_only(module, verifier_config, meter) {
159 metrics
162 .verifier_runtime_per_module_timeout_latency
163 .observe(per_module_meter_verifier_timer.stop_and_discard());
164 metrics
165 .verifier_timeout_metrics
166 .with_label_values(&[
167 BytecodeVerifierMetrics::OVERALL_TAG,
168 BytecodeVerifierMetrics::TIMEOUT_TAG,
169 ])
170 .inc();
171
172 return Err(e);
173 };
174
175 per_module_meter_verifier_timer.stop_and_record();
177 metrics
178 .verifier_timeout_metrics
179 .with_label_values(&[
180 BytecodeVerifierMetrics::OVERALL_TAG,
181 BytecodeVerifierMetrics::SUCCESS_TAG,
182 ])
183 .inc();
184 }
185
186 Ok(())
187 }
188
189 fn verify_module_timeout_only(
193 module: &CompiledModule,
194 verifier_config: &VerifierConfig,
195 meter: &mut (impl Meter + ?Sized),
196 ) -> Result<(), SuiError> {
197 meter.enter_scope(module.self_id().name().as_str(), Scope::Module);
198
199 if let Err(e) = verify_module_with_config_metered(verifier_config, module, meter) {
200 if check_for_verifier_timeout(&e.major_status()) {
202 if e.major_status()
203 == move_core_types::vm_status::StatusCode::REFERENCE_SAFETY_INCONSISTENT
204 {
205 let mut bytes = vec![];
206 let _ = module.serialize_with_version(
207 move_binary_format::file_format_common::VERSION_MAX,
208 &mut bytes,
209 );
210 debug_fatal!(
211 "Reference safety inconsistency detected in module: {:?}",
212 bytes
213 );
214 }
215 return Err(SuiErrorKind::ModuleVerificationFailure {
216 error: format!("Verification timed out: {}", e),
217 }
218 .into());
219 }
220 } else if let Err(err) = sui_verify_module_metered_check_timeout_only(
221 module,
222 &BTreeMap::new(),
223 meter,
224 verifier_config,
225 ) {
226 return Err(err.into());
227 }
228
229 if meter.transfer(Scope::Module, Scope::Package, 1.0).is_err() {
230 return Err(SuiErrorKind::ModuleVerificationFailure {
231 error: "Verification timed out".to_string(),
232 }
233 .into());
234 }
235
236 Ok(())
237 }
238}