harness.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 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 std::{collections::HashMap, sync::Arc};
  19. use darkfi::{
  20. blockchain::{BlockInfo, Blockchain, BlockchainOverlay, Header, HeaderHash},
  21. net::Settings,
  22. rpc::jsonrpc::JsonSubscriber,
  23. system::sleep,
  24. tx::{ContractCallLeaf, TransactionBuilder},
  25. validator::{
  26. consensus::{Fork, Proposal},
  27. utils::deploy_native_contracts,
  28. verification::{apply_producer_transaction, verify_block},
  29. Validator, ValidatorConfig,
  30. },
  31. zk::{empty_witnesses, ProvingKey, ZkCircuit},
  32. Result,
  33. };
  34. use darkfi_contract_test_harness::vks;
  35. use darkfi_money_contract::{
  36. client::pow_reward_v1::PoWRewardCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
  37. };
  38. use darkfi_sdk::{
  39. crypto::{
  40. keypair::{Keypair, Network},
  41. MerkleTree, MONEY_CONTRACT_ID,
  42. },
  43. ContractCall,
  44. };
  45. use darkfi_serial::Encodable;
  46. use num_bigint::BigUint;
  47. use sled_overlay::sled;
  48. use url::Url;
  49. use crate::{
  50. proto::{DarkfidP2pHandler, ProposalMessage},
  51. task::sync::sync_task,
  52. DarkfiNode, DarkfiNodePtr,
  53. };
  54. pub struct HarnessConfig {
  55. pub pow_target: u32,
  56. pub pow_fixed_difficulty: Option<BigUint>,
  57. pub confirmation_threshold: usize,
  58. pub alice_url: String,
  59. pub bob_url: String,
  60. }
  61. pub struct Harness {
  62. pub config: HarnessConfig,
  63. pub vks: Vec<(Vec<u8>, String, Vec<u8>)>,
  64. pub validator_config: ValidatorConfig,
  65. pub alice: DarkfiNodePtr,
  66. pub bob: DarkfiNodePtr,
  67. }
  68. impl Harness {
  69. pub async fn new(
  70. config: HarnessConfig,
  71. verify_fees: bool,
  72. ex: &Arc<smol::Executor<'static>>,
  73. ) -> Result<Self> {
  74. // Generate default genesis block
  75. let mut genesis_block = BlockInfo::default();
  76. // Retrieve genesis producer transaction
  77. let producer_tx = genesis_block.txs.pop().unwrap();
  78. // Append it again so its added to the merkle tree
  79. genesis_block.append_txs(vec![producer_tx]);
  80. // Compute genesis contracts states monotree root
  81. let (_, vks) = vks::get_cached_pks_and_vks()?;
  82. let sled_db = sled::Config::new().temporary(true).open()?;
  83. vks::inject(&sled_db, &vks)?;
  84. let overlay = BlockchainOverlay::new(&Blockchain::new(&sled_db)?)?;
  85. deploy_native_contracts(&overlay, config.pow_target).await?;
  86. genesis_block.header.state_root =
  87. overlay.lock().unwrap().get_state_monotree()?.get_headroot()?.unwrap();
  88. // Generate validators configuration
  89. // NOTE: we are not using consensus constants here so we
  90. // don't get circular dependencies.
  91. let validator_config = ValidatorConfig {
  92. confirmation_threshold: config.confirmation_threshold,
  93. pow_target: config.pow_target,
  94. pow_fixed_difficulty: config.pow_fixed_difficulty.clone(),
  95. genesis_block,
  96. verify_fees,
  97. };
  98. // Generate validators
  99. let mut settings =
  100. Settings { localnet: true, inbound_connections: 3, ..Default::default() };
  101. // Alice
  102. let alice_url = Url::parse(&config.alice_url)?;
  103. settings.inbound_addrs = vec![alice_url.clone()];
  104. let alice = generate_node(&vks, &validator_config, &settings, ex, true, None).await?;
  105. // Bob
  106. let bob_url = Url::parse(&config.bob_url)?;
  107. settings.inbound_addrs = vec![bob_url];
  108. settings.peers = vec![alice_url];
  109. let bob = generate_node(&vks, &validator_config, &settings, ex, false, None).await?;
  110. Ok(Self { config, vks, validator_config, alice, bob })
  111. }
  112. pub async fn validate_chains(&self, total_blocks: usize) -> Result<()> {
  113. let alice = &self.alice.validator;
  114. let bob = &self.bob.validator;
  115. alice
  116. .validate_blockchain(self.config.pow_target, self.config.pow_fixed_difficulty.clone())
  117. .await?;
  118. bob.validate_blockchain(self.config.pow_target, self.config.pow_fixed_difficulty.clone())
  119. .await?;
  120. let alice_blockchain_len = alice.blockchain.len();
  121. assert_eq!(alice_blockchain_len, bob.blockchain.len());
  122. assert_eq!(alice_blockchain_len, total_blocks);
  123. assert!(alice.blockchain.headers.is_empty_sync());
  124. assert!(bob.blockchain.headers.is_empty_sync());
  125. Ok(())
  126. }
  127. pub async fn validate_fork_chains(&self, total_forks: usize, fork_sizes: Vec<usize>) {
  128. let alice = &self.alice.validator.consensus.forks.read().await;
  129. let bob = &self.bob.validator.consensus.forks.read().await;
  130. let alice_forks_len = alice.len();
  131. assert_eq!(alice_forks_len, bob.len());
  132. assert_eq!(alice_forks_len, total_forks);
  133. for (index, fork) in alice.iter().enumerate() {
  134. assert_eq!(fork.proposals.len(), fork_sizes[index]);
  135. assert_eq!(fork.diffs.len(), fork_sizes[index]);
  136. assert!(fork.healthcheck().is_ok());
  137. }
  138. for (index, fork) in bob.iter().enumerate() {
  139. assert_eq!(fork.proposals.len(), fork_sizes[index]);
  140. assert_eq!(fork.diffs.len(), fork_sizes[index]);
  141. assert!(fork.healthcheck().is_ok());
  142. }
  143. }
  144. pub async fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
  145. // We append the block as a proposal to Alice,
  146. // and then we broadcast it to rest nodes
  147. for block in blocks {
  148. let proposal = Proposal::new(block.clone());
  149. self.alice.validator.append_proposal(&proposal).await?;
  150. let message = ProposalMessage(proposal);
  151. self.alice.p2p_handler.p2p.broadcast(&message).await;
  152. }
  153. // Sleep a bit so blocks can be propagated and then
  154. // trigger confirmation check to Alice and Bob
  155. sleep(10).await;
  156. self.alice.validator.confirmation().await?;
  157. self.bob.validator.confirmation().await?;
  158. Ok(())
  159. }
  160. pub async fn generate_next_block(&self, fork: &mut Fork) -> Result<BlockInfo> {
  161. // Grab fork last block
  162. let previous = fork.overlay.lock().unwrap().last_block()?;
  163. // Next block info
  164. let block_height = previous.header.height + 1;
  165. let last_nonce = previous.header.nonce;
  166. // Generate a producer transaction
  167. let keypair = Keypair::default();
  168. let (zkbin, _) = fork
  169. .overlay
  170. .lock()
  171. .unwrap()
  172. .contracts
  173. .get_zkas(&MONEY_CONTRACT_ID, MONEY_CONTRACT_ZKAS_MINT_NS_V1)?;
  174. let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
  175. let pk = ProvingKey::build(zkbin.k, &circuit);
  176. // Build the transaction debris
  177. let debris = PoWRewardCallBuilder {
  178. signature_keypair: keypair,
  179. block_height,
  180. fees: 0,
  181. recipient: None,
  182. spend_hook: None,
  183. user_data: None,
  184. mint_zkbin: zkbin.clone(),
  185. mint_pk: pk.clone(),
  186. }
  187. .build()?;
  188. // Generate and sign the actual transaction
  189. let mut data = vec![MoneyFunction::PoWRewardV1 as u8];
  190. debris.params.encode(&mut data)?;
  191. let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
  192. let mut tx_builder =
  193. TransactionBuilder::new(ContractCallLeaf { call, proofs: debris.proofs }, vec![])?;
  194. let mut tx = tx_builder.build()?;
  195. let sigs = tx.create_sigs(&[keypair.secret])?;
  196. tx.signatures = vec![sigs];
  197. // We increment timestamp so we don't have to use sleep
  198. let timestamp = previous.header.timestamp.checked_add(1.into())?;
  199. // Generate header
  200. let header = Header::new(previous.hash(), block_height, timestamp, last_nonce);
  201. // Generate the block
  202. let mut block = BlockInfo::new_empty(header);
  203. // Add producer transaction to the block
  204. block.append_txs(vec![tx]);
  205. // Compute block contracts states monotree root
  206. let overlay = fork.overlay.lock().unwrap().full_clone()?;
  207. let _ = apply_producer_transaction(
  208. &overlay,
  209. block.header.height,
  210. fork.module.target,
  211. block.txs.last().unwrap(),
  212. &mut MerkleTree::new(1),
  213. )
  214. .await?;
  215. block.header.state_root =
  216. overlay.lock().unwrap().get_state_monotree()?.get_headroot()?.unwrap();
  217. // Attach signature
  218. block.sign(&keypair.secret);
  219. // Append new block to fork
  220. verify_block(
  221. &fork.overlay,
  222. &fork.diffs,
  223. &fork.module,
  224. &mut fork.state_monotree,
  225. &block,
  226. &previous,
  227. self.alice.validator.verify_fees,
  228. )
  229. .await?;
  230. fork.append_proposal(&Proposal::new(block.clone())).await?;
  231. Ok(block)
  232. }
  233. }
  234. // Note: This function should mirror `darkfid::Darkfid::init`
  235. pub async fn generate_node(
  236. vks: &Vec<(Vec<u8>, String, Vec<u8>)>,
  237. config: &ValidatorConfig,
  238. settings: &Settings,
  239. ex: &Arc<smol::Executor<'static>>,
  240. skip_sync: bool,
  241. checkpoint: Option<(u32, HeaderHash)>,
  242. ) -> Result<DarkfiNodePtr> {
  243. let sled_db = sled::Config::new().temporary(true).open()?;
  244. vks::inject(&sled_db, vks)?;
  245. let validator = Validator::new(&sled_db, config).await?;
  246. let mut subscribers = HashMap::new();
  247. subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks"));
  248. subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs"));
  249. subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals"));
  250. subscribers.insert("dnet", JsonSubscriber::new("dnet.subscribe_events"));
  251. let p2p_handler = DarkfidP2pHandler::init(settings, ex).await?;
  252. let node = DarkfiNode::new(
  253. Network::Mainnet,
  254. p2p_handler.clone(),
  255. validator.clone(),
  256. 50,
  257. subscribers.clone(),
  258. )
  259. .await?;
  260. p2p_handler.clone().start(ex, &validator, &subscribers).await?;
  261. node.validator.consensus.generate_empty_fork().await?;
  262. if !skip_sync {
  263. sync_task(&node, checkpoint).await?;
  264. } else {
  265. *node.validator.synced.write().await = true;
  266. }
  267. node.validator.purge_pending_txs().await?;
  268. Ok(node)
  269. }