gear_core/
ids.rs

1// This file is part of Gear.
2
3// Copyright (C) 2022-2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Base identifiers for messaging primitives.
20
21use blake2::{Blake2b, Digest, digest::typenum::U32};
22pub use gprimitives::{ActorId, CodeId, MessageId, ReservationId};
23
24/// BLAKE2b-256 hasher state.
25type Blake2b256 = Blake2b<U32>;
26
27/// Creates a unique identifier by passing given argument to blake2b hash-function.
28///
29/// # SAFETY: DO NOT ADJUST HASH FUNCTION, BECAUSE MESSAGE ID IS SENSITIVE FOR IT.
30pub fn hash(data: &[u8]) -> [u8; 32] {
31    let mut ctx = Blake2b256::new();
32    ctx.update(data);
33    ctx.finalize().into()
34}
35
36/// Creates a unique identifier by passing given argument to blake2b hash-function.
37///
38/// # SAFETY: DO NOT ADJUST HASH FUNCTION, BECAUSE MESSAGE ID IS SENSITIVE FOR IT.
39pub fn hash_of_array<T: AsRef<[u8]>, const N: usize>(array: [T; N]) -> [u8; 32] {
40    let mut ctx = Blake2b256::new();
41    for data in array {
42        ctx.update(data);
43    }
44    ctx.finalize().into()
45}
46
47pub mod prelude {
48    //! The purpose of this module is to make it easier to import `gprimitives` extensions.
49    use super::*;
50
51    mod private {
52        use super::*;
53
54        pub trait Sealed {}
55
56        impl Sealed for ActorId {}
57        impl Sealed for CodeId {}
58        impl Sealed for MessageId {}
59        impl Sealed for ReservationId {}
60    }
61
62    /// Program (actor) identifier extension.
63    pub trait ActorIdExt: private::Sealed {
64        /// System program identifier.
65        const SYSTEM: Self;
66
67        /// Generates `ActorId` from given `CodeId` and `salt`.
68        fn generate_from_user(code_id: CodeId, salt: &[u8]) -> Self;
69
70        /// Generates `ActorId` from given `MessageId`, `CodeId` and `salt`.
71        fn generate_from_program(message_id: MessageId, code_id: CodeId, salt: &[u8]) -> Self;
72    }
73
74    impl ActorIdExt for ActorId {
75        const SYSTEM: Self = Self::new(*b"geargeargeargeargeargeargeargear");
76
77        fn generate_from_user(code_id: CodeId, salt: &[u8]) -> Self {
78            const SALT: &[u8] = b"program_from_user";
79            hash_of_array([SALT, code_id.as_ref(), salt]).into()
80        }
81
82        fn generate_from_program(message_id: MessageId, code_id: CodeId, salt: &[u8]) -> Self {
83            const SALT: &[u8] = b"program_from_wasm";
84            hash_of_array([SALT, message_id.as_ref(), code_id.as_ref(), salt]).into()
85        }
86    }
87
88    /// Message identifier extension.
89    pub trait MessageIdExt: private::Sealed {
90        /// Generates `MessageId` for non-program outgoing message.
91        fn generate_from_user(block_number: u32, user_id: ActorId, local_nonce: u128) -> MessageId;
92
93        /// Generates `MessageId` for program outgoing message.
94        fn generate_outgoing(origin_msg_id: MessageId, local_nonce: u32) -> MessageId;
95
96        /// Generates `MessageId` for reply message depend on status code.
97        ///
98        /// # SAFETY: DO NOT ADJUST REPLY MESSAGE ID GENERATION,
99        /// BECAUSE AUTO-REPLY LOGIC DEPENDS ON PRE-DEFINED REPLY ID.
100        fn generate_reply(origin_msg_id: MessageId) -> MessageId;
101
102        /// Generates `MessageId` for signal message depend on status code.
103        fn generate_signal(origin_msg_id: MessageId) -> MessageId;
104    }
105
106    impl MessageIdExt for MessageId {
107        fn generate_from_user(block_number: u32, user_id: ActorId, local_nonce: u128) -> MessageId {
108            const SALT: &[u8] = b"external";
109            hash_of_array([
110                SALT,
111                &block_number.to_le_bytes(),
112                user_id.as_ref(),
113                &local_nonce.to_le_bytes(),
114            ])
115            .into()
116        }
117
118        fn generate_outgoing(origin_msg_id: MessageId, local_nonce: u32) -> MessageId {
119            const SALT: &[u8] = b"outgoing";
120            hash_of_array([SALT, origin_msg_id.as_ref(), &local_nonce.to_le_bytes()]).into()
121        }
122
123        fn generate_reply(origin_msg_id: MessageId) -> MessageId {
124            const SALT: &[u8] = b"reply";
125            hash_of_array([SALT, origin_msg_id.as_ref()]).into()
126        }
127
128        fn generate_signal(origin_msg_id: MessageId) -> MessageId {
129            const SALT: &[u8] = b"signal";
130            hash_of_array([SALT, origin_msg_id.as_ref()]).into()
131        }
132    }
133
134    /// Code identifier extension.
135    pub trait CodeIdExt: private::Sealed {
136        /// Generates `CodeId` from given code.
137        fn generate(code: &[u8]) -> Self;
138    }
139
140    impl CodeIdExt for CodeId {
141        fn generate(code: &[u8]) -> Self {
142            hash(code).into()
143        }
144    }
145
146    /// Reservation identifier extension.
147    pub trait ReservationIdExt: private::Sealed {
148        /// Generates `ReservationId` from given message and nonce.
149        fn generate(msg_id: MessageId, nonce: u64) -> Self;
150    }
151
152    impl ReservationIdExt for ReservationId {
153        fn generate(msg_id: MessageId, nonce: u64) -> Self {
154            const SALT: &[u8] = b"reservation";
155            hash_of_array([SALT, msg_id.as_ref(), &nonce.to_le_bytes()]).into()
156        }
157    }
158}