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