main.rs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2026 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::{
  19. fs::{create_dir, read_dir, read_to_string},
  20. io::{stdin, Cursor, Read},
  21. process::exit,
  22. str::FromStr,
  23. sync::Arc,
  24. };
  25. use clap::{Parser, Subcommand};
  26. use darkfi::{
  27. blockchain::{block_store::append_tx_to_merkle_tree, BlockInfo, Blockchain, BlockchainOverlay},
  28. cli_desc,
  29. tx::{ContractCallLeaf, TransactionBuilder},
  30. util::{encoding::base64, parse::decode_base10, path::expand_path, time::Timestamp},
  31. validator::{
  32. utils::deploy_native_contracts,
  33. verification::{apply_transaction, verify_genesis_block},
  34. },
  35. zk::{empty_witnesses, ProvingKey, ZkCircuit},
  36. zkas::ZkBinary,
  37. Result,
  38. };
  39. use darkfi_contract_test_harness::vks;
  40. use darkfi_money_contract::{
  41. client::genesis_mint_v1::GenesisMintCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
  42. };
  43. use darkfi_sdk::{
  44. crypto::{
  45. contract_id::MONEY_CONTRACT_ID,
  46. keypair::{Address, PublicKey, SecretKey},
  47. FuncId, MerkleTree,
  48. },
  49. pasta::{group::ff::PrimeField, pallas},
  50. ContractCall,
  51. };
  52. use darkfi_serial::{deserialize_async, serialize_async, AsyncEncodable};
  53. use sled_overlay::sled;
  54. use smol::Executor;
  55. #[derive(Parser)]
  56. #[command(about = cli_desc!())]
  57. struct Args {
  58. #[command(subcommand)]
  59. command: Subcmd,
  60. }
  61. #[derive(Subcommand)]
  62. enum Subcmd {
  63. /// Read a Darkfi genesis block from stdin and display it
  64. Display,
  65. /// Generate a Darkfi genesis block and write it to stdin
  66. Generate {
  67. #[arg(short, long, default_value = "genesis_txs")]
  68. /// Path to folder containing the genesis transactions
  69. txs_folder: String,
  70. #[arg(short, long)]
  71. /// Genesis timestamp to use, instead of current one
  72. genesis_timestamp: Option<u64>,
  73. #[arg(short, long, default_value = "120")]
  74. /// Configured PoW target
  75. pow_target: u32,
  76. },
  77. /// Read a Darkfi genesis block from stdin and verify it
  78. Verify,
  79. /// Generate a Darkfi genesis transaction using the secret
  80. /// key from stdin
  81. GenerateTx {
  82. /// Amounts to mint for this genesis transaction
  83. amounts: Vec<String>,
  84. #[arg(short, long)]
  85. /// Optional recipient's public key, in case we want to mint to a different address
  86. recipient: Option<String>,
  87. #[arg(short, long)]
  88. /// Optional contract spend hook to use
  89. spend_hook: Option<String>,
  90. #[arg(short, long)]
  91. /// Optional user data to use
  92. user_data: Option<String>,
  93. },
  94. }
  95. /// Auxiliary function to read a base64 genesis block from stdin
  96. async fn read_block() -> Result<BlockInfo> {
  97. println!("Reading genesis block from stdin...");
  98. let mut buf = String::new();
  99. stdin().read_to_string(&mut buf)?;
  100. let bytes = base64::decode(buf.trim()).unwrap();
  101. let block = deserialize_async(&bytes).await?;
  102. Ok(block)
  103. }
  104. fn main() -> Result<()> {
  105. // Initialize an executor
  106. let executor = Arc::new(Executor::new());
  107. smol::block_on(executor.run(async {
  108. // Parse arguments
  109. let args = Args::parse();
  110. // Execute a subcommand
  111. match args.command {
  112. Subcmd::Display => {
  113. let genesis_block = read_block().await;
  114. // TODO: display in more details
  115. println!("{genesis_block:?}");
  116. }
  117. Subcmd::Generate { txs_folder, genesis_timestamp, pow_target } => {
  118. // Generate the genesis block
  119. let mut genesis_block = BlockInfo::default();
  120. // Retrieve genesis producer transaction
  121. let producer_tx = genesis_block.txs.pop().unwrap();
  122. // Initialize a temporary sled database
  123. let sled_db = sled::Config::new().temporary(true).open()?;
  124. // Create an overlay over whole blockchain
  125. let blockchain = Blockchain::new(&sled_db)?;
  126. let overlay = BlockchainOverlay::new(&blockchain)?;
  127. let (_, vks) = vks::get_cached_pks_and_vks()?;
  128. vks::inject(&overlay, &vks)?;
  129. deploy_native_contracts(&overlay, 0).await?;
  130. // Grab genesis transactions from folder
  131. let txs_folder = expand_path(&txs_folder).unwrap();
  132. if !txs_folder.exists() {
  133. create_dir(&txs_folder)?;
  134. }
  135. let mut tree = MerkleTree::new(1);
  136. for file in read_dir(txs_folder)? {
  137. let file = file?;
  138. let bytes = base64::decode(read_to_string(file.path())?.trim()).unwrap();
  139. let tx = deserialize_async(&bytes).await?;
  140. apply_transaction(&overlay, 0, pow_target, &tx, &mut tree).await?;
  141. genesis_block.txs.push(tx);
  142. }
  143. // Update timestamp if one was provided
  144. if let Some(timestamp) = genesis_timestamp {
  145. genesis_block.header.timestamp = Timestamp::from_u64(timestamp);
  146. }
  147. // Append producer tx
  148. append_tx_to_merkle_tree(&mut tree, &producer_tx);
  149. genesis_block.txs.push(producer_tx);
  150. // Update the transactions root
  151. genesis_block.header.transactions_root = tree.root(0).unwrap();
  152. // Grab the updated contracts states root
  153. let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
  154. genesis_block.header.state_root =
  155. overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
  156. // Write generated genesis block to stdin
  157. let encoded = base64::encode(&serialize_async(&genesis_block).await);
  158. println!("{encoded}");
  159. }
  160. Subcmd::Verify => {
  161. let genesis_block = read_block().await?;
  162. let hash = genesis_block.hash();
  163. println!("Verifying genesis block: {hash}");
  164. // Initialize a temporary sled database
  165. let sled_db = sled::Config::new().temporary(true).open()?;
  166. // Create an overlay over whole blockchain
  167. let blockchain = Blockchain::new(&sled_db)?;
  168. let overlay = BlockchainOverlay::new(&blockchain)?;
  169. let (_, vks) = vks::get_cached_pks_and_vks()?;
  170. vks::inject(&overlay, &vks)?;
  171. deploy_native_contracts(&overlay, 0).await?;
  172. // Update the contracts states monotree
  173. let diff = overlay.lock().unwrap().overlay.lock().unwrap().diff(&[])?;
  174. overlay.lock().unwrap().contracts.update_state_monotree(&diff)?;
  175. // Validate genesis block
  176. verify_genesis_block(&overlay, &[diff], &genesis_block, 0).await?;
  177. println!("Genesis block {hash} verified successfully!");
  178. }
  179. Subcmd::GenerateTx { amounts, recipient, spend_hook, user_data } => {
  180. let mut buf = String::new();
  181. stdin().read_to_string(&mut buf)?;
  182. let signature_secret = SecretKey::from_str(buf.trim())?;
  183. let mut coin_amounts = vec![];
  184. for amount in amounts {
  185. if let Err(e) = f64::from_str(&amount) {
  186. eprintln!("Invalid amount: {e:?}");
  187. exit(2);
  188. }
  189. coin_amounts.push(decode_base10(&amount, 8, true)?);
  190. }
  191. let recipient = match recipient {
  192. Some(r) => match Address::from_str(&r) {
  193. Ok(r) => Some(*r.public_key()),
  194. Err(e) => {
  195. eprintln!("Invalid recipient: {e:?}");
  196. exit(2);
  197. }
  198. },
  199. None => None,
  200. };
  201. let spend_hook = match spend_hook {
  202. Some(s) => match FuncId::from_str(&s) {
  203. Ok(s) => Some(s),
  204. Err(e) => {
  205. eprintln!("Invalid spend hook: {e:?}");
  206. exit(2);
  207. }
  208. },
  209. None => None,
  210. };
  211. let user_data = match user_data {
  212. Some(u) => {
  213. let bytes: [u8; 32] = match bs58::decode(&u).into_vec()?.try_into() {
  214. Ok(b) => b,
  215. Err(e) => {
  216. eprintln!("Invalid user data: {e:?}");
  217. exit(2);
  218. }
  219. };
  220. match pallas::Base::from_repr(bytes).into() {
  221. Some(v) => Some(v),
  222. None => {
  223. eprintln!("Invalid user data");
  224. exit(2);
  225. }
  226. }
  227. }
  228. None => None,
  229. };
  230. // Grab mint proving keys and zkbin
  231. let (pks, _) = vks::get_cached_pks_and_vks()?;
  232. let mut mint = None;
  233. for (bincode, namespace, pk) in pks {
  234. if namespace.as_str() != MONEY_CONTRACT_ZKAS_MINT_NS_V1 {
  235. continue
  236. }
  237. let mut reader = Cursor::new(pk);
  238. let zkbin = ZkBinary::decode(&bincode, false)?;
  239. let circuit = ZkCircuit::new(empty_witnesses(&zkbin)?, &zkbin);
  240. let proving_key = ProvingKey::read(&mut reader, circuit)?;
  241. mint = Some((proving_key, zkbin));
  242. }
  243. let Some((mint_pk, mint_zkbin)) = mint else {
  244. eprintln!("Mint proving keys not found.");
  245. exit(2);
  246. };
  247. // Build the contract call
  248. let builder = GenesisMintCallBuilder {
  249. signature_public: PublicKey::from_secret(signature_secret),
  250. amounts: coin_amounts,
  251. recipient,
  252. spend_hook,
  253. user_data,
  254. mint_zkbin,
  255. mint_pk,
  256. };
  257. let debris = builder.build()?;
  258. // Encode and build the transaction
  259. let mut data = vec![MoneyFunction::GenesisMintV1 as u8];
  260. debris.params.encode_async(&mut data).await?;
  261. let call = ContractCall { contract_id: *MONEY_CONTRACT_ID, data };
  262. let mut tx_builder = TransactionBuilder::new(
  263. ContractCallLeaf { call, proofs: debris.proofs },
  264. vec![],
  265. )?;
  266. let mut tx = tx_builder.build()?;
  267. let sigs = tx.create_sigs(&[signature_secret])?;
  268. tx.signatures = vec![sigs];
  269. println!("{}", base64::encode(&serialize_async(&tx).await));
  270. }
  271. }
  272. Ok(())
  273. }))
  274. }