miner.rs 8.6 KB

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