diff --git a/core/src/genesis.rs b/core/src/genesis.rs index d26b3b9ae..98ed3aa97 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -20,6 +20,9 @@ use crate::core; use crate::global; use crate::pow::{Difficulty, Proof, ProofOfWork}; +use crate::core::hash::Hash; +use crate::keychain::BlindingFactor; + /// Genesis block definition for development networks. The proof of work size /// is small enough to mine it on the fly, so it does not contain its own /// proof of work solution. Can also be easily mutated for different tests. @@ -135,18 +138,37 @@ pub fn genesis_testnet4() -> core::Block { pub fn genesis_main() -> core::Block { core::Block::with_header(core::BlockHeader { height: 0, - timestamp: Utc.ymd(2019, 0, 15).and_hms(12, 0, 0), + timestamp: Utc.ymd(2019, 1, 15).and_hms(12, 0, 0), // REPLACE + prev_root: Hash::default(), // REPLACE + output_root: Hash::default(), // REPLACE + range_proof_root: Hash::default(), // REPLACE + kernel_root: Hash::default(), // REPLACE + total_kernel_offset: BlindingFactor::zero(), // REPLACE output_mmr_size: 1, kernel_mmr_size: 1, pow: ProofOfWork { total_difficulty: Difficulty::from_num(10_u64.pow(8)), secondary_scaling: 1856, - nonce: 1, + nonce: 1, // REPLACE proof: Proof { - nonces: vec![0; 42], + nonces: vec![0; 42], // REPLACE edge_bits: 29, }, }, ..Default::default() }) } + + +#[cfg(test)] +mod test { + use super::*; + + // TODO update the hash once genesis is set + #[test] + fn mainnet_genesis_hash() { + let gen_hash = genesis_main().hash(); + println!("mainnet genesis hash: {}", gen_hash.to_hex()); + //assert_eq!(gene_hash.to_hex, ""); + } +} diff --git a/etc/gen_gen/src/bin/gen_gen.rs b/etc/gen_gen/src/bin/gen_gen.rs index efea9185a..60f0f0e9e 100644 --- a/etc/gen_gen/src/bin/gen_gen.rs +++ b/etc/gen_gen/src/bin/gen_gen.rs @@ -14,11 +14,12 @@ //! Main for building the genesis generation utility. -use std::fs; +use std::{fs, io, path, process}; +use std::io::{BufRead, Write}; use std::sync::Arc; use chrono::prelude::Utc; -use chrono::Duration; +use chrono::{Duration, Timelike, Datelike}; use curl; use serde_json; @@ -30,14 +31,23 @@ use grin_store as store; use grin_util as util; use grin_core::core::verifier_cache::LruVerifierCache; -use grin_keychain::{ExtKeychain, Keychain, BlindingFactor}; +use grin_keychain::{BlindingFactor, ExtKeychain, Keychain}; static BCHAIN_INFO_URL: &str = "https://blockchain.info/latestblock"; static BCYPHER_URL: &str = "https://api.blockcypher.com/v1/btc/main"; static BCHAIR_URL: &str = "https://api.blockchair.com/bitcoin/blocks?limit=2"; +static GENESIS_RS_PATH: &str = "../../core/src/genesis.rs"; +static PLUGIN_PATH: &str = "cuckaroo_mean_cuda_29.cuckooplugin"; + fn main() { core::global::set_mining_mode(core::global::ChainTypes::Mainnet); + if !path::Path::new(GENESIS_RS_PATH).exists() { + panic!("File {} not found, make sure you're running this from the gen_gen directory", GENESIS_RS_PATH); + } + if !path::Path::new(PLUGIN_PATH).exists() { + panic!("File {} not found, make sure you're running this from the gen_gen directory", PLUGIN_PATH); + } // get the latest bitcoin hash let h1 = get_bchain_head(); @@ -71,8 +81,7 @@ fn main() { } // mine a Cuckaroo29 block - let plugin_path = "cuckaroo_mean_cuda_29.cuckooplugin"; - let plugin_lib = cuckoo::PluginLibrary::new(plugin_path).unwrap(); + let plugin_lib = cuckoo::PluginLibrary::new(PLUGIN_PATH).unwrap(); let solver_ctx = plugin_lib.create_solver_ctx(&mut plugin_lib.get_default_params()); let mut solver_sols = plugin::SolverSolutions::default(); @@ -80,7 +89,14 @@ fn main() { let mut nonce = 0; while solver_sols.num_sols == 0 { solver_sols = plugin::SolverSolutions::default(); - plugin_lib.run_solver(solver_ctx, gen.header.pre_pow(), nonce, 1, &mut solver_sols, &mut solver_stats); + plugin_lib.run_solver( + solver_ctx, + gen.header.pre_pow(), + nonce, + 1, + &mut solver_sols, + &mut solver_stats, + ); nonce += 1; } @@ -89,10 +105,95 @@ fn main() { gen.header.pow.proof.nonces = solver_sols.sols[0].to_u64s(); assert!(gen.header.pow.is_secondary(), "Not a secondary header"); core::pow::verify_size(&gen.header).unwrap(); - gen.validate(&BlindingFactor::zero(), Arc::new(util::RwLock::new(LruVerifierCache::new()))).unwrap(); + gen.validate( + &BlindingFactor::zero(), + Arc::new(util::RwLock::new(LruVerifierCache::new())), + ) + .unwrap(); + + println!("Final genesis hash: {}", gen.hash().to_hex()); // TODO check again the bitcoin block to make sure it's not been orphaned - // TODO Commit genesis block info in git and tag + + update_genesis_rs(&gen); + println!("genesis.rs has been updated, check it and press c+enter to proceed."); + let mut input = String::new(); + io::stdin().read_line(&mut input).unwrap(); + if input != "c" { + return + } + + // Commit genesis block info in git and tag + process::Command::new("git") + .args(&["commit", "-am", "Minor: finalized genesis block"]) + .status() + .expect("git commit failed"); + process::Command::new("git") + .args(&["tag", "-a", "v1.0", "-m", "Mainnet release"]) + .status() + .expect("git tag failed"); + process::Command::new("git") + .args(&["push", "origin", "v1.0"]) + .status() + .expect("git tag push failed"); + println!("All done!"); +} + +fn update_genesis_rs(gen: &core::core::Block) { + // TODO coinbase output and kernel + + // set the replacement patterns + let mut replacements = vec![]; + replacements.push(( + "timestamp".to_string(), + format!( + "Utc.ymd({}, {}, {}).and_hms({}, {}, {})", + gen.header.timestamp.date().year(), + gen.header.timestamp.date().month(), + gen.header.timestamp.date().day(), + gen.header.timestamp.time().hour(), + gen.header.timestamp.time().minute(), + gen.header.timestamp.time().second(), + ), + )); + replacements.push(( + "output_root".to_string(), + format!("Hash::from_hex(\"{}\")", gen.header.output_root.to_hex()), + )); + replacements.push(( + "range_proof_root".to_string(), + format!("Hash::from_hex(\"{}\")", gen.header.range_proof_root.to_hex()), + )); + replacements.push(( + "kernel_root".to_string(), + format!("Hash::from_hex(\"{}\")", gen.header.kernel_root.to_hex()), + )); + + // check each possible replacement in the file + let mut replaced = String::new(); + { + let genesis_rs = fs::File::open(GENESIS_RS_PATH).unwrap(); + let reader = io::BufReader::new(&genesis_rs); + for rline in reader.lines() { + let line = rline.unwrap(); + let mut has_replaced = false; + if line.contains("REPLACE") { + for (pos, replacement) in replacements.iter().enumerate() { + if line.contains(&replacement.0) { + replaced.push_str(&format!("{}: {},\n", replacement.0, replacement.1)); + replacements.remove(pos); + has_replaced = true; + break; + } + } + if !has_replaced { + replaced.push_str(&format!("{}\n", line)); + } + } + } + } + let mut genesis_rs = fs::File::create(GENESIS_RS_PATH).unwrap(); + genesis_rs.write_all(replaced.as_bytes()).unwrap(); } fn setup_chain(dir_name: &str, genesis: core::core::Block) -> chain::Chain {