utils.rs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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::{
  20. ecvrf::VrfProof, pasta_prelude::PrimeField, DAO_CONTRACT_ID, DEPLOYOOOR_CONTRACT_ID,
  21. MONEY_CONTRACT_ID,
  22. },
  23. pasta::{group::ff::FromUniformBytes, pallas},
  24. };
  25. use darkfi_serial::AsyncDecodable;
  26. use log::info;
  27. use smol::io::Cursor;
  28. use crate::{
  29. blockchain::{BlockInfo, BlockchainOverlayPtr},
  30. runtime::vm_runtime::Runtime,
  31. validator::consensus::{Fork, Proposal},
  32. Error, Result,
  33. };
  34. /// Deploy DarkFi native wasm contracts to provided blockchain overlay.
  35. /// If overlay already contains the contracts, it will just open the
  36. /// necessary db and trees, and give back what it has. This means that
  37. /// on subsequent runs, our native contracts will already be in a deployed
  38. /// state, so what we actually do here is a redeployment. This kind of
  39. /// operation should only modify the contract's state in case it wasn't
  40. /// deployed before (meaning the initial run). Otherwise, it shouldn't
  41. /// touch anything, or just potentially update the db schemas or whatever
  42. /// is necessary. This logic should be handled in the init function of
  43. /// the actual contract, so make sure the native contracts handle this well.
  44. pub async fn deploy_native_contracts(overlay: &BlockchainOverlayPtr) -> Result<()> {
  45. info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
  46. // The Money contract uses an empty payload to deploy itself.
  47. let money_contract_deploy_payload = vec![];
  48. // The DAO contract uses an empty payload to deploy itself.
  49. let dao_contract_deploy_payload = vec![];
  50. // The Deployooor contract uses an empty payload to deploy itself.
  51. let deployooor_contract_deploy_payload = vec![];
  52. let native_contracts = vec![
  53. (
  54. "Money Contract",
  55. *MONEY_CONTRACT_ID,
  56. include_bytes!("../contract/money/darkfi_money_contract.wasm").to_vec(),
  57. money_contract_deploy_payload,
  58. ),
  59. (
  60. "DAO Contract",
  61. *DAO_CONTRACT_ID,
  62. include_bytes!("../contract/dao/darkfi_dao_contract.wasm").to_vec(),
  63. dao_contract_deploy_payload,
  64. ),
  65. (
  66. "Deployooor Contract",
  67. *DEPLOYOOOR_CONTRACT_ID,
  68. include_bytes!("../contract/deployooor/darkfi_deployooor_contract.wasm").to_vec(),
  69. deployooor_contract_deploy_payload,
  70. ),
  71. ];
  72. // Grab last known block height to verify against next one.
  73. // If no blocks exist, we verify against genesis block height (0).
  74. let verifying_block_height = match overlay.lock().unwrap().last() {
  75. Ok((last_block_height, _)) => last_block_height + 1,
  76. Err(_) => 0,
  77. };
  78. for nc in native_contracts {
  79. info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1);
  80. let mut runtime = Runtime::new(&nc.2[..], overlay.clone(), nc.1, verifying_block_height)?;
  81. runtime.deploy(&nc.3)?;
  82. info!(target: "validator::utils::deploy_native_contracts", "Successfully deployed {}", nc.0);
  83. }
  84. info!(target: "validator::utils::deploy_native_contracts", "Finished deployment of native WASM contracts");
  85. Ok(())
  86. }
  87. /// Compute a block's rank, assuming the its valid.
  88. /// Genesis block has rank 0.
  89. /// First 2 blocks rank is equal to their nonce, since their previous
  90. /// previous block producer doesn't exist or have a VRF.
  91. pub async fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Result<u64> {
  92. // Genesis block has rank 0
  93. if block.header.height == 0 {
  94. return Ok(0)
  95. }
  96. // Compute nonce u64
  97. let mut nonce = [0u8; 8];
  98. nonce.copy_from_slice(&block.header.nonce.to_repr()[..8]);
  99. let nonce = u64::from_be_bytes(nonce);
  100. // First 2 blocks have rank equal to their nonce
  101. if block.header.height < 3 {
  102. return Ok(nonce)
  103. }
  104. // Extract VRF proof from the previous previous producer transaction
  105. let tx = previous_previous.txs.last().unwrap();
  106. let data = &tx.calls[0].data.data;
  107. let mut decoder = Cursor::new(&data);
  108. // PoW uses MoneyPoWRewardParamsV1
  109. decoder.set_position(499);
  110. let vrf_proof: VrfProof = AsyncDecodable::decode_async(&mut decoder).await?;
  111. // Compute VRF u64
  112. let mut vrf = [0u8; 64];
  113. vrf[..blake3::OUT_LEN].copy_from_slice(vrf_proof.hash_output().as_bytes());
  114. let vrf_pallas = pallas::Base::from_uniform_bytes(&vrf);
  115. let mut vrf = [0u8; 8];
  116. vrf.copy_from_slice(&vrf_pallas.to_repr()[..8]);
  117. let vrf = u64::from_be_bytes(vrf);
  118. // Finally, compute the rank
  119. let rank = nonce % vrf;
  120. Ok(rank)
  121. }
  122. /// Auxiliary function to calculate the middle value between provided u64 numbers
  123. pub fn get_mid(a: u64, b: u64) -> u64 {
  124. (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
  125. }
  126. /// Auxiliary function to calculate the median of a given `Vec<u64>`.
  127. /// The function sorts the vector internally.
  128. pub fn median(mut v: Vec<u64>) -> u64 {
  129. if v.len() == 1 {
  130. return v[0]
  131. }
  132. let n = v.len() / 2;
  133. v.sort_unstable();
  134. if v.len() % 2 == 0 {
  135. v[n]
  136. } else {
  137. get_mid(v[n - 1], v[n])
  138. }
  139. }
  140. /// Given a proposal, find the index of the fork chain it extends, along with the specific
  141. /// extended proposal index. Additionally, check that proposal doesn't already exists in any
  142. /// fork chain.
  143. pub fn find_extended_fork_index(forks: &[Fork], proposal: &Proposal) -> Result<(usize, usize)> {
  144. // Grab provided proposal hash
  145. let proposal_hash = proposal.block.hash()?;
  146. // Keep track of fork and proposal indexes
  147. let (mut fork_index, mut proposal_index) = (None, None);
  148. // Loop through all the forks
  149. for (f_index, fork) in forks.iter().enumerate() {
  150. // Traverse fork proposals sequence in reverse
  151. for (p_index, p_hash) in fork.proposals.iter().enumerate().rev() {
  152. // Check we haven't already seen that proposal
  153. if &proposal_hash == p_hash {
  154. return Err(Error::ProposalAlreadyExists)
  155. }
  156. // Check if proposal extends this fork
  157. if &proposal.block.header.previous == p_hash {
  158. // Proposal must only extend a single fork
  159. if fork_index.is_some() {
  160. return Err(Error::ProposalAlreadyExists)
  161. }
  162. (fork_index, proposal_index) = (Some(f_index), Some(p_index));
  163. }
  164. }
  165. }
  166. if let (Some(f_index), Some(p_index)) = (fork_index, proposal_index) {
  167. return Ok((f_index, p_index))
  168. }
  169. Err(Error::ExtendedChainIndexNotFound)
  170. }
  171. /// Auxiliary function to find best ranked forks indexes.
  172. pub fn best_forks_indexes(forks: &[Fork]) -> Result<Vec<usize>> {
  173. // Check if node has any forks
  174. if forks.is_empty() {
  175. return Err(Error::ForksNotFound)
  176. }
  177. // Find the best ranked forks
  178. let mut best = 0;
  179. let mut indexes = vec![];
  180. for (f_index, fork) in forks.iter().enumerate() {
  181. let rank = fork.rank;
  182. // Fork ranks lower that current best
  183. if rank < best {
  184. continue
  185. }
  186. // Fork has same rank as current best
  187. if rank == best {
  188. indexes.push(f_index);
  189. continue
  190. }
  191. // Fork ranks higher that current best
  192. best = rank;
  193. indexes = vec![f_index];
  194. }
  195. Ok(indexes)
  196. }