junobuild_shared/
assert.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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
use crate::canister::memory_size;
use crate::msg::{
    ERROR_NO_TIMESTAMP, ERROR_NO_VERSION, ERROR_TIMESTAMP_OUTDATED_OR_FUTURE,
    ERROR_VERSION_OUTDATED_OR_FUTURE,
};
use crate::types::config::ConfigMaxMemorySize;
use crate::types::interface::MemorySize;
use crate::types::state::Version;

/// Asserts the validity of a given user timestamp against the current timestamp.
/// e.g. the timestamp of an existing entity persisted in a smart contract.
///
/// This function checks if the provided user timestamp matches the current system timestamp.
/// It is designed to ensure that operations relying on timestamps are executed with current
/// or synchronized timestamps to prevent replay or outdated requests.
///
/// # Parameters
/// - `user_timestamp`: An `Option<u64>` representing the user-provided timestamp. This can be `None`
///   if the user did not provide a timestamp, or `Some(u64)` if a timestamp was provided.
/// - `current_timestamp`: A `u64` representing the current system timestamp. This should be
///   the accurate current time in a format consistent with `user_timestamp`.
///
/// # Returns
/// - `Ok(())` if the `user_timestamp` matches the `current_timestamp`.
/// - `Err(String)` if:
///   - The `user_timestamp` is `None`, indicating no timestamp was provided. The error string
///     will be `ERROR_NO_TIMESTAMP.to_string()`, where `ERROR_NO_TIMESTAMP` is a constant string
///     describing the error.
///   - The `user_timestamp` does not match the `current_timestamp`, indicating either an outdated
///     or a future timestamp. The error string will format to include the error description
///     (from a constant `ERROR_TIMESTAMP_OUTDATED_OR_FUTURE`), the current timestamp, and the
///     provided user timestamp.
///
/// # Examples
/// ```
/// let current_timestamp = 1625097600; // Example timestamp
/// let user_timestamp = Some(1625097600);
/// assert_eq!(assert_timestamp(user_timestamp, current_timestamp), Ok(()));
///
/// let wrong_timestamp = Some(1625097601);
/// assert!(assert_timestamp(wrong_timestamp, current_timestamp).is_err());
///
/// let no_timestamp = None;
/// assert!(assert_timestamp(no_timestamp, current_timestamp).is_err());
/// ```
///
#[deprecated]
pub fn assert_timestamp(user_timestamp: Option<u64>, current_timestamp: u64) -> Result<(), String> {
    match user_timestamp {
        None => {
            return Err(ERROR_NO_TIMESTAMP.to_string());
        }
        Some(user_timestamp) => {
            if current_timestamp != user_timestamp {
                return Err(format!(
                    "{} ({} - {})",
                    ERROR_TIMESTAMP_OUTDATED_OR_FUTURE, current_timestamp, user_timestamp
                ));
            }
        }
    }

    Ok(())
}

/// Asserts the validity of a given user version against the required version.
/// This function checks if the provided user version matches the current system version.
/// It is designed to ensure that operations relying on version numbers are executed with the
/// correct versions to prevent issues with compatibility or outdated requests.
///
/// # Parameters
/// - `user_version`: An `Option<u64>` representing the user-provided version. This can be `None`
///   if the user did not provide a version, or `Some(u64)` if a version was provided.
/// - `current_version`: An `Option<u64>` representing the required system version. This can be `None`
///   which means no specific version requirement is needed.
///
/// # Returns
/// - `Ok(())` if the `user_version` matches the `current_version` or if no specific `current_version` is provided.
/// - `Err(String)` if:
///   - The `user_version` is `None`, indicating no version was provided. The error string
///     will be `ERROR_NO_VERSION.to_string()`, where `ERROR_NO_VERSION` is a constant string
///     describing the error.
///   - The `user_version` does not match the `current_version`, indicating either an incorrect
///     or incompatible version. The error string will format to include the error description
///     (from a constant `ERROR_VERSION_MISMATCH`), the required version, and the provided user version.
///
/// # Examples
/// ```
/// let current_version = Some(3); // Example version
/// let user_version = Some(3);
/// assert_eq!(assert_version(user_version, current_version), Ok(()));
///
/// let wrong_version = Some(2);
/// assert!(assert_version(wrong_version, current_version).is_err());
///
/// let no_version = None;
/// let no_current_version = None;
/// assert!(assert_version(no_version, no_current_version).is_ok());
/// ```
///
pub fn assert_version(
    user_version: Option<Version>,
    current_version: Option<Version>,
) -> Result<(), String> {
    match current_version {
        None => (),
        Some(current_version) => match user_version {
            None => {
                return Err(ERROR_NO_VERSION.to_string());
            }
            Some(user_version) => {
                if current_version != user_version {
                    return Err(format!(
                        "{} ({} - {})",
                        ERROR_VERSION_OUTDATED_OR_FUTURE, current_version, user_version
                    ));
                }
            }
        },
    }

    Ok(())
}

/// Validates the length of a description field in entities such as documents or assets.
///
/// Ensures that the description does not exceed 1024 characters. If the description exceeds
/// this limit, the function returns an error message.
///
/// # Parameters
///
/// - `description`: An optional reference to a `String` that represents the description field
///   of an entity. If the description is `None`, the function considers it valid and does not
///   perform any length checks.
///
/// # Returns
///
/// - `Ok(())`: If the description is valid (either `None` or within the length limit).
/// - `Err(String)`: If the description exceeds 1024 characters, containing an error message.
///
/// # Examples
///
/// ```
/// let valid_description = Some(String::from("This is a valid description."));
/// assert_eq!(assert_description_length(&valid_description), Ok(()));
///
/// let invalid_description = Some(String::from("a".repeat(1025)));
/// assert_eq!(
///     assert_description_length(&invalid_description),
///     Err(String::from("Description field should not contains more than 1024 characters."))
/// );
///
/// let none_description: Option<String> = None;
/// assert_eq!(assert_description_length(&none_description), Ok(()));
/// ```
pub fn assert_description_length(description: &Option<String>) -> Result<(), String> {
    match description {
        None => (),
        Some(description) => {
            if description.len() > 1024 {
                return Err(
                    "Description field should not contains more than 1024 characters.".to_string(),
                );
            }
        }
    }

    Ok(())
}

pub fn assert_max_memory_size(
    config_max_memory_size: &Option<ConfigMaxMemorySize>,
) -> Result<(), String> {
    if let Some(max_memory_size) = &config_max_memory_size {
        let MemorySize { heap, stable } = memory_size();

        if let Some(max_heap) = max_memory_size.heap {
            if heap > max_heap {
                return Err(format!(
                    "Heap memory usage exceeded: {} bytes used, {} bytes allowed.",
                    heap, max_heap
                ));
            }
        }

        if let Some(max_stable) = max_memory_size.stable {
            if stable > max_stable {
                return Err(format!(
                    "Stable memory usage exceeded: {} bytes used, {} bytes allowed.",
                    stable, max_stable
                ));
            }
        }
    }

    Ok(())
}