1use bincode::{Decode, Encode, error::EncodeError};
2use num_bigint::BigUint;
3use rand::Rng;
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7use crate::{
8 core::{difficulty::calculate_block_difficulty, transaction::Transaction},
9 crypto::{
10 Hash,
11 address_inclusion_filter::{AddressInclusionFilter, AddressInclusionFilterError},
12 merkle_tree::MerkleTree,
13 },
14 economics::SCIP_1_MIGRATION,
15};
16
17pub const MAX_TRANSACTIONS_PER_BLOCK: usize = 500;
18
19#[derive(Error, Debug, Serialize, Deserialize, Clone, Encode, Decode)]
20pub enum BlockError {
21 #[error("Block is missing required metadata")]
22 IncompleteBlock,
23
24 #[error("Encoding error")]
25 EncodeError,
26
27 #[error("Block hash is invalid")]
28 InvalidBlockHash,
29
30 #[error("Block difficulties don't match real difficulties")]
31 DifficultyMismatch,
32
33 #[error("Block pow difficulty is not up to target")]
34 BlockPowDifficultyIncorrect,
35
36 #[error("Transaction is incomplete")]
37 IncompleteTransaction,
38
39 #[error("Merkle root tree is invalid")]
40 InvalidMerkleTreeRoot,
41
42 #[error("Address inclusion filter error: {0}")]
43 AddressInclusionFilter(#[from] AddressInclusionFilterError),
44
45 #[error("Address inclusion filter is incorrect")]
46 IncorrectAddressInclusionFilter,
47}
48
49#[derive(Encode, Decode, Serialize, Deserialize, Clone, Debug, PartialEq, Hash)]
52pub struct Block {
53 pub transactions: Vec<Transaction>,
54 pub timestamp: u64,
55 pub nonce: u64,
56 pub meta: BlockMetadata,
57}
58
59impl Block {
60 pub fn new_block_now(
62 transactions: Vec<Transaction>,
63 block_pow_difficulty: &[u8; 32],
64 tx_pow_difficulty: &[u8; 32],
65 previous_block: Hash,
66 merkle_tree_root: &[u8; 32],
67 address_inclusion_filter: AddressInclusionFilter,
68 ) -> Self {
69 Block {
70 transactions,
71 timestamp: chrono::Utc::now().timestamp() as u64,
72 nonce: 0,
73 meta: BlockMetadata {
74 block_pow_difficulty: *block_pow_difficulty,
75 tx_pow_difficulty: *tx_pow_difficulty,
76 previous_block,
77 hash: None,
78 merkle_tree_root: *merkle_tree_root,
79 address_inclusion_filter,
80 },
81 }
82 }
83
84 pub fn get_hashing_buf(&self) -> Result<Vec<u8>, EncodeError> {
87 use sha2::{Digest, Sha256};
88
89 let mut hash_less_block = self.clone();
91 hash_less_block.meta.hash = None;
92
93 let mut transactions_digest = Vec::with_capacity(hash_less_block.transactions.len() * 32);
95
96 for tx in &mut hash_less_block.transactions {
97 let mut encoded_tx_io =
99 bincode::encode_to_vec(tx.inputs.clone(), bincode::config::standard())?;
100 encoded_tx_io.extend(bincode::encode_to_vec(
101 tx.inputs.clone(),
102 bincode::config::standard(),
103 )?);
104 let digest = Sha256::digest(&encoded_tx_io);
105
106 transactions_digest.extend_from_slice(&digest);
107
108 tx.inputs.clear();
110 tx.outputs.clear();
111 }
112
113 let mut buf = bincode::encode_to_vec(hash_less_block, bincode::config::standard())?;
115 if self.timestamp > SCIP_1_MIGRATION {
116 buf.extend_from_slice(&transactions_digest);
117 }
118
119 Ok(buf)
120 }
121
122 #[deprecated]
125 pub fn compute_pow(&mut self) -> Result<(), EncodeError> {
126 let tx_difficulty_big_int = BigUint::from_bytes_be(&calculate_block_difficulty(
127 &self.meta.block_pow_difficulty,
128 self.transactions.len(),
129 ));
130 let mut rng: rand::prelude::ThreadRng = rand::rng();
131 loop {
132 self.nonce = rng.random();
133 let hashing_buf = self.get_hashing_buf()?;
134 if BigUint::from_bytes_be(&*Hash::new(&hashing_buf)) <= tx_difficulty_big_int {
135 self.meta.hash = Some(Hash::new(&hashing_buf));
136 return Ok(());
137 }
138 }
139 }
140
141 pub fn check_meta(&self) -> Result<(), BlockError> {
143 self.check_completeness()?;
144 self.validate_block_hash()?;
145 self.validate_address_inclusion_filter()?;
146 self.validate_merkle_tree()?;
147 Ok(())
148 }
149
150 pub fn check_completeness(&self) -> Result<(), BlockError> {
152 self.meta
153 .hash
154 .ok_or(BlockError::IncompleteBlock)
155 .map(|_| ())?;
156 Ok(())
157 }
158
159 pub fn validate_block_hash(&self) -> Result<(), BlockError> {
161 self.check_completeness()?;
162 if !self
163 .meta
164 .hash
165 .ok_or(BlockError::IncompleteBlock)?
166 .compare_with_data(
167 &self
168 .get_hashing_buf()
169 .map_err(|_| BlockError::EncodeError)?,
170 )
171 {
172 return Err(BlockError::InvalidBlockHash);
173 }
174 Ok(())
175 }
176
177 pub fn validate_difficulties(
179 &self,
180 real_block_pow_difficulty: &[u8; 32],
181 real_tx_pow_difficulty: &[u8; 32],
182 ) -> Result<(), BlockError> {
183 if self.meta.block_pow_difficulty != *real_block_pow_difficulty
184 || self.meta.tx_pow_difficulty != *real_tx_pow_difficulty
185 {
186 return Err(BlockError::DifficultyMismatch);
187 }
188 if BigUint::from_bytes_be(&*self.meta.hash.unwrap())
189 > BigUint::from_bytes_be(&calculate_block_difficulty(
190 real_block_pow_difficulty,
191 self.transactions.len(),
192 ))
193 {
194 return Err(BlockError::BlockPowDifficultyIncorrect);
195 }
196 Ok(())
197 }
198
199 pub fn validate_merkle_tree(&self) -> Result<(), BlockError> {
201 let mut ids = vec![];
202 for tx in &self.transactions {
203 tx.check_completeness()
204 .map_err(|_| BlockError::IncompleteTransaction)?;
205 ids.push(tx.transaction_id.unwrap());
206 }
207 let tree = MerkleTree::build(&ids);
208 if tree.root_hash() != self.meta.merkle_tree_root {
209 return Err(BlockError::InvalidMerkleTreeRoot);
210 }
211 Ok(())
212 }
213
214 pub fn validate_address_inclusion_filter(&self) -> Result<(), BlockError> {
216 if AddressInclusionFilter::create_filter(&self.transactions)?
217 != self.meta.address_inclusion_filter
218 {
219 return Err(BlockError::IncorrectAddressInclusionFilter);
220 }
221 Ok(())
222 }
223
224 pub fn address_count(&self) -> usize {
225 self.transactions
226 .iter()
227 .fold(0, |acc, tx| acc + tx.address_count())
228 }
229}
230
231#[derive(Encode, Decode, Serialize, Deserialize, Clone, Debug, PartialEq, Hash)]
233pub struct BlockMetadata {
234 pub block_pow_difficulty: [u8; 32],
235 pub tx_pow_difficulty: [u8; 32],
236 pub previous_block: Hash,
237 pub hash: Option<Hash>,
238 pub merkle_tree_root: [u8; 32],
239 pub address_inclusion_filter: AddressInclusionFilter,
240}