sui_verifier_v1/
struct_with_key_verifier.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

//! This pass verifies necessary properties for Move Objects, i.e. structs with the `key` ability.
//! The properties checked are
//! - The first field is named "id"
//! - The first field has type `sui::object::UID`

use crate::verification_failure;
use move_binary_format::file_format::{CompiledModule, SignatureToken};
use sui_types::{
    error::ExecutionError,
    fp_ensure,
    id::{OBJECT_MODULE_NAME, UID_STRUCT_NAME},
    SUI_FRAMEWORK_ADDRESS,
};

pub fn verify_module(module: &CompiledModule) -> Result<(), ExecutionError> {
    verify_key_structs(module)
}

fn verify_key_structs(module: &CompiledModule) -> Result<(), ExecutionError> {
    let struct_defs = &module.struct_defs;
    for def in struct_defs {
        let handle = module.datatype_handle_at(def.struct_handle);
        if !handle.abilities.has_key() {
            continue;
        }
        let name = module.identifier_at(handle.name);

        // Check that the first field of the struct must be named "id".
        let first_field = match def.field(0) {
            Some(field) => field,
            None => {
                return Err(verification_failure(format!(
                    "First field of struct {} must be 'id', no field found",
                    name
                )))
            }
        };
        let first_field_name = module.identifier_at(first_field.name).as_str();
        if first_field_name != "id" {
            return Err(verification_failure(format!(
                "First field of struct {} must be 'id', {} found",
                name, first_field_name
            )));
        }
        // Check that the "id" field must have a struct type.
        let uid_field_type = &first_field.signature.0;
        let uid_field_type = match uid_field_type {
            SignatureToken::Datatype(struct_type) => struct_type,
            _ => {
                return Err(verification_failure(format!(
                    "First field of struct {} must be of type {}::object::UID, \
                    {:?} type found",
                    name, SUI_FRAMEWORK_ADDRESS, uid_field_type
                )))
            }
        };
        // check that the struct type for "id" field must be SUI_FRAMEWORK_ADDRESS::object::UID.
        let uid_type_struct = module.datatype_handle_at(*uid_field_type);
        let uid_type_struct_name = module.identifier_at(uid_type_struct.name);
        let uid_type_module = module.module_handle_at(uid_type_struct.module);
        let uid_type_module_address = module.address_identifier_at(uid_type_module.address);
        let uid_type_module_name = module.identifier_at(uid_type_module.name);
        fp_ensure!(
            uid_type_struct_name == UID_STRUCT_NAME
                && uid_type_module_address == &SUI_FRAMEWORK_ADDRESS
                && uid_type_module_name == OBJECT_MODULE_NAME,
            verification_failure(format!(
                "First field of struct {} must be of type {}::object::UID, \
                {}::{}::{} type found",
                name,
                SUI_FRAMEWORK_ADDRESS,
                uid_type_module_address,
                uid_type_module_name,
                uid_type_struct_name
            ))
        );
    }
    Ok(())
}