darkfi/validator/
utils.rs1use darkfi_sdk::{
20 crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID},
21 tx::TransactionHash,
22};
23use log::info;
24use num_bigint::BigUint;
25use randomx::{RandomXCache, RandomXFlags, RandomXVM};
26
27use crate::{
28 blockchain::{BlockInfo, BlockchainOverlayPtr, Header},
29 runtime::vm_runtime::Runtime,
30 validator::consensus::{Fork, Proposal},
31 Error, Result,
32};
33
34pub async fn deploy_native_contracts(
46 overlay: &BlockchainOverlayPtr,
47 block_target: u32,
48) -> Result<()> {
49 info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
50
51 let money_contract_deploy_payload = vec![];
53
54 let dao_contract_deploy_payload = vec![];
56
57 let deployooor_contract_deploy_payload = vec![];
59
60 let native_contracts = vec![
61 (
62 "Money Contract",
63 *MONEY_CONTRACT_ID,
64 include_bytes!("../contract/money/darkfi_money_contract.wasm").to_vec(),
65 money_contract_deploy_payload,
66 ),
67 (
68 "DAO Contract",
69 *DAO_CONTRACT_ID,
70 include_bytes!("../contract/dao/darkfi_dao_contract.wasm").to_vec(),
71 dao_contract_deploy_payload,
72 ),
73 (
74 "Deployooor Contract",
75 *DEPLOYOOOR_CONTRACT_ID,
76 include_bytes!("../contract/deployooor/darkfi_deployooor_contract.wasm").to_vec(),
77 deployooor_contract_deploy_payload,
78 ),
79 ];
80
81 let verifying_block_height = match overlay.lock().unwrap().last() {
84 Ok((last_block_height, _)) => last_block_height + 1,
85 Err(_) => 0,
86 };
87
88 for (call_idx, nc) in native_contracts.into_iter().enumerate() {
89 info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1);
90
91 let mut runtime = Runtime::new(
92 &nc.2[..],
93 overlay.clone(),
94 nc.1,
95 verifying_block_height,
96 block_target,
97 TransactionHash::none(),
98 call_idx as u8,
99 )?;
100
101 runtime.deploy(&nc.3)?;
102
103 info!(target: "validator::utils::deploy_native_contracts", "Successfully deployed {}", nc.0);
104 }
105
106 info!(target: "validator::utils::deploy_native_contracts", "Finished deployment of native WASM contracts");
107
108 Ok(())
109}
110
111pub fn header_rank(header: &Header, target: &BigUint) -> Result<(BigUint, BigUint)> {
117 if header.height == 0 {
119 return Ok((0u64.into(), 0u64.into()))
120 }
121
122 let flags = RandomXFlags::default();
124 let cache = RandomXCache::new(flags, header.previous.inner()).unwrap();
125 let vm = RandomXVM::new(flags, &cache).unwrap();
126
127 let out_hash = vm.hash(header.hash().inner());
129 let out_hash = BigUint::from_bytes_be(&out_hash);
130
131 if out_hash > *target {
133 return Err(Error::PoWInvalidOutHash)
134 }
135
136 let max = BigUint::from_bytes_be(&[0xFF; 32]);
138
139 let target_distance = &max - target;
141 let target_distance_sq = &target_distance * &target_distance;
142
143 let hash_distance = max - out_hash;
145 let hash_distance_sq = &hash_distance * &hash_distance;
146
147 Ok((target_distance_sq, hash_distance_sq))
148}
149
150pub fn block_rank(block: &BlockInfo, target: &BigUint) -> (BigUint, BigUint) {
156 if block.header.height == 0 {
158 return (0u64.into(), 0u64.into())
159 }
160
161 let max = BigUint::from_bytes_be(&[0xFF; 32]);
163
164 let target_distance = &max - target;
166 let target_distance_sq = &target_distance * &target_distance;
167
168 let flags = RandomXFlags::default();
170 let cache = RandomXCache::new(flags, block.header.previous.inner()).unwrap();
171 let vm = RandomXVM::new(flags, &cache).unwrap();
172
173 let out_hash = vm.hash(block.hash().inner());
175 let out_hash = BigUint::from_bytes_be(&out_hash);
176 let hash_distance = max - out_hash;
177 let hash_distance_sq = &hash_distance * &hash_distance;
178
179 (target_distance_sq, hash_distance_sq)
180}
181
182pub fn get_mid(a: u64, b: u64) -> u64 {
184 (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
185}
186
187pub fn median(mut v: Vec<u64>) -> u64 {
190 if v.len() == 1 {
191 return v[0]
192 }
193
194 let n = v.len() / 2;
195 v.sort_unstable();
196
197 if v.len() % 2 == 0 {
198 v[n]
199 } else {
200 get_mid(v[n - 1], v[n])
201 }
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> {
245 if forks.is_empty() {
247 return Err(Error::ForksNotFound)
248 }
249
250 let mut best = &BigUint::from(0u64);
252 let mut indexes = vec![];
253 for (f_index, fork) in forks.iter().enumerate() {
254 let rank = &fork.targets_rank;
255
256 if rank < best {
258 continue
259 }
260
261 if rank == best {
263 indexes.push(f_index);
264 continue
265 }
266
267 best = rank;
269 indexes = vec![f_index];
270 }
271
272 if indexes.len() == 1 {
274 return Ok(indexes[0])
275 }
276
277 let mut best_index = indexes[0];
279 for index in &indexes[1..] {
280 if forks[*index].hashes_rank > forks[best_index].hashes_rank {
281 best_index = *index;
282 }
283 }
284
285 Ok(best_index)
286}