1use crate::events::BlockEvent;
5use alloc::{
6 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
7 vec::Vec,
8};
9use core::num::NonZeroU64;
10use gear_core::ids::prelude::CodeIdExt as _;
11use gprimitives::{ActorId, CodeId, H256, MessageId};
12use parity_scale_codec::{Decode, Encode};
13use scale_info::TypeInfo;
14
15pub type ProgramStates = BTreeMap<ActorId, StateHashWithQueueSize>;
16
17#[derive(Debug, Clone, Copy, Default, Encode, Decode, TypeInfo, PartialEq, Eq, Hash)]
18#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
19pub struct BlockHeader {
20 pub height: u32,
21 pub timestamp: u64,
22 pub parent_hash: H256,
23}
24
25impl BlockHeader {
26 pub fn dummy(height: u32) -> Self {
27 let mut parent_hash = [0; 32];
28 parent_hash[..4].copy_from_slice(&height.to_le_bytes());
29
30 Self {
31 height,
32 timestamp: height as u64 * 12,
33 parent_hash: parent_hash.into(),
34 }
35 }
36}
37
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct BlockData {
40 pub hash: H256,
41 pub header: BlockHeader,
42 pub events: Vec<BlockEvent>,
43}
44
45impl BlockData {
46 pub fn to_simple(&self) -> SimpleBlockData {
47 SimpleBlockData {
48 hash: self.hash,
49 header: self.header,
50 }
51 }
52}
53
54#[derive(
55 Debug, derive_more::Display, Copy, Clone, PartialEq, Eq, Encode, Decode, TypeInfo, Default,
56)]
57#[display("Block(hash: {hash}, height: {}, parent: {}, ts: {})", header.height, header.parent_hash, header.timestamp)]
58pub struct SimpleBlockData {
59 pub hash: H256,
60 pub header: BlockHeader,
61}
62
63#[derive(Clone, Debug, Copy, Default, PartialEq, Eq, Encode, Decode, derive_more::IsVariant)]
65pub enum PromisePolicy {
66 Enabled,
68 #[default]
70 Disabled,
71}
72
73#[derive(Debug, Copy, Clone, PartialEq, Eq, derive_more::IsVariant, Default)]
75pub enum PromiseEmissionMode {
76 AlwaysEmit,
79 #[default]
81 ConsensusDriven,
82}
83
84#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy, Default, Encode, Decode, TypeInfo)]
85#[cfg_attr(feature = "std", derive(serde::Serialize))]
86pub struct StateHashWithQueueSize {
87 pub hash: H256,
88 pub canonical_queue_size: u8,
89 pub injected_queue_size: u8,
90}
91
92impl StateHashWithQueueSize {
93 pub fn zero() -> Self {
94 Self {
95 hash: H256::zero(),
96 canonical_queue_size: 0,
97 injected_queue_size: 0,
98 }
99 }
100}
101
102#[derive(Debug, Clone, Default, Encode, Decode, TypeInfo, PartialEq, Eq)]
103pub struct CodeBlobInfo {
104 pub timestamp: u64,
105 pub tx_hash: H256,
106}
107
108#[derive(Clone, PartialEq, Eq, derive_more::Debug)]
109pub struct CodeAndIdUnchecked {
110 #[debug("{:#x} bytes", code.len())]
111 pub code: Vec<u8>,
112 pub code_id: CodeId,
113}
114
115#[derive(Clone, PartialEq, Eq, derive_more::Debug)]
116pub struct CodeAndId {
117 #[debug("{:#x} bytes", code.len())]
118 code: Vec<u8>,
119 code_id: CodeId,
120}
121
122impl CodeAndId {
123 pub fn new(code: Vec<u8>) -> Self {
124 let code_id = CodeId::generate(&code);
125 Self { code, code_id }
126 }
127
128 pub fn code(&self) -> &[u8] {
129 &self.code
130 }
131
132 pub fn code_id(&self) -> CodeId {
133 self.code_id
134 }
135
136 pub fn from_unchecked(code_and_id: CodeAndIdUnchecked) -> Self {
141 let CodeAndIdUnchecked { code, code_id } = code_and_id;
142 assert_eq!(
143 code_id,
144 CodeId::generate(&code),
145 "CodeId does not match the provided code"
146 );
147 Self { code, code_id }
148 }
149
150 pub fn into_unchecked(self) -> CodeAndIdUnchecked {
151 CodeAndIdUnchecked {
152 code: self.code,
153 code_id: self.code_id,
154 }
155 }
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode, TypeInfo)]
161pub struct ProtocolTimelines {
162 pub genesis_ts: u64,
164 pub era: NonZeroU64,
166 pub election: u64,
170 pub slot: NonZeroU64,
172}
173
174impl ProtocolTimelines {
175 #[inline(always)]
179 pub fn era_from_ts(&self, ts: u64) -> Option<u64> {
180 ts.checked_sub(self.genesis_ts)
181 .map(|delta| delta / self.era.get())
182 }
183
184 #[inline(always)]
188 pub fn era_start_ts(&self, era_index: u64) -> Option<u64> {
189 era_index
190 .checked_mul(self.era.get())?
191 .checked_add(self.genesis_ts)
192 }
193
194 #[inline(always)]
202 pub fn era_election_start_ts(&self, era_index: u64) -> Option<u64> {
203 self.era_start_ts(era_index)?.checked_add(
204 self.era
205 .get()
206 .checked_sub(self.election)
207 .expect("Incorrect Timelines - era duration < election duration"),
208 )
209 }
210
211 #[inline(always)]
215 pub fn slot_from_ts(&self, ts: u64) -> Option<u64> {
216 ts.checked_sub(self.genesis_ts)
217 .map(|delta| delta / self.slot.get())
218 }
219}
220
221pub type Rfm = (ActorId, ActorId);
223
224pub type Sd = (ActorId, MessageId);
226
227pub type Sum = ActorId;
229
230pub type ScheduledTask = gear_core::tasks::ScheduledTask<Rfm, Sd, Sum>;
232
233pub type Schedule = BTreeMap<u32, BTreeSet<ScheduledTask>>;
235
236#[cfg(test)]
237mod tests {
238 use super::*;
239
240 fn mock_timelines() -> ProtocolTimelines {
241 ProtocolTimelines {
242 genesis_ts: 10,
243 era: NonZeroU64::new(234).unwrap(),
244 election: 200,
245 slot: NonZeroU64::new(10).unwrap(),
246 }
247 }
248
249 #[test]
250 fn test_era_from_ts_calculation() {
251 let timelines = mock_timelines();
252
253 assert_eq!(timelines.era_from_ts(10), Some(0));
255 assert_eq!(timelines.era_from_ts(45), Some(0));
256 assert_eq!(timelines.era_from_ts(243), Some(0));
257
258 assert_eq!(timelines.era_from_ts(244), Some(1));
260 assert_eq!(timelines.era_from_ts(333), Some(1));
261 }
262
263 #[test]
264 fn era_from_ts_returns_none_before_genesis() {
265 let result = ProtocolTimelines {
266 genesis_ts: 100,
267 ..mock_timelines()
268 }
269 .era_from_ts(50);
270 assert_eq!(result, None);
271 }
272
273 #[test]
274 fn test_era_start_calculation() {
275 let timelines = mock_timelines();
276
277 assert_eq!(timelines.era_start_ts(0), Some(10));
279 assert_eq!(timelines.era_start_ts(0), Some(10));
280 assert_eq!(timelines.era_start_ts(0), Some(10));
281
282 assert_eq!(timelines.era_start_ts(1), Some(244));
284 assert_eq!(timelines.era_start_ts(1), Some(244));
285 }
286}