main.rs 4.5 KB

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