iota_verifier_latest/
struct_with_key_verifier.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5//! This pass verifies necessary properties for Move Objects, i.e. structs with
6//! the `key` ability. The properties checked are
7//! - The first field is named "id"
8//! - The first field has type `iota::object::UID`
9
10use iota_types::{
11    IOTA_FRAMEWORK_ADDRESS,
12    error::ExecutionError,
13    fp_ensure,
14    id::{OBJECT_MODULE_NAME, UID_STRUCT_NAME},
15};
16use move_binary_format::file_format::{CompiledModule, SignatureToken};
17
18use crate::verification_failure;
19
20pub fn verify_module(module: &CompiledModule) -> Result<(), ExecutionError> {
21    verify_key_structs(module)?;
22    verify_no_key_enums(module)
23}
24
25fn verify_key_structs(module: &CompiledModule) -> Result<(), ExecutionError> {
26    let struct_defs = &module.struct_defs;
27    for def in struct_defs {
28        let handle = module.datatype_handle_at(def.struct_handle);
29        if !handle.abilities.has_key() {
30            continue;
31        }
32        let name = module.identifier_at(handle.name);
33
34        // Check that the first field of the struct must be named "id".
35        let first_field = match def.field(0) {
36            Some(field) => field,
37            None => {
38                return Err(verification_failure(format!(
39                    "First field of struct {} must be 'id', no field found",
40                    name
41                )));
42            }
43        };
44        let first_field_name = module.identifier_at(first_field.name).as_str();
45        if first_field_name != "id" {
46            return Err(verification_failure(format!(
47                "First field of struct {} must be 'id', {} found",
48                name, first_field_name
49            )));
50        }
51        // Check that the "id" field must have a struct type.
52        let uid_field_type = &first_field.signature.0;
53        let uid_field_type = match uid_field_type {
54            SignatureToken::Datatype(struct_type) => struct_type,
55            _ => {
56                return Err(verification_failure(format!(
57                    "First field of struct {} must be of type {}::object::UID, \
58                    {:?} type found",
59                    name, IOTA_FRAMEWORK_ADDRESS, uid_field_type
60                )));
61            }
62        };
63        // check that the struct type for "id" field must be
64        // IOTA_FRAMEWORK_ADDRESS::object::UID.
65        let uid_type_struct = module.datatype_handle_at(*uid_field_type);
66        let uid_type_struct_name = module.identifier_at(uid_type_struct.name);
67        let uid_type_module = module.module_handle_at(uid_type_struct.module);
68        let uid_type_module_address = module.address_identifier_at(uid_type_module.address);
69        let uid_type_module_name = module.identifier_at(uid_type_module.name);
70        fp_ensure!(
71            uid_type_struct_name == UID_STRUCT_NAME
72                && uid_type_module_address == &IOTA_FRAMEWORK_ADDRESS
73                && uid_type_module_name == OBJECT_MODULE_NAME,
74            verification_failure(format!(
75                "First field of struct {} must be of type {}::object::UID, \
76                {}::{}::{} type found",
77                name,
78                IOTA_FRAMEWORK_ADDRESS,
79                uid_type_module_address,
80                uid_type_module_name,
81                uid_type_struct_name
82            ))
83        );
84    }
85    Ok(())
86}
87
88fn verify_no_key_enums(module: &CompiledModule) -> Result<(), ExecutionError> {
89    for def in &module.enum_defs {
90        let handle = module.datatype_handle_at(def.enum_handle);
91        if handle.abilities.has_key() {
92            return Err(verification_failure(format!(
93                "Enum {} cannot have the 'key' ability. Enums cannot have the 'key' ability.",
94                module.identifier_at(handle.name)
95            )));
96        }
97    }
98    Ok(())
99}