acme_chains/actors/blocks/
mod.rs

1/*
2   Appellation: blocks
3   Context: module
4   Creator: FL03 <jo3mccain@icloud.com> (https://pzzld.eth.link/)
5   Description:
6       ... Summary ...
7*/
8pub use block::*;
9pub use utils::*;
10
11mod block;
12
13pub type BoxedBlock = Box<dyn AbstractBlock>;
14
15pub trait AbstractBlock<Data = String, Index = u8, Hash = String, Nonce = u8, Ts = i64> {
16    fn constructor(
17        &self,
18        id: Index,
19        hash: Hash,
20        nonce: Nonce,
21        previous: Hash,
22        timestamp: Ts,
23    ) -> Self
24        where
25            Self: Sized;
26}
27
28pub trait BlockSpec<Dt = String, Id = u8, Hs = Vec<u8>, Nc = u8, Ts = i64> {
29    fn constructor(
30        &self,
31        id: Id,
32        hash: Hs,
33        nonce: Nc,
34        previous: Hs,
35        timestamp: Ts,
36        transactions: Vec<Dt>,
37    ) -> Self
38    where
39        Self: Sized;
40    fn consensus(
41        &self,
42        id: Id,
43        hash: Hs,
44        previous: Hs,
45        timestamp: Ts,
46        transactions: Vec<Dt>,
47    ) -> (Nc, Hs)
48    where
49        Self: Sized;
50}
51
52mod utils {
53    use crate::{BData, BHash, BId, BNonce, BTStamp, DIFFICULTY_PREFIX};
54    use log;
55    use sha2::Digest;
56
57    pub fn create_block(
58        data: BData,
59        id: BId,
60        previous: BHash,
61        timestamp: BTStamp,
62    ) -> (BNonce, BHash) {
63        log::info!("Creating a new block...");
64        let mut nonce = 0;
65        loop {
66            if nonce % 100000 == 0 {
67                log::info!("nonce: {}", nonce);
68            }
69            let hash = calculate_block_hash(id, data.clone(), nonce, previous.clone(), timestamp);
70            let binary_hash = convert_hash_into_binary(&hash);
71            if binary_hash.starts_with(DIFFICULTY_PREFIX.as_ref()) {
72                log::info!(
73                    "mined! nonce: {}, hash: {}, binary hash: {:#?}",
74                    nonce,
75                    hex::encode(&hash),
76                    binary_hash
77                );
78                return (nonce, hex::encode(hash).into());
79            }
80            nonce += 1;
81        }
82    }
83
84    pub fn convert_hash_into_binary(hash: &[u8]) -> Vec<u8> {
85        let mut res: String = String::default();
86        for c in hash {
87            res.push_str(&format!("{:b}", c));
88        }
89        res.into_bytes()
90    }
91
92    pub fn calculate_block_hash(
93        id: BId,
94        data: BData,
95        nonce: BNonce,
96        previous: BHash,
97        timestamp: BTStamp,
98    ) -> Vec<u8> {
99        let cache = serde_json::json!(
100            {
101                "id": id,
102                "data": data.clone(),
103                "nonce": nonce,
104                "previous": previous,
105                "timestamp": timestamp
106            }
107        );
108        let mut hasher = sha2::Sha256::new();
109        hasher.update(cache.to_string().as_bytes());
110        hasher.finalize().as_slice().to_owned()
111    }
112
113    #[cfg(test)]
114    mod tests {
115        use super::*;
116
117        #[test]
118        fn test_block_hash() {
119            let id: BId = 10;
120            let data = "test".to_string();
121            let nonce: BNonce = 890890;
122            let previous = "previous_hash".to_string();
123            let timestamp: BTStamp = crate::block_ts_utc();
124            let hash = calculate_block_hash(id, data.clone(), nonce, previous.clone(), timestamp);
125            assert_eq!(&hash, &hash)
126        }
127    }
128}