sui_verifier_v0/
one_time_witness_verifier.rs1use 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::{
24 base_types::{TX_CONTEXT_MODULE_NAME, TX_CONTEXT_STRUCT_NAME},
25 error::ExecutionError,
26 move_package::{is_test_fun, FnInfoMap},
27 SUI_FRAMEWORK_ADDRESS,
28};
29
30use crate::{verification_failure, INIT_FN_NAME};
31
32pub fn verify_module(
33 module: &CompiledModule,
34 fn_info_map: &FnInfoMap,
35) -> Result<(), ExecutionError> {
36 if ModuleId::new(SUI_FRAMEWORK_ADDRESS, ident_str!("sui").to_owned()) == module.self_id() {
45 return Ok(());
46 }
47
48 let mod_handle = module.module_handle_at(module.self_module_handle_idx);
49 let mod_name = module.identifier_at(mod_handle.name).as_str();
50 let struct_defs = &module.struct_defs;
51 let mut one_time_witness_candidate = None;
52 for def in struct_defs {
54 let struct_handle = module.datatype_handle_at(def.struct_handle);
55 let struct_name = module.identifier_at(struct_handle.name).as_str();
56 if mod_name.to_ascii_uppercase() == struct_name {
57 if let Ok(field_count) = def.declared_field_count() {
59 if field_count == 1 && def.field(0).unwrap().signature.0 == SignatureToken::Bool {
62 verify_one_time_witness(module, struct_name, struct_handle)
65 .map_err(verification_failure)?;
66 one_time_witness_candidate = Some((struct_name, struct_handle, def));
71 break; }
73 }
74 }
75 }
76 for fn_def in &module.function_defs {
77 let fn_handle = module.function_handle_at(fn_def.function);
78 let fn_name = module.identifier_at(fn_handle.name);
79 if fn_name == INIT_FN_NAME {
80 if let Some((candidate_name, candidate_handle, _)) = one_time_witness_candidate {
81 verify_init_one_time_witness(module, fn_handle, candidate_name, candidate_handle)
84 .map_err(verification_failure)?;
85 } else {
86 verify_init_single_param(module, fn_handle).map_err(verification_failure)?;
89 }
90 }
91 if let Some((candidate_name, _, def)) = one_time_witness_candidate {
92 if !is_test_fun(fn_name, module, fn_info_map) {
96 verify_no_instantiations(module, fn_def, candidate_name, def)
97 .map_err(verification_failure)?;
98 }
99 }
100 }
101
102 Ok(())
103}
104
105fn verify_one_time_witness(
108 module: &CompiledModule,
109 candidate_name: &str,
110 candidate_handle: &DatatypeHandle,
111) -> Result<(), String> {
112 let drop_set = AbilitySet::EMPTY | Ability::Drop;
114 let abilities = candidate_handle.abilities;
115 if abilities != drop_set {
116 return Err(format!(
117 "one-time witness type candidate {}::{} must have a single ability: drop",
118 module.self_id(),
119 candidate_name,
120 ));
121 }
122
123 if !candidate_handle.type_parameters.is_empty() {
124 return Err(format!(
125 "one-time witness type candidate {}::{} cannot have type parameters",
126 module.self_id(),
127 candidate_name,
128 ));
129 }
130 Ok(())
131}
132
133fn verify_init_one_time_witness(
135 module: &CompiledModule,
136 fn_handle: &FunctionHandle,
137 candidate_name: &str,
138 candidate_handle: &DatatypeHandle,
139) -> Result<(), String> {
140 let fn_sig = module.signature_at(fn_handle.parameters);
141 if fn_sig.len() != 2 || !is_one_time_witness(module, &fn_sig.0[0], candidate_handle) {
142 return Err(format!(
145 "init function of a module containing one-time witness type candidate must have \
146 {}::{} as the first parameter (a struct which has no fields or a single field of type \
147 bool)",
148 module.self_id(),
149 candidate_name,
150 ));
151 }
152
153 Ok(())
154}
155
156fn is_one_time_witness(
158 view: &CompiledModule,
159 tok: &SignatureToken,
160 candidate_handle: &DatatypeHandle,
161) -> bool {
162 matches!(tok, SignatureToken::Datatype(idx) if view.datatype_handle_at(*idx) == candidate_handle)
163}
164
165fn verify_init_single_param(
167 module: &CompiledModule,
168 fn_handle: &FunctionHandle,
169) -> Result<(), String> {
170 let fn_sig = module.signature_at(fn_handle.parameters);
171 if fn_sig.len() != 1 {
172 return Err(format!(
173 "Expected last (and at most second) parameter for {0}::{1} to be &mut {2}::{3}::{4} or \
174 &{2}::{3}::{4}; optional first parameter must be of one-time witness type whose name \
175 is the same as the capitalized module name ({5}::{6}) and which has no fields or a \
176 single field of type bool",
177 module.self_id(),
178 INIT_FN_NAME,
179 SUI_FRAMEWORK_ADDRESS,
180 TX_CONTEXT_MODULE_NAME,
181 TX_CONTEXT_STRUCT_NAME,
182 module.self_id(),
183 module.self_id().name().as_str().to_uppercase(),
184 ));
185 }
186
187 Ok(())
188}
189
190fn verify_no_instantiations(
192 module: &CompiledModule,
193 fn_def: &FunctionDefinition,
194 struct_name: &str,
195 struct_def: &StructDefinition,
196) -> Result<(), String> {
197 if fn_def.code.is_none() {
198 return Ok(());
199 }
200 for bcode in &fn_def.code.as_ref().unwrap().code {
201 let struct_def_idx = match bcode {
202 Bytecode::Pack(idx) => idx,
203 _ => continue,
204 };
205 if module.struct_def_at(*struct_def_idx) == struct_def {
208 let fn_handle = module.function_handle_at(fn_def.function);
209 let fn_name = module.identifier_at(fn_handle.name);
210 return Err(format!(
211 "one-time witness type {}::{} is instantiated \
212 in the {}::{} function and must never be",
213 module.self_id(),
214 struct_name,
215 module.self_id(),
216 fn_name,
217 ));
218 }
219 }
220
221 Ok(())
222}