junobuild_shared/
assert.rs

1use crate::canister::memory_size;
2use crate::errors::{
3    JUNO_ERROR_MEMORY_HEAP_EXCEEDED, JUNO_ERROR_MEMORY_STABLE_EXCEEDED, JUNO_ERROR_NO_TIMESTAMP,
4    JUNO_ERROR_NO_VERSION, JUNO_ERROR_TIMESTAMP_OUTDATED_OR_FUTURE,
5    JUNO_ERROR_VERSION_OUTDATED_OR_FUTURE,
6};
7use crate::types::config::ConfigMaxMemorySize;
8use crate::types::interface::MemorySize;
9use crate::types::state::Version;
10
11/// Asserts the validity of a given user timestamp against the current timestamp.
12/// e.g. the timestamp of an existing entity persisted in a smart contract.
13///
14/// This function checks if the provided user timestamp matches the current system timestamp.
15/// It is designed to ensure that operations relying on timestamps are executed with current
16/// or synchronized timestamps to prevent replay or outdated requests.
17///
18/// # Parameters
19/// - `user_timestamp`: An `Option<u64>` representing the user-provided timestamp. This can be `None`
20///   if the user did not provide a timestamp, or `Some(u64)` if a timestamp was provided.
21/// - `current_timestamp`: A `u64` representing the current system timestamp. This should be
22///   the accurate current time in a format consistent with `user_timestamp`.
23///
24/// # Returns
25/// - `Ok(())` if the `user_timestamp` matches the `current_timestamp`.
26/// - `Err(String)` if:
27///   - The `user_timestamp` is `None`, indicating no timestamp was provided. The error string
28///     will be `ERROR_NO_TIMESTAMP.to_string()`, where `ERROR_NO_TIMESTAMP` is a constant string
29///     describing the error.
30///   - The `user_timestamp` does not match the `current_timestamp`, indicating either an outdated
31///     or a future timestamp. The error string will format to include the error description
32///     (from a constant `ERROR_TIMESTAMP_OUTDATED_OR_FUTURE`), the current timestamp, and the
33///     provided user timestamp.
34///
35/// # Examples
36/// ```
37/// let current_timestamp = 1625097600; // Example timestamp
38/// let user_timestamp = Some(1625097600);
39/// assert_eq!(assert_timestamp(user_timestamp, current_timestamp), Ok(()));
40///
41/// let wrong_timestamp = Some(1625097601);
42/// assert!(assert_timestamp(wrong_timestamp, current_timestamp).is_err());
43///
44/// let no_timestamp = None;
45/// assert!(assert_timestamp(no_timestamp, current_timestamp).is_err());
46/// ```
47///
48#[deprecated]
49pub fn assert_timestamp(user_timestamp: Option<u64>, current_timestamp: u64) -> Result<(), String> {
50    match user_timestamp {
51        None => {
52            return Err(JUNO_ERROR_NO_TIMESTAMP.to_string());
53        }
54        Some(user_timestamp) => {
55            if current_timestamp != user_timestamp {
56                return Err(format!(
57                    "{} ({} - {})",
58                    JUNO_ERROR_TIMESTAMP_OUTDATED_OR_FUTURE, current_timestamp, user_timestamp
59                ));
60            }
61        }
62    }
63
64    Ok(())
65}
66
67/// Asserts the validity of a given user version against the required version.
68/// This function checks if the provided user version matches the current system version.
69/// It is designed to ensure that operations relying on version numbers are executed with the
70/// correct versions to prevent issues with compatibility or outdated requests.
71///
72/// # Parameters
73/// - `user_version`: An `Option<u64>` representing the user-provided version. This can be `None`
74///   if the user did not provide a version, or `Some(u64)` if a version was provided.
75/// - `current_version`: An `Option<u64>` representing the required system version. This can be `None`
76///   which means no specific version requirement is needed.
77///
78/// # Returns
79/// - `Ok(())` if the `user_version` matches the `current_version` or if no specific `current_version` is provided.
80/// - `Err(String)` if:
81///   - The `user_version` is `None`, indicating no version was provided. The error string
82///     will be `ERROR_NO_VERSION.to_string()`, where `ERROR_NO_VERSION` is a constant string
83///     describing the error.
84///   - The `user_version` does not match the `current_version`, indicating either an incorrect
85///     or incompatible version. The error string will format to include the error description
86///     (from a constant `ERROR_VERSION_MISMATCH`), the required version, and the provided user version.
87///
88/// # Examples
89/// ```
90/// let current_version = Some(3); // Example version
91/// let user_version = Some(3);
92/// assert_eq!(assert_version(user_version, current_version), Ok(()));
93///
94/// let wrong_version = Some(2);
95/// assert!(assert_version(wrong_version, current_version).is_err());
96///
97/// let no_version = None;
98/// let no_current_version = None;
99/// assert!(assert_version(no_version, no_current_version).is_ok());
100/// ```
101///
102pub fn assert_version(
103    user_version: Option<Version>,
104    current_version: Option<Version>,
105) -> Result<(), String> {
106    match current_version {
107        None => (),
108        Some(current_version) => match user_version {
109            None => {
110                return Err(JUNO_ERROR_NO_VERSION.to_string());
111            }
112            Some(user_version) => {
113                if current_version != user_version {
114                    return Err(format!(
115                        "{} ({} - {})",
116                        JUNO_ERROR_VERSION_OUTDATED_OR_FUTURE, current_version, user_version
117                    ));
118                }
119            }
120        },
121    }
122
123    Ok(())
124}
125
126/// Validates the length of a description field in entities such as documents or assets.
127///
128/// Ensures that the description does not exceed 1024 characters. If the description exceeds
129/// this limit, the function returns an error message.
130///
131/// # Parameters
132///
133/// - `description`: An optional reference to a `String` that represents the description field
134///   of an entity. If the description is `None`, the function considers it valid and does not
135///   perform any length checks.
136///
137/// # Returns
138///
139/// - `Ok(())`: If the description is valid (either `None` or within the length limit).
140/// - `Err(String)`: If the description exceeds 1024 characters, containing an error message.
141///
142/// # Examples
143///
144/// ```
145/// let valid_description = Some(String::from("This is a valid description."));
146/// assert_eq!(assert_description_length(&valid_description), Ok(()));
147///
148/// let invalid_description = Some(String::from("a".repeat(1025)));
149/// assert_eq!(
150///     assert_description_length(&invalid_description),
151///     Err(String::from("Description field should not contains more than 1024 characters."))
152/// );
153///
154/// let none_description: Option<String> = None;
155/// assert_eq!(assert_description_length(&none_description), Ok(()));
156/// ```
157pub fn assert_description_length(description: &Option<String>) -> Result<(), String> {
158    match description {
159        None => (),
160        Some(description) => {
161            if description.len() > 1024 {
162                return Err(
163                    "Description field should not contains more than 1024 characters.".to_string(),
164                );
165            }
166        }
167    }
168
169    Ok(())
170}
171
172pub fn assert_max_memory_size(
173    config_max_memory_size: &Option<ConfigMaxMemorySize>,
174) -> Result<(), String> {
175    if let Some(max_memory_size) = &config_max_memory_size {
176        let MemorySize { heap, stable } = memory_size();
177
178        if let Some(max_heap) = max_memory_size.heap {
179            if heap > max_heap as u64 {
180                return Err(format!(
181                    "{} ({} bytes used, {} bytes allowed)",
182                    JUNO_ERROR_MEMORY_HEAP_EXCEEDED, heap, max_heap
183                ));
184            }
185        }
186
187        if let Some(max_stable) = max_memory_size.stable {
188            if stable > max_stable as u64 {
189                return Err(format!(
190                    "{} ({} bytes used, {} bytes allowed)",
191                    JUNO_ERROR_MEMORY_STABLE_EXCEEDED, stable, max_stable
192                ));
193            }
194        }
195    }
196
197    Ok(())
198}