darkfi/validator/
utils.rs1use std::sync::LazyLock;
20
21use darkfi_sdk::{
22 crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID},
23 tx::TransactionHash,
24};
25use num_bigint::BigUint;
26use randomx::{RandomXCache, RandomXFlags, RandomXVM};
27use tracing::info;
28
29use crate::{
30 blockchain::{BlockInfo, BlockchainOverlayPtr, Header},
31 runtime::vm_runtime::Runtime,
32 validator::{
33 consensus::{Fork, Proposal},
34 pow::PoWModule,
35 },
36 Error, Result,
37};
38
39pub static MAX_32_BYTES: LazyLock<BigUint> = LazyLock::new(|| BigUint::from_bytes_le(&[0xFF; 32]));
42
43pub async fn deploy_native_contracts(
56 overlay: &BlockchainOverlayPtr,
57 block_target: u32,
58) -> Result<()> {
59 info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
60
61 let money_contract_deploy_payload = vec![];
63
64 let dao_contract_deploy_payload = vec![];
66
67 let deployooor_contract_deploy_payload = vec![];
69
70 let native_contracts = vec![
71 (
72 "Money Contract",
73 *MONEY_CONTRACT_ID,
74 include_bytes!("../contract/money/darkfi_money_contract.wasm").to_vec(),
75 money_contract_deploy_payload,
76 ),
77 (
78 "DAO Contract",
79 *DAO_CONTRACT_ID,
80 include_bytes!("../contract/dao/darkfi_dao_contract.wasm").to_vec(),
81 dao_contract_deploy_payload,
82 ),
83 (
84 "Deployooor Contract",
85 *DEPLOYOOOR_CONTRACT_ID,
86 include_bytes!("../contract/deployooor/darkfi_deployooor_contract.wasm").to_vec(),
87 deployooor_contract_deploy_payload,
88 ),
89 ];
90
91 let verifying_block_height = match overlay.lock().unwrap().last() {
94 Ok((last_block_height, _)) => last_block_height + 1,
95 Err(_) => 0,
96 };
97
98 for (call_idx, nc) in native_contracts.into_iter().enumerate() {
99 info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1);
100
101 let mut runtime = Runtime::new(
102 &nc.2[..],
103 overlay.clone(),
104 nc.1,
105 verifying_block_height,
106 block_target,
107 TransactionHash::none(),
108 call_idx as u8,
109 )?;
110
111 runtime.deploy(&nc.3)?;
112
113 info!(target: "validator::utils::deploy_native_contracts", "Successfully deployed {}", nc.0);
114 }
115
116 info!(target: "validator::utils::deploy_native_contracts", "Finished deployment of native WASM contracts");
117
118 Ok(())
119}
120
121pub fn header_rank(module: &mut PoWModule, header: &Header) -> Result<(BigUint, BigUint, BigUint)> {
130 let (target, difficulty) = module.next_mine_target_and_difficulty()?;
132
133 if header.height == 0 {
135 return Ok((difficulty, 0u64.into(), 0u64.into()))
136 }
137
138 let out_hash = module.verify_block_target(header, &target)?;
140
141 let target_distance = &*MAX_32_BYTES - target;
143 let target_distance_sq = &target_distance * &target_distance;
144
145 let hash_distance = &*MAX_32_BYTES - out_hash;
147 let hash_distance_sq = &hash_distance * &hash_distance;
148
149 Ok((difficulty, target_distance_sq, hash_distance_sq))
150}
151
152pub fn block_rank(block: &BlockInfo, target: &BigUint) -> Result<(BigUint, BigUint)> {
159 if block.header.height == 0 {
161 return Ok((0u64.into(), 0u64.into()))
162 }
163
164 let target_distance = &*MAX_32_BYTES - target;
166 let target_distance_sq = &target_distance * &target_distance;
167
168 let flags = RandomXFlags::get_recommended_flags();
170 let cache = RandomXCache::new(flags, block.header.previous.inner())?;
171 let vm = RandomXVM::new(flags, Some(cache), None)?;
172
173 let out_hash = vm.calculate_hash(block.hash().inner())?;
175 let out_hash = BigUint::from_bytes_le(&out_hash);
176 let hash_distance = &*MAX_32_BYTES - out_hash;
177 let hash_distance_sq = &hash_distance * &hash_distance;
178
179 Ok((target_distance_sq, hash_distance_sq))
180}
181
182pub fn get_mid(a: u64, b: u64) -> u64 {
185 (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
186}
187
188pub fn median(mut v: Vec<u64>) -> u64 {
191 if v.len() == 1 {
192 return v[0]
193 }
194
195 let n = v.len() / 2;
196 v.sort_unstable();
197
198 if v.len().is_multiple_of(2) {
199 return get_mid(v[n - 1], v[n])
200 }
201 v[n]
202}
203
204pub fn find_extended_fork_index(forks: &[Fork], proposal: &Proposal) -> Result<(usize, usize)> {
208 let proposal_hash = proposal.hash;
210
211 let (mut fork_index, mut proposal_index) = (None, None);
213
214 for (f_index, fork) in forks.iter().enumerate() {
216 for (p_index, p_hash) in fork.proposals.iter().enumerate().rev() {
218 if proposal_hash == *p_hash {
220 return Err(Error::ProposalAlreadyExists)
221 }
222
223 if proposal.block.header.previous == *p_hash {
225 (fork_index, proposal_index) = (Some(f_index), Some(p_index));
226 }
227 }
228 }
229
230 if let (Some(f_index), Some(p_index)) = (fork_index, proposal_index) {
231 return Ok((f_index, p_index))
232 }
233
234 Err(Error::ExtendedChainIndexNotFound)
235}
236
237pub fn best_fork_index(forks: &[Fork]) -> Result<usize> {
244 if forks.is_empty() {
246 return Err(Error::ForksNotFound)
247 }
248
249 let mut best = &BigUint::from(0u64);
251 let mut indexes = vec![];
252 for (f_index, fork) in forks.iter().enumerate() {
253 let rank = &fork.targets_rank;
254
255 if rank < best {
257 continue
258 }
259
260 if rank == best {
262 indexes.push(f_index);
263 continue
264 }
265
266 best = rank;
268 indexes = vec![f_index];
269 }
270
271 if indexes.len() == 1 {
273 return Ok(indexes[0])
274 }
275
276 let mut best_index = indexes[0];
278 for index in &indexes[1..] {
279 if forks[*index].hashes_rank > forks[best_index].hashes_rank {
280 best_index = *index;
281 }
282 }
283
284 Ok(best_index)
285}
286
287pub fn worst_fork_index(forks: &[Fork]) -> Result<usize> {
294 if forks.is_empty() {
296 return Err(Error::ForksNotFound)
297 }
298
299 let mut worst = &forks[0].targets_rank;
301 let mut indexes = vec![0];
302 for (f_index, fork) in forks[1..].iter().enumerate() {
303 let rank = &fork.targets_rank;
304
305 if rank > worst {
307 continue
308 }
309
310 if rank == worst {
312 indexes.push(f_index + 1);
313 continue
314 }
315
316 worst = rank;
318 indexes = vec![f_index + 1];
319 }
320
321 if indexes.len() == 1 {
323 return Ok(indexes[0])
324 }
325
326 let mut worst_index = indexes[0];
328 for index in &indexes[1..] {
329 if forks[*index].hashes_rank < forks[worst_index].hashes_rank {
330 worst_index = *index;
331 }
332 }
333
334 Ok(worst_index)
335}