diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 13add54ac..d29474e22 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -33,7 +33,7 @@ use sumtree; use types::*; use util::LOGGER; -use core::global::{MiningParameterMode, MINING_PARAMETER_MODE}; +use core::global; const MAX_ORPHANS: usize = 20; @@ -184,16 +184,14 @@ impl Chain { } fn ctx_from_head(&self, head: Tip, opts: Options) -> pipe::BlockContext { - let opts_in = opts; - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); - let opts_in = match *param_ref { - MiningParameterMode::AutomatedTesting => opts_in | EASY_POW, - MiningParameterMode::UserTesting => opts_in | EASY_POW, - MiningParameterMode::Production => opts_in, - }; + let opts = if global::is_production_mode() { + opts + } else { + opts | EASY_POW + }; pipe::BlockContext { - opts: opts_in, + opts: opts, store: self.store.clone(), head: head, pow_verifier: self.pow_verifier, diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index 78af92cde..41b7994b3 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -30,7 +30,7 @@ use core::core::hash::Hashed; use core::core::target::Difficulty; use core::consensus; use core::global; -use core::global::MiningParameterMode; +use core::global::ChainTypes; use keychain::Keychain; @@ -43,7 +43,7 @@ fn clean_output_dir(dir_name: &str) { fn setup(dir_name: &str) -> Chain { let _ = env_logger::init(); clean_output_dir(dir_name); - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let mut genesis_block = None; if !chain::Chain::chain_exists(dir_name.to_string()) { genesis_block = pow::mine_genesis_block(None); diff --git a/chain/tests/test_coinbase_maturity.rs b/chain/tests/test_coinbase_maturity.rs index 00c8d984c..d2928fc0a 100644 --- a/chain/tests/test_coinbase_maturity.rs +++ b/chain/tests/test_coinbase_maturity.rs @@ -28,7 +28,7 @@ use core::core::build; use core::core::transaction; use core::consensus; use core::global; -use core::global::MiningParameterMode; +use core::global::ChainTypes; use keychain::Keychain; @@ -42,7 +42,7 @@ fn clean_output_dir(dir_name: &str) { fn test_coinbase_maturity() { let _ = env_logger::init(); clean_output_dir(".grin"); - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let mut genesis_block = None; if !chain::Chain::chain_exists(".grin".to_string()) { diff --git a/core/src/genesis.rs b/core/src/genesis.rs index 92f7af262..4a7bf5ea6 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -17,18 +17,16 @@ use time; use core; -use consensus::MINIMUM_DIFFICULTY; +use consensus; use core::target::Difficulty; use global; -/// Genesis block definition. It has no rewards, no inputs, no outputs, no -/// fees and a height of zero. -pub fn genesis() -> core::Block { - let proof_size = global::proofsize(); - let empty_hash = core::hash::Hash([0x0; 32]); +/// 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. +pub fn genesis_dev() -> core::Block { core::Block { header: core::BlockHeader { - version: 1, height: 0, previous: core::hash::Hash([0xff; 32]), timestamp: time::Tm { @@ -37,13 +35,56 @@ pub fn genesis() -> core::Block { tm_mday: 4, ..time::empty_tm() }, - difficulty: Difficulty::from_num(MINIMUM_DIFFICULTY), - total_difficulty: Difficulty::from_num(MINIMUM_DIFFICULTY), - utxo_root: empty_hash, - range_proof_root: empty_hash, - kernel_root: empty_hash, nonce: global::get_genesis_nonce(), - pow: core::Proof::zero(proof_size), // TODO get actual PoW solution + ..Default::default() + }, + inputs: vec![], + outputs: vec![], + kernels: vec![], + } +} + +/// First testnet genesis block, still subject to change (especially the date, +/// will hopefully come before Christmas). +pub fn genesis_testnet1() -> core::Block { + core::Block { + header: core::BlockHeader { + height: 0, + previous: core::hash::Hash([0xff; 32]), + timestamp: time::Tm { + tm_year: 2017 - 1900, + tm_mon: 12, + tm_mday: 25, + ..time::empty_tm() + }, + nonce: 1, + pow: core::Proof::zero(consensus::PROOFSIZE), + ..Default::default() + }, + inputs: vec![], + outputs: vec![], + kernels: vec![], + } +} + +/// Placeholder for mainnet genesis block, will definitely change before +/// release so no use trying to pre-mine it. +pub fn genesis_main() -> core::Block { + core::Block { + header: core::BlockHeader { + height: 0, + previous: core::hash::Hash([0xff; 32]), + timestamp: time::Tm { + tm_year: 2018 - 1900, + tm_mon: 7, + tm_mday: 14, + ..time::empty_tm() + }, + difficulty: Difficulty::from_num(1000), + total_difficulty: Difficulty::from_num(1000), + nonce: global::get_genesis_nonce(), + pow: core::Proof::zero(consensus::PROOFSIZE), + ..Default::default() }, inputs: vec![], outputs: vec![], diff --git a/core/src/global.rs b/core/src/global.rs index 2c1d6e6a5..3f55dcc74 100644 --- a/core/src/global.rs +++ b/core/src/global.rs @@ -47,77 +47,85 @@ pub const AUTOMATED_TESTING_COINBASE_MATURITY: u64 = 3; /// User testing coinbase maturity pub const USER_TESTING_COINBASE_MATURITY: u64 = 3; -/// Mining parameter modes +/// Types of chain a server can run with, dictates the genesis block and +/// and mining parameters used. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum MiningParameterMode { +pub enum ChainTypes { /// For CI testing AutomatedTesting, /// For User testing UserTesting, - /// For production, use the values in consensus.rs - Production, + /// First test network + Testnet1, + + /// Main production network + Mainnet, } lazy_static!{ /// The mining parameter mode - pub static ref MINING_PARAMETER_MODE: RwLock = - RwLock::new(MiningParameterMode::Production); + pub static ref CHAIN_TYPE: RwLock = + RwLock::new(ChainTypes::Mainnet); } /// Set the mining mode -pub fn set_mining_mode(mode: MiningParameterMode) { - let mut param_ref = MINING_PARAMETER_MODE.write().unwrap(); +pub fn set_mining_mode(mode: ChainTypes) { + let mut param_ref = CHAIN_TYPE.write().unwrap(); *param_ref = mode; } /// The sizeshift pub fn sizeshift() -> u8 { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); + let param_ref = CHAIN_TYPE.read().unwrap(); match *param_ref { - MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_SIZESHIFT, - MiningParameterMode::UserTesting => USER_TESTING_SIZESHIFT, - MiningParameterMode::Production => DEFAULT_SIZESHIFT, + ChainTypes::AutomatedTesting => AUTOMATED_TESTING_SIZESHIFT, + ChainTypes::UserTesting => USER_TESTING_SIZESHIFT, + ChainTypes::Testnet1 => DEFAULT_SIZESHIFT, + ChainTypes::Mainnet => DEFAULT_SIZESHIFT, } } /// The proofsize pub fn proofsize() -> usize { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); + let param_ref = CHAIN_TYPE.read().unwrap(); match *param_ref { - MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE, - MiningParameterMode::UserTesting => USER_TESTING_PROOF_SIZE, - MiningParameterMode::Production => PROOFSIZE, + ChainTypes::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE, + ChainTypes::UserTesting => USER_TESTING_PROOF_SIZE, + ChainTypes::Testnet1 => PROOFSIZE, + ChainTypes::Mainnet => PROOFSIZE, } } /// Coinbase maturity pub fn coinbase_maturity() -> u64 { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); + let param_ref = CHAIN_TYPE.read().unwrap(); match *param_ref { - MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_COINBASE_MATURITY, - MiningParameterMode::UserTesting => USER_TESTING_COINBASE_MATURITY, - MiningParameterMode::Production => COINBASE_MATURITY, + ChainTypes::AutomatedTesting => AUTOMATED_TESTING_COINBASE_MATURITY, + ChainTypes::UserTesting => USER_TESTING_COINBASE_MATURITY, + ChainTypes::Testnet1 => COINBASE_MATURITY, + ChainTypes::Mainnet => COINBASE_MATURITY, } } /// Are we in automated testing mode? pub fn is_automated_testing_mode() -> bool { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); - MiningParameterMode::AutomatedTesting == *param_ref + let param_ref = CHAIN_TYPE.read().unwrap(); + ChainTypes::AutomatedTesting == *param_ref } /// Are we in user testing mode? pub fn is_user_testing_mode() -> bool { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); - MiningParameterMode::UserTesting == *param_ref + let param_ref = CHAIN_TYPE.read().unwrap(); + ChainTypes::UserTesting == *param_ref } -/// Are we in production mode? +/// Are we in production mode (a live public network)? pub fn is_production_mode() -> bool { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); - MiningParameterMode::Production == *param_ref + let param_ref = CHAIN_TYPE.read().unwrap(); + ChainTypes::Testnet1 == *param_ref || + ChainTypes::Mainnet == *param_ref } @@ -126,78 +134,14 @@ pub fn is_production_mode() -> bool { /// as the genesis block POW solution turns out to be the same for every new /// block chain /// at the moment - pub fn get_genesis_nonce() -> u64 { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); + let param_ref = CHAIN_TYPE.read().unwrap(); match *param_ref { // won't make a difference - MiningParameterMode::AutomatedTesting => 0, + ChainTypes::AutomatedTesting => 0, // Magic nonce for current genesis block at cuckoo16 - MiningParameterMode::UserTesting => 27944, - // Magic nonce for current genesis at cuckoo30 - MiningParameterMode::Production => 1429942738856787200, - } -} + ChainTypes::UserTesting => 27944, -/// Returns the genesis POW for cuckoo16 (UserTesting) and cuckoo30 (Production) -pub fn get_genesis_pow() -> [u32; 42] { - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); - match *param_ref { - // pow solution for genesis block at cuckoo16 - MiningParameterMode::UserTesting => [ - 0x37f, 0x9f6, 0x136d, 0x13d3, 0x155e, 0x16dd, 0x186b, 0x1b11, 0x208e, 0x23cd, - 0x24d1, 0x278f, 0x2a1b, 0x2a28, 0x2a44, 0x2ae2, 0x2c37, 0x36af, 0x391d, 0x3c2e, - 0x3d9a, 0x3f00, 0x429f, 0x45b2, 0x47ce, 0x47f1, 0x492f, 0x4bd8, 0x4fee, 0x51f0, - 0x5207, 0x58e5, 0x5905, 0x5aca, 0x5dfb, 0x628d, 0x7310, 0x75e5, 0x76d4, 0x76df, - 0x77bd, 0x7ab9 - ], - // pow solution for genesis block at cuckoo30 - // TODO - likely this is no longer correct (block header changes) - MiningParameterMode::Production => [ - 7444824, - 11926557, - 28520390, - 30594072, - 50854023, - 52797085, - 57882033, - 59816511, - 61404804, - 84947619, - 87779345, - 115270337, - 162618676, - 166860710, - 178656003, - 178971372, - 200454733, - 209197630, - 221231015, - 228598741, - 241012783, - 245401183, - 279080304, - 295848517, - 327300943, - 329741709, - 366394532, - 382493153, - 389329248, - 404353381, - 406012911, - 418813499, - 426573907, - 452566575, - 456930760, - 463021458, - 474340589, - 476248039, - 478197093, - 487576917, - 495653489, - 501862896, - ], - // TODO - for completeness do we provide one here for AutomatedTesting? - _ => panic!("unexpected"), + _ => panic!("Pre-set"), } } diff --git a/grin.toml b/grin.toml index c5ef57069..050ffdd66 100644 --- a/grin.toml +++ b/grin.toml @@ -32,13 +32,13 @@ seeding_type = "None" #if seeding_type = List, the list of peers to connect to. #seeds = ["192.168.0.1:8080","192.168.0.2:8080"] -#The mining parameter mode, which defines the set of cuckoo parameters -#used for mining. Can be: +#The chain type, which defines the genesis block and the set of cuckoo +#parameters used for mining. Can be: #AutomatedTesting - For CI builds and instant blockchain creation #UserTesting - For regular user testing (cuckoo 16) -#Production - Full production cuckoo parameter (cuckoo 30) +#Testnet1 - Full production cuckoo parameter (cuckoo 30) -mining_parameter_mode = "UserTesting" +chain_type = "UserTesting" #7 = Bit flags for FULL_NODE, this structure needs to be changed #internally to make it more configurable diff --git a/grin/src/adapters.rs b/grin/src/adapters.rs index 72832d080..d025aa2c3 100644 --- a/grin/src/adapters.rs +++ b/grin/src/adapters.rs @@ -21,6 +21,7 @@ use core::core::{self, Output}; use core::core::block::BlockHeader; use core::core::hash::{Hash, Hashed}; use core::core::target::Difficulty; +use core::global; use p2p::{self, NetAdapter, PeerData, PeerStore, Server, State}; use pool; use util::secp::pedersen::Commitment; @@ -28,7 +29,6 @@ use util::OneTime; use store; use sync; use util::LOGGER; -use core::global::{MiningParameterMode, MINING_PARAMETER_MODE}; /// Implementation of the NetAdapter for the blockchain. Gets notified when new /// blocks and transactions are received and forwards to the chain and pool @@ -286,12 +286,11 @@ impl NetToChainAdapter { } else { chain::NONE }; - let param_ref = MINING_PARAMETER_MODE.read().unwrap(); - let opts = match *param_ref { - MiningParameterMode::AutomatedTesting => opts | chain::EASY_POW, - MiningParameterMode::UserTesting => opts | chain::EASY_POW, - MiningParameterMode::Production => opts, - }; + let opts = if global::is_production_mode() { + opts + } else { + opts | chain::EASY_POW + }; opts } } diff --git a/grin/src/server.rs b/grin/src/server.rs index 723fcb313..cbc9faf55 100644 --- a/grin/src/server.rs +++ b/grin/src/server.rs @@ -28,6 +28,7 @@ use tokio_timer::Timer; use adapters::*; use api; use chain; +use core::{global, genesis}; use miner; use p2p; use pool; @@ -37,7 +38,6 @@ use types::*; use pow; use util::LOGGER; -use core::global; /// Grin server holding internal structures. pub struct Server { @@ -91,7 +91,12 @@ impl Server { let mut genesis_block = None; if !chain::Chain::chain_exists(config.db_root.clone()) { - genesis_block = pow::mine_genesis_block(config.mining_config.clone()); + let chain_type = config.chain_type.clone().unwrap(); + if chain_type == global::ChainTypes::Testnet1 { + genesis_block = Some(genesis::genesis_testnet1()); + } else { + genesis_block = pow::mine_genesis_block(config.mining_config.clone()); + } } let shared_chain = Arc::new(chain::Chain::init( diff --git a/grin/src/types.rs b/grin/src/types.rs index 2846a37a7..fe697c783 100644 --- a/grin/src/types.rs +++ b/grin/src/types.rs @@ -21,7 +21,7 @@ use pool; use store; use pow; use wallet; -use core::global::MiningParameterMode; +use core::global::ChainTypes; /// Error type wrapping underlying module errors. #[derive(Debug)] @@ -91,8 +91,8 @@ pub struct ServerConfig { /// Network address for the Rest API HTTP server. pub api_http_addr: String, - /// Setup the server for tests and testnet - pub mining_parameter_mode: Option, + /// Setup the server for tests, testnet or mainnet + pub chain_type: Option, /// Method used to get the list of seed nodes for initial bootstrap. pub seeding_type: Seeding, @@ -125,7 +125,7 @@ impl Default for ServerConfig { seeds: None, p2p_config: Some(p2p::P2PConfig::default()), mining_config: Some(pow::types::MinerConfig::default()), - mining_parameter_mode: Some(MiningParameterMode::Production), + chain_type: Some(ChainTypes::Testnet1), pool_config: pool::PoolConfig::default(), } } diff --git a/grin/tests/simulnet.rs b/grin/tests/simulnet.rs index 80de80acf..38c87d528 100644 --- a/grin/tests/simulnet.rs +++ b/grin/tests/simulnet.rs @@ -41,7 +41,7 @@ use tokio_timer::Timer; use core::consensus; use core::global; -use core::global::{MiningParameterMode, MINING_PARAMETER_MODE}; +use core::global::ChainTypes; use wallet::WalletConfig; use framework::{LocalServerContainer, LocalServerContainerConfig, LocalServerContainerPool, @@ -51,7 +51,7 @@ use framework::{LocalServerContainer, LocalServerContainerConfig, LocalServerCon /// Block and mining into a wallet for a bit #[test] fn basic_genesis_mine() { - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let test_name_dir = "genesis_mine"; framework::clean_all_output(test_name_dir); @@ -80,7 +80,7 @@ fn basic_genesis_mine() { /// messages they all end up connected. #[test] fn simulate_seeding() { - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let test_name_dir = "simulate_seeding"; framework::clean_all_output(test_name_dir); @@ -133,7 +133,7 @@ fn simulate_seeding() { //#[test] #[allow(dead_code)] fn simulate_parallel_mining() { - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let test_name_dir = "simulate_parallel_mining"; // framework::clean_all_output(test_name_dir); @@ -187,7 +187,7 @@ fn simulate_parallel_mining() { #[test] fn a_simulate_block_propagation() { util::init_test_logger(); - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let test_name_dir = "grin-prop"; framework::clean_all_output(test_name_dir); @@ -246,7 +246,7 @@ fn a_simulate_block_propagation() { #[test] fn simulate_full_sync() { util::init_test_logger(); - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let test_name_dir = "grin-sync"; framework::clean_all_output(test_name_dir); diff --git a/pool/src/pool.rs b/pool/src/pool.rs index adbb25663..059724177 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -608,7 +608,7 @@ mod tests { use keychain::Keychain; use std::sync::{Arc, RwLock}; use blake2; - use core::global::MiningParameterMode; + use core::global::ChainTypes; use core::core::SwitchCommitHash; macro_rules! expect_output_parent { @@ -795,7 +795,7 @@ mod tests { #[test] fn test_immature_coinbase() { - global::set_mining_mode(MiningParameterMode::AutomatedTesting); + global::set_mining_mode(ChainTypes::AutomatedTesting); let mut dummy_chain = DummyChainImpl::new(); let coinbase_output = test_coinbase_output(15); dummy_chain.update_utxo_set(DummyUtxoSet::empty().with_output(coinbase_output)); diff --git a/pow/src/lib.rs b/pow/src/lib.rs index 9fe3458dc..774cb2a51 100644 --- a/pow/src/lib.rs +++ b/pow/src/lib.rs @@ -94,12 +94,10 @@ pub fn pow20( } /// Mines a genesis block, using the config specified miner if specified. -/// Otherwise, -/// uses the internal miner -/// +/// Otherwise, uses the internal miner pub fn mine_genesis_block(miner_config: Option) -> Option { info!(util::LOGGER, "Genesis block not found, initializing..."); - let mut gen = genesis::genesis(); + let mut gen = genesis::genesis_dev(); let diff = gen.header.difficulty.clone(); let sz = global::sizeshift() as u32; @@ -120,9 +118,8 @@ pub fn mine_genesis_block(miner_config: Option) -> Option( miner: &mut T, bh: &mut BlockHeader, @@ -131,42 +128,36 @@ pub fn pow_size( ) -> Result<(), Error> { let start_nonce = bh.nonce; - // try the pre-mined solution first for the genesis block (height 0) - if bh.height == 0 { - if global::is_production_mode() || global::is_user_testing_mode() { - let p = Proof::new(global::get_genesis_pow().to_vec()); - if p.clone().to_difficulty() >= diff { - bh.pow = p; - return Ok(()); - } - } + // set the nonce for faster solution finding in user testing + if bh.height == 0 && global::is_user_testing_mode() { + bh.nonce = global::get_genesis_nonce(); } - // try to find a cuckoo cycle on that header hash - loop { - // can be trivially optimized by avoiding re-serialization every time but this - // is not meant as a fast miner implementation - let pow_hash = bh.hash(); + // try to find a cuckoo cycle on that header hash + loop { + // can be trivially optimized by avoiding re-serialization every time but this + // is not meant as a fast miner implementation + let pow_hash = bh.hash(); - // if we found a cycle (not guaranteed) and the proof hash is higher that the - // diff, we're all good + // if we found a cycle (not guaranteed) and the proof hash is higher that the + // diff, we're all good - if let Ok(proof) = miner.mine(&pow_hash[..]) { - if proof.clone().to_difficulty() >= diff { - bh.pow = proof; - return Ok(()); - } - } + if let Ok(proof) = miner.mine(&pow_hash[..]) { + if proof.clone().to_difficulty() >= diff { + bh.pow = proof; + return Ok(()); + } + } - // otherwise increment the nonce - bh.nonce += 1; + // otherwise increment the nonce + bh.nonce += 1; - // and if we're back where we started, update the time (changes the hash as - // well) - if bh.nonce == start_nonce { - bh.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 }); - } - } + // and if we're back where we started, update the time (changes the hash as + // well) + if bh.nonce == start_nonce { + bh.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 }); + } + } } #[cfg(test)] @@ -176,14 +167,13 @@ mod test { use core::core::target::Difficulty; use core::genesis; use core::consensus::MINIMUM_DIFFICULTY; - use core::global::MiningParameterMode; - + use core::global::ChainTypes; #[test] fn genesis_pow() { - global::set_mining_mode(MiningParameterMode::AutomatedTesting); - let mut b = genesis::genesis(); - b.header.nonce = 310; + global::set_mining_mode(ChainTypes::AutomatedTesting); + let mut b = genesis::genesis_dev(); + b.header.nonce = 485; let mut internal_miner = cuckoo::Miner::new( consensus::EASINESS, global::sizeshift() as u32, diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 18c336e3c..08ac0e35e 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -57,7 +57,7 @@ fn start_from_config_file(mut global_config: GlobalConfig) { .unwrap() .server .clone() - .mining_parameter_mode + .chain_type .unwrap(), ); @@ -102,7 +102,7 @@ fn main() { .unwrap() .server .clone() - .mining_parameter_mode + .chain_type .unwrap(), ); } else {