main.rs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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 std::{
  19. fs::{read_dir, read_to_string},
  20. io::{stdin, Read},
  21. };
  22. use anyhow::Result;
  23. use clap::{Parser, Subcommand};
  24. use darkfi::{
  25. blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
  26. cli_desc,
  27. tx::Transaction,
  28. util::{
  29. path::expand_path,
  30. time::{TimeKeeper, Timestamp},
  31. },
  32. validator::{utils::genesis_txs_total, verification::verify_genesis_block},
  33. };
  34. use darkfi_contract_test_harness::vks;
  35. use darkfi_serial::{deserialize, serialize};
  36. #[derive(Parser)]
  37. #[command(about = cli_desc!())]
  38. struct Args {
  39. #[command(subcommand)]
  40. command: Subcmd,
  41. }
  42. #[derive(Subcommand)]
  43. enum Subcmd {
  44. /// Read a Darkfi genesis block from stdin and display it
  45. Display,
  46. /// Generate a Darkfi genesis block and write it to stdin
  47. Generate {
  48. #[arg(short, long, default_value = "genesis_txs")]
  49. /// Path to folder containing the genesis transactions
  50. txs_folder: String,
  51. #[arg(short, long)]
  52. /// Genesis timestamp to use, instead of current one
  53. genesis_timestamp: Option<u64>,
  54. },
  55. /// Read a Darkfi genesis block from stdin and verify it
  56. Verify,
  57. }
  58. /// Auxiliary function to read a bs58 genesis block from stdin
  59. fn read_block() -> Result<BlockInfo> {
  60. eprintln!("Reading genesis block from stdin...");
  61. let mut buf = String::new();
  62. stdin().read_to_string(&mut buf)?;
  63. let bytes = bs58::decode(&buf.trim()).into_vec()?;
  64. let block = deserialize(&bytes)?;
  65. Ok(block)
  66. }
  67. #[async_std::main]
  68. async fn main() -> Result<()> {
  69. // Parse arguments
  70. let args = Args::parse();
  71. // Execute a subcommand
  72. match args.command {
  73. Subcmd::Display => {
  74. let genesis_block = read_block()?;
  75. println!("{genesis_block:#?}");
  76. Ok(())
  77. }
  78. Subcmd::Generate { txs_folder, genesis_timestamp } => {
  79. // Grab genesis transactions from folder
  80. let txs_folder = expand_path(&txs_folder).unwrap();
  81. let mut genesis_txs: Vec<Transaction> = vec![];
  82. for file in read_dir(txs_folder)? {
  83. let bytes = bs58::decode(&read_to_string(file?.path())?.trim()).into_vec()?;
  84. let tx = deserialize(&bytes)?;
  85. genesis_txs.push(tx);
  86. }
  87. // Generate the genesis block
  88. let mut genesis_block = BlockInfo::default();
  89. // Update timestamp if one was provided
  90. if let Some(timestamp) = genesis_timestamp {
  91. genesis_block.header.timestamp = Timestamp(timestamp);
  92. }
  93. // Append genesis transactions
  94. if !genesis_txs.is_empty() {
  95. // Retrieve genesis producer transaction
  96. let producer_tx = genesis_block.txs.pop().unwrap();
  97. // Append genesis transactions and calculate their total
  98. genesis_block.txs.append(&mut genesis_txs);
  99. genesis_block.txs.push(producer_tx);
  100. let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?;
  101. genesis_block.slots[0].total_tokens = genesis_txs_total;
  102. }
  103. // Write generated genesis block to stdin
  104. let encoded = bs58::encode(&serialize(&genesis_block)).into_string();
  105. println!("{}", encoded);
  106. Ok(())
  107. }
  108. Subcmd::Verify => {
  109. let genesis_block = read_block()?;
  110. let hash = genesis_block.hash()?;
  111. println!("Verifying genesis block: {hash}");
  112. // Initialize a temporary sled database
  113. let sled_db = sled::Config::new().temporary(true).open()?;
  114. let (_, vks) = vks::read_or_gen_vks_and_pks()?;
  115. vks::inject(&sled_db, &vks)?;
  116. // Create an overlay over whole blockchain
  117. let blockchain = Blockchain::new(&sled_db)?;
  118. let overlay = BlockchainOverlay::new(&blockchain)?;
  119. // Generate a dummy time keeper
  120. let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0);
  121. // Grab block txs total
  122. let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?;
  123. verify_genesis_block(&overlay, &time_keeper, &genesis_block, genesis_txs_total).await?;
  124. println!("Genesis block {hash} verified successfully!");
  125. Ok(())
  126. }
  127. }
  128. }