Pārlūkot izejas kodu

script/research/gg: Genesis Generator cli util added

aggstam 2 gadi atpakaļ
vecāks
revīzija
372b8f2234

+ 4 - 0
script/research/gg/.gitignore

@@ -0,0 +1,4 @@
+/target
+Cargo.lock
+rustfmt.toml
+/genesis_txs

+ 31 - 0
script/research/gg/Cargo.toml

@@ -0,0 +1,31 @@
+[package]
+name = "gg"
+version = "0.4.1"
+description = """\
+Genesis Generator, a command-line utility to generate,\
+display and verify a bs58 encoded Darkfi genesis block\
+"""
+authors = ["Dyne.org foundation <foundation@dyne.org>"]
+repository = "https://github.com/darkrenaissance/darkfi"
+license = "AGPL-3.0-only"
+edition = "2021"
+
+[workspace]
+
+[dependencies]
+# Darkfi
+darkfi = {path = "../../../", features = ["validator"]}
+darkfi-contract-test-harness = {path = "../../../src/contract/test-harness"}
+darkfi-serial = {path = "../../../src/serial"}
+
+# Misc
+anyhow = "1.0.75"
+async-std = {version = "1.12.0", features = ["attributes"]}
+bs58 = "0.5.0"
+clap = {version = "4.4.1", features = ["derive"]}
+sled = "0.34.7"
+
+[patch.crates-io]
+halo2_proofs = {git="https://github.com/parazyd/halo2", branch="v4"}
+halo2_gadgets = {git="https://github.com/parazyd/halo2", branch="v4"}
+blake2b_simd = {git="https://github.com/parazyd/blake2_simd", branch="impl-common"}

+ 154 - 0
script/research/gg/src/main.rs

@@ -0,0 +1,154 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+use std::{
+    fs::{read_dir, read_to_string},
+    io::{stdin, Read},
+};
+
+use anyhow::Result;
+use clap::{Parser, Subcommand};
+use darkfi::{
+    blockchain::{BlockInfo, Blockchain, BlockchainOverlay},
+    cli_desc,
+    tx::Transaction,
+    util::{
+        path::expand_path,
+        time::{TimeKeeper, Timestamp},
+    },
+    validator::{utils::genesis_txs_total, verification::verify_genesis_block},
+};
+use darkfi_contract_test_harness::vks;
+use darkfi_serial::{deserialize, serialize};
+
+#[derive(Parser)]
+#[command(about = cli_desc!())]
+struct Args {
+    #[command(subcommand)]
+    command: Subcmd,
+}
+
+#[derive(Subcommand)]
+enum Subcmd {
+    /// Read a Darkfi genesis block from stdin and display it
+    Display,
+
+    /// Generate a Darkfi genesis block and write it to stdin
+    Generate {
+        #[arg(short, long, default_value = "genesis_txs")]
+        /// Path to folder containing the genesis transactions
+        txs_folder: String,
+
+        #[arg(short, long)]
+        /// Genesis timestamp to use, instead of current one
+        genesis_timestamp: Option<u64>,
+    },
+
+    /// Read a Darkfi genesis block from stdin and verify it
+    Verify,
+}
+
+/// Auxiliary function to read a bs58 genesis block from stdin
+fn read_block() -> Result<BlockInfo> {
+    eprintln!("Reading genesis block from stdin...");
+    let mut buf = String::new();
+    stdin().read_to_string(&mut buf)?;
+    let bytes = bs58::decode(&buf.trim()).into_vec()?;
+    let block = deserialize(&bytes)?;
+    Ok(block)
+}
+
+#[async_std::main]
+async fn main() -> Result<()> {
+    // Parse arguments
+    let args = Args::parse();
+
+    // Execute a subcommand
+    match args.command {
+        Subcmd::Display => {
+            let genesis_block = read_block()?;
+            println!("{genesis_block:#?}");
+            Ok(())
+        }
+
+        Subcmd::Generate { txs_folder, genesis_timestamp } => {
+            // Grab genesis transactions from folder
+            let txs_folder = expand_path(&txs_folder).unwrap();
+            let mut genesis_txs: Vec<Transaction> = vec![];
+            for file in read_dir(txs_folder)? {
+                let bytes = bs58::decode(&read_to_string(file?.path())?.trim()).into_vec()?;
+                let tx = deserialize(&bytes)?;
+                genesis_txs.push(tx);
+            }
+
+            // Generate the genesis block
+            let mut genesis_block = BlockInfo::default();
+
+            // Update timestamp if one was provided
+            if let Some(timestamp) = genesis_timestamp {
+                genesis_block.header.timestamp = Timestamp(timestamp);
+            }
+
+            // Append genesis transactions
+            if !genesis_txs.is_empty() {
+                // Retrieve genesis producer transaction
+                let producer_tx = genesis_block.txs.pop().unwrap();
+
+                // Append genesis transactions and calculate their total
+                genesis_block.txs.append(&mut genesis_txs);
+                genesis_block.txs.push(producer_tx);
+                let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?;
+                genesis_block.slots[0].total_tokens = genesis_txs_total;
+            }
+
+            // Write generated genesis block to stdin
+            let encoded = bs58::encode(&serialize(&genesis_block)).into_string();
+            println!("{}", encoded);
+
+            Ok(())
+        }
+
+        Subcmd::Verify => {
+            let genesis_block = read_block()?;
+            let hash = genesis_block.hash()?;
+
+            println!("Verifying genesis block: {hash}");
+
+            // Initialize a temporary sled database
+            let sled_db = sled::Config::new().temporary(true).open()?;
+            let (_, vks) = vks::read_or_gen_vks_and_pks()?;
+            vks::inject(&sled_db, &vks)?;
+
+            // Create an overlay over whole blockchain
+            let blockchain = Blockchain::new(&sled_db)?;
+            let overlay = BlockchainOverlay::new(&blockchain)?;
+
+            // Generate a dummy time keeper
+            let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0);
+
+            // Grab block txs total
+            let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?;
+
+            verify_genesis_block(&overlay, &time_keeper, &genesis_block, genesis_txs_total).await?;
+
+            println!("Genesis block {hash} verified successfully!");
+
+            Ok(())
+        }
+    }
+}