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::{digest::typenum::U32, Blake2b, Digest};
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
47/// Program identifier.
48pub type ProgramId = ActorId;
49
50pub mod prelude {
51    //! The purpose of this module is to make it easier to import `gprimitives` extensions.
52    use super::*;
53
54    mod private {
55        use super::*;
56
57        pub trait Sealed {}
58
59        impl Sealed for ActorId {}
60        impl Sealed for CodeId {}
61        impl Sealed for MessageId {}
62        impl Sealed for ReservationId {}
63    }
64
65    /// Program (actor) identifier extension.
66    pub trait ActorIdExt: private::Sealed {
67        /// System program identifier.
68        const SYSTEM: Self;
69
70        /// Generates `ActorId` from given `CodeId` and `salt`.
71        fn generate_from_user(code_id: CodeId, salt: &[u8]) -> Self;
72
73        /// Generates `ActorId` from given `MessageId`, `CodeId` and `salt`.
74        fn generate_from_program(message_id: MessageId, code_id: CodeId, salt: &[u8]) -> Self;
75    }
76
77    impl ActorIdExt for ActorId {
78        const SYSTEM: Self = Self::new(*b"geargeargeargeargeargeargeargear");
79
80        fn generate_from_user(code_id: CodeId, salt: &[u8]) -> Self {
81            const SALT: &[u8] = b"program_from_user";
82            hash_of_array([SALT, code_id.as_ref(), salt]).into()
83        }
84
85        fn generate_from_program(message_id: MessageId, code_id: CodeId, salt: &[u8]) -> Self {
86            const SALT: &[u8] = b"program_from_wasm";
87            hash_of_array([SALT, message_id.as_ref(), code_id.as_ref(), salt]).into()
88        }
89    }
90
91    /// Message identifier extension.
92    pub trait MessageIdExt: private::Sealed {
93        /// Generates `MessageId` for non-program outgoing message.
94        fn generate_from_user(
95            block_number: u32,
96            user_id: ProgramId,
97            local_nonce: u128,
98        ) -> MessageId;
99
100        /// Generates `MessageId` for program outgoing message.
101        fn generate_outgoing(origin_msg_id: MessageId, local_nonce: u32) -> MessageId;
102
103        /// Generates `MessageId` for reply message depend on status code.
104        ///
105        /// # SAFETY: DO NOT ADJUST REPLY MESSAGE ID GENERATION,
106        /// BECAUSE AUTO-REPLY LOGIC DEPENDS ON PRE-DEFINED REPLY ID.
107        fn generate_reply(origin_msg_id: MessageId) -> MessageId;
108
109        /// Generates `MessageId` for signal message depend on status code.
110        fn generate_signal(origin_msg_id: MessageId) -> MessageId;
111    }
112
113    impl MessageIdExt for MessageId {
114        fn generate_from_user(
115            block_number: u32,
116            user_id: ProgramId,
117            local_nonce: u128,
118        ) -> MessageId {
119            const SALT: &[u8] = b"external";
120            hash_of_array([
121                SALT,
122                &block_number.to_le_bytes(),
123                user_id.as_ref(),
124                &local_nonce.to_le_bytes(),
125            ])
126            .into()
127        }
128
129        fn generate_outgoing(origin_msg_id: MessageId, local_nonce: u32) -> MessageId {
130            const SALT: &[u8] = b"outgoing";
131            hash_of_array([SALT, origin_msg_id.as_ref(), &local_nonce.to_le_bytes()]).into()
132        }
133
134        fn generate_reply(origin_msg_id: MessageId) -> MessageId {
135            const SALT: &[u8] = b"reply";
136            hash_of_array([SALT, origin_msg_id.as_ref()]).into()
137        }
138
139        fn generate_signal(origin_msg_id: MessageId) -> MessageId {
140            const SALT: &[u8] = b"signal";
141            hash_of_array([SALT, origin_msg_id.as_ref()]).into()
142        }
143    }
144
145    /// Code identifier extension.
146    pub trait CodeIdExt: private::Sealed {
147        /// Generates `CodeId` from given code.
148        fn generate(code: &[u8]) -> Self;
149    }
150
151    impl CodeIdExt for CodeId {
152        fn generate(code: &[u8]) -> Self {
153            hash(code).into()
154        }
155    }
156
157    /// Reservation identifier extension.
158    pub trait ReservationIdExt: private::Sealed {
159        /// Generates `ReservationId` from given message and nonce.
160        fn generate(msg_id: MessageId, nonce: u64) -> Self;
161    }
162
163    impl ReservationIdExt for ReservationId {
164        fn generate(msg_id: MessageId, nonce: u64) -> Self {
165            const SALT: &[u8] = b"reservation";
166            hash_of_array([SALT, msg_id.as_ref(), &nonce.to_le_bytes()]).into()
167        }
168    }
169}