1use move_binary_format::file_format::{
19 Ability, AbilitySet, Bytecode, CompiledModule, DatatypeHandle, FunctionDefinition,
20 FunctionHandle, SignatureToken, StructDefinition,
21};
22use move_core_types::{ident_str, language_storage::ModuleId};
23use sui_types::bridge::BRIDGE_SUPPORTED_ASSET;
24use sui_types::{
25 BRIDGE_ADDRESS, SUI_FRAMEWORK_ADDRESS,
26 base_types::{TX_CONTEXT_MODULE_NAME, TX_CONTEXT_STRUCT_NAME},
27 error::ExecutionError,
28 move_package::{FnInfoMap, is_test_fun},
29};
30
31use crate::{INIT_FN_NAME, verification_failure};
32
33pub fn verify_module(
34 module: &CompiledModule,
35 fn_info_map: &FnInfoMap,
36) -> Result<(), ExecutionError> {
37 let self_id = module.self_id();
46
47 if ModuleId::new(SUI_FRAMEWORK_ADDRESS, ident_str!("sui").to_owned()) == self_id {
48 return Ok(());
49 }
50
51 if BRIDGE_SUPPORTED_ASSET
52 .iter()
53 .any(|token| ModuleId::new(BRIDGE_ADDRESS, ident_str!(token).to_owned()) == self_id)
54 {
55 return Ok(());
56 }
57
58 let mod_handle = module.module_handle_at(module.self_module_handle_idx);
59 let mod_name = module.identifier_at(mod_handle.name).as_str();
60 let struct_defs = &module.struct_defs;
61 let mut one_time_witness_candidate = None;
62 for def in struct_defs {
64 let struct_handle = module.datatype_handle_at(def.struct_handle);
65 let struct_name = module.identifier_at(struct_handle.name).as_str();
66 if mod_name.to_ascii_uppercase() == struct_name {
67 if let Ok(field_count) = def.declared_field_count() {
69 if field_count == 1 && def.field(0).unwrap().signature.0 == SignatureToken::Bool {
72 verify_one_time_witness(module, struct_name, struct_handle)
75 .map_err(verification_failure)?;
76 one_time_witness_candidate = Some((struct_name, struct_handle, def));
81 break; }
83 }
84 }
85 }
86 for fn_def in &module.function_defs {
87 let fn_handle = module.function_handle_at(fn_def.function);
88 let fn_name = module.identifier_at(fn_handle.name);
89 if fn_name == INIT_FN_NAME {
90 if let Some((candidate_name, candidate_handle, _)) = one_time_witness_candidate {
91 verify_init_one_time_witness(module, fn_handle, candidate_name, candidate_handle)
94 .map_err(verification_failure)?;
95 } else {
96 verify_init_single_param(module, fn_handle).map_err(verification_failure)?;
99 }
100 }
101 if let Some((candidate_name, _, def)) = one_time_witness_candidate {
102 if !is_test_fun(fn_name, module, fn_info_map) {
106 verify_no_instantiations(module, fn_def, candidate_name, def)
107 .map_err(verification_failure)?;
108 }
109 }
110 }
111
112 Ok(())
113}
114
115fn verify_one_time_witness(
118 module: &CompiledModule,
119 candidate_name: &str,
120 candidate_handle: &DatatypeHandle,
121) -> Result<(), String> {
122 let drop_set = AbilitySet::EMPTY | Ability::Drop;
124 let abilities = candidate_handle.abilities;
125 if abilities != drop_set {
126 return Err(format!(
127 "one-time witness type candidate {}::{} must have a single ability: drop",
128 module.self_id(),
129 candidate_name,
130 ));
131 }
132
133 if !candidate_handle.type_parameters.is_empty() {
134 return Err(format!(
135 "one-time witness type candidate {}::{} cannot have type parameters",
136 module.self_id(),
137 candidate_name,
138 ));
139 }
140 Ok(())
141}
142
143fn verify_init_one_time_witness(
145 module: &CompiledModule,
146 fn_handle: &FunctionHandle,
147 candidate_name: &str,
148 candidate_handle: &DatatypeHandle,
149) -> Result<(), String> {
150 let fn_sig = module.signature_at(fn_handle.parameters);
151 if fn_sig.len() != 2 || !is_one_time_witness(module, &fn_sig.0[0], candidate_handle) {
152 return Err(format!(
155 "init function of a module containing one-time witness type candidate must have \
156 {}::{} as the first parameter (a struct which has no fields or a single field of type \
157 bool)",
158 module.self_id(),
159 candidate_name,
160 ));
161 }
162
163 Ok(())
164}
165
166fn is_one_time_witness(
168 view: &CompiledModule,
169 tok: &SignatureToken,
170 candidate_handle: &DatatypeHandle,
171) -> bool {
172 matches!(tok, SignatureToken::Datatype(idx) if view.datatype_handle_at(*idx) == candidate_handle)
173}
174
175fn verify_init_single_param(
177 module: &CompiledModule,
178 fn_handle: &FunctionHandle,
179) -> Result<(), String> {
180 let fn_sig = module.signature_at(fn_handle.parameters);
181 if fn_sig.len() != 1 {
182 return Err(format!(
183 "Expected last (and at most second) parameter for {0}::{1} to be &mut {2}::{3}::{4} or \
184 &{2}::{3}::{4}; optional first parameter must be of one-time witness type whose name \
185 is the same as the capitalized module name ({5}::{6}) and which has no fields or a \
186 single field of type bool",
187 module.self_id(),
188 INIT_FN_NAME,
189 SUI_FRAMEWORK_ADDRESS,
190 TX_CONTEXT_MODULE_NAME,
191 TX_CONTEXT_STRUCT_NAME,
192 module.self_id(),
193 module.self_id().name().as_str().to_uppercase(),
194 ));
195 }
196
197 Ok(())
198}
199
200fn verify_no_instantiations(
202 module: &CompiledModule,
203 fn_def: &FunctionDefinition,
204 struct_name: &str,
205 struct_def: &StructDefinition,
206) -> Result<(), String> {
207 if fn_def.code.is_none() {
208 return Ok(());
209 }
210 for bcode in &fn_def.code.as_ref().unwrap().code {
211 let struct_def_idx = match bcode {
212 Bytecode::Pack(idx) => idx,
213 _ => continue,
214 };
215 if module.struct_def_at(*struct_def_idx) == struct_def {
218 let fn_handle = module.function_handle_at(fn_def.function);
219 let fn_name = module.identifier_at(fn_handle.name);
220 return Err(format!(
221 "one-time witness type {}::{} is instantiated \
222 in the {}::{} function and must never be",
223 module.self_id(),
224 struct_name,
225 module.self_id(),
226 fn_name,
227 ));
228 }
229 }
230
231 Ok(())
232}