From 372b8f2234bca4db03af39404e9dd3d003c5d71a Mon Sep 17 00:00:00 2001 From: aggstam Date: Thu, 19 Oct 2023 18:24:15 +0300 Subject: [PATCH] script/research/gg: Genesis Generator cli util added --- script/research/gg/.gitignore | 4 + script/research/gg/Cargo.toml | 31 +++++++ script/research/gg/src/main.rs | 154 +++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 script/research/gg/.gitignore create mode 100644 script/research/gg/Cargo.toml create mode 100644 script/research/gg/src/main.rs diff --git a/script/research/gg/.gitignore b/script/research/gg/.gitignore new file mode 100644 index 000000000..af4873523 --- /dev/null +++ b/script/research/gg/.gitignore @@ -0,0 +1,4 @@ +/target +Cargo.lock +rustfmt.toml +/genesis_txs diff --git a/script/research/gg/Cargo.toml b/script/research/gg/Cargo.toml new file mode 100644 index 000000000..1803be9ae --- /dev/null +++ b/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 "] +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"} diff --git a/script/research/gg/src/main.rs b/script/research/gg/src/main.rs new file mode 100644 index 000000000..41a62724e --- /dev/null +++ b/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 . + */ + +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, + }, + + /// 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 { + 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 = 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(()) + } + } +}