iota_verifier_latest/
one_time_witness_verifier.rs1use iota_sdk_types::{Address, Identifier};
25use iota_types::{
26 IOTA_FRAMEWORK_ADDRESS,
27 error::ExecutionError,
28 move_package::{FnInfoMap, is_test_fun},
29};
30use move_binary_format::file_format::{
31 Ability, AbilitySet, Bytecode, CompiledModule, DatatypeHandle, FunctionDefinition,
32 FunctionHandle, SignatureToken, StructDefinition,
33};
34use move_core_types::{ident_str, language_storage::ModuleId};
35
36use crate::{INIT_FN_NAME, verification_failure};
37
38pub fn verify_module(
39 module: &CompiledModule,
40 fn_info_map: &FnInfoMap,
41) -> Result<(), ExecutionError> {
42 let self_id = module.self_id();
52
53 if ModuleId::new(IOTA_FRAMEWORK_ADDRESS, ident_str!("iota").to_owned()) == self_id {
54 return Ok(());
55 }
56
57 let mod_handle = module.module_handle_at(module.self_module_handle_idx);
58 let mod_name = module.identifier_at(mod_handle.name).as_str();
59 let struct_defs = &module.struct_defs;
60 let mut one_time_witness_candidate = None;
61 for def in struct_defs {
63 let struct_handle = module.datatype_handle_at(def.struct_handle);
64 let struct_name = module.identifier_at(struct_handle.name).as_str();
65 if mod_name.to_ascii_uppercase() == struct_name {
66 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.as_str(), module, fn_info_map) {
107 verify_no_instantiations(module, fn_def, candidate_name, def)
108 .map_err(verification_failure)?;
109 }
110 }
111 }
112
113 Ok(())
114}
115
116fn verify_one_time_witness(
119 module: &CompiledModule,
120 candidate_name: &str,
121 candidate_handle: &DatatypeHandle,
122) -> Result<(), String> {
123 let drop_set = AbilitySet::EMPTY | Ability::Drop;
125 let abilities = candidate_handle.abilities;
126 if abilities != drop_set {
127 return Err(format!(
128 "one-time witness type candidate {}::{} must have a single ability: drop",
129 module.self_id(),
130 candidate_name,
131 ));
132 }
133
134 if !candidate_handle.type_parameters.is_empty() {
135 return Err(format!(
136 "one-time witness type candidate {}::{} cannot have type parameters",
137 module.self_id(),
138 candidate_name,
139 ));
140 }
141 Ok(())
142}
143
144fn verify_init_one_time_witness(
147 module: &CompiledModule,
148 fn_handle: &FunctionHandle,
149 candidate_name: &str,
150 candidate_handle: &DatatypeHandle,
151) -> Result<(), String> {
152 let fn_sig = module.signature_at(fn_handle.parameters);
153 if fn_sig.len() != 2 || !is_one_time_witness(module, &fn_sig.0[0], candidate_handle) {
154 return Err(format!(
157 "init function of a module containing one-time witness type candidate must have \
158 {}::{} as the first parameter (a struct which has no fields or a single field of type \
159 bool)",
160 module.self_id(),
161 candidate_name,
162 ));
163 }
164
165 Ok(())
166}
167
168fn is_one_time_witness(
170 view: &CompiledModule,
171 tok: &SignatureToken,
172 candidate_handle: &DatatypeHandle,
173) -> bool {
174 matches!(tok, SignatureToken::Datatype(idx) if view.datatype_handle_at(*idx) == candidate_handle)
175}
176
177fn verify_init_single_param(
180 module: &CompiledModule,
181 fn_handle: &FunctionHandle,
182) -> Result<(), String> {
183 let fn_sig = module.signature_at(fn_handle.parameters);
184 if fn_sig.len() != 1 {
185 return Err(format!(
186 "Expected last (and at most second) parameter for {0}::{1} to be &mut {2}::{3}::{4} or \
187 &{2}::{3}::{4}; optional first parameter must be of one-time witness type whose name \
188 is the same as the capitalized module name ({5}::{6}) and which has no fields or a \
189 single field of type bool",
190 module.self_id(),
191 INIT_FN_NAME,
192 Address::FRAMEWORK,
193 Identifier::TX_CONTEXT_MODULE,
194 Identifier::TX_CONTEXT,
195 module.self_id(),
196 module.self_id().name().as_str().to_uppercase(),
197 ));
198 }
199
200 Ok(())
201}
202
203fn verify_no_instantiations(
206 module: &CompiledModule,
207 fn_def: &FunctionDefinition,
208 struct_name: &str,
209 struct_def: &StructDefinition,
210) -> Result<(), String> {
211 if fn_def.code.is_none() {
212 return Ok(());
213 }
214 for bcode in &fn_def.code.as_ref().unwrap().code {
215 let struct_def_idx = match bcode {
216 Bytecode::Pack(idx) => idx,
217 _ => continue,
218 };
219 if module.struct_def_at(*struct_def_idx) == struct_def {
222 let fn_handle = module.function_handle_at(fn_def.function);
223 let fn_name = module.identifier_at(fn_handle.name);
224 return Err(format!(
225 "one-time witness type {}::{} is instantiated \
226 in the {}::{} function and must never be",
227 module.self_id(),
228 struct_name,
229 module.self_id(),
230 fn_name,
231 ));
232 }
233 }
234
235 Ok(())
236}