miner.rs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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::{
  19. blockchain::BlockInfo,
  20. tx::Transaction,
  21. validator::{
  22. consensus::{Fork, Proposal},
  23. pow::PoWModule,
  24. },
  25. zk::{empty_witnesses, ProvingKey, ZkCircuit},
  26. zkas::ZkBinary,
  27. Result,
  28. };
  29. use darkfi_consensus_contract::model::SECRET_KEY_PREFIX;
  30. use darkfi_money_contract::{
  31. client::pow_reward_v1::PoWRewardCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
  32. };
  33. use darkfi_sdk::{
  34. crypto::{poseidon_hash, PublicKey, SecretKey, MONEY_CONTRACT_ID},
  35. pasta::pallas,
  36. ContractCall,
  37. };
  38. use darkfi_serial::Encodable;
  39. use log::info;
  40. use rand::rngs::OsRng;
  41. use smol::channel::Receiver;
  42. use crate::{proto::BlockInfoMessage, Darkfid};
  43. // TODO: handle all ? so the task don't stop on errors
  44. /// async task used for participating in the PoW consensus protocol
  45. pub async fn miner_task(
  46. node: &Darkfid,
  47. recipient: &PublicKey,
  48. stop_signal: &Receiver<()>,
  49. ) -> Result<()> {
  50. // TODO: For now we asume we have a single miner that produces block,
  51. // until the PoW consensus and proper validations have been added.
  52. // The miner workflow would be:
  53. // First we wait for next finalization, for optimal conditions.
  54. // After that we ask all our connected peers for their blocks,
  55. // and append them to our consensus state, creating their forks.
  56. // Then we evaluate each fork and find the best one, so we can
  57. // mine its next.
  58. // We start running 2 tasks, one listenning for blocks(proposals)
  59. // from other miners, and one mining the best fork next block.
  60. // These two tasks run in parallel. If we receive a block from
  61. // another miner, we evaluate it and if it produces a higher
  62. // ranking fork that the one we currectly mine, we stop, check
  63. // if we can finalize any fork, and then start mining that fork
  64. // next block. If we manage to mine the block next, we broadcast
  65. // it and then execute the finalization check and start mining
  66. // next best fork block.
  67. info!(target: "darkfid::task::miner_task", "Starting miner task...");
  68. // Start miner loop
  69. miner_loop(node, recipient, stop_signal).await?;
  70. Ok(())
  71. }
  72. /// Miner loop
  73. async fn miner_loop(
  74. node: &Darkfid,
  75. recipient: &PublicKey,
  76. stop_signal: &Receiver<()>,
  77. ) -> Result<()> {
  78. // Grab zkas proving keys and bin for PoWReward transaction
  79. info!(target: "darkfid::task::miner_task", "Generating zkas bin and proving keys...");
  80. let blockchain = node.validator.read().await.blockchain.clone();
  81. let (zkbin, _) = blockchain.contracts.get_zkas(
  82. &blockchain.sled_db,
  83. &MONEY_CONTRACT_ID,
  84. MONEY_CONTRACT_ZKAS_MINT_NS_V1,
  85. )?;
  86. let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
  87. let pk = ProvingKey::build(zkbin.k, &circuit);
  88. // Generate a random master secret key, to derive all signing keys from.
  89. // This enables us to deanonimize proposals from reward recipient(miner).
  90. // TODO: maybe miner wants to keep this master secret so they can
  91. // verify their signature in the future?
  92. info!(target: "darkfid::task::miner_task", "Generating signing key...");
  93. let mut secret = SecretKey::random(&mut OsRng);
  94. // Generate a new fork to be able to extend
  95. info!(target: "darkfid::task::miner_task", "Generating new empty fork...");
  96. node.validator.write().await.consensus.generate_pow_slot()?;
  97. info!(target: "darkfid::task::miner_task", "Miner loop starts!");
  98. // Miner loop
  99. loop {
  100. // Grab next block
  101. let (mut next_block, module) =
  102. generate_next_block(node, &mut secret, recipient, &zkbin, &pk).await?;
  103. module.mine_block(&mut next_block, stop_signal)?;
  104. // Sign the mined block
  105. next_block.sign(&secret)?;
  106. // Verify it
  107. node.validator.read().await.consensus.module.verify_current_block(&next_block)?;
  108. // Append the mined block as a proposal
  109. let proposal = Proposal::new(next_block)?;
  110. let mut lock = node.validator.write().await;
  111. lock.consensus.append_proposal(&proposal).await?;
  112. // Check if we can finalize anything and broadcast them
  113. let finalized = lock.finalization().await?;
  114. if !finalized.is_empty() {
  115. for block in finalized {
  116. let message = BlockInfoMessage::from(&block);
  117. node.sync_p2p.broadcast(&message).await;
  118. }
  119. }
  120. }
  121. }
  122. /// Auxiliary function to generate next block in an atomic manner
  123. async fn generate_next_block(
  124. node: &Darkfid,
  125. secret: &mut SecretKey,
  126. recipient: &PublicKey,
  127. zkbin: &ZkBinary,
  128. pk: &ProvingKey,
  129. ) -> Result<(BlockInfo, PoWModule)> {
  130. let lock = node.validator.read().await;
  131. // Grab best current fork
  132. let fork_index = lock.consensus.best_forks_indexes()?[0];
  133. let fork = &lock.consensus.forks[fork_index];
  134. // Generate new signing key for next block
  135. let height = fork.slots.last().unwrap().id;
  136. // We are deriving the next secret key for optimization.
  137. // Next secret is the poseidon hash of:
  138. // [prefix, current(previous) secret, signing(block) height].
  139. let next_secret = poseidon_hash([SECRET_KEY_PREFIX, secret.inner(), height.into()]);
  140. *secret = SecretKey::from(next_secret);
  141. // Generate reward transaction
  142. let tx = generate_pow_transaction(fork, secret, recipient, zkbin, pk)?;
  143. // Mine next block proposal
  144. let next_block = lock.consensus.generate_unsigned_block(fork, tx).await?;
  145. let module = lock.consensus.forks[fork_index].module.clone();
  146. Ok((next_block, module))
  147. }
  148. /// Auxiliary function to generate a Money::PoWReward transaction
  149. fn generate_pow_transaction(
  150. fork: &Fork,
  151. secret: &SecretKey,
  152. recipient: &PublicKey,
  153. zkbin: &ZkBinary,
  154. pk: &ProvingKey,
  155. ) -> Result<Transaction> {
  156. // Grab next block height
  157. let block_height = fork.slots.last().unwrap().id;
  158. // Grab extended proposal info
  159. let last_proposal = fork.last_proposal()?;
  160. let last_nonce = last_proposal.block.header.nonce;
  161. let fork_hash = last_proposal.hash;
  162. let fork_previous_hash = last_proposal.block.header.previous;
  163. // We're just going to be using a zero spend-hook and user-data
  164. let spend_hook = pallas::Base::zero();
  165. let user_data = pallas::Base::zero();
  166. // Build the transaction debris
  167. let debris = PoWRewardCallBuilder {
  168. secret: *secret,
  169. recipient: *recipient,
  170. block_height,
  171. last_nonce,
  172. fork_hash,
  173. fork_previous_hash,
  174. spend_hook,
  175. user_data,
  176. mint_zkbin: zkbin.clone(),
  177. mint_pk: pk.clone(),
  178. }
  179. .build()?;
  180. // Generate and sign the actual transaction
  181. let mut data = vec![MoneyFunction::PoWRewardV1 as u8];
  182. debris.params.encode(&mut data)?;
  183. let calls = vec![ContractCall { contract_id: *MONEY_CONTRACT_ID, data }];
  184. let proofs = vec![debris.proofs];
  185. let mut tx = Transaction { calls, proofs, signatures: vec![] };
  186. let sigs = tx.create_sigs(&mut OsRng, &[*secret])?;
  187. tx.signatures = vec![sigs];
  188. Ok(tx)
  189. }