utils.rs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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, PublicKey, CONSENSUS_CONTRACT_ID,
  21. DAO_CONTRACT_ID, MONEY_CONTRACT_ID,
  22. },
  23. pasta::{group::ff::FromUniformBytes, pallas},
  24. };
  25. use darkfi_serial::{serialize_async, AsyncDecodable};
  26. use log::info;
  27. use smol::io::Cursor;
  28. use crate::{
  29. blockchain::{BlockInfo, BlockchainOverlayPtr},
  30. error::TxVerifyFailed,
  31. runtime::vm_runtime::Runtime,
  32. tx::Transaction,
  33. util::time::TimeKeeper,
  34. validator::consensus::{Fork, Proposal},
  35. Error, Result,
  36. };
  37. /// Deploy DarkFi native wasm contracts to provided blockchain overlay.
  38. /// If overlay already contains the contracts, it will just open the
  39. /// necessary db and trees, and give back what it has. This means that
  40. /// on subsequent runs, our native contracts will already be in a deployed
  41. /// state, so what we actually do here is a redeployment. This kind of
  42. /// operation should only modify the contract's state in case it wasn't
  43. /// deployed before (meaning the initial run). Otherwise, it shouldn't
  44. /// touch anything, or just potentially update the db schemas or whatever
  45. /// is necessary. This logic should be handled in the init function of
  46. /// the actual contract, so make sure the native contracts handle this well.
  47. pub async fn deploy_native_contracts(
  48. overlay: &BlockchainOverlayPtr,
  49. time_keeper: &TimeKeeper,
  50. faucet_pubkeys: &Vec<PublicKey>,
  51. ) -> Result<()> {
  52. info!(target: "validator::utils::deploy_native_contracts", "Deploying native WASM contracts");
  53. // The faucet pubkeys are pubkeys which are allowed to create clear inputs
  54. // in the Money contract.
  55. let money_contract_deploy_payload = serialize_async(faucet_pubkeys).await;
  56. // The DAO contract uses an empty payload to deploy itself.
  57. let dao_contract_deploy_payload = vec![];
  58. // The Consensus contract uses an empty payload to deploy itself.
  59. let consensus_contract_deploy_payload = vec![];
  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. "Consensus Contract",
  75. *CONSENSUS_CONTRACT_ID,
  76. include_bytes!("../contract/consensus/darkfi_consensus_contract.wasm").to_vec(),
  77. consensus_contract_deploy_payload,
  78. ),
  79. ];
  80. for nc in native_contracts {
  81. info!(target: "validator::utils::deploy_native_contracts", "Deploying {} with ContractID {}", nc.0, nc.1);
  82. let mut runtime = Runtime::new(&nc.2[..], overlay.clone(), nc.1, time_keeper.clone())?;
  83. runtime.deploy(&nc.3)?;
  84. info!(target: "validator::utils::deploy_native_contracts", "Successfully deployed {}", nc.0);
  85. }
  86. info!(target: "validator::utils::deploy_native_contracts", "Finished deployment of native WASM contracts");
  87. Ok(())
  88. }
  89. /// Compute a block's rank, assuming the its valid.
  90. /// Genesis block has rank 0.
  91. /// First 2 blocks rank is equal to their nonce, since their previous
  92. /// previous block producer doesn't exist or have a VRF.
  93. pub async fn block_rank(
  94. block: &BlockInfo,
  95. previous_previous: &BlockInfo,
  96. pos_testing_mode: bool,
  97. ) -> Result<u64> {
  98. // Genesis block has rank 0
  99. if block.header.height == 0 {
  100. return Ok(0)
  101. }
  102. // Compute nonce u64
  103. let mut nonce = [0u8; 8];
  104. nonce.copy_from_slice(&block.header.nonce.to_repr()[..8]);
  105. let nonce = u64::from_be_bytes(nonce);
  106. // First 2 blocks or testing ones have rank equal to their nonce
  107. if block.header.height < 3 || pos_testing_mode {
  108. return Ok(nonce)
  109. }
  110. // Extract VRF proof from the previous previous producer transaction
  111. let tx = previous_previous.txs.last().unwrap();
  112. let data = &tx.calls[0].data.data;
  113. let position = match previous_previous.header.version {
  114. // PoW uses MoneyPoWRewardParamsV1
  115. 1 => 563,
  116. // PoS uses ConsensusProposalParamsV1
  117. 2 => 490,
  118. _ => return Err(Error::BlockVersionIsInvalid(previous_previous.header.version)),
  119. };
  120. let mut decoder = Cursor::new(&data);
  121. decoder.set_position(position);
  122. let vrf_proof: VrfProof = AsyncDecodable::decode_async(&mut decoder).await?;
  123. // Compute VRF u64
  124. let mut vrf = [0u8; 64];
  125. vrf[..blake3::OUT_LEN].copy_from_slice(vrf_proof.hash_output().as_bytes());
  126. let vrf_pallas = pallas::Base::from_uniform_bytes(&vrf);
  127. let mut vrf = [0u8; 8];
  128. vrf.copy_from_slice(&vrf_pallas.to_repr()[..8]);
  129. let vrf = u64::from_be_bytes(vrf);
  130. // Finally, compute the rank
  131. let rank = nonce % vrf;
  132. Ok(rank)
  133. }
  134. /// Auxiliary function to calculate the middle value between provided u64 numbers
  135. pub fn get_mid(a: u64, b: u64) -> u64 {
  136. (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
  137. }
  138. /// Auxiliary function to calculate the median of a given `Vec<u64>`.
  139. /// The function sorts the vector internally.
  140. pub fn median(mut v: Vec<u64>) -> u64 {
  141. if v.len() == 1 {
  142. return v[0]
  143. }
  144. let n = v.len() / 2;
  145. v.sort_unstable();
  146. if v.len() % 2 == 0 {
  147. v[n]
  148. } else {
  149. get_mid(v[n - 1], v[n])
  150. }
  151. }
  152. /// Auxiliary function to calculate the total amount of minted tokens in provided
  153. /// genesis transactions set. This includes both staked and normal tokens.
  154. /// If a non-genesis transaction is found, execution fails.
  155. /// Set must also include the genesis transaction(empty) at last position.
  156. pub async fn genesis_txs_total(txs: &[Transaction]) -> Result<u64> {
  157. let mut total = 0;
  158. if txs.is_empty() {
  159. return Ok(total)
  160. }
  161. // Iterate transactions, exluding producer(last) one
  162. for tx in &txs[..txs.len() - 1] {
  163. // Transaction must contain a single Consensus::GenesisStake (0x00)
  164. // or Money::GenesisMint (0x01) call
  165. if tx.calls.len() != 1 {
  166. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  167. }
  168. let call = &tx.calls[0];
  169. let data = &call.data.data;
  170. let function = data[0];
  171. if !(call.data.contract_id == *CONSENSUS_CONTRACT_ID ||
  172. call.data.contract_id == *MONEY_CONTRACT_ID) ||
  173. (call.data.contract_id == *CONSENSUS_CONTRACT_ID && function != 0x00_u8) ||
  174. (call.data.contract_id == *MONEY_CONTRACT_ID && function != 0x01_u8)
  175. {
  176. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  177. }
  178. // Extract transaction input value.
  179. // Consensus::GenesisStake uses ConsensusGenesisStakeParamsV1, while
  180. // Money::GenesisMint uses MoneyGenesisMintParamsV1. Both params structs
  181. // have the value at same position (1).
  182. let position = 1;
  183. let mut decoder = Cursor::new(&data);
  184. decoder.set_position(position);
  185. let value: u64 = AsyncDecodable::decode_async(&mut decoder).await?;
  186. total += value;
  187. }
  188. let tx = txs.last().unwrap();
  189. if tx != &Transaction::default() {
  190. return Err(TxVerifyFailed::ErroneousTxs(vec![tx.clone()]).into())
  191. }
  192. Ok(total)
  193. }
  194. /// Retrieve previous slot producers, last proposal hashes,
  195. /// and their second to last hashes, from all provided forks.
  196. pub fn previous_slot_info(
  197. forks: &Vec<Fork>,
  198. slot: u64,
  199. ) -> Result<(u64, Vec<blake3::Hash>, Vec<blake3::Hash>)> {
  200. let mut producers = 0;
  201. let mut last_hashes = vec![];
  202. let mut second_to_last_hashes = vec![];
  203. for fork in forks {
  204. let last_proposal = fork.last_proposal()?;
  205. if last_proposal.block.header.height == slot {
  206. producers += 1;
  207. }
  208. last_hashes.push(last_proposal.hash);
  209. second_to_last_hashes.push(last_proposal.block.header.previous);
  210. }
  211. Ok((producers, last_hashes, second_to_last_hashes))
  212. }
  213. /// Given a proposal, find the index of the fork chain it extends, along with the specific
  214. /// extended proposal index.
  215. pub fn find_extended_fork_index(forks: &[Fork], proposal: &Proposal) -> Result<(usize, usize)> {
  216. for (f_index, fork) in forks.iter().enumerate() {
  217. // Traverse fork proposals sequence in reverse
  218. for (p_index, p_hash) in fork.proposals.iter().enumerate().rev() {
  219. if &proposal.block.header.previous == p_hash {
  220. return Ok((f_index, p_index))
  221. }
  222. }
  223. }
  224. Err(Error::ExtendedChainIndexNotFound)
  225. }
  226. /// Auxiliary function to find best ranked forks indexes.
  227. pub fn best_forks_indexes(forks: &[Fork]) -> Result<Vec<usize>> {
  228. // Check if node has any forks
  229. if forks.is_empty() {
  230. return Err(Error::ForksNotFound)
  231. }
  232. // Find the best ranked forks
  233. let mut best = 0;
  234. let mut indexes = vec![];
  235. for (f_index, fork) in forks.iter().enumerate() {
  236. let rank = fork.rank;
  237. // Fork ranks lower that current best
  238. if rank < best {
  239. continue
  240. }
  241. // Fork has same rank as current best
  242. if rank == best {
  243. indexes.push(f_index);
  244. continue
  245. }
  246. // Fork ranks higher that current best
  247. best = rank;
  248. indexes = vec![f_index];
  249. }
  250. Ok(indexes)
  251. }