darkfi/validator/
utils.rs1use darkfi_sdk::{
20 crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID},
21 tx::TransactionHash,
22};
23use num_bigint::BigUint;
24use randomx::{RandomXCache, RandomXFlags, RandomXVM};
25use tracing::info;
26
27use crate::{
28 blockchain::{BlockInfo, BlockchainOverlayPtr, Header},
29 runtime::vm_runtime::Runtime,
30 validator::{
31 consensus::{Fork, Proposal},
32 pow::PoWModule,
33 },
34 Error, Result,
35};
36
37pub async fn deploy_native_contracts(
49 overlay: &BlockchainOverlayPtr,
50 block_target: u32,
51) -> Result<()> {
52 info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
53
54 let money_contract_deploy_payload = vec![];
56
57 let dao_contract_deploy_payload = vec![];
59
60 let deployooor_contract_deploy_payload = vec![];
62
63 let native_contracts = vec![
64 (
65 "Money Contract",
66 *MONEY_CONTRACT_ID,
67 include_bytes!("../contract/money/darkfi_money_contract.wasm").to_vec(),
68 money_contract_deploy_payload,
69 ),
70 (
71 "DAO Contract",
72 *DAO_CONTRACT_ID,
73 include_bytes!("../contract/dao/darkfi_dao_contract.wasm").to_vec(),
74 dao_contract_deploy_payload,
75 ),
76 (
77 "Deployooor Contract",
78 *DEPLOYOOOR_CONTRACT_ID,
79 include_bytes!("../contract/deployooor/darkfi_deployooor_contract.wasm").to_vec(),
80 deployooor_contract_deploy_payload,
81 ),
82 ];
83
84 let verifying_block_height = match overlay.lock().unwrap().last() {
87 Ok((last_block_height, _)) => last_block_height + 1,
88 Err(_) => 0,
89 };
90
91 for (call_idx, nc) in native_contracts.into_iter().enumerate() {
92 info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1);
93
94 let mut runtime = Runtime::new(
95 &nc.2[..],
96 overlay.clone(),
97 nc.1,
98 verifying_block_height,
99 block_target,
100 TransactionHash::none(),
101 call_idx as u8,
102 )?;
103
104 runtime.deploy(&nc.3)?;
105
106 info!(target: "validator::utils::deploy_native_contracts", "Successfully deployed {}", nc.0);
107 }
108
109 info!(target: "validator::utils::deploy_native_contracts", "Finished deployment of native WASM contracts");
110
111 Ok(())
112}
113
114pub fn header_rank(module: &PoWModule, header: &Header) -> Result<(BigUint, BigUint, BigUint)> {
123 let (target, difficulty) = module.next_mine_target_and_difficulty()?;
125
126 if header.height == 0 {
128 return Ok((difficulty, 0u64.into(), 0u64.into()))
129 }
130
131 let out_hash = module.verify_block_target(header, &target)?;
133
134 let max = BigUint::from_bytes_le(&[0xFF; 32]);
136
137 let target_distance = &max - target;
139 let target_distance_sq = &target_distance * &target_distance;
140
141 let hash_distance = max - out_hash;
143 let hash_distance_sq = &hash_distance * &hash_distance;
144
145 Ok((difficulty, target_distance_sq, hash_distance_sq))
146}
147
148pub fn block_rank(block: &BlockInfo, target: &BigUint) -> Result<(BigUint, BigUint)> {
154 if block.header.height == 0 {
156 return Ok((0u64.into(), 0u64.into()))
157 }
158
159 let max = BigUint::from_bytes_le(&[0xFF; 32]);
161
162 let target_distance = &max - target;
164 let target_distance_sq = &target_distance * &target_distance;
165
166 let flags = RandomXFlags::get_recommended_flags();
168 let cache = RandomXCache::new(flags, block.header.previous.inner())?;
169 let vm = RandomXVM::new(flags, Some(cache), None)?;
170
171 let out_hash = vm.calculate_hash(block.hash().inner())?;
173 let out_hash = BigUint::from_bytes_le(&out_hash);
174 let hash_distance = max - out_hash;
175 let hash_distance_sq = &hash_distance * &hash_distance;
176
177 Ok((target_distance_sq, hash_distance_sq))
178}
179
180pub fn get_mid(a: u64, b: u64) -> u64 {
182 (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
183}
184
185pub fn median(mut v: Vec<u64>) -> u64 {
188 if v.len() == 1 {
189 return v[0]
190 }
191
192 let n = v.len() / 2;
193 v.sort_unstable();
194
195 if v.len().is_multiple_of(2) {
196 v[n]
197 } else {
198 get_mid(v[n - 1], v[n])
199 }
200}
201
202pub fn find_extended_fork_index(forks: &[Fork], proposal: &Proposal) -> Result<(usize, usize)> {
206 let proposal_hash = proposal.hash;
208
209 let (mut fork_index, mut proposal_index) = (None, None);
211
212 for (f_index, fork) in forks.iter().enumerate() {
214 for (p_index, p_hash) in fork.proposals.iter().enumerate().rev() {
216 if &proposal_hash == p_hash {
218 return Err(Error::ProposalAlreadyExists)
219 }
220
221 if &proposal.block.header.previous == p_hash {
223 (fork_index, proposal_index) = (Some(f_index), Some(p_index));
224 }
225 }
226 }
227
228 if let (Some(f_index), Some(p_index)) = (fork_index, proposal_index) {
229 return Ok((f_index, p_index))
230 }
231
232 Err(Error::ExtendedChainIndexNotFound)
233}
234
235pub fn best_fork_index(forks: &[Fork]) -> Result<usize> {
243 if forks.is_empty() {
245 return Err(Error::ForksNotFound)
246 }
247
248 let mut best = &BigUint::from(0u64);
250 let mut indexes = vec![];
251 for (f_index, fork) in forks.iter().enumerate() {
252 let rank = &fork.targets_rank;
253
254 if rank < best {
256 continue
257 }
258
259 if rank == best {
261 indexes.push(f_index);
262 continue
263 }
264
265 best = rank;
267 indexes = vec![f_index];
268 }
269
270 if indexes.len() == 1 {
272 return Ok(indexes[0])
273 }
274
275 let mut best_index = indexes[0];
277 for index in &indexes[1..] {
278 if forks[*index].hashes_rank > forks[best_index].hashes_rank {
279 best_index = *index;
280 }
281 }
282
283 Ok(best_index)
284}