From 131ea2f79943c1b5a2c9bfaea1db3350fe53ed4a Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Wed, 9 Aug 2017 17:40:23 +0100 Subject: [PATCH] Ci mode fixes (#86) * playing around with changing cuckoo sizes on the fly * modifying tests to use global cuckoo parameters, and checking results * check for pow size * Changing global function names, and removing length from POW serialization --- Cargo.toml | 1 + chain/src/chain.rs | 31 +-- chain/src/pipe.rs | 11 +- chain/tests/mine_simple_chain.rs | 15 +- core/Cargo.toml | 1 + core/src/consensus.rs | 6 - core/src/core/block.rs | 7 +- core/src/core/mod.rs | 63 +++-- core/src/genesis.rs | 5 +- core/src/global.rs | 86 +++++++ core/src/lib.rs | 3 + core/src/pow/cuckoo.rs | 110 ++++----- core/src/pow/mod.rs | 21 +- grin.toml | 11 +- grin/src/adapters.rs | 18 +- grin/src/miner.rs | 26 +- grin/src/plugin.rs | 17 +- grin/src/server.rs | 17 +- grin/src/types.rs | 5 +- grin/tests/framework.rs | 7 +- grin/tests/simulnet.rs | 399 ++++++++++++++++--------------- src/bin/grin.rs | 5 + 22 files changed, 508 insertions(+), 357 deletions(-) create mode 100644 core/src/global.rs diff --git a/Cargo.toml b/Cargo.toml index 1b87dfac..90c41543 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ grin_api = { path = "./api" } grin_wallet = { path = "./wallet" } grin_grin = { path = "./grin" } grin_config = { path = "./config" } +grin_core = { path = "./core" } secp256k1zkp = { path = "./secp256k1zkp" } blake2-rfc = "~0.2.17" diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 19e4fb12..975ee20a 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -30,6 +30,9 @@ use pipe; use store; use types::*; +use core::global; +use core::global::{MiningParameterMode,MINING_PARAMETER_MODE}; + const MAX_ORPHANS: usize = 20; /// Helper macro to transform a Result into an Option with None in case @@ -54,8 +57,6 @@ pub struct Chain { head: Arc>, block_process_lock: Arc>, orphans: Arc>>, - - test_mode: bool, } unsafe impl Sync for Chain {} @@ -68,7 +69,6 @@ impl Chain { /// on /// the genesis block if necessary. pub fn init( - test_mode: bool, db_root: String, adapter: Arc, ) -> Result { @@ -81,13 +81,11 @@ impl Chain { info!("No genesis block found, creating and saving one."); let mut gen = genesis::genesis(); let diff = gen.header.difficulty.clone(); - let sz = if test_mode { - consensus::TEST_SIZESHIFT - } else { - consensus::DEFAULT_SIZESHIFT - }; - let mut internal_miner = pow::cuckoo::Miner::new(consensus::EASINESS, sz as u32); - pow::pow_size(&mut internal_miner, &mut gen.header, diff, sz as u32).unwrap(); + + let sz = global::sizeshift(); + let proof_size = global::proofsize(); + + let mut internal_miner = pow::cuckoo::Miner::new(consensus::EASINESS, sz as u32, proof_size); pow::pow_size(&mut internal_miner, &mut gen.header, diff, sz as u32).unwrap(); chain_store.save_block(&gen)?; // saving a new tip based on genesis @@ -107,7 +105,6 @@ impl Chain { head: Arc::new(Mutex::new(head)), block_process_lock: Arc::new(Mutex::new(true)), orphans: Arc::new(Mutex::new(VecDeque::with_capacity(MAX_ORPHANS + 1))), - test_mode: test_mode, }) } @@ -158,10 +155,14 @@ impl Chain { } fn ctx_from_head(&self, head: Tip, opts: Options) -> pipe::BlockContext { - let mut opts_in = opts; - if self.test_mode { - opts_in = opts_in | EASY_POW; - } + 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, + }; + pipe::BlockContext { opts: opts_in, store: self.store.clone(), diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index 3f7382de..287347c4 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -28,6 +28,8 @@ use core::pow; use core::ser; use types::*; use store; +use core::global; +use core::global::{MiningParameterMode,MINING_PARAMETER_MODE}; /// Contextual information required to process a new block and either reject or /// accept it. @@ -119,9 +121,9 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E if header.height != prev.height + 1 { return Err(Error::InvalidBlockHeight); } - if header.timestamp <= prev.timestamp { + if header.timestamp <= prev.timestamp && !global::is_automated_testing_mode(){ // prevent time warp attacks and some timestamp manipulations by forcing strict - // time progression + // time progression (but not in CI mode) return Err(Error::InvalidBlockTime); } if header.timestamp > @@ -147,10 +149,11 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E return Err(Error::DifficultyTooLow); } + let param_ref=MINING_PARAMETER_MODE.read().unwrap(); let cycle_size = if ctx.opts.intersects(EASY_POW) { - consensus::TEST_SIZESHIFT + global::sizeshift() } else { - consensus::DEFAULT_SIZESHIFT + consensus::DEFAULT_SIZESHIFT }; debug!("Validating block with cuckoo size {}", cycle_size); if !pow::verify_size(header, cycle_size as u32) { diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index 55402778..18e22f16 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -32,17 +32,20 @@ use grin_core::core::target::Difficulty; use grin_core::pow; use grin_core::core; use grin_core::consensus; +use grin_core::pow::cuckoo; +use grin_core::global; +use grin_core::global::{MiningParameterMode,MINING_PARAMETER_MODE}; use grin::{ServerConfig, MinerConfig}; -use grin::PluginMiner; use grin_core::pow::MiningWorker; #[test] fn mine_empty_chain() { env_logger::init(); + global::set_mining_mode(MiningParameterMode::AutomatedTesting); let mut rng = OsRng::new().unwrap(); - let chain = grin_chain::Chain::init(true, ".grin".to_string(), Arc::new(NoopAdapter {})) + let chain = grin_chain::Chain::init(".grin".to_string(), Arc::new(NoopAdapter {})) .unwrap(); // mine and add a few blocks @@ -57,9 +60,7 @@ fn mine_empty_chain() { }; miner_config.cuckoo_miner_plugin_dir = Some(String::from("../target/debug/deps")); - let mut cuckoo_miner = PluginMiner::new(consensus::EASINESS, consensus::TEST_SIZESHIFT as u32); - cuckoo_miner.init(miner_config, server_config); - + let mut cuckoo_miner = cuckoo::Miner::new(consensus::EASINESS, global::sizeshift() as u32, global::proofsize()); for n in 1..4 { let prev = chain.head_header().unwrap(); let mut b = core::Block::new(&prev, vec![], reward_key).unwrap(); @@ -72,7 +73,7 @@ fn mine_empty_chain() { &mut cuckoo_miner, &mut b.header, difficulty, - consensus::TEST_SIZESHIFT as u32, + global::sizeshift() as u32, ).unwrap(); let bhash = b.hash(); @@ -89,7 +90,7 @@ fn mine_empty_chain() { fn mine_forks() { env_logger::init(); let mut rng = OsRng::new().unwrap(); - let chain = grin_chain::Chain::init(true, ".grin2".to_string(), Arc::new(NoopAdapter {})) + let chain = grin_chain::Chain::init(".grin2".to_string(), Arc::new(NoopAdapter {})) .unwrap(); // mine and add a few blocks diff --git a/core/Cargo.toml b/core/Cargo.toml index 9d541278..67f16e3e 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -14,5 +14,6 @@ rand = "^0.3" serde = "~1.0.8" serde_derive = "~1.0.8" time = "^0.1" +lazy_static = "~0.2.8" secp256k1zkp = { path = "../secp256k1zkp" } diff --git a/core/src/consensus.rs b/core/src/consensus.rs index 6b586999..54ba6ca0 100644 --- a/core/src/consensus.rs +++ b/core/src/consensus.rs @@ -35,15 +35,9 @@ pub const BLOCK_TIME_SEC: u64 = 60; /// Cuckoo-cycle proof size (cycle length) pub const PROOFSIZE: usize = 42; - /// Default Cuckoo Cycle size shift used for mining and validating. pub const DEFAULT_SIZESHIFT: u8 = 30; -/// Lower Cuckoo size shift for tests and testnet -/// This should be changed to correspond with the -/// loaded plugin if using cuckoo-miner -pub const TEST_SIZESHIFT: u8 = 16; - /// Default Cuckoo Cycle easiness, high enough to have good likeliness to find /// a solution. pub const EASINESS: u32 = 50; diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 4e052ca5..c7452b4a 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -24,9 +24,11 @@ use core::{Input, Output, Proof, TxKernel, Transaction, COINBASE_KERNEL, COINBAS use core::transaction::merkle_inputs_outputs; use consensus::REWARD; use consensus::MINIMUM_DIFFICULTY; +use consensus::PROOFSIZE; use core::hash::{Hash, Hashed, ZERO_HASH}; use core::target::Difficulty; use ser::{self, Readable, Reader, Writeable, Writer}; +use global; bitflags! { /// Options for block validation @@ -62,6 +64,7 @@ pub struct BlockHeader { impl Default for BlockHeader { fn default() -> BlockHeader { + let proof_size = global::proofsize(); BlockHeader { height: 0, previous: ZERO_HASH, @@ -72,7 +75,7 @@ impl Default for BlockHeader { tx_merkle: ZERO_HASH, features: DEFAULT_BLOCK, nonce: 0, - pow: Proof::zero(), + pow: Proof::zero(proof_size), } } } @@ -279,7 +282,7 @@ impl Block { height: prev.height + 1, timestamp: time::now(), previous: prev.hash(), - total_difficulty: prev.pow.to_difficulty() + prev.total_difficulty.clone(), + total_difficulty: prev.pow.clone().to_difficulty() + prev.total_difficulty.clone(), ..Default::default() }, inputs: inputs, diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index af4f88fe..57bed9f8 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -30,13 +30,14 @@ use std::cmp::Ordering; use secp::{self, Secp256k1}; use secp::pedersen::*; -use consensus::PROOFSIZE; pub use self::block::{Block, BlockHeader, DEFAULT_BLOCK}; pub use self::transaction::{Transaction, Input, Output, TxKernel, COINBASE_KERNEL, COINBASE_OUTPUT, DEFAULT_OUTPUT}; use self::hash::{Hash, Hashed, ZERO_HASH}; use ser::{Writeable, Writer, Reader, Readable, Error}; +use global; + /// Implemented by types that hold inputs and outputs including Pedersen /// commitments. Handles the collection of the commitments as well as their /// summing, taking potential explicit overages of fees into account. @@ -81,15 +82,17 @@ pub trait Committed { } /// Proof of work -#[derive(Copy)] -pub struct Proof(pub [u32; PROOFSIZE]); +pub struct Proof { + pub nonces:Vec, + pub proof_size: usize, +} impl fmt::Debug for Proof { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "Cuckoo(")); - for (i, val) in self.0[..].iter().enumerate() { + for (i, val) in self.nonces[..].iter().enumerate() { try!(write!(f, "{:x}", val)); - if i < PROOFSIZE - 1 { + if i < self.nonces.len() - 1 { try!(write!(f, " ")); } } @@ -98,39 +101,58 @@ impl fmt::Debug for Proof { } impl PartialOrd for Proof { fn partial_cmp(&self, other: &Proof) -> Option { - self.0.partial_cmp(&other.0) + self.nonces.partial_cmp(&other.nonces) } } impl PartialEq for Proof { fn eq(&self, other: &Proof) -> bool { - self.0[..] == other.0[..] + self.nonces[..] == other.nonces[..] } } impl Eq for Proof {} impl Clone for Proof { fn clone(&self) -> Proof { - *self + let mut out_nonces = Vec::new(); + for n in self.nonces.iter() { + out_nonces.push(*n as u32); + } + Proof { + proof_size: out_nonces.len(), + nonces: out_nonces, + } } } impl Proof { + /// Builds a proof with all bytes zeroed out - pub fn zero() -> Proof { - Proof([0; PROOFSIZE]) + pub fn new(in_nonces:Vec) -> Proof { + Proof { + proof_size: in_nonces.len(), + nonces: in_nonces, + } + } + + /// Builds a proof with all bytes zeroed out + pub fn zero(proof_size:usize) -> Proof { + Proof { + proof_size: proof_size, + nonces: vec![0;proof_size], + } } /// Converts the proof to a vector of u64s pub fn to_u64s(&self) -> Vec { - let mut nonces = Vec::with_capacity(PROOFSIZE); - for n in self.0.iter() { - nonces.push(*n as u64); + let mut out_nonces = Vec::with_capacity(self.proof_size); + for n in self.nonces.iter() { + out_nonces.push(*n as u64); } - nonces + out_nonces } /// Converts the proof to a vector of u32s pub fn to_u32s(&self) -> Vec { - self.0.to_vec() + self.clone().nonces } /// Converts the proof to a proof-of-work Target so they can be compared. @@ -142,18 +164,19 @@ impl Proof { impl Readable for Proof { fn read(reader: &mut Reader) -> Result { - let mut pow = [0u32; PROOFSIZE]; - for n in 0..PROOFSIZE { + let proof_size = global::proofsize(); + let mut pow = vec![0u32; proof_size]; + for n in 0..proof_size { pow[n] = try!(reader.read_u32()); } - Ok(Proof(pow)) + Ok(Proof::new(pow)) } } impl Writeable for Proof { fn write(&self, writer: &mut W) -> Result<(), Error> { - for n in 0..PROOFSIZE { - try!(writer.write_u32(self.0[n])); + for n in 0..self.proof_size { + try!(writer.write_u32(self.nonces[n])); } Ok(()) } diff --git a/core/src/genesis.rs b/core/src/genesis.rs index d7425cd9..30d31478 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -18,12 +18,15 @@ use time; use core; use consensus::MINIMUM_DIFFICULTY; +use consensus::PROOFSIZE; use core::hash::Hashed; 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(); core::Block { header: core::BlockHeader { height: 0, @@ -40,7 +43,7 @@ pub fn genesis() -> core::Block { tx_merkle: [].hash(), features: core::DEFAULT_BLOCK, nonce: 0, - pow: core::Proof::zero(), // TODO get actual PoW solution + pow: core::Proof::zero(proof_size), // TODO get actual PoW solution }, inputs: vec![], outputs: vec![], diff --git a/core/src/global.rs b/core/src/global.rs new file mode 100644 index 00000000..dde84dbe --- /dev/null +++ b/core/src/global.rs @@ -0,0 +1,86 @@ +// Copyright 2017 The Grin Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Values that should be shared across all modules, without necessarily +//! having to pass them all over the place, but aren't consensus values. +//! should be used sparingly. + +/// An enum collecting sets of parameters used throughout the +/// code wherever mining is needed. This should allow for +/// different sets of parameters for different purposes, +/// e.g. CI, User testing, production values + +use std::sync::{RwLock}; +use consensus::PROOFSIZE; +use consensus::DEFAULT_SIZESHIFT; + +/// Define these here, as they should be developer-set, not really tweakable +/// by users + +pub const AUTOMATED_TESTING_SIZESHIFT:u8 = 10; + +pub const AUTOMATED_TESTING_PROOF_SIZE:usize = 4; + +pub const USER_TESTING_SIZESHIFT:u8 = 16; + +pub const USER_TESTING_PROOF_SIZE:usize = 42; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum MiningParameterMode { + /// For CI testing + AutomatedTesting, + + /// For User testing + UserTesting, + + /// For production, use the values in consensus.rs + Production, +} + +lazy_static!{ + pub static ref MINING_PARAMETER_MODE: RwLock = RwLock::new(MiningParameterMode::Production); +} + +pub fn set_mining_mode(mode:MiningParameterMode){ + let mut param_ref=MINING_PARAMETER_MODE.write().unwrap(); + *param_ref=mode; +} + +pub fn sizeshift() -> u8 { + let param_ref=MINING_PARAMETER_MODE.read().unwrap(); + match *param_ref { + MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_SIZESHIFT, + MiningParameterMode::UserTesting => USER_TESTING_SIZESHIFT, + MiningParameterMode::Production => DEFAULT_SIZESHIFT, + } +} + +pub fn proofsize() -> usize { + let param_ref=MINING_PARAMETER_MODE.read().unwrap(); + match *param_ref { + MiningParameterMode::AutomatedTesting => AUTOMATED_TESTING_PROOF_SIZE, + MiningParameterMode::UserTesting => USER_TESTING_PROOF_SIZE, + MiningParameterMode::Production => PROOFSIZE, + } +} + +pub fn is_automated_testing_mode() -> bool { + let param_ref=MINING_PARAMETER_MODE.read().unwrap(); + if let MiningParameterMode::AutomatedTesting=*param_ref { + return true; + } else { + return false; + } +} + diff --git a/core/src/lib.rs b/core/src/lib.rs index 63cccb9e..9fd4d457 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -33,6 +33,8 @@ extern crate serde; #[macro_use] extern crate serde_derive; extern crate time; +#[macro_use] +extern crate lazy_static; #[macro_use] pub mod macros; @@ -42,3 +44,4 @@ pub mod core; pub mod genesis; pub mod pow; pub mod ser; +pub mod global; diff --git a/core/src/pow/cuckoo.rs b/core/src/pow/cuckoo.rs index f73ad377..a604e011 100644 --- a/core/src/pow/cuckoo.rs +++ b/core/src/pow/cuckoo.rs @@ -23,7 +23,6 @@ use std::cmp; use crypto::digest::Digest; use crypto::sha2::Sha256; -use consensus::PROOFSIZE; use core::Proof; use pow::siphash::siphash24; use pow::MiningWorker; @@ -101,9 +100,9 @@ impl Cuckoo { pub fn verify(&self, proof: Proof, ease: u64) -> bool { let easiness = ease * (self.size as u64) / 100; let nonces = proof.to_u64s(); - let mut us = [0; PROOFSIZE]; - let mut vs = [0; PROOFSIZE]; - for n in 0..PROOFSIZE { + let mut us = vec![0; proof.proof_size]; + let mut vs = vec![0; proof.proof_size]; + for n in 0..proof.proof_size { if nonces[n] >= easiness || (n != 0 && nonces[n] <= nonces[n - 1]) { return false; } @@ -111,10 +110,10 @@ impl Cuckoo { vs[n] = self.new_node(nonces[n], 1); } let mut i = 0; - let mut count = PROOFSIZE; + let mut count = proof.proof_size; loop { let mut j = i; - for k in 0..PROOFSIZE { + for k in 0..proof.proof_size { // find unique other j with same vs[j] if k != i && vs[k] == vs[i] { if j != i { @@ -127,7 +126,7 @@ impl Cuckoo { return false; } i = j; - for k in 0..PROOFSIZE { + for k in 0..proof.proof_size { // find unique other i with same us[i] if k != j && us[k] == us[j] { if i != j { @@ -154,6 +153,7 @@ impl Cuckoo { /// tests, being impractical with sizes greater than 2^22. pub struct Miner { easiness: u64, + proof_size: usize, cuckoo: Option, graph: Vec, sizeshift: u32, @@ -163,7 +163,8 @@ impl MiningWorker for Miner { /// Creates a new miner fn new(ease: u32, - sizeshift: u32) -> Miner { + sizeshift: u32, + proof_size: usize) -> Miner { let size = 1 << sizeshift; let graph = vec![0; size + 1]; let easiness = (ease as u64) * (size as u64) / 100; @@ -172,6 +173,7 @@ impl MiningWorker for Miner { cuckoo: None, graph: graph, sizeshift: sizeshift, + proof_size: proof_size, } } @@ -186,7 +188,7 @@ impl MiningWorker for Miner { /// What type of cycle we have found? enum CycleSol { /// A cycle of the right length is a valid proof. - ValidProof([u32; PROOFSIZE]), + ValidProof(Vec), /// A cycle of the wrong length is great, but not a proof. InvalidCycle(usize), /// No cycles have been found. @@ -214,7 +216,7 @@ impl Miner { let sol = self.find_sol(nu, &us, nv, &vs); match sol { CycleSol::ValidProof(res) => { - return Ok(Proof(res)) + return Ok(Proof::new(res.to_vec())); }, CycleSol::InvalidCycle(_) => continue, CycleSol::NoCycle => { @@ -266,7 +268,7 @@ impl Miner { nu += 1; nv += 1; } - if nu + nv + 1 == PROOFSIZE { + if nu + nv + 1 == self.proof_size { self.solution(&us, nu as u32, &vs, nv as u32) } else { CycleSol::InvalidCycle(nu + nv + 1) @@ -299,7 +301,7 @@ impl Miner { }); } let mut n = 0; - let mut sol = [0; PROOFSIZE]; + let mut sol = vec![0; self.proof_size]; for nonce in 0..self.easiness { let edge = self.cuckoo.as_mut().unwrap().new_edge(nonce); if cycle.contains(&edge) { @@ -308,7 +310,7 @@ impl Miner { cycle.remove(&edge); } } - return if n == PROOFSIZE { + return if n == self.proof_size { CycleSol::ValidProof(sol) } else { CycleSol::NoCycle @@ -329,68 +331,68 @@ mod test { use super::*; use core::Proof; - static V1: Proof = Proof([0xe13, 0x410c, 0x7974, 0x8317, 0xb016, 0xb992, 0xe3c8, 0x1038a, - 0x116f0, 0x15ed2, 0x165a2, 0x17793, 0x17dd1, 0x1f885, 0x20932, - 0x20936, 0x2171b, 0x28968, 0x2b184, 0x30b8e, 0x31d28, 0x35782, - 0x381ea, 0x38321, 0x3b414, 0x3e14b, 0x43615, 0x49a51, 0x4a319, - 0x58271, 0x5dbb9, 0x5dbcf, 0x62db4, 0x653d2, 0x655f6, 0x66382, - 0x7057d, 0x765b0, 0x79c7c, 0x83167, 0x86e7b, 0x8a5f4]); - static V2: Proof = Proof([0x33b8, 0x3fd9, 0x8f2b, 0xba0d, 0x11e2d, 0x1d51d, 0x2786e, 0x29625, - 0x2a862, 0x2a972, 0x2e6d7, 0x319df, 0x37ce7, 0x3f771, 0x4373b, - 0x439b7, 0x48626, 0x49c7d, 0x4a6f1, 0x4a808, 0x4e518, 0x519e3, - 0x526bb, 0x54988, 0x564e9, 0x58a6c, 0x5a4dd, 0x63fa2, 0x68ad1, - 0x69e52, 0x6bf53, 0x70841, 0x76343, 0x763a4, 0x79681, 0x7d006, - 0x7d633, 0x7eebe, 0x7fe7c, 0x811fa, 0x863c1, 0x8b149]); - static V3: Proof = Proof([0x24ae, 0x5180, 0x9f3d, 0xd379, 0x102c9, 0x15787, 0x16df4, 0x19509, - 0x19a78, 0x235a0, 0x24210, 0x24410, 0x2567f, 0x282c3, 0x2d986, - 0x2efde, 0x319d7, 0x334d7, 0x336dd, 0x34296, 0x35809, 0x3ad40, - 0x46d81, 0x48c92, 0x4b374, 0x4c353, 0x4fe4c, 0x50e4f, 0x53202, - 0x5d167, 0x6527c, 0x6a8b5, 0x6c70d, 0x76d90, 0x794f4, 0x7c411, - 0x7c5d4, 0x7f59f, 0x7fead, 0x872d8, 0x875b4, 0x95c6b]); + static V1:[u32;42] = [0xe13, 0x410c, 0x7974, 0x8317, 0xb016, 0xb992, 0xe3c8, 0x1038a, + 0x116f0, 0x15ed2, 0x165a2, 0x17793, 0x17dd1, 0x1f885, 0x20932, + 0x20936, 0x2171b, 0x28968, 0x2b184, 0x30b8e, 0x31d28, 0x35782, + 0x381ea, 0x38321, 0x3b414, 0x3e14b, 0x43615, 0x49a51, 0x4a319, + 0x58271, 0x5dbb9, 0x5dbcf, 0x62db4, 0x653d2, 0x655f6, 0x66382, + 0x7057d, 0x765b0, 0x79c7c, 0x83167, 0x86e7b, 0x8a5f4]; + static V2:[u32;42] = [0x33b8, 0x3fd9, 0x8f2b, 0xba0d, 0x11e2d, 0x1d51d, 0x2786e, 0x29625, + 0x2a862, 0x2a972, 0x2e6d7, 0x319df, 0x37ce7, 0x3f771, 0x4373b, + 0x439b7, 0x48626, 0x49c7d, 0x4a6f1, 0x4a808, 0x4e518, 0x519e3, + 0x526bb, 0x54988, 0x564e9, 0x58a6c, 0x5a4dd, 0x63fa2, 0x68ad1, + 0x69e52, 0x6bf53, 0x70841, 0x76343, 0x763a4, 0x79681, 0x7d006, + 0x7d633, 0x7eebe, 0x7fe7c, 0x811fa, 0x863c1, 0x8b149]; + static V3:[u32;42] = [0x24ae, 0x5180, 0x9f3d, 0xd379, 0x102c9, 0x15787, 0x16df4, 0x19509, + 0x19a78, 0x235a0, 0x24210, 0x24410, 0x2567f, 0x282c3, 0x2d986, + 0x2efde, 0x319d7, 0x334d7, 0x336dd, 0x34296, 0x35809, 0x3ad40, + 0x46d81, 0x48c92, 0x4b374, 0x4c353, 0x4fe4c, 0x50e4f, 0x53202, + 0x5d167, 0x6527c, 0x6a8b5, 0x6c70d, 0x76d90, 0x794f4, 0x7c411, + 0x7c5d4, 0x7f59f, 0x7fead, 0x872d8, 0x875b4, 0x95c6b]; // cuckoo28 at 50% edges of letter 'u' - static V4: Proof = Proof([0x1abd16, 0x7bb47e, 0x860253, 0xfad0b2, 0x121aa4d, 0x150a10b, - 0x20605cb, 0x20ae7e3, 0x235a9be, 0x2640f4a, 0x2724c36, 0x2a6d38c, - 0x2c50b28, 0x30850f2, 0x309668a, 0x30c85bd, 0x345f42c, 0x3901676, - 0x432838f, 0x472158a, 0x4d04e9d, 0x4d6a987, 0x4f577bf, 0x4fbc49c, - 0x593978d, 0x5acd98f, 0x5e60917, 0x6310602, 0x6385e88, 0x64f149c, - 0x66d472e, 0x68e4df9, 0x6b4a89c, 0x6bb751d, 0x6e09792, 0x6e57e1d, - 0x6ecfcdd, 0x70abddc, 0x7291dfd, 0x788069e, 0x79a15b1, 0x7d1a1e9]); + static V4:[u32;42] = [0x1abd16, 0x7bb47e, 0x860253, 0xfad0b2, 0x121aa4d, 0x150a10b, + 0x20605cb, 0x20ae7e3, 0x235a9be, 0x2640f4a, 0x2724c36, 0x2a6d38c, + 0x2c50b28, 0x30850f2, 0x309668a, 0x30c85bd, 0x345f42c, 0x3901676, + 0x432838f, 0x472158a, 0x4d04e9d, 0x4d6a987, 0x4f577bf, 0x4fbc49c, + 0x593978d, 0x5acd98f, 0x5e60917, 0x6310602, 0x6385e88, 0x64f149c, + 0x66d472e, 0x68e4df9, 0x6b4a89c, 0x6bb751d, 0x6e09792, 0x6e57e1d, + 0x6ecfcdd, 0x70abddc, 0x7291dfd, 0x788069e, 0x79a15b1, 0x7d1a1e9]; /// Find a 42-cycle on Cuckoo20 at 75% easiness and verifiy against a few /// known cycle proofs /// generated by other implementations. #[test] fn mine20_vectors() { - let nonces1 = Miner::new(75, 20).mine(&[49]).unwrap(); - assert_eq!(V1, nonces1); + let nonces1 = Miner::new(75, 20, 42).mine(&[49]).unwrap(); + assert_eq!(Proof::new(V1.to_vec()), nonces1); - let nonces2 = Miner::new(70, 20).mine(&[50]).unwrap(); - assert_eq!(V2, nonces2); + let nonces2 = Miner::new(70, 20, 42).mine(&[50]).unwrap(); + assert_eq!(Proof::new(V2.to_vec()), nonces2); - let nonces3 = Miner::new(70, 20).mine(&[51]).unwrap(); - assert_eq!(V3, nonces3); + let nonces3 = Miner::new(70, 20, 42).mine(&[51]).unwrap(); + assert_eq!(Proof::new(V3.to_vec()), nonces3); } #[test] fn validate20_vectors() { - assert!(Cuckoo::new(&[49], 20).verify(V1.clone(), 75)); - assert!(Cuckoo::new(&[50], 20).verify(V2.clone(), 70)); - assert!(Cuckoo::new(&[51], 20).verify(V3.clone(), 70)); + assert!(Cuckoo::new(&[49], 20).verify(Proof::new(V1.to_vec().clone()), 75)); + assert!(Cuckoo::new(&[50], 20).verify(Proof::new(V2.to_vec().clone()), 70)); + assert!(Cuckoo::new(&[51], 20).verify(Proof::new(V3.to_vec().clone()), 70)); } #[test] fn validate28_vectors() { - assert!(Cuckoo::new(&[117], 28).verify(V4.clone(), 50)); + assert!(Cuckoo::new(&[117], 28).verify(Proof::new(V4.to_vec().clone()), 50)); } #[test] fn validate_fail() { // edge checks - assert!(!Cuckoo::new(&[49], 20).verify(Proof([0; 42]), 75)); - assert!(!Cuckoo::new(&[49], 20).verify(Proof([0xffff; 42]), 75)); + assert!(!Cuckoo::new(&[49], 20).verify(Proof::new(vec![0; 42]), 75)); + assert!(!Cuckoo::new(&[49], 20).verify(Proof::new(vec![0xffff; 42]), 75)); // wrong data for proof - assert!(!Cuckoo::new(&[50], 20).verify(V1.clone(), 75)); - assert!(!Cuckoo::new(&[117], 20).verify(V4.clone(), 50)); + assert!(!Cuckoo::new(&[50], 20).verify(Proof::new(V1.to_vec().clone()), 75)); + assert!(!Cuckoo::new(&[117], 20).verify(Proof::new(V4.to_vec().clone()), 50)); } #[test] @@ -398,13 +400,13 @@ mod test { // cuckoo20 for n in 1..5 { let h = [n; 32]; - let nonces = Miner::new(75, 20).mine(&h).unwrap(); + let nonces = Miner::new(75, 20, 42).mine(&h).unwrap(); assert!(Cuckoo::new(&h, 20).verify(nonces, 75)); } // cuckoo18 for n in 1..5 { let h = [n; 32]; - let nonces = Miner::new(75, 18).mine(&h).unwrap(); + let nonces = Miner::new(75, 18, 42).mine(&h).unwrap(); assert!(Cuckoo::new(&h, 18).verify(nonces, 75)); } } diff --git a/core/src/pow/mod.rs b/core/src/pow/mod.rs index 0eb637a4..7e5c4098 100644 --- a/core/src/pow/mod.rs +++ b/core/src/pow/mod.rs @@ -31,6 +31,8 @@ use consensus::EASINESS; use core::BlockHeader; use core::hash::Hashed; use core::Proof; +use global; +use global::{MiningParameterMode, MINING_PARAMETER_MODE}; use core::target::Difficulty; use pow::cuckoo::{Cuckoo, Error}; @@ -41,7 +43,7 @@ use pow::cuckoo::{Cuckoo, Error}; pub trait MiningWorker { /// This only sets parameters and does initialisation work now - fn new(ease: u32, sizeshift: u32) -> Self; + fn new(ease: u32, sizeshift: u32, proof_size:usize) -> Self; /// Actually perform a mining attempt on the given input and /// return a proof if found @@ -54,10 +56,10 @@ pub trait MiningWorker { pub fn verify_size(bh: &BlockHeader, cuckoo_sz: u32) -> bool { // make sure the pow hash shows a difficulty at least as large as the target // difficulty - if bh.difficulty > bh.pow.to_difficulty() { + if bh.difficulty > bh.pow.clone().to_difficulty() { return false; } - Cuckoo::new(&bh.hash()[..], cuckoo_sz).verify(bh.pow, EASINESS as u64) + Cuckoo::new(&bh.hash()[..], cuckoo_sz).verify(bh.pow.clone(), EASINESS as u64) } /// Uses the much easier Cuckoo20 (mostly for @@ -82,7 +84,7 @@ pub fn pow_size(miner:&mut T, bh: &mut BlockHeader, // diff, we're all good if let Ok(proof) = miner.mine(&pow_hash[..]) { - if proof.to_difficulty() >= diff { + if proof.clone().to_difficulty() >= diff { bh.pow = proof; return Ok(()); } @@ -104,16 +106,17 @@ mod test { use super::*; use core::target::Difficulty; use genesis; - use consensus::MINIMUM_DIFFICULTY; + use consensus::MINIMUM_DIFFICULTY; #[test] fn genesis_pow() { + global::set_mining_mode(MiningParameterMode::AutomatedTesting); let mut b = genesis::genesis(); b.header.nonce = 310; - let mut internal_miner = cuckoo::Miner::new(EASINESS, 12); - pow_size(&mut internal_miner, &mut b.header, Difficulty::from_num(MINIMUM_DIFFICULTY), 12).unwrap(); + let mut internal_miner = cuckoo::Miner::new(EASINESS, global::sizeshift() as u32, global::proofsize()); + pow_size(&mut internal_miner, &mut b.header, Difficulty::from_num(MINIMUM_DIFFICULTY), global::sizeshift() as u32).unwrap(); assert!(b.header.nonce != 310); - assert!(b.header.pow.to_difficulty() >= Difficulty::from_num(MINIMUM_DIFFICULTY)); - assert!(verify_size(&b.header, 12)); + assert!(b.header.pow.clone().to_difficulty() >= Difficulty::from_num(MINIMUM_DIFFICULTY)); + assert!(verify_size(&b.header, global::sizeshift() as u32)); } } diff --git a/grin.toml b/grin.toml index 066c1096..f85c11ad 100644 --- a/grin.toml +++ b/grin.toml @@ -28,12 +28,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"] -#Whether to run in test mode. This affects the size of -#cuckoo graph. -#If this is true, CONSENSUS::TEST_SIZESHIFT is used -#If this is false, CONSENSUS::DEFAULT_SIZESHIFT is used +#The mining parameter mode, which defines the set of cuckoo parameters +#used for mining. Can be: +#AutomatedTesting - For CI builds and instant blockchain creation +#UserTesting - For regular user testing, much lighter than production more +#Production - Full production cuckoo parameters -test_mode = true +mining_parameter_mode = "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 8a614da5..ca3c3d92 100644 --- a/grin/src/adapters.rs +++ b/grin/src/adapters.rs @@ -27,12 +27,13 @@ use secp::pedersen::Commitment; use util::OneTime; use store; use sync; +use core::global; +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 /// implementations. pub struct NetToChainAdapter { - test_mode: bool, chain: Arc, peer_store: Arc, tx_pool: Arc>>, @@ -192,13 +193,11 @@ impl NetAdapter for NetToChainAdapter { } impl NetToChainAdapter { - pub fn new(test_mode: bool, - chain_ref: Arc, + pub fn new(chain_ref: Arc, tx_pool: Arc>>, peer_store: Arc) -> NetToChainAdapter { NetToChainAdapter { - test_mode: test_mode, chain: chain_ref, peer_store: peer_store, tx_pool: tx_pool, @@ -218,14 +217,17 @@ impl NetToChainAdapter { /// Prepare options for the chain pipeline fn chain_opts(&self) -> chain::Options { - let mut opts = if self.syncer.borrow().syncing() { + let opts = if self.syncer.borrow().syncing() { chain::SYNC } else { chain::NONE }; - if self.test_mode { - opts = opts | chain::EASY_POW; - } + 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, + }; opts } } diff --git a/grin/src/miner.rs b/grin/src/miner.rs index ab564d88..7d20b1f9 100644 --- a/grin/src/miner.rs +++ b/grin/src/miner.rs @@ -16,16 +16,15 @@ //! block and mine the block to produce a valid header with its proof-of-work. use rand::{self, Rng}; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, RwLock}; use std::thread; use std; -use std::{env, str}; +use std::{str}; use time; -use adapters::{ChainToPoolAndNetAdapter, PoolToChainAdapter}; +use adapters::{PoolToChainAdapter}; use api; use core::consensus; -use core::consensus::*; use core::core; use core::core::Proof; use core::pow::cuckoo; @@ -34,12 +33,12 @@ use core::core::{Block, BlockHeader}; use core::core::hash::{Hash, Hashed}; use core::pow::MiningWorker; use core::ser; -use core::ser::{Writer, Writeable, AsFixedBytes}; +use core::ser::{AsFixedBytes}; use chain; use secp; use pool; -use types::{MinerConfig, ServerConfig, Error}; +use types::{MinerConfig, ServerConfig}; use util; use wallet::{CbAmount, WalletReceiveRequest, CbData}; @@ -50,7 +49,6 @@ use itertools::Itertools; const MAX_TX: u32 = 5000; const PRE_NONCE_SIZE: usize = 113; -const POST_NONCE_SIZE: usize = 5; /// Serializer that outputs pre and post nonce portions of a block header /// which can then be sent off to miner to mutate at will @@ -174,7 +172,7 @@ impl Miner { while head.hash() == *latest_hash && time::get_time().sec < deadline { if let Some(s) = job_handle.get_solution() { - sol = Some(Proof(s.solution_nonces)); + sol = Some(Proof::new(s.solution_nonces.to_vec())); b.header.nonce=s.get_nonce_as_u64(); break; } @@ -193,7 +191,6 @@ impl Miner { /// The inner part of mining loop for synchronous mode pub fn inner_loop_sync(&self, miner:&mut T, - difficulty:Difficulty, b:&mut Block, cuckoo_size: u32, head:&BlockHeader, @@ -221,7 +218,7 @@ impl Miner { let pow_hash = b.hash(); if let Ok(proof) = miner.mine(&pow_hash[..]) { - let proof_diff=proof.to_difficulty(); + let proof_diff=proof.clone().to_difficulty(); /*debug!("(Server ID: {}) Header difficulty is: {}, Proof difficulty is: {}", self.debug_output_id, b.header.difficulty, @@ -256,16 +253,17 @@ impl Miner { pub fn run_loop(&self, miner_config:MinerConfig, server_config:ServerConfig, - cuckoo_size:u32) { + cuckoo_size:u32, + proof_size:usize) { info!("(Server ID: {}) Starting miner loop.", self.debug_output_id); let mut plugin_miner=None; let mut miner=None; if miner_config.use_cuckoo_miner { - plugin_miner = Some(PluginMiner::new(consensus::EASINESS, cuckoo_size)); + plugin_miner = Some(PluginMiner::new(consensus::EASINESS, cuckoo_size, proof_size)); plugin_miner.as_mut().unwrap().init(miner_config.clone(),server_config); } else { - miner = Some(cuckoo::Miner::new(consensus::EASINESS, cuckoo_size)); + miner = Some(cuckoo::Miner::new(consensus::EASINESS, cuckoo_size, proof_size)); } let mut coinbase = self.get_coinbase(); @@ -293,7 +291,6 @@ impl Miner { &latest_hash); } else { sol = self.inner_loop_sync(p, - b.header.difficulty.clone(), &mut b, cuckoo_size, &head, @@ -302,7 +299,6 @@ impl Miner { } if let Some(mut m) = miner.as_mut() { sol = self.inner_loop_sync(m, - b.header.difficulty.clone(), &mut b, cuckoo_size, &head, diff --git a/grin/src/plugin.rs b/grin/src/plugin.rs index 6796cba8..e2e0451f 100644 --- a/grin/src/plugin.rs +++ b/grin/src/plugin.rs @@ -22,8 +22,8 @@ use std::env; use core::pow::cuckoo; use core::pow::cuckoo::Error; use core::pow::MiningWorker; -use core::consensus::{TEST_SIZESHIFT, DEFAULT_SIZESHIFT}; - +use core::consensus::DEFAULT_SIZESHIFT; +use core::global; use std::collections::HashMap; use core::core::Proof; @@ -105,13 +105,7 @@ impl PluginMiner { panic!("Unable to load plugin directory... Please check configuration values"); } - //The miner implementation needs to match what's in the consensus sizeshift value - // - let sz = if server_config.test_mode { - TEST_SIZESHIFT - } else { - DEFAULT_SIZESHIFT - }; + let sz = global::sizeshift(); //So this is built dynamically based on the plugin implementation //type and the consensus sizeshift @@ -165,7 +159,8 @@ impl MiningWorker for PluginMiner { /// configurable somehow fn new(ease: u32, - sizeshift: u32) -> Self { + sizeshift: u32, + proof_size: usize) -> Self { PluginMiner::default() } @@ -175,7 +170,7 @@ impl MiningWorker for PluginMiner { fn mine(&mut self, header: &[u8]) -> Result { let result = self.miner.as_mut().unwrap().mine(&header, &mut self.last_solution).unwrap(); if result == true { - return Ok(Proof(self.last_solution.solution_nonces)); + return Ok(Proof::new(self.last_solution.solution_nonces.to_vec())); } Err(Error::NoSolution) } diff --git a/grin/src/server.rs b/grin/src/server.rs index 2b5a38a1..e8f32ae3 100644 --- a/grin/src/server.rs +++ b/grin/src/server.rs @@ -42,6 +42,7 @@ use sync; use types::*; use plugin::PluginMiner; +use core::global; /// Grin server holding internal structures. pub struct Server { @@ -85,14 +86,12 @@ impl Server { let tx_pool = Arc::new(RwLock::new(pool::TransactionPool::new(pool_adapter.clone()))); let chain_adapter = Arc::new(ChainToPoolAndNetAdapter::new(tx_pool.clone())); - let shared_chain = Arc::new(chain::Chain::init(config.test_mode, - config.db_root.clone(), + let shared_chain = Arc::new(chain::Chain::init(config.db_root.clone(), chain_adapter.clone())?); pool_adapter.set_chain(shared_chain.clone()); let peer_store = Arc::new(p2p::PeerStore::new(config.db_root.clone())?); - let net_adapter = Arc::new(NetToChainAdapter::new(config.test_mode, - shared_chain.clone(), + let net_adapter = Arc::new(NetToChainAdapter::new(shared_chain.clone(), tx_pool.clone(), peer_store.clone())); let p2p_server = @@ -145,15 +144,15 @@ impl Server { /// Start mining for blocks on a separate thread. Uses toy miner by default, /// mostly for testing, but can also load a plugin from cuckoo-miner pub fn start_miner(&self, config: MinerConfig) { - let cuckoo_size = match self.config.test_mode { - true => consensus::TEST_SIZESHIFT as u32, - false => consensus::DEFAULT_SIZESHIFT as u32, - }; + let cuckoo_size = global::sizeshift(); + let proof_size = global::proofsize(); + + let mut miner = miner::Miner::new(config.clone(), self.chain.clone(), self.tx_pool.clone()); miner.set_debug_output_id(format!("Port {}",self.config.p2p_config.unwrap().port)); let server_config = self.config.clone(); thread::spawn(move || { - miner.run_loop(config.clone(), server_config, cuckoo_size); + miner.run_loop(config.clone(), server_config, cuckoo_size as u32, proof_size); }); } diff --git a/grin/src/types.rs b/grin/src/types.rs index 41389c69..8c186254 100644 --- a/grin/src/types.rs +++ b/grin/src/types.rs @@ -19,6 +19,7 @@ use api; use chain; use p2p; use store; +use core::global::MiningParameterMode; /// Error type wrapping underlying module errors. #[derive(Debug)] @@ -79,7 +80,7 @@ pub struct ServerConfig { pub api_http_addr: String, /// Setup the server for tests and testnet - pub test_mode: bool, + pub mining_parameter_mode: Option, /// Method used to get the list of seed nodes for initial bootstrap. pub seeding_type: Seeding, @@ -143,7 +144,7 @@ impl Default for ServerConfig { seeds: None, p2p_config: Some(p2p::P2PConfig::default()), mining_config: Some(MinerConfig::default()), - test_mode: true, + mining_parameter_mode: Some(MiningParameterMode::Production), } } } diff --git a/grin/tests/framework.rs b/grin/tests/framework.rs index 95b89753..0ecf324f 100644 --- a/grin/tests/framework.rs +++ b/grin/tests/framework.rs @@ -53,7 +53,10 @@ use core::consensus; pub fn clean_all_output(test_name_dir:&str){ let target_dir = format!("target/test_servers/{}", test_name_dir); - fs::remove_dir_all(target_dir); + let result = fs::remove_dir_all(target_dir); + if let Err(e) = result { + println!("{}",e); + } } /// Errors that can be returned by LocalServerContainer @@ -227,7 +230,7 @@ impl LocalServerContainer { let mut miner_config = grin::MinerConfig { enable_mining: self.config.start_miner, burn_reward: self.config.burn_mining_rewards, - use_cuckoo_miner: true, + use_cuckoo_miner: false, cuckoo_miner_async_mode: Some(false), cuckoo_miner_plugin_dir: Some(String::from("../target/debug/deps")), cuckoo_miner_plugin_type: Some(String::from("simple")), diff --git a/grin/tests/simulnet.rs b/grin/tests/simulnet.rs index 1c744cfc..d1c9f2a6 100644 --- a/grin/tests/simulnet.rs +++ b/grin/tests/simulnet.rs @@ -40,198 +40,217 @@ use tokio_core::reactor; use tokio_timer::Timer; use core::consensus; +use core::global; +use core::global::{MiningParameterMode, MINING_PARAMETER_MODE}; use wallet::WalletConfig; -use framework::{LocalServerContainer, LocalServerContainerConfig, - LocalServerContainerPoolConfig, LocalServerContainerPool}; +use framework::{LocalServerContainer, LocalServerContainerConfig, LocalServerContainerPoolConfig, + LocalServerContainerPool}; /// Testing the frameworks by starting a fresh server, creating a genesis /// Block and mining into a wallet for a bit - #[test] -fn basic_genesis_mine(){ - env_logger::init(); +fn basic_genesis_mine() { + env_logger::init(); + global::set_mining_mode(MiningParameterMode::AutomatedTesting); - let test_name_dir="genesis_mine"; - framework::clean_all_output(test_name_dir); + let test_name_dir = "genesis_mine"; + framework::clean_all_output(test_name_dir); - //Create a server pool - let mut pool_config = LocalServerContainerPoolConfig::default(); - pool_config.base_name = String::from(test_name_dir); - pool_config.run_length_in_seconds = 20; + // Create a server pool + let mut pool_config = LocalServerContainerPoolConfig::default(); + pool_config.base_name = String::from(test_name_dir); + pool_config.run_length_in_seconds = 5; - pool_config.base_api_port=30000; - pool_config.base_p2p_port=31000; - pool_config.base_wallet_port=32000; + pool_config.base_api_port = 30000; + pool_config.base_p2p_port = 31000; + pool_config.base_wallet_port = 32000; - let mut pool = LocalServerContainerPool::new(pool_config); + let mut pool = LocalServerContainerPool::new(pool_config); - //Create a server to add into the pool - let mut server_config = LocalServerContainerConfig::default(); - server_config.start_miner=true; - server_config.start_wallet=true; + // Create a server to add into the pool + let mut server_config = LocalServerContainerConfig::default(); + server_config.start_miner = true; + server_config.start_wallet = true; - pool.create_server(&mut server_config); - pool.run_all_servers(); + pool.create_server(&mut server_config); + pool.run_all_servers(); } /// Creates 5 servers, first being a seed and check that through peer address /// messages they all end up connected. - #[test] -fn simulate_seeding () { - env_logger::init(); +fn simulate_seeding() { + env_logger::init(); + global::set_mining_mode(MiningParameterMode::AutomatedTesting); - let test_name_dir="simulate_seeding"; - framework::clean_all_output(test_name_dir); + let test_name_dir = "simulate_seeding"; + framework::clean_all_output(test_name_dir); - //Create a server pool - let mut pool_config = LocalServerContainerPoolConfig::default(); - pool_config.base_name = String::from(test_name_dir); - pool_config.run_length_in_seconds = 30; + // Create a server pool + let mut pool_config = LocalServerContainerPoolConfig::default(); + pool_config.base_name = String::from(test_name_dir); + pool_config.run_length_in_seconds = 30; - //have to select different ports because of tests being run in parallel - pool_config.base_api_port=30020; - pool_config.base_p2p_port=31020; - pool_config.base_wallet_port=32020; + // have to select different ports because of tests being run in parallel + pool_config.base_api_port = 30020; + pool_config.base_p2p_port = 31020; + pool_config.base_wallet_port = 32020; - let mut pool = LocalServerContainerPool::new(pool_config); + let mut pool = LocalServerContainerPool::new(pool_config); - //Create a first seed server to add into the pool - let mut server_config = LocalServerContainerConfig::default(); - //server_config.start_miner = true; - server_config.start_wallet = true; - server_config.is_seeding = true; + // Create a first seed server to add into the pool + let mut server_config = LocalServerContainerConfig::default(); + // server_config.start_miner = true; + server_config.start_wallet = true; + server_config.is_seeding = true; - pool.create_server(&mut server_config); + pool.create_server(&mut server_config); - //point next servers at first seed - server_config.is_seeding = false; - server_config.seed_addr = String::from(format!("{}:{}", server_config.base_addr, - server_config.p2p_server_port)); + // point next servers at first seed + server_config.is_seeding = false; + server_config.seed_addr = String::from(format!( + "{}:{}", + server_config.base_addr, + server_config.p2p_server_port + )); - for i in 0..4 { - pool.create_server(&mut server_config); - } + for i in 0..4 { + pool.create_server(&mut server_config); + } - pool.connect_all_peers(); + pool.connect_all_peers(); - let result_vec = pool.run_all_servers(); + let result_vec = pool.run_all_servers(); } -/// Create 1 server, start it mining, then connect 4 other peers mining and using the first -/// as a seed. Meant to test the evolution of mining difficulty with miners running at +/// Create 1 server, start it mining, then connect 4 other peers mining and +/// using the first +/// as a seed. Meant to test the evolution of mining difficulty with miners +/// running at /// different rates -//Just going to comment this out as an automatically run test for the time being, -//As it's more for actively testing and hurts CI a lot +// Just going to comment this out as an automatically run test for the time +// being, +// As it's more for actively testing and hurts CI a lot //#[test] -fn simulate_parallel_mining(){ - env_logger::init(); +fn simulate_parallel_mining() { + env_logger::init(); + global::set_mining_mode(MiningParameterMode::AutomatedTesting); - let test_name_dir="simulate_parallel_mining"; - //framework::clean_all_output(test_name_dir); + let test_name_dir = "simulate_parallel_mining"; + // framework::clean_all_output(test_name_dir); - //Create a server pool - let mut pool_config = LocalServerContainerPoolConfig::default(); - pool_config.base_name = String::from(test_name_dir); - pool_config.run_length_in_seconds = 60; -//have to select different ports because of tests being run in parallel - pool_config.base_api_port=30040; - pool_config.base_p2p_port=31040; - pool_config.base_wallet_port=32040; + // Create a server pool + let mut pool_config = LocalServerContainerPoolConfig::default(); + pool_config.base_name = String::from(test_name_dir); + pool_config.run_length_in_seconds = 60; + // have to select different ports because of tests being run in parallel + pool_config.base_api_port = 30040; + pool_config.base_p2p_port = 31040; + pool_config.base_wallet_port = 32040; - let mut pool = LocalServerContainerPool::new(pool_config); + let mut pool = LocalServerContainerPool::new(pool_config); - //Create a first seed server to add into the pool - let mut server_config = LocalServerContainerConfig::default(); - server_config.start_miner = true; - server_config.start_wallet = true; - server_config.is_seeding = true; + // Create a first seed server to add into the pool + let mut server_config = LocalServerContainerConfig::default(); + server_config.start_miner = true; + server_config.start_wallet = true; + server_config.is_seeding = true; - pool.create_server(&mut server_config); + pool.create_server(&mut server_config); - //point next servers at first seed - server_config.is_seeding=false; - server_config.seed_addr=String::from(format!("{}:{}",server_config.base_addr, - server_config.p2p_server_port)); + // point next servers at first seed + server_config.is_seeding = false; + server_config.seed_addr = String::from(format!( + "{}:{}", + server_config.base_addr, + server_config.p2p_server_port + )); - //And create 4 more, then let them run for a while - for i in 1..4 { - //fudge in some slowdown - server_config.miner_slowdown_in_millis = i*2; - pool.create_server(&mut server_config); - } + // And create 4 more, then let them run for a while + for i in 1..4 { + // fudge in some slowdown + server_config.miner_slowdown_in_millis = i * 2; + pool.create_server(&mut server_config); + } - pool.connect_all_peers(); + pool.connect_all_peers(); - let result_vec=pool.run_all_servers(); + let result_vec = pool.run_all_servers(); - //Check mining difficulty here?, though I'd think it's more valuable - //to simply output it. Can at least see the evolution of the difficulty target - //in the debug log output for now + // Check mining difficulty here?, though I'd think it's more valuable + // to simply output it. Can at least see the evolution of the difficulty target + // in the debug log output for now } -//TODO: Convert these tests to newer framework format +// TODO: Convert these tests to newer framework format /// Create a network of 5 servers and mine a block, verifying that the block /// gets propagated to all. - #[test] fn a_simulate_block_propagation() { - env_logger::init(); + env_logger::init(); + global::set_mining_mode(MiningParameterMode::AutomatedTesting); - let test_name_dir="test_servers/grin-prop"; - framework::clean_all_output(test_name_dir); + let test_name_dir = "grin-prop"; + framework::clean_all_output(test_name_dir); - let mut evtlp = reactor::Core::new().unwrap(); - let handle = evtlp.handle(); + let mut evtlp = reactor::Core::new().unwrap(); + let handle = evtlp.handle(); - let miner_config = grin::MinerConfig{ - enable_mining: true, - burn_reward: true, - use_cuckoo_miner: true, - cuckoo_miner_async_mode: None, - cuckoo_miner_plugin_dir: Some(String::from("../target/debug/deps")), - cuckoo_miner_plugin_type: Some(String::from("simple")), - ..Default::default() - }; + let miner_config = grin::MinerConfig { + enable_mining: true, + burn_reward: true, + use_cuckoo_miner: false, + cuckoo_miner_async_mode: None, + cuckoo_miner_plugin_dir: Some(String::from("../target/debug/deps")), + cuckoo_miner_plugin_type: Some(String::from("simple")), + ..Default::default() + }; - // instantiates 5 servers on different ports - let mut servers = vec![]; - for n in 0..5 { - let s = grin::Server::future( - grin::ServerConfig{ - api_http_addr: format!("127.0.0.1:{}", 19000+n), - db_root: format!("target/{}/grin-prop-{}", test_name_dir, n), - p2p_config: Some(p2p::P2PConfig{port: 18000+n, ..p2p::P2PConfig::default()}), - ..Default::default() - }, &handle).unwrap(); - servers.push(s); - } + // instantiates 5 servers on different ports + let mut servers = vec![]; + for n in 0..5 { + let s = grin::Server::future( + grin::ServerConfig { + api_http_addr: format!("127.0.0.1:{}", 19000 + n), + db_root: format!("target/{}/grin-prop-{}", test_name_dir, n), + p2p_config: Some(p2p::P2PConfig { + port: 18000 + n, + ..p2p::P2PConfig::default() + }), + ..Default::default() + }, + &handle, + ).unwrap(); + servers.push(s); + } - // everyone connects to everyone else - for n in 0..5 { - for m in 0..5 { - if m == n { continue } - let addr = format!("{}:{}", "127.0.0.1", 18000+m); - servers[n].connect_peer(addr.parse().unwrap()).unwrap(); - } - } + // everyone connects to everyone else + for n in 0..5 { + for m in 0..5 { + if m == n { + continue; + } + let addr = format!("{}:{}", "127.0.0.1", 18000 + m); + servers[n].connect_peer(addr.parse().unwrap()).unwrap(); + } + } - // start mining - servers[0].start_miner(miner_config); - let original_height = servers[0].head().height; + // start mining + servers[0].start_miner(miner_config); + let original_height = servers[0].head().height; - // monitor for a change of head on a different server and check whether - // chain height has changed - evtlp.run(change(&servers[4]).and_then(|tip| { - assert!(tip.height == original_height+1); - Ok(()) - })); + // monitor for a change of head on a different server and check whether + // chain height has changed + evtlp.run(change(&servers[4]).and_then(|tip| { + assert!(tip.height == original_height + 1); + Ok(()) + })); } @@ -239,79 +258,85 @@ fn a_simulate_block_propagation() { /// Creates 2 different disconnected servers, mine a few blocks on one, connect /// them and check that the 2nd gets all the blocks - #[test] fn simulate_full_sync() { - env_logger::init(); + env_logger::init(); + global::set_mining_mode(MiningParameterMode::AutomatedTesting); - let test_name_dir="test_servers/grin-sync"; - framework::clean_all_output(test_name_dir); + let test_name_dir = "grin-sync"; + framework::clean_all_output(test_name_dir); - let mut evtlp = reactor::Core::new().unwrap(); - let handle = evtlp.handle(); + let mut evtlp = reactor::Core::new().unwrap(); + let handle = evtlp.handle(); - let miner_config = grin::MinerConfig{ - enable_mining: true, - burn_reward: true, - use_cuckoo_miner: true, - cuckoo_miner_async_mode: Some(false), - cuckoo_miner_plugin_dir: Some(String::from("../target/debug/deps")), - cuckoo_miner_plugin_type: Some(String::from("simple")), - ..Default::default() - }; + let miner_config = grin::MinerConfig { + enable_mining: true, + burn_reward: true, + use_cuckoo_miner: false, + cuckoo_miner_async_mode: Some(false), + cuckoo_miner_plugin_dir: Some(String::from("../target/debug/deps")), + cuckoo_miner_plugin_type: Some(String::from("simple")), + ..Default::default() + }; - // instantiates 2 servers on different ports - let mut servers = vec![]; - for n in 0..2 { - let s = grin::Server::future( - grin::ServerConfig{ - db_root: format!("target/{}/grin-sync-{}", test_name_dir, n), - p2p_config: Some(p2p::P2PConfig{port: 11000+n, ..p2p::P2PConfig::default()}), - ..Default::default() - }, &handle).unwrap(); - servers.push(s); - } + // instantiates 2 servers on different ports + let mut servers = vec![]; + for n in 0..2 { + let s = grin::Server::future( + grin::ServerConfig { + db_root: format!("target/{}/grin-sync-{}", test_name_dir, n), + p2p_config: Some(p2p::P2PConfig { + port: 11000 + n, + ..p2p::P2PConfig::default() + }), + ..Default::default() + }, + &handle, + ).unwrap(); + servers.push(s); + } - // mine a few blocks on server 1 - servers[0].start_miner(miner_config); - thread::sleep(time::Duration::from_secs(45)); + // mine a few blocks on server 1 + servers[0].start_miner(miner_config); + thread::sleep(time::Duration::from_secs(5)); - // connect 1 and 2 - let addr = format!("{}:{}", "127.0.0.1", 11001); - servers[0].connect_peer(addr.parse().unwrap()).unwrap(); + // connect 1 and 2 + let addr = format!("{}:{}", "127.0.0.1", 11001); + servers[0].connect_peer(addr.parse().unwrap()).unwrap(); - // 2 should get blocks - evtlp.run(change(&servers[1])); + // 2 should get blocks + evtlp.run(change(&servers[1])); } -// Builds the change future, monitoring for a change of head on the provided server +// Builds the change future, monitoring for a change of head on the provided +// server fn change<'a>(s: &'a grin::Server) -> HeadChange<'a> { - let start_head = s.head(); - HeadChange { - server: s, - original: start_head, - } + let start_head = s.head(); + HeadChange { + server: s, + original: start_head, + } } /// Future that monitors when a server has had its head updated. Current /// implementation isn't optimized, only use for tests. struct HeadChange<'a> { - server: &'a grin::Server, - original: chain::Tip, + server: &'a grin::Server, + original: chain::Tip, } impl<'a> Future for HeadChange<'a> { - type Item = chain::Tip; - type Error = (); + type Item = chain::Tip; + type Error = (); - fn poll(&mut self) -> Poll { - let new_head = self.server.head(); - if new_head.last_block_h != self.original.last_block_h { - Ok(Async::Ready(new_head)) - } else { - // egregious polling, asking the task to schedule us every iteration - park().unpark(); - Ok(Async::NotReady) - } - } + fn poll(&mut self) -> Poll { + let new_head = self.server.head(); + if new_head.last_block_h != self.original.last_block_h { + Ok(Async::Ready(new_head)) + } else { + // egregious polling, asking the task to schedule us every iteration + park().unpark(); + Ok(Async::NotReady) + } + } } diff --git a/src/bin/grin.rs b/src/bin/grin.rs index e8c8ce24..d133f35e 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -27,6 +27,7 @@ extern crate grin_api as api; extern crate grin_grin as grin; extern crate grin_wallet as wallet; extern crate grin_config as config; +extern crate grin_core as core; extern crate secp256k1zkp as secp; use std::thread; @@ -41,12 +42,16 @@ use secp::Secp256k1; use config::GlobalConfig; use wallet::WalletConfig; +use core::global; fn start_from_config_file(mut global_config: GlobalConfig) { info!( "Starting the Grin server from configuration file at {}", global_config.config_file_path.unwrap().to_str().unwrap() ); + + global::set_mining_mode(global_config.members.as_mut().unwrap().server.clone().mining_parameter_mode.unwrap()); + grin::Server::start(global_config.members.as_mut().unwrap().server.clone()).unwrap(); loop { thread::sleep(Duration::from_secs(60));