utils.rs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_sdk::{
  19. crypto::{DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID, MONEY_CONTRACT_ID},
  20. tx::TransactionHash,
  21. };
  22. use log::info;
  23. use num_bigint::BigUint;
  24. use randomx::{RandomXCache, RandomXFlags, RandomXVM};
  25. use crate::{
  26. blockchain::{BlockInfo, BlockchainOverlayPtr},
  27. runtime::vm_runtime::Runtime,
  28. validator::consensus::{Fork, Proposal},
  29. Error, Result,
  30. };
  31. /// Deploy DarkFi native wasm contracts to provided blockchain overlay.
  32. /// If overlay already contains the contracts, it will just open the
  33. /// necessary db and trees, and give back what it has. This means that
  34. /// on subsequent runs, our native contracts will already be in a deployed
  35. /// state, so what we actually do here is a redeployment. This kind of
  36. /// operation should only modify the contract's state in case it wasn't
  37. /// deployed before (meaning the initial run). Otherwise, it shouldn't
  38. /// touch anything, or just potentially update the db schemas or whatever
  39. /// is necessary. This logic should be handled in the init function of
  40. /// the actual contract, so make sure the native contracts handle this well.
  41. pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<()> {
  42. info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
  43. // The Money contract uses an empty payload to deploy itself.
  44. let money_contract_deploy_payload = vec![];
  45. // The DAO contract uses an empty payload to deploy itself.
  46. let dao_contract_deploy_payload = vec![];
  47. // The Deployooor contract uses an empty payload to deploy itself.
  48. let deployooor_contract_deploy_payload = vec![];
  49. let native_contracts = vec![
  50. (
  51. "Money Contract",
  52. *MONEY_CONTRACT_ID,
  53. include_bytes!("../contract/money/darkfi_money_contract.wasm").to_vec(),
  54. money_contract_deploy_payload,
  55. ),
  56. (
  57. "DAO Contract",
  58. *DAO_CONTRACT_ID,
  59. include_bytes!("../contract/dao/darkfi_dao_contract.wasm").to_vec(),
  60. dao_contract_deploy_payload,
  61. ),
  62. (
  63. "Deployooor Contract",
  64. *DEPLOYOOOR_CONTRACT_ID,
  65. include_bytes!("../contract/deployooor/darkfi_deployooor_contract.wasm").to_vec(),
  66. deployooor_contract_deploy_payload,
  67. ),
  68. ];
  69. // Grab last known block height to verify against next one.
  70. // If no blocks exist, we verify against genesis block height (0).
  71. let verifying_block_height = match overlay.lock().unwrap().last() {
  72. Ok((last_block_height, _)) => last_block_height + 1,
  73. Err(_) => 0,
  74. };
  75. for (call_idx, nc) in native_contracts.into_iter().enumerate() {
  76. info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1);
  77. let mut runtime = Runtime::new(
  78. &nc.2[..],
  79. overlay.clone(),
  80. nc.1,
  81. verifying_block_height,
  82. TransactionHash::none(),
  83. call_idx as u32,
  84. )?;
  85. runtime.deploy(&nc.3)?;
  86. info!(target: "validator::utils::deploy_native_contracts", "Successfully deployed {}", nc.0);
  87. }
  88. info!(target: "validator::utils::deploy_native_contracts", "Finished deployment of native WASM contracts");
  89. Ok(())
  90. }
  91. /// Compute a block's rank, assuming that its valid, based on provided mining target.
  92. /// Block's rank is the tuple of its squared mining target distance from max 32 bytes int,
  93. /// along with its squared RandomX hash number distance from max 32 bytes int.
  94. /// Genesis block has rank (0, 0).
  95. pub fn block_rank(block: &BlockInfo, target: &BigUint) -> (BigUint, BigUint) {
  96. // Genesis block has rank 0
  97. if block.header.height == 0 {
  98. return (0u64.into(), 0u64.into())
  99. }
  100. // Grab the max 32 bytes int
  101. let max = BigUint::from_bytes_be(&[0xFF; 32]);
  102. // Compute the squared mining target distance
  103. let target_distance = &max - target;
  104. let target_distance_sq = &target_distance * &target_distance;
  105. // Setup RandomX verifier
  106. let flags = RandomXFlags::default();
  107. let cache = RandomXCache::new(flags, block.header.previous.inner()).unwrap();
  108. let vm = RandomXVM::new(flags, &cache).unwrap();
  109. // Compute the output hash distance
  110. let out_hash = vm.hash(block.hash().inner());
  111. let out_hash = BigUint::from_bytes_be(&out_hash);
  112. let hash_distance = max - out_hash;
  113. let hash_distance_sq = &hash_distance * &hash_distance;
  114. (target_distance_sq, hash_distance_sq)
  115. }
  116. /// Auxiliary function to calculate the middle value between provided u64 numbers
  117. pub fn get_mid(a: u64, b: u64) -> u64 {
  118. (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
  119. }
  120. /// Auxiliary function to calculate the median of a given `Vec<u64>`.
  121. /// The function sorts the vector internally.
  122. pub fn median(mut v: Vec<u64>) -> u64 {
  123. if v.len() == 1 {
  124. return v[0]
  125. }
  126. let n = v.len() / 2;
  127. v.sort_unstable();
  128. if v.len() % 2 == 0 {
  129. v[n]
  130. } else {
  131. get_mid(v[n - 1], v[n])
  132. }
  133. }
  134. /// Given a proposal, find the index of a fork chain it extends, along with the specific
  135. /// extended proposal index. Additionally, check that proposal doesn't already exists in any
  136. /// fork chain.
  137. pub fn find_extended_fork_index(forks: &[Fork], proposal: &Proposal) -> Result<(usize, usize)> {
  138. // Grab provided proposal hash
  139. let proposal_hash = proposal.hash;
  140. // Keep track of fork and proposal indexes
  141. let (mut fork_index, mut proposal_index) = (None, None);
  142. // Loop through all the forks
  143. for (f_index, fork) in forks.iter().enumerate() {
  144. // Traverse fork proposals sequence in reverse
  145. for (p_index, p_hash) in fork.proposals.iter().enumerate().rev() {
  146. // Check we haven't already seen that proposal
  147. if &proposal_hash == p_hash {
  148. return Err(Error::ProposalAlreadyExists)
  149. }
  150. // Check if proposal extends this fork
  151. if &proposal.block.header.previous == p_hash {
  152. (fork_index, proposal_index) = (Some(f_index), Some(p_index));
  153. }
  154. }
  155. }
  156. if let (Some(f_index), Some(p_index)) = (fork_index, proposal_index) {
  157. return Ok((f_index, p_index))
  158. }
  159. Err(Error::ExtendedChainIndexNotFound)
  160. }
  161. /// Auxiliary function to find best ranked fork.
  162. /// The best ranked fork is the one with the highest sum of
  163. /// its blocks squared mining target distances, from max 32
  164. /// bytes int. In case of a tie, the fork with the highest
  165. /// sum of its blocks squared RandomX hash number distances,
  166. /// from max 32 bytes int, wins.
  167. pub fn best_fork_index(forks: &[Fork]) -> Result<usize> {
  168. // Check if node has any forks
  169. if forks.is_empty() {
  170. return Err(Error::ForksNotFound)
  171. }
  172. // Find the best ranked forks
  173. let mut best = &BigUint::from(0u64);
  174. let mut indexes = vec![];
  175. for (f_index, fork) in forks.iter().enumerate() {
  176. let rank = &fork.targets_rank;
  177. // Fork ranks lower that current best
  178. if rank < best {
  179. continue
  180. }
  181. // Fork has same rank as current best
  182. if rank == best {
  183. indexes.push(f_index);
  184. continue
  185. }
  186. // Fork ranks higher that current best
  187. best = rank;
  188. indexes = vec![f_index];
  189. }
  190. // If a single best ranking fork exists, return it
  191. if indexes.len() == 1 {
  192. return Ok(indexes[0])
  193. }
  194. // Break tie using their hash distances rank
  195. let mut best_index = indexes[0];
  196. for index in &indexes[1..] {
  197. if forks[*index].hashes_rank > forks[best_index].hashes_rank {
  198. best_index = *index;
  199. }
  200. }
  201. Ok(best_index)
  202. }