Skip to content

Commit

Permalink
script/research/gg: Genesis Generator cli util added
Browse files Browse the repository at this point in the history
  • Loading branch information
aggstam committed Oct 19, 2023
1 parent 71b8d8d commit 372b8f2
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
4 changes: 4 additions & 0 deletions script/research/gg/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/target
Cargo.lock
rustfmt.toml
/genesis_txs
31 changes: 31 additions & 0 deletions script/research/gg/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>"]
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 changes: 154 additions & 0 deletions script/research/gg/src/main.rs
Original file line number Diff line number Diff line change
@@ -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(())
}
}
}

0 comments on commit 372b8f2

Please sign in to comment.