mirror of
https://github.com/mimblewimble/grin.git
synced 2025-05-08 10:11:14 +03:00
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
This commit is contained in:
parent
d32ab967f0
commit
131ea2f799
22 changed files with 508 additions and 357 deletions
|
@ -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"
|
||||
|
|
|
@ -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<Mutex<Tip>>,
|
||||
block_process_lock: Arc<Mutex<bool>>,
|
||||
orphans: Arc<Mutex<VecDeque<(Options, Block)>>>,
|
||||
|
||||
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<ChainAdapter>,
|
||||
) -> Result<Chain, Error> {
|
||||
|
@ -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(),
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<u32>,
|
||||
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<Ordering> {
|
||||
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<u32>) -> 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<u64> {
|
||||
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<u32> {
|
||||
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<Proof, Error> {
|
||||
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<W: Writer>(&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(())
|
||||
}
|
||||
|
|
|
@ -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![],
|
||||
|
|
86
core/src/global.rs
Normal file
86
core/src/global.rs
Normal file
|
@ -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<MiningParameterMode> = 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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<Cuckoo>,
|
||||
graph: Vec<u32>,
|
||||
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<u32>),
|
||||
/// 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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T: MiningWorker>(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));
|
||||
}
|
||||
}
|
||||
|
|
11
grin.toml
11
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
|
||||
|
|
|
@ -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<chain::Chain>,
|
||||
peer_store: Arc<PeerStore>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
|
@ -192,13 +193,11 @@ impl NetAdapter for NetToChainAdapter {
|
|||
}
|
||||
|
||||
impl NetToChainAdapter {
|
||||
pub fn new(test_mode: bool,
|
||||
chain_ref: Arc<chain::Chain>,
|
||||
pub fn new(chain_ref: Arc<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
peer_store: Arc<PeerStore>)
|
||||
-> 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T: MiningWorker>(&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,
|
||||
|
|
|
@ -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<Proof, cuckoo::Error> {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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<MiningParameterMode>,
|
||||
|
||||
/// 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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")),
|
||||
|
|
|
@ -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<Self::Item, Self::Error> {
|
||||
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<Self::Item, Self::Error> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Add table
Reference in a new issue