saito_core/core/
defs.rs

1use std::cell::RefCell;
2use std::collections::VecDeque;
3use std::time::Duration;
4
5use ahash::AHashMap;
6use tokio::sync::mpsc::Sender;
7
8pub type Currency = u64;
9
10/// Time in milliseconds
11pub type Timestamp = u64;
12pub type SaitoSignature = [u8; 64];
13pub type SaitoPublicKey = [u8; 33];
14pub type SaitoPrivateKey = [u8; 32];
15pub type SaitoHash = [u8; 32];
16pub type BlockHash = SaitoHash;
17
18pub type ForkId = SaitoHash;
19// pub type SlipUuid = [u8; 17];
20pub const UTXO_KEY_LENGTH: usize = 59;
21pub type SaitoUTXOSetKey = [u8; UTXO_KEY_LENGTH];
22pub type UtxoSet = AHashMap<SaitoUTXOSetKey, bool>;
23pub type PeerIndex = u64;
24pub type BlockId = u64;
25
26pub const CHANNEL_SAFE_BUFFER: usize = 16;
27
28pub const NOLAN_PER_SAITO: Currency = 100_000_000;
29
30pub const PROJECT_PUBLIC_KEY: &str = "q6TTBeSStCLXEPoS5TUVAxNiGGnRDZQenpvAXXAfTmtA";
31
32// #[cfg(test)]
33// pub const GENESIS_PERIOD: u64 = 100;
34
35// #[cfg(not(test))]
36// pub const GENESIS_PERIOD: u64 = 100_000;
37
38// prune blocks from index after N blocks
39// pub const PRUNE_AFTER_BLOCKS: u64 = 8;
40// max recursion when paying stakers -- number of blocks including  -- number of blocks including GTT
41// pub const MAX_STAKER_RECURSION: u64 = 3;
42// max token supply - used in validating block #1
43pub const MAX_TOKEN_SUPPLY: Currency = 7_000_000_000 * NOLAN_PER_SAITO;
44// minimum golden tickets required ( NUMBER_OF_TICKETS / number of preceding blocks )
45pub const MIN_GOLDEN_TICKETS_NUMERATOR: u64 = 2;
46// minimum golden tickets required ( number of tickets / NUMBER_OF_PRECEDING_BLOCKS )
47pub const MIN_GOLDEN_TICKETS_DENOMINATOR: u64 = 6;
48
49pub const BLOCK_FILE_EXTENSION: &str = ".sai";
50pub const STAT_BIN_COUNT: usize = 3;
51
52pub const PEER_RECONNECT_WAIT_PERIOD: Timestamp = Duration::from_secs(10).as_millis() as Timestamp;
53pub const WS_KEEP_ALIVE_PERIOD: Timestamp = Duration::from_secs(10).as_millis() as Timestamp;
54
55/// NOTE : Lock ordering is decided from how frequent the usage is for that resource. Please make sure to follow the order given below to avoid deadlocks
56/// network controller
57/// sockets
58/// configs
59/// blockchain
60/// mempool
61/// peers
62/// wallet
63///
64
65pub const LOCK_ORDER_NETWORK_CONTROLLER: u8 = 1;
66pub const LOCK_ORDER_SOCKETS: u8 = 2;
67pub const LOCK_ORDER_CONFIGS: u8 = 3;
68pub const LOCK_ORDER_BLOCKCHAIN: u8 = 4;
69pub const LOCK_ORDER_MEMPOOL: u8 = 5;
70pub const LOCK_ORDER_PEERS: u8 = 6;
71pub const LOCK_ORDER_WALLET: u8 = 7;
72
73thread_local! {
74    pub static LOCK_ORDER: RefCell<VecDeque<u8>> = RefCell::new(VecDeque::default());
75}
76
77#[macro_export]
78macro_rules! iterate {
79    ($collection:expr, $min:expr) => {{
80        #[cfg(feature = "with-rayon")]
81        {
82            $collection.par_iter().with_min_len($min)
83        }
84
85        #[cfg(not(feature = "with-rayon"))]
86        {
87            $collection.iter()
88        }
89    }};
90}
91
92#[macro_export]
93macro_rules! iterate_mut {
94    ($collection:expr) => {{
95        #[cfg(feature = "with-rayon")]
96        {
97            $collection.par_iter_mut()
98        }
99
100        #[cfg(not(feature = "with-rayon"))]
101        {
102            $collection.iter_mut()
103        }
104    }};
105}
106
107#[macro_export]
108macro_rules! drain {
109    ($collection:expr, $min:expr) => {{
110        #[cfg(feature = "with-rayon")]
111        {
112            $collection.par_drain(..).with_min_len($min)
113        }
114
115        #[cfg(not(feature = "with-rayon"))]
116        {
117            $collection.drain(..)
118        }
119    }};
120}
121
122#[derive(Clone, Debug)]
123pub struct StatVariable {
124    pub total: u64,
125    pub count_since_last_stat: u64,
126    pub last_stat_at: Timestamp,
127    pub bins: VecDeque<(u64, Timestamp)>,
128    pub avg: f64,
129    pub max_avg: f64,
130    pub min_avg: f64,
131    pub name: String,
132    pub sender: Sender<String>,
133}
134
135impl StatVariable {
136    pub fn new(name: String, bin_count: usize, sender: Sender<String>) -> StatVariable {
137        StatVariable {
138            total: 0,
139            count_since_last_stat: 0,
140            last_stat_at: 0,
141            bins: VecDeque::with_capacity(bin_count),
142            avg: 0.0,
143            max_avg: 0.0,
144            min_avg: f64::MAX,
145            name,
146            sender,
147        }
148    }
149    pub fn increment(&mut self) {
150        {
151            self.total += 1;
152            self.count_since_last_stat += 1;
153        }
154    }
155    pub fn increment_by(&mut self, amount: u64) {
156        {
157            self.total += amount;
158            self.count_since_last_stat += amount;
159        }
160    }
161    pub async fn calculate_stats(&mut self, current_time_in_ms: Timestamp) {
162        let time_elapsed_in_ms = current_time_in_ms - self.last_stat_at;
163        self.last_stat_at = current_time_in_ms;
164        if self.bins.len() == self.bins.capacity() - 1 {
165            self.bins.pop_front();
166        }
167        self.bins
168            .push_back((self.count_since_last_stat, time_elapsed_in_ms));
169        self.count_since_last_stat = 0;
170
171        let mut total = 0;
172        let mut total_time_in_ms = 0;
173        for (count, time) in self.bins.iter() {
174            total += *count;
175            total_time_in_ms += *time;
176        }
177
178        self.avg = (1_000.0 * total as f64) / total_time_in_ms as f64;
179        if self.avg > self.max_avg {
180            self.max_avg = self.avg;
181        }
182        if self.avg < self.min_avg {
183            self.min_avg = self.avg;
184        }
185        self.sender
186            .send(self.print(current_time_in_ms))
187            .await
188            .expect("failed sending stat update");
189    }
190    pub fn format_timestamp(timestamp: Timestamp) -> String {
191        chrono::DateTime::from_timestamp_millis(timestamp as i64)
192            .unwrap()
193            .to_string()
194    }
195    fn print(&self, current_time_in_ms: Timestamp) -> String {
196        format!(
197            // target : "saito_stats",
198            "{} - {} - total : {:?}, current_rate : {:.2}, max_rate : {:.2}, min_rate : {:.2}",
199            Self::format_timestamp(current_time_in_ms),
200            format!("{:width$}", self.name, width = 40),
201            self.total,
202            self.avg,
203            self.max_avg,
204            self.min_avg
205        )
206    }
207}
208
209pub trait PrintForLog<T: TryFrom<Vec<u8>>> {
210    fn to_base58(&self) -> String;
211    fn to_hex(&self) -> String;
212    fn from_hex(str: &str) -> Result<T, String>;
213
214    fn from_base58(str: &str) -> Result<T, String>;
215}
216
217#[macro_export]
218macro_rules! impl_print {
219    ($st:ident) => {
220        impl PrintForLog<$st> for $st {
221            fn to_base58(&self) -> String {
222                bs58::encode(self).into_string()
223            }
224
225            fn to_hex(&self) -> String {
226                hex::encode(self)
227            }
228
229            fn from_hex(str: &str) -> Result<$st, String> {
230                let result = hex::decode(str);
231                if result.is_err() {
232                    return Err(format!(
233                        "couldn't convert string : {:?} to hex type. {:?}",
234                        str,
235                        result.err().unwrap()
236                    ));
237                }
238                let result = result.unwrap();
239                let result = result.try_into();
240                if result.is_err() {
241                    return Err(format!(
242                        "couldn't convert : {:?} with length : {:?} to hex type. {:?}",
243                        str,
244                        str.len(),
245                        result.err().unwrap()
246                    ));
247                }
248                Ok(result.unwrap())
249            }
250            fn from_base58(str: &str) -> Result<$st, String> {
251                let result = bs58::decode(str).into_vec();
252                if result.is_err() {
253                    return Err(format!(
254                        "couldn't convert string : {:?} to base58. {:?}",
255                        str,
256                        result.err().unwrap()
257                    ));
258                }
259                let result = result.unwrap();
260                let result = result.try_into();
261                if result.is_err() {
262                    return Err(format!(
263                        "couldn't convert : {:?} with length : {:?} to base58. {:?}",
264                        str,
265                        str.len(),
266                        result.err().unwrap()
267                    ));
268                }
269                Ok(result.unwrap())
270            }
271        }
272    };
273}
274impl_print!(SaitoHash);
275impl_print!(SaitoPublicKey);
276impl_print!(SaitoSignature);
277impl_print!(SaitoUTXOSetKey);