Skip to main content

gear_core/
ids.rs

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