sui_verifier_latest/
struct_with_key_verifier.rs

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