From 4c6a193e01d0e429e7e8cea829c65a2e6659384c Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Tue, 24 Apr 2018 09:18:24 +0100 Subject: [PATCH] [WIP] Miner removal (#979) * Beginning to remove in-process miner * rustfmt * rustfmt * rustfmt * rustfmt * remove pow crate and put remnants into core * rustfmt * fix test compilation in core and chain * rustfmt * Updating server tests to use test miner * rustfmt * rustfmt * remove pow from test matrix * adding basic stratum stats to TUI * run stratum server at all times, and halt messages while syncing * fix core tests * add ability to run internal test miner for cuckoo 16 testing * modify build instructions --- .travis.yml | 1 - Cargo.lock | 63 --- Cargo.toml | 1 - chain/Cargo.toml | 2 - chain/src/chain.rs | 4 +- chain/src/pipe.rs | 4 +- chain/tests/data_file_integrity.rs | 22 +- chain/tests/mine_simple_chain.rs | 24 +- chain/tests/store_indices.rs | 4 +- chain/tests/test_coinbase_maturity.rs | 34 +- config/Cargo.toml | 1 - config/src/config.rs | 14 +- config/src/lib.rs | 3 +- config/src/types.rs | 5 +- core/src/core/block.rs | 1 + core/src/core/mod.rs | 2 +- core/src/lib.rs | 1 + {pow/src => core/src/pow}/cuckoo.rs | 67 ++-- pow/src/lib.rs => core/src/pow/mod.rs | 93 ++--- {pow/src => core/src/pow}/siphash.rs | 0 doc/build.md | 21 +- grin.toml | 175 ++------- pow/Cargo.toml | 28 -- pow/src/plugin.rs | 226 ----------- pow/src/types.rs | 89 ----- servers/Cargo.toml | 1 - servers/src/common/stats.rs | 76 +--- servers/src/common/types.rs | 48 ++- servers/src/grin/server.rs | 99 ++--- servers/src/lib.rs | 7 +- servers/src/mining/mine_block.rs | 48 +-- servers/src/mining/miner.rs | 544 -------------------------- servers/src/mining/mod.rs | 2 +- servers/src/mining/stratumserver.rs | 31 +- servers/src/mining/test_miner.rs | 203 ++++++++++ servers/tests/api.rs | 3 +- servers/tests/dandelion.rs | 3 +- servers/tests/framework/mod.rs | 56 +-- servers/tests/simulnet.rs | 15 +- servers/tests/stratum.rs | 19 +- servers/tests/wallet.rs | 3 +- src/bin/grin.rs | 12 +- src/bin/tui/mining.rs | 254 ++++++------ src/bin/tui/mod.rs | 1 - src/bin/tui/status.rs | 8 +- src/bin/tui/table.rs | 27 +- 46 files changed, 661 insertions(+), 1684 deletions(-) rename {pow/src => core/src/pow}/cuckoo.rs (90%) rename pow/src/lib.rs => core/src/pow/mod.rs (62%) rename {pow/src => core/src/pow}/siphash.rs (100%) delete mode 100644 pow/Cargo.toml delete mode 100644 pow/src/plugin.rs delete mode 100644 pow/src/types.rs delete mode 100644 servers/src/mining/miner.rs create mode 100644 servers/src/mining/test_miner.rs diff --git a/.travis.yml b/.travis.yml index e4ef352ed..e4838b887 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ env: - TEST_DIR=wallet - TEST_DIR=p2p - TEST_DIR=api - - TEST_DIR=pow - TEST_DIR=keychain - TEST_DIR=core - TEST_DIR=util diff --git a/Cargo.lock b/Cargo.lock index 76eb88e91..3272243bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -391,29 +391,6 @@ dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cuckoo_miner" -version = "0.1.0" -source = "git+https://github.com/mimblewimble/cuckoo-miner?tag=grin_integration_25#40cb3146a56d338452b350bbfab18bf0805d1d9d" -dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cursive" version = "0.8.2-alpha.0" @@ -546,11 +523,6 @@ dependencies = [ "miniz_oxide_c_api 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fs_extra" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -615,7 +587,6 @@ dependencies = [ "grin_core 0.2.0", "grin_keychain 0.2.0", "grin_p2p 0.2.0", - "grin_pow 0.2.0", "grin_servers 0.2.0", "grin_util 0.2.0", "grin_wallet 0.2.0", @@ -660,7 +631,6 @@ dependencies = [ "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "grin_core 0.2.0", "grin_keychain 0.2.0", - "grin_pow 0.2.0", "grin_store 0.2.0", "grin_util 0.2.0", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -676,7 +646,6 @@ name = "grin_config" version = "0.2.0" dependencies = [ "grin_p2p 0.2.0", - "grin_pow 0.2.0", "grin_servers 0.2.0", "grin_util 0.2.0", "grin_wallet 0.2.0", @@ -753,22 +722,6 @@ dependencies = [ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "grin_pow" -version = "0.2.0" -dependencies = [ - "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "cuckoo_miner 0.1.0 (git+https://github.com/mimblewimble/cuckoo-miner?tag=grin_integration_25)", - "grin_core 0.2.0", - "grin_util 0.2.0", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "slog 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "grin_servers" version = "0.2.0" @@ -782,7 +735,6 @@ dependencies = [ "grin_keychain 0.2.0", "grin_p2p 0.2.0", "grin_pool 0.2.0", - "grin_pow 0.2.0", "grin_store 0.2.0", "grin_util 0.2.0", "grin_wallet 0.2.0", @@ -1590,18 +1542,6 @@ dependencies = [ "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rust-crypto" -version = "0.2.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc-demangle" version = "0.1.7" @@ -2413,7 +2353,6 @@ dependencies = [ "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum csv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7ef22b37c7a51c564a365892c012dc0271221fdcc64c69b19ba4d6fa8bd96d9c" -"checksum cuckoo_miner 0.1.0 (git+https://github.com/mimblewimble/cuckoo-miner?tag=grin_integration_25)" = "" "checksum cursive 0.8.2-alpha.0 (git+https://github.com/yeastplume/Cursive?tag=grin_integration_1)" = "" "checksum daemonize 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0239832c1b4ca406d5ec73728cf4c7336d25cf85dd32db9e047e9e706ee0e935" "checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d" @@ -2430,7 +2369,6 @@ dependencies = [ "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" -"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f32b9e9aaa890fe8b9453b27ebbf3d11136a5ce59032500effd0e707bbcd80" @@ -2522,7 +2460,6 @@ dependencies = [ "checksum rocksdb 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7f893478c2c158fb87f574245888209153278d5b6d990f07df2e4bb7a33416eb" "checksum route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3255338088df8146ba63d60a9b8e3556f1146ce2973bc05a75181a42ce2256" "checksum router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b1797ff166029cb632237bb5542696e54961b4cf75a324c6f05c9cf0584e4e" -"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" diff --git a/Cargo.toml b/Cargo.toml index e24d83a6d..490fd106b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ grin_config = { path = "./config" } grin_core = { path = "./core" } grin_keychain = { path = "./keychain" } grin_p2p = { path = "./p2p"} -grin_pow = { path = "./pow"} grin_servers = { path = "./servers" } grin_util = { path = "./util"} grin_wallet = { path = "./wallet" } diff --git a/chain/Cargo.toml b/chain/Cargo.toml index 521b874ed..d9ec2d432 100644 --- a/chain/Cargo.toml +++ b/chain/Cargo.toml @@ -22,5 +22,3 @@ grin_util = { path = "../util" } [dev-dependencies] env_logger = "0.3" rand = "0.3" - -grin_pow = { path = "../pow" } diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 71e3f0685..ba5a7c8dd 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -131,7 +131,7 @@ pub struct Chain { txhashset: Arc>, // POW verification function - pow_verifier: fn(&BlockHeader, u32) -> bool, + pow_verifier: fn(&BlockHeader, u8) -> bool, } unsafe impl Sync for Chain {} @@ -157,7 +157,7 @@ impl Chain { db_root: String, adapter: Arc, genesis: Block, - pow_verifier: fn(&BlockHeader, u32) -> bool, + pow_verifier: fn(&BlockHeader, u8) -> bool, ) -> Result { let chain_store = store::ChainKVStore::new(db_root.clone())?; diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index da381b470..dd5a5df26 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -39,7 +39,7 @@ pub struct BlockContext { /// The head pub head: Tip, /// The POW verification function - pub pow_verifier: fn(&BlockHeader, u32) -> bool, + pub pow_verifier: fn(&BlockHeader, u8) -> bool, /// MMR sum tree states pub txhashset: Arc>, } @@ -233,7 +233,7 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E } if !ctx.opts.contains(Options::SKIP_POW) { - let n = global::sizeshift() as u32; + let n = global::sizeshift(); if !(ctx.pow_verifier)(header, n) { error!( LOGGER, diff --git a/chain/tests/data_file_integrity.rs b/chain/tests/data_file_integrity.rs index a1f2cd032..f88fa3daa 100644 --- a/chain/tests/data_file_integrity.rs +++ b/chain/tests/data_file_integrity.rs @@ -16,7 +16,6 @@ extern crate env_logger; extern crate grin_chain as chain; extern crate grin_core as core; extern crate grin_keychain as keychain; -extern crate grin_pow as pow; extern crate grin_util as util; extern crate rand; extern crate time; @@ -34,7 +33,7 @@ use core::global::ChainTypes; use keychain::Keychain; -use pow::{cuckoo, types, MiningWorker}; +use core::pow; fn clean_output_dir(dir_name: &str) { let _ = fs::remove_dir_all(dir_name); @@ -44,7 +43,7 @@ fn setup(dir_name: &str) -> Chain { util::init_test_logger(); clean_output_dir(dir_name); global::set_mining_mode(ChainTypes::AutomatedTesting); - let genesis_block = pow::mine_genesis_block(None).unwrap(); + let genesis_block = pow::mine_genesis_block().unwrap(); chain::Chain::init( dir_name.to_string(), Arc::new(NoopAdapter {}), @@ -70,19 +69,6 @@ fn data_files() { let chain = setup(chain_dir); let keychain = Keychain::from_random_seed().unwrap(); - // mine and add a few blocks - let mut miner_config = types::MinerConfig { - enable_mining: true, - burn_reward: true, - ..Default::default() - }; - miner_config.miner_plugin_dir = Some(String::from("../target/debug/deps")); - - 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 difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -94,10 +80,10 @@ fn data_files() { chain.set_txhashset_roots(&mut b, false).unwrap(); pow::pow_size( - &mut cuckoo_miner, &mut b.header, difficulty, - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); // let prev_bhash = b.header.previous; diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index 741f1d94f..cdf2502fa 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -16,7 +16,6 @@ extern crate env_logger; extern crate grin_chain as chain; extern crate grin_core as core; extern crate grin_keychain as keychain; -extern crate grin_pow as pow; extern crate grin_util as util; extern crate rand; extern crate time; @@ -35,7 +34,7 @@ use core::global::ChainTypes; use keychain::Keychain; -use pow::{cuckoo, types, MiningWorker}; +use core::pow; fn clean_output_dir(dir_name: &str) { let _ = fs::remove_dir_all(dir_name); @@ -45,7 +44,7 @@ fn setup(dir_name: &str) -> Chain { let _ = env_logger::init(); clean_output_dir(dir_name); global::set_mining_mode(ChainTypes::AutomatedTesting); - let genesis_block = pow::mine_genesis_block(None).unwrap(); + let genesis_block = pow::mine_genesis_block().unwrap(); chain::Chain::init( dir_name.to_string(), Arc::new(NoopAdapter {}), @@ -59,19 +58,6 @@ fn mine_empty_chain() { let chain = setup(".grin"); let keychain = Keychain::from_random_seed().unwrap(); - // mine and add a few blocks - let mut miner_config = types::MinerConfig { - enable_mining: true, - burn_reward: true, - ..Default::default() - }; - miner_config.miner_plugin_dir = Some(String::from("../target/debug/deps")); - - 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 difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -83,10 +69,10 @@ fn mine_empty_chain() { chain.set_txhashset_roots(&mut b, false).unwrap(); pow::pow_size( - &mut cuckoo_miner, &mut b.header, difficulty, - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); let bhash = b.hash(); @@ -438,7 +424,7 @@ fn prepare_block_nosum( #[ignore] fn actual_diff_iter_output() { global::set_mining_mode(ChainTypes::AutomatedTesting); - let genesis_block = pow::mine_genesis_block(None).unwrap(); + let genesis_block = pow::mine_genesis_block().unwrap(); let chain = chain::Chain::init( "../.grin".to_string(), Arc::new(NoopAdapter {}), diff --git a/chain/tests/store_indices.rs b/chain/tests/store_indices.rs index e317435c4..205970622 100644 --- a/chain/tests/store_indices.rs +++ b/chain/tests/store_indices.rs @@ -16,7 +16,6 @@ extern crate env_logger; extern crate grin_chain as chain; extern crate grin_core as core; extern crate grin_keychain as keychain; -extern crate grin_pow as pow; extern crate rand; use std::fs; @@ -29,6 +28,7 @@ use core::core::target::Difficulty; use keychain::Keychain; use core::global; use core::global::ChainTypes; +use core::pow; fn clean_output_dir(dir_name: &str) { let _ = fs::remove_dir_all(dir_name); @@ -47,7 +47,7 @@ fn test_various_store_indices() { &chain::store::ChainKVStore::new(chain_dir.to_string()).unwrap() as &ChainStore; global::set_mining_mode(ChainTypes::AutomatedTesting); - let genesis = pow::mine_genesis_block(None).unwrap(); + let genesis = pow::mine_genesis_block().unwrap(); chain_store.save_block(&genesis).unwrap(); chain_store .setup_height(&genesis.header, &Tip::new(genesis.hash())) diff --git a/chain/tests/test_coinbase_maturity.rs b/chain/tests/test_coinbase_maturity.rs index c1b5f1c25..fc45cec94 100644 --- a/chain/tests/test_coinbase_maturity.rs +++ b/chain/tests/test_coinbase_maturity.rs @@ -16,7 +16,6 @@ extern crate env_logger; extern crate grin_chain as chain; extern crate grin_core as core; extern crate grin_keychain as keychain; -extern crate grin_pow as pow; extern crate rand; extern crate time; @@ -34,7 +33,7 @@ use core::global::ChainTypes; use keychain::Keychain; -use pow::{cuckoo, types, MiningWorker}; +use core::pow; fn clean_output_dir(dir_name: &str) { let _ = fs::remove_dir_all(dir_name); @@ -46,7 +45,7 @@ fn test_coinbase_maturity() { clean_output_dir(".grin"); global::set_mining_mode(ChainTypes::AutomatedTesting); - let genesis_block = pow::mine_genesis_block(None).unwrap(); + let genesis_block = pow::mine_genesis_block().unwrap(); let chain = chain::Chain::init( ".grin".to_string(), @@ -55,19 +54,6 @@ fn test_coinbase_maturity() { pow::verify_size, ).unwrap(); - let mut miner_config = types::MinerConfig { - enable_mining: true, - burn_reward: true, - ..Default::default() - }; - miner_config.miner_plugin_dir = Some(String::from("../target/debug/deps")); - - let mut cuckoo_miner = cuckoo::Miner::new( - consensus::EASINESS, - global::sizeshift() as u32, - global::proofsize(), - ); - let prev = chain.head_header().unwrap(); let keychain = Keychain::from_random_seed().unwrap(); @@ -85,10 +71,10 @@ fn test_coinbase_maturity() { chain.set_txhashset_roots(&mut block, false).unwrap(); pow::pow_size( - &mut cuckoo_miner, &mut block.header, difficulty, - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); assert_eq!(block.outputs.len(), 1); @@ -145,10 +131,10 @@ fn test_coinbase_maturity() { } pow::pow_size( - &mut cuckoo_miner, &mut block.header, difficulty, - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); // mine enough blocks to increase the height sufficiently for @@ -168,10 +154,10 @@ fn test_coinbase_maturity() { chain.set_txhashset_roots(&mut block, false).unwrap(); pow::pow_size( - &mut cuckoo_miner, &mut block.header, difficulty, - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); chain.process_block(block, chain::Options::MINE).unwrap(); @@ -203,10 +189,10 @@ fn test_coinbase_maturity() { chain.set_txhashset_roots(&mut block, false).unwrap(); pow::pow_size( - &mut cuckoo_miner, &mut block.header, difficulty, - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); let result = chain.process_block(block, chain::Options::MINE); diff --git a/config/Cargo.toml b/config/Cargo.toml index e190c6a19..dd76e934f 100644 --- a/config/Cargo.toml +++ b/config/Cargo.toml @@ -12,6 +12,5 @@ toml = "0.4" grin_servers = { path = "../servers" } grin_p2p = { path = "../p2p" } -grin_pow = { path = "../pow"} grin_util = { path = "../util" } grin_wallet = { path = "../wallet"} diff --git a/config/src/config.rs b/config/src/config.rs index 06cbed429..98a1ed258 100644 --- a/config/src/config.rs +++ b/config/src/config.rs @@ -20,8 +20,7 @@ use std::path::PathBuf; use std::fs::File; use toml; -use servers::ServerConfig; -use pow::types::MinerConfig; +use servers::{ServerConfig, StratumServerConfig}; use util::LoggingConfig; use types::{ConfigError, ConfigMembers, GlobalConfig}; use wallet::WalletConfig; @@ -38,7 +37,7 @@ impl Default for ConfigMembers { fn default() -> ConfigMembers { ConfigMembers { server: ServerConfig::default(), - mining: Some(MinerConfig::default()), + mining_server: Some(StratumServerConfig::default()), logging: Some(LoggingConfig::default()), wallet: WalletConfig::default(), } @@ -136,7 +135,7 @@ impl GlobalConfig { Ok(mut gc) => { // Put the struct back together, because the config // file was flattened a bit - gc.server.mining_config = gc.mining.clone(); + gc.server.stratum_mining_config = gc.mining_server.clone(); self.using_config_file = true; self.members = Some(gc); return Ok(self); @@ -177,13 +176,14 @@ impl GlobalConfig { }*/ /// Enable mining - pub fn mining_enabled(&mut self) -> bool { + pub fn stratum_enabled(&mut self) -> bool { return self.members .as_mut() .unwrap() - .mining + .mining_server .as_mut() .unwrap() - .enable_mining; + .enable_stratum_server + .unwrap(); } } diff --git a/config/src/lib.rs b/config/src/lib.rs index 4cb3d4532..8306a84ed 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -25,9 +25,8 @@ extern crate serde; extern crate serde_derive; extern crate toml; -extern crate grin_servers as servers; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; diff --git a/config/src/types.rs b/config/src/types.rs index c2dd20b57..59eac6e60 100644 --- a/config/src/types.rs +++ b/config/src/types.rs @@ -18,8 +18,7 @@ use std::path::PathBuf; use std::io; use std::fmt; -use servers::ServerConfig; -use pow::types::MinerConfig; +use servers::{ServerConfig, StratumServerConfig}; use util::LoggingConfig; use wallet::WalletConfig; @@ -98,7 +97,7 @@ pub struct ConfigMembers { #[serde(default)] pub server: ServerConfig, /// Mining config - pub mining: Option, + pub mining_server: Option, /// Logging config pub logging: Option, diff --git a/core/src/core/block.rs b/core/src/core/block.rs index d1d78033c..7d2751d57 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -1079,6 +1079,7 @@ mod test { #[test] fn block_10_tx_serialized_size() { let keychain = Keychain::from_random_seed().unwrap(); + global::set_mining_mode(global::ChainTypes::Mainnet); let mut txs = vec![]; for _ in 0..10 { diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 5d1684dcd..08eda1698 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -234,7 +234,7 @@ mod test { use core::block::Error::KernelLockHeight; use ser; use keychain; - use keychain::{BlindingFactor, Keychain}; + use keychain::Keychain; #[test] pub fn test_amount_to_hr() { diff --git a/core/src/lib.rs b/core/src/lib.rs index 8d4bc2a34..e06a47bf8 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -47,3 +47,4 @@ pub mod core; pub mod genesis; pub mod ser; pub mod global; +pub mod pow; diff --git a/pow/src/cuckoo.rs b/core/src/pow/cuckoo.rs similarity index 90% rename from pow/src/cuckoo.rs rename to core/src/pow/cuckoo.rs index 340136e2c..c983bbdc6 100644 --- a/pow/src/cuckoo.rs +++ b/core/src/pow/cuckoo.rs @@ -22,9 +22,8 @@ use std::cmp; use blake2; -use core::core::Proof; -use siphash::siphash24; -use MiningWorker; +use core::Proof; +use pow::siphash::siphash24; const MAXPATHLEN: usize = 8192; @@ -55,7 +54,7 @@ impl Cuckoo { /// Initializes a new Cuckoo Cycle setup, using the provided byte array to /// generate a seed. In practice for PoW applications the byte array is a /// serialized block header. - pub fn new(header: &[u8], sizeshift: u32) -> Cuckoo { + pub fn new(header: &[u8], sizeshift: u8) -> Cuckoo { let size = 1 << sizeshift; let hashed = blake2::blake2b::blake2b(32, &[], header); let hashed = hashed.as_bytes(); @@ -148,32 +147,8 @@ impl Cuckoo { pub struct Miner { easiness: u64, proof_size: usize, - cuckoo: Option, + cuckoo: Cuckoo, graph: Vec, - sizeshift: u32, -} - -impl MiningWorker for Miner { - /// Creates a new miner - fn new(ease: u32, 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; - Miner { - easiness: easiness, - cuckoo: None, - graph: graph, - sizeshift: sizeshift, - proof_size: proof_size, - } - } - - fn mine(&mut self, header: &[u8]) -> Result { - let size = 1 << self.sizeshift; - self.graph = vec![0; size + 1]; - self.cuckoo = Some(Cuckoo::new(header, self.sizeshift)); - self.mine_impl() - } } /// What type of cycle we have found? @@ -187,13 +162,27 @@ enum CycleSol { } impl Miner { + /// Creates a new miner + pub fn new(header: &[u8], ease: u32, proof_size: usize, sizeshift: u8) -> Miner { + let cuckoo = Cuckoo::new(header, sizeshift); + let size = 1 << sizeshift; + let graph = vec![0; size + 1]; + let easiness = (ease as u64) * (size as u64) / 100; + Miner { + easiness: easiness, + cuckoo: cuckoo, + graph: graph, + proof_size: proof_size, + } + } + /// Searches for a solution - pub fn mine_impl(&mut self) -> Result { + pub fn mine(&mut self) -> Result { let mut us = [0; MAXPATHLEN]; let mut vs = [0; MAXPATHLEN]; for nonce in 0..self.easiness { - us[0] = self.cuckoo.as_mut().unwrap().new_node(nonce, 0) as u32; - vs[0] = self.cuckoo.as_mut().unwrap().new_node(nonce, 1) as u32; + us[0] = self.cuckoo.new_node(nonce, 0) as u32; + vs[0] = self.cuckoo.new_node(nonce, 1) as u32; let u = self.graph[us[0] as usize]; let v = self.graph[vs[0] as usize]; if us[0] == 0 { @@ -292,7 +281,7 @@ impl Miner { let mut n = 0; let mut sol = vec![0; self.proof_size]; for nonce in 0..self.easiness { - let edge = self.cuckoo.as_mut().unwrap().new_edge(nonce); + let edge = self.cuckoo.new_edge(nonce); if cycle.contains(&edge) { sol[n] = nonce as u32; n += 1; @@ -317,7 +306,7 @@ fn u8_to_u64(p: &[u8], i: usize) -> u64 { #[cfg(test)] mod test { use super::*; - use core::core::Proof; + use core::Proof; static V1: [u32; 42] = [ 0x3bbd, 0x4e96, 0x1013b, 0x1172b, 0x1371b, 0x13e6a, 0x1aaa6, 0x1b575, 0x1e237, 0x1ee88, @@ -355,13 +344,13 @@ mod test { /// generated by other implementations. #[test] fn mine20_vectors() { - let nonces1 = Miner::new(75, 20, 42).mine(&[49]).unwrap(); + let nonces1 = Miner::new(&[49], 75, 42, 20).mine().unwrap(); assert_eq!(Proof::new(V1.to_vec()), nonces1); - let nonces2 = Miner::new(70, 20, 42).mine(&[50]).unwrap(); + let nonces2 = Miner::new(&[50], 70, 42, 20).mine().unwrap(); assert_eq!(Proof::new(V2.to_vec()), nonces2); - let nonces3 = Miner::new(70, 20, 42).mine(&[51]).unwrap(); + let nonces3 = Miner::new(&[51], 70, 42, 20).mine().unwrap(); assert_eq!(Proof::new(V3.to_vec()), nonces3); } @@ -399,13 +388,13 @@ mod test { // cuckoo20 for n in 1..5 { let h = [n; 32]; - let nonces = Miner::new(75, 20, 42).mine(&h).unwrap(); + let nonces = Miner::new(&h, 75, 42, 20).mine().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, 42).mine(&h).unwrap(); + let nonces = Miner::new(&h, 75, 42, 18).mine().unwrap(); assert!(Cuckoo::new(&h, 18).verify(nonces, 75)); } } diff --git a/pow/src/lib.rs b/core/src/pow/mod.rs similarity index 62% rename from pow/src/lib.rs rename to core/src/pow/mod.rs index d430d8109..f80cbd544 100644 --- a/pow/src/lib.rs +++ b/core/src/pow/mod.rs @@ -29,62 +29,31 @@ #![warn(missing_docs)] extern crate blake2_rfc as blake2; -#[macro_use] -extern crate lazy_static; extern crate rand; extern crate serde; -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate slog; extern crate time; -extern crate grin_core as core; extern crate grin_util as util; -// Re-export (mostly for stat collection) -pub extern crate cuckoo_miner as cuckoo_; -pub use cuckoo_ as cuckoo_miner; - mod siphash; -pub mod plugin; pub mod cuckoo; -pub mod types; -use core::consensus; -use core::core::BlockHeader; -use core::core::Proof; -use core::core::target::Difficulty; -use core::global; -use core::genesis; -use cuckoo::{Cuckoo, Error}; - -/// Should be implemented by anything providing mining services -/// - -pub trait MiningWorker { - /// This only sets parameters and does initialisation work now - fn new(ease: u32, sizeshift: u32, proof_size: usize) -> Self - where - Self: Sized; - - /// Actually perform a mining attempt on the given input and - /// return a proof if found - fn mine(&mut self, header: &[u8]) -> Result; -} +use consensus; +use core::{Block, BlockHeader}; +use core::target::Difficulty; +use global; +use genesis; +use pow::cuckoo::{Cuckoo, Error}; /// Validates the proof of work of a given header, and that the proof of work /// satisfies the requirements of the header. -pub fn verify_size(bh: &BlockHeader, cuckoo_sz: u32) -> bool { +pub fn verify_size(bh: &BlockHeader, cuckoo_sz: u8) -> bool { Cuckoo::new(&bh.pre_pow_hash()[..], cuckoo_sz) .verify(bh.pow.clone(), consensus::EASINESS as u64) } -/// Mines a genesis block, using the config specified miner if specified. -/// Otherwise, uses the internal miner -pub fn mine_genesis_block( - miner_config: Option, -) -> Result { +/// Mines a genesis block using the internal miner +pub fn mine_genesis_block() -> Result { let mut gen = genesis::genesis_testnet2(); if global::is_user_testing_mode() || global::is_automated_testing_mode() { gen = genesis::genesis_dev(); @@ -94,31 +63,21 @@ pub fn mine_genesis_block( // total_difficulty on the genesis header *is* the difficulty of that block let genesis_difficulty = gen.header.total_difficulty.clone(); - let sz = global::sizeshift() as u32; + let sz = global::sizeshift(); let proof_size = global::proofsize(); - let mut miner: Box = match miner_config { - Some(c) => if c.enable_mining { - let mut p = plugin::PluginMiner::new(consensus::EASINESS, sz, proof_size); - p.init(c.clone()); - Box::new(p) - } else { - Box::new(cuckoo::Miner::new(consensus::EASINESS, sz, proof_size)) - }, - None => Box::new(cuckoo::Miner::new(consensus::EASINESS, sz, proof_size)), - }; - pow_size(&mut *miner, &mut gen.header, genesis_difficulty, sz as u32).unwrap(); + pow_size(&mut gen.header, genesis_difficulty, proof_size, sz).unwrap(); Ok(gen) } /// Runs a proof of work computation over the provided block using the provided /// Mining Worker, until the required difficulty target is reached. May take a /// while for a low target... -pub fn pow_size( - miner: &mut T, +pub fn pow_size( bh: &mut BlockHeader, diff: Difficulty, - _: u32, + proof_size: usize, + sz: u8, ) -> Result<(), Error> { let start_nonce = bh.nonce; @@ -135,7 +94,9 @@ pub fn pow_size( // if we found a cycle (not guaranteed) and the proof hash is higher that the // diff, we're all good - if let Ok(proof) = miner.mine(&pow_hash[..]) { + if let Ok(proof) = + cuckoo::Miner::new(&pow_hash[..], consensus::EASINESS, proof_size, sz).mine() + { if proof.clone().to_difficulty() >= diff { bh.pow = proof.clone(); return Ok(()); @@ -157,28 +118,24 @@ pub fn pow_size( mod test { use super::*; use global; - use core::core::target::Difficulty; - use core::genesis; - use core::global::ChainTypes; + use core::target::Difficulty; + use genesis; + use global::ChainTypes; + /// We'll be generating genesis blocks differently + #[ignore] #[test] fn genesis_pow() { - global::set_mining_mode(ChainTypes::AutomatedTesting); let mut b = genesis::genesis_dev(); b.header.nonce = 485; - let mut internal_miner = cuckoo::Miner::new( - consensus::EASINESS, - global::sizeshift() as u32, - global::proofsize(), - ); pow_size( - &mut internal_miner, &mut b.header, Difficulty::one(), - global::sizeshift() as u32, + global::proofsize(), + global::sizeshift(), ).unwrap(); assert!(b.header.nonce != 310); assert!(b.header.pow.clone().to_difficulty() >= Difficulty::one()); - assert!(verify_size(&b.header, global::sizeshift() as u32)); + assert!(verify_size(&b.header, global::sizeshift())); } } diff --git a/pow/src/siphash.rs b/core/src/pow/siphash.rs similarity index 100% rename from pow/src/siphash.rs rename to core/src/pow/siphash.rs diff --git a/doc/build.md b/doc/build.md index add9a0493..79b5a8598 100644 --- a/doc/build.md +++ b/doc/build.md @@ -9,12 +9,15 @@ What's working so far? * Linux x86_64 and MacOS [grin + mining + development] * Not Windows 10 yet [grin kind-of builds. No mining yet. Help wanted!] +## Mining in Grin + +Please note that all mining functions for Grin have moved into a separate, standalone package called +[grin_miner](https://github.com/mimblewimble/grin-miner). Once your Grin code node is up and running, +you can start mining by building and runing grin-miner against your running Grin node. ## Requirements -But basically: - rust 1.24+ (use [rustup]((https://www.rustup.rs/))- i.e. `curl https://sh.rustup.rs -sSf | sh; source $HOME/.cargo/env`) -- cmake 3.2+ (for [Cuckoo mining plugins]((https://github.com/mimblewimble/cuckoo-miner))) - rocksdb + libs for compiling rocksdb: - clang (clanglib or clang-devel or libclang-dev) - llvm (Fedora llvm-devel, Debian llvm-dev) @@ -39,20 +42,6 @@ as a validating node on your low powered device might be possible. To cross-compile `grin` on a x86 Linux platform and produce ARM binaries, say, for a Raspberry Pi. - -### Building the Cuckoo-Miner plugins - -Building `grin_pow` might fail if you're not on a x86_64 system, -because that crate also builds external Cuckoo mining plugins. - -To avoid building mining plugins, ensure your `pow/Cargo.toml` has a line in section `[dependencies.cuckoo_miner]` - -``` -features=["no-plugin-build"] -``` - -and that it's not commented out. - ### Build errors See [Troubleshooting](https://github.com/mimblewimble/docs/wiki/Troubleshooting) diff --git a/grin.toml b/grin.toml index dcb1c5a35..cb632722b 100644 --- a/grin.toml +++ b/grin.toml @@ -56,7 +56,7 @@ chain_type = "Testnet2" capabilities = [7] #skip waiting for sync on startup, (optional param, mostly for testing) -#skip_sync_wait = false +skip_sync_wait = true #whether to run the ncurses TUI. Ncurses must be installed and this #will also disable logging to stdout @@ -65,6 +65,14 @@ run_tui = true #Whether to run the wallet listener with the server by default run_wallet_listener = true +#Whether to run a test miner. This is only for developer testing (chaintype +#usertesting) at cuckoo 16, and will only mine into the default wallet port. +#real mining should use the standalone grin-miner +run_test_miner = false + +#test miner wallet URL (burns if this doesn't exist) +#test_miner_wallet_url = "http://127.0.0.1:13415" + #The P2P server details (i.e. the server that communicates with other #grin server nodes @@ -91,6 +99,27 @@ port = 13414 #until we get to at least this number #peer_min_preferred_count = 8 +########################################### +### STRATUM MINING SERVER CONFIGURATION ### +########################################### +[mining_server] + +#flag whether stratum server is enabled +enable_stratum_server = true + +#what port and address for the stratum server to listen on +stratum_server_addr = "0.0.0.0:13416" + +#The amount of time, in seconds, to attempt to mine on a particular +#header before stopping and re-collecting transactions from the pool +attempt_time_per_block = 90 + +#the wallet reciever to which coinbase rewards will be sent +wallet_listener_url = "http://127.0.0.1:13415" + +#whether to ignore the reward (mostly for testing) +burn_reward = false + ######################################### ### WALLET CONFIGURATION ### ######################################### @@ -132,147 +161,3 @@ log_file_path = "grin.log" # Whether to append to the log file (true), or replace it on every run (false) log_file_append = true - -######################################### -### MINING CONFIGURATION ### -######################################### - -#Mining details. This section is optional. If it's not here, the server -#will default to not mining. -[mining] - -#flag whether mining is enabled - -enable_mining = false - -#Whether to use async mode for the miner, if the plugin supports it. -#this allows for many searches to be run in parallel, e.g. if the system -#has multiple GPUs, or if you want to mine using multiple plugins - -miner_async_mode = true - -#The directory in which mining plugins are installed -#if not specified, grin will look in the directory /deps relative -#to the executable - -#miner_plugin_dir = "target/debug/plugins" - -#The amount of time, in seconds, to attempt to mine on a particular -#header before stopping and re-collecting transactions from the pool - -attempt_time_per_block = 90 - -#the wallet reciever to which coinbase rewards will be sent - -wallet_listener_url = "http://127.0.0.1:13415" - -#whether to ignore the reward (mostly for testing) - -burn_reward = false - -#testing value, optional -#slow_down_in_millis = 30 - - -#################################### -### STRATUM SERVER CONFIGURATION ### -#################################### - -#flag whether stratum server is enabled -enable_stratum_server = false - -#what port and address for the stratum server to listen on -stratum_server_addr = "127.0.0.1:13416" - -######################################### -### CUCKOO MINER PLUGIN CONFIGURATION ### -######################################### - -# These entries configure instances of cuckoo miner -# plugins if the 'use_cuckoo_miner' value above is -# set to 'true'. -# -# Multiple plugins can be specified, (e.g. a cpu -# miner and a gpu miner running in parallel). However, -# if 'use_async_mode' above is set to 'false', only -# the first plugin specified will be used for mining -# in single-threaded mode - -# You'll likely get the best performance using a -# single GPU plugin and single CPU plugin in parallel - -# Parameters can be set per-device. On CPU plugins -# you'll likely only be using device 0 (for now), -# but in CUDA plugins the device number corresponds -# to the device ID. (use nvidia-smi to find this) - -#The fastest cpu algorithm, but consumes the most memory -#Also requires instructions that aren't available on -#older processors. In this case, use mean_compat_cpu -#instead -#[[mining.miner_plugin_config]] -#type_filter = "mean_cpu" -#[mining.miner_plugin_config.device_parameters.0] -#NUM_THREADS = 1 - -#As above, but for older processors -[[mining.miner_plugin_config]] -type_filter = "mean_compat_cpu" -[mining.miner_plugin_config.device_parameters.0] -NUM_THREADS = 1 - -#note lean_cpu currently has a bug which prevents it from -#working with threads > 1 - -#[[mining.miner_plugin_config]] -#type_filter = "lean_cpu" -#[mining.miner_plugin_config.device_parameters.0] -#NUM_THREADS = 1 - -#CUDA Miner -# -# Note! 4+ GB GPU cards only! -# If you have 6GB GPU RAM, set N_BLOCKS = 128 -# Docs: https://github.com/tromp/cuckoo/blob/master/GPU.md -# -#Can currently be used only in Production (30) Mode -#This plugin is not built by default. To build: -#1) Ensure the latest cuda toolkit is installed -# (nvcc should be in your PATH) -# Wrong gcc? install gcc-5 g++-5; export CC=`which gcc-5`; # then build -#2) Uncomment the 'build-cuda-plugin' feature -# in pow/Cargo.toml -# -#Parameters can be set per device, as below. In sync mode -#device 0 is currently the only device used. In async mode -#device 0 is used by default, and all other devices are -#disabled unless explicitly enabled by setting the 'USE_DEVICE' -#param to 1 on each device, as demonstrated below. - -#[[mining.miner_plugin_config]] -#type_filter = "cuda" -#[mining.miner_plugin_config.device_parameters.0] -#USE_DEVICE = 1 - -# Below are advanced optional per-device tweakable params - -#N_TRIMS = 256 -#N_BLOCKS = 128 -#GENU_BLOCKS = 128 -#GENU_TPB = 8 -#GENV_STAGE1_TPB = 32 -#GENV_STAGE2_TPB = 128 -#TRIM_STAGE1_TPB = 32 -#TRIM_STAGE2_TPB = 128 -#RENAME_0_STAGE1_TPB = 32 -#RENAME_0_STAGE2_TPB = 64 -#RENAME_1_STAGE1_TPB = 32 -#RENAME_1_STAGE2_TPB = 128 -#TRIM_3_TPB = 32 -#RENAME_3_TPB = 8 - -#[mining.miner_plugin_config.device_parameters.1] -#USE_DEVICE = 1 - -#[mining.miner_plugin_config.device_parameters.2] -#USE_DEVICE = 1 diff --git a/pow/Cargo.toml b/pow/Cargo.toml deleted file mode 100644 index a5535ceb3..000000000 --- a/pow/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "grin_pow" -version = "0.2.0" - -authors = ["Grin Developers "] -workspace = ".." -publish = false - -[dependencies] -blake2-rfc = "0.2" -lazy_static = "0.2" -rand = "0.3" -serde = "1" -serde_derive = "1" -slog = { version = "~2.1", features = ["max_level_trace", "release_max_level_trace"] } -time = "0.1" - -grin_core = { path = "../core" } -grin_util = { path = "../util" } - -[dependencies.cuckoo_miner] -git = "https://github.com/mimblewimble/cuckoo-miner" -tag = "grin_integration_25" -#path = "../../cuckoo-miner" -#uncomment this feature to turn off plugin builds -#features=["no-plugin-build"] -#uncomment this feature to enable cuda builds (cuda toolkit must be installed) -#features=["build-cuda-plugins"] diff --git a/pow/src/plugin.rs b/pow/src/plugin.rs deleted file mode 100644 index 706bc642d..000000000 --- a/pow/src/plugin.rs +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright 2018 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. - -//! Plugin wrapper for cuckoo miner, implementing common traits -//! with the existing embedded miner. This is all included conditionally -//! for compatibility reasons with those who aren't interested in playing -//! with cuckoo-miner at present - -use std::env; - -use cuckoo; -use cuckoo::Error; -use MiningWorker; -use core::global; - -use core::core::Proof; -use types::MinerConfig; -use util::LOGGER; - -use std::sync::Mutex; - -use cuckoo_miner::{CuckooMiner, CuckooMinerConfig, CuckooMinerDeviceStats, CuckooMinerError, - CuckooMinerSolution, CuckooPluginManager}; - -// For now, we're just going to keep a static reference around to the loaded -// config -// And not allow querying the plugin directory twice once a plugin has been -// selected -// This is to keep compatibility with multi-threaded testing, so that spawned -// testing threads don't try to load/unload the library while another thread is -// using it. -lazy_static!{ - static ref LOADED_CONFIG: Mutex>> = Mutex::new(None); -} - -/// plugin miner -pub struct PluginMiner { - /// the miner - pub miner: Option, - last_solution: CuckooMinerSolution, - config: Vec, -} - -impl Default for PluginMiner { - fn default() -> PluginMiner { - PluginMiner { - miner: None, - config: Vec::new(), - last_solution: CuckooMinerSolution::new(), - } - } -} - -impl PluginMiner { - /// Init the plugin miner - pub fn init(&mut self, miner_config: MinerConfig) { - // Get directory of executable - let mut exe_path = env::current_exe().unwrap(); - exe_path.pop(); - let exe_path = exe_path.to_str().unwrap(); - let plugin_install_path = match miner_config.miner_plugin_dir.clone() { - Some(s) => s, - None => String::from(format!("{}/plugins", exe_path)), - }; - - let mut plugin_vec_filters = Vec::new(); - if let None = miner_config.miner_plugin_config { - plugin_vec_filters.push(String::from("simple")); - } else { - for p in miner_config.clone().miner_plugin_config.unwrap() { - plugin_vec_filters.push(p.type_filter); - } - } - - // First, load and query the plugins in the given directory - // These should all be stored in 'plugins' at the moment relative - // to the executable path, though they should appear somewhere else - // when packaging is more//thought out - - let mut loaded_config_ref = LOADED_CONFIG.lock().unwrap(); - - // Load from here instead - if let Some(ref c) = *loaded_config_ref { - debug!(LOGGER, "Not re-loading plugin or directory."); - // this will load the associated plugin - let result = CuckooMiner::new(c.clone()); - self.miner = Some(result.unwrap()); - self.config = c.clone(); - return; - } - - let mut plugin_manager = CuckooPluginManager::new().unwrap(); - let result = plugin_manager.load_plugin_dir(plugin_install_path); - - if let Err(_) = result { - error!( - LOGGER, - "Unable to load cuckoo-miner plugin directory, either from configuration or [exe_path]/plugins." - ); - panic!("Unable to load plugin directory... Please check configuration values"); - } - - let sz = global::sizeshift(); - - let mut cuckoo_configs = Vec::new(); - let mut index = 0; - for f in plugin_vec_filters { - // So this is built dynamically based on the plugin implementation - // type and the consensus sizeshift - let filter = format!("{}_{}", f, sz); - - let caps = plugin_manager.get_available_plugins(&filter).unwrap(); - // insert it into the miner configuration being created below - - let mut config = CuckooMinerConfig::new(); - - info!( - LOGGER, - "Cuckoo plugin {} - {}", - index, - caps[0].full_path.clone() - ); - config.plugin_full_path = caps[0].full_path.clone(); - if let Some(l) = miner_config.clone().miner_plugin_config { - if let Some(dp) = l[index].device_parameters.clone() { - for (device, param_map) in dp.into_iter() { - for (param_name, param_value) in param_map.into_iter() { - let device_id = match device.parse::() { - Ok(n) => n, - Err(e) => { - error!(LOGGER, "Error initializing mining plugin: {:?}", e); - panic!("Unable to init mining plugin."); - } - }; - debug!( - LOGGER, - "Cuckoo Plugin {}: Setting mining parameter {} to {} on Device {}", - index, - param_name, - param_value, - device_id - ); - config - .parameter_list - .push((param_name, device_id, param_value)); - } - } - } - } - cuckoo_configs.push(config); - index += 1; - } - // Store this config now, because we just want one instance - // of the plugin lib per invocation now - *loaded_config_ref = Some(cuckoo_configs.clone()); - - // this will load the associated plugin - let result = CuckooMiner::new(cuckoo_configs.clone()); - if let Err(e) = result { - error!(LOGGER, "Error initializing mining plugin: {:?}", e); - // error!(LOGGER, "Accepted values are: {:?}", caps[0].parameters); - panic!("Unable to init mining plugin."); - } - - self.config = cuckoo_configs.clone(); - self.miner = Some(result.unwrap()); - } - - /// Get the miner - pub fn get_consumable(&mut self) -> CuckooMiner { - // this will load the associated plugin - let result = CuckooMiner::new(self.config.clone()); - if let Err(e) = result { - error!(LOGGER, "Error initializing mining plugin: {:?}", e); - panic!("Unable to init mining plugin."); - } - result.unwrap() - } - - /// Returns the number of mining plugins that have been loaded - pub fn loaded_plugin_count(&self) -> usize { - self.config.len() - } - - /// Get stats - pub fn get_stats(&self, index: usize) -> Result, CuckooMinerError> { - self.miner.as_ref().unwrap().get_stats(index) - } -} - -impl MiningWorker for PluginMiner { - /// This will initialise a plugin according to what's currently - /// included in CONSENSUS::TEST_SIZESHIFT, just using the edgetrim - /// version of the miner for now, though this should become - /// configurable somehow - - fn new(_ease: u32, _sizeshift: u32, _proof_size: usize) -> Self { - PluginMiner::default() - } - - /// And simply calls the mine function of the loaded plugin - /// returning whether a solution was found and the solution itself - - fn mine(&mut self, header: &[u8]) -> Result { - let result = self.miner - .as_mut() - .unwrap() - .mine(&header, &mut self.last_solution, 0) - .unwrap(); - if result == true { - return Ok(Proof::new(self.last_solution.solution_nonces.to_vec())); - } - Err(Error::NoSolution) - } -} diff --git a/pow/src/types.rs b/pow/src/types.rs deleted file mode 100644 index 4cac0cb6e..000000000 --- a/pow/src/types.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2018 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. -//! Mining configuration type - -use std::collections::HashMap; - -/// CuckooMinerPlugin configuration -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CuckooMinerPluginConfig { - /// The type of plugin to load (i.e. filters on filename) - pub type_filter: String, - - /// device params - pub device_parameters: Option>>, -} - -impl Default for CuckooMinerPluginConfig { - fn default() -> CuckooMinerPluginConfig { - CuckooMinerPluginConfig { - type_filter: String::new(), - device_parameters: None, - } - } -} - -/// Mining configuration -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct MinerConfig { - /// Whether to start the miner with the server (requires using cuckoo-miner) - pub enable_mining: bool, - - /// Whether to use the async version of mining - pub miner_async_mode: Option, - - /// plugin dir - pub miner_plugin_dir: Option, - - /// Cuckoo miner plugin configuration, one for each plugin - pub miner_plugin_config: Option>, - - /// How long to wait before stopping the miner, recollecting transactions - /// and starting again - pub attempt_time_per_block: u32, - - /// Base address to the HTTP wallet receiver - pub wallet_listener_url: String, - - /// Attributes the reward to a random private key instead of contacting the - /// wallet receiver. Mostly used for tests. - pub burn_reward: bool, - - /// a testing attribute for the time being that artifically slows down the - /// mining loop by adding a sleep to the thread - pub slow_down_in_millis: Option, - - /// Run a stratum mining server rather than mining locally in-process - pub enable_stratum_server: Option, - - /// If enabled, the address and port to listen on - pub stratum_server_addr: Option, -} - -impl Default for MinerConfig { - fn default() -> MinerConfig { - MinerConfig { - enable_mining: false, - miner_async_mode: None, - miner_plugin_dir: None, - miner_plugin_config: None, - wallet_listener_url: "http://localhost:13415".to_string(), - burn_reward: false, - slow_down_in_millis: Some(0), - attempt_time_per_block: 2, - enable_stratum_server: None, - stratum_server_addr: None, - } - } -} diff --git a/servers/Cargo.toml b/servers/Cargo.toml index 35c2767b8..1ef3a7512 100644 --- a/servers/Cargo.toml +++ b/servers/Cargo.toml @@ -24,7 +24,6 @@ grin_core = { path = "../core" } grin_keychain = { path = "../keychain" } grin_p2p = { path = "../p2p" } grin_pool = { path = "../pool" } -grin_pow = { path = "../pow" } grin_store = { path = "../store" } grin_util = { path = "../util" } grin_wallet = { path = "../wallet" } diff --git a/servers/src/common/stats.rs b/servers/src/common/stats.rs index eaeac2849..e6691e945 100644 --- a/servers/src/common/stats.rs +++ b/servers/src/common/stats.rs @@ -21,7 +21,6 @@ use std::time::SystemTime; use chain; use p2p; -use pow; /// Server state info collection struct, to be passed around into internals /// and populated when required @@ -29,8 +28,6 @@ use pow; pub struct ServerStateInfo { /// whether we're in a state of waiting for peers at startup pub awaiting_peers: Arc, - /// Mining stats - pub mining_stats: Arc>, /// Stratum stats pub stratum_stats: Arc>, } @@ -39,7 +36,6 @@ impl Default for ServerStateInfo { fn default() -> ServerStateInfo { ServerStateInfo { awaiting_peers: Arc::new(AtomicBool::new(false)), - mining_stats: Arc::new(RwLock::new(MiningStats::default())), stratum_stats: Arc::new(RwLock::new(StratumStats::default())), } } @@ -58,8 +54,6 @@ pub struct ServerStats { pub is_syncing: bool, /// Whether we're awaiting peers pub awaiting_peers: bool, - /// Handle to current mining stats - pub mining_stats: MiningStats, /// Handle to current stratum server stats pub stratum_stats: StratumStats, /// Peer stats @@ -68,37 +62,17 @@ pub struct ServerStats { pub diff_stats: DiffStats, } -/// Struct to return relevant information about the mining process -/// back to interested callers (such as the TUI) -#[derive(Clone)] -pub struct MiningStats { - /// whether mining is enabled - pub is_enabled: bool, - /// whether we're currently mining - pub is_mining: bool, - /// combined graphs per second - pub combined_gps: f64, - /// what block height we're mining at - pub block_height: u64, - /// current network difficulty we're working on - pub network_difficulty: u64, - /// cuckoo size used for mining - pub cuckoo_size: u16, - /// Individual device status from Cuckoo-Miner - pub device_stats: Option>>, -} - /// Struct to return relevant information about stratum workers #[derive(Clone, Serialize, Debug)] pub struct WorkerStats { /// Unique ID for this worker pub id: String, - /// whether stratum worker is currently connected - pub is_connected: bool, + /// whether stratum worker is currently connected + pub is_connected: bool, /// Timestamp of most recent communication with this worker pub last_seen: SystemTime, - /// pow difficulty this worker is using - pub pow_difficulty: u64, + /// pow difficulty this worker is using + pub pow_difficulty: u64, /// number of valid shares submitted pub num_accepted: u64, /// number of invalid shares submitted @@ -110,20 +84,20 @@ pub struct WorkerStats { /// Struct to return relevant information about the stratum server #[derive(Clone, Serialize, Debug)] pub struct StratumStats { - /// whether stratum server is enabled - pub is_enabled: bool, - /// whether stratum server is running - pub is_running: bool, - /// Number of connected workers - pub num_workers: usize, - /// what block height we're mining at - pub block_height: u64, - /// current network difficulty we're working on - pub network_difficulty: u64, - /// cuckoo size used for mining - pub cuckoo_size: u16, - /// Individual worker status - pub worker_stats: Vec, + /// whether stratum server is enabled + pub is_enabled: bool, + /// whether stratum server is running + pub is_running: bool, + /// Number of connected workers + pub num_workers: usize, + /// what block height we're mining at + pub block_height: u64, + /// current network difficulty we're working on + pub network_difficulty: u64, + /// cuckoo size used for mining + pub cuckoo_size: u16, + /// Individual worker status + pub worker_stats: Vec, } /// Stats on the last WINDOW blocks and the difficulty calculation @@ -198,20 +172,6 @@ impl PeerStats { } } -impl Default for MiningStats { - fn default() -> MiningStats { - MiningStats { - is_enabled: false, - is_mining: false, - combined_gps: 0.0, - block_height: 0, - network_difficulty: 0, - cuckoo_size: 0, - device_stats: None, - } - } -} - impl Default for WorkerStats { fn default() -> WorkerStats { WorkerStats { diff --git a/servers/src/common/types.rs b/servers/src/common/types.rs index c4368b147..24328e37e 100644 --- a/servers/src/common/types.rs +++ b/servers/src/common/types.rs @@ -22,9 +22,9 @@ use core::core; use p2p; use pool; use store; -use pow; use wallet; use core::global::ChainTypes; +use core::pow; /// Error type wrapping underlying module errors. #[derive(Debug)] @@ -161,7 +161,7 @@ pub struct ServerConfig { pub p2p_config: p2p::P2PConfig, /// Configuration for the mining daemon - pub mining_config: Option, + pub stratum_mining_config: Option, /// Transaction pool configuration #[serde(default)] @@ -177,6 +177,12 @@ pub struct ServerConfig { /// Whether to run the wallet listener with the server by default pub run_wallet_listener: Option, + + /// Whether to run the test miner (internal, cuckoo 16) + pub run_test_miner: Option, + + /// Test miner wallet URL + pub test_miner_wallet_url: Option, } impl Default for ServerConfig { @@ -188,7 +194,7 @@ impl Default for ServerConfig { seeding_type: Seeding::default(), seeds: None, p2p_config: p2p::P2PConfig::default(), - mining_config: Some(pow::types::MinerConfig::default()), + stratum_mining_config: Some(StratumServerConfig::default()), chain_type: ChainTypes::default(), archive_mode: None, chain_validation_mode: ChainValidationMode::default(), @@ -196,6 +202,42 @@ impl Default for ServerConfig { skip_sync_wait: None, run_tui: None, run_wallet_listener: Some(false), + run_test_miner: Some(false), + test_miner_wallet_url: None, + } + } +} + +/// Stratum (Mining server) configuration +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct StratumServerConfig { + /// Run a stratum mining server (the only way to communicate to mine this + /// node via grin-miner + pub enable_stratum_server: Option, + + /// If enabled, the address and port to listen on + pub stratum_server_addr: Option, + + /// How long to wait before stopping the miner, recollecting transactions + /// and starting again + pub attempt_time_per_block: u32, + + /// Base address to the HTTP wallet receiver + pub wallet_listener_url: String, + + /// Attributes the reward to a random private key instead of contacting the + /// wallet receiver. Mostly used for tests. + pub burn_reward: bool, +} + +impl Default for StratumServerConfig { + fn default() -> StratumServerConfig { + StratumServerConfig { + wallet_listener_url: "http://localhost:13415".to_string(), + burn_reward: false, + attempt_time_per_block: 2, + enable_stratum_server: None, + stratum_server_addr: None, } } } diff --git a/servers/src/grin/server.rs b/servers/src/grin/server.rs index 15f4d1344..813970f54 100644 --- a/servers/src/grin/server.rs +++ b/servers/src/grin/server.rs @@ -25,11 +25,10 @@ use std::time; use common::adapters::*; use api; use chain; -use core::{consensus, genesis, global}; +use core::{consensus, genesis, global, pow}; use core::core::target::Difficulty; use core::core::hash::Hashed; use grin::dandelion_monitor; -use mining::miner; use mining::stratumserver; use p2p; use pool; @@ -37,8 +36,8 @@ use grin::seed; use grin::sync; use common::types::*; use common::stats::*; -use pow; use util::LOGGER; +use mining::test_miner::Miner; /// Grin server holding internal structures. pub struct Server { @@ -66,16 +65,11 @@ impl Server { where F: FnMut(Arc), { - let mut mining_config = config.mining_config.clone(); + let mut mining_config = config.stratum_mining_config.clone(); + let enable_test_miner = config.run_test_miner; + let test_miner_wallet_url = config.test_miner_wallet_url.clone(); let serv = Arc::new(Server::new(config)?); - if mining_config.as_mut().unwrap().enable_mining { - { - let mut mining_stats = serv.state_info.mining_stats.write().unwrap(); - mining_stats.is_enabled = true; - } - serv.start_miner(mining_config.clone().unwrap()); - } let enable_stratum_server = mining_config.as_mut().unwrap().enable_stratum_server; if let Some(s) = enable_stratum_server { if s { @@ -87,6 +81,12 @@ impl Server { } } + if let Some(s) = enable_test_miner { + if s { + serv.start_test_miner(test_miner_wallet_url); + } + } + info_callback(serv.clone()); loop { thread::sleep(time::Duration::from_secs(1)); @@ -127,7 +127,7 @@ impl Server { global::ChainTypes::Testnet2 => genesis::genesis_testnet2(), global::ChainTypes::AutomatedTesting => genesis::genesis_dev(), global::ChainTypes::UserTesting => genesis::genesis_dev(), - _ => pow::mine_genesis_block(config.mining_config.clone())?, + global::ChainTypes::Mainnet => genesis::genesis_testnet2(), //TODO: Fix, obviously }; info!(LOGGER, "Starting server, genesis block: {}", genesis.hash()); @@ -262,36 +262,8 @@ impl Server { self.p2p.peers.peer_count() } - /// 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: pow::types::MinerConfig) { - let cuckoo_size = global::sizeshift(); - let proof_size = global::proofsize(); - let currently_syncing = self.currently_syncing.clone(); - - let mut miner = miner::Miner::new( - config.clone(), - self.chain.clone(), - self.tx_pool.clone(), - self.stop.clone(), - ); - let mining_stats = self.state_info.mining_stats.clone(); - miner.set_debug_output_id(format!("Port {}", self.config.p2p_config.port)); - let _ = thread::Builder::new() - .name("miner".to_string()) - .spawn(move || { - // TODO push this down in the run loop so miner gets paused anytime we - // decide to sync again - let secs_5 = time::Duration::from_secs(5); - while currently_syncing.load(Ordering::Relaxed) { - thread::sleep(secs_5); - } - miner.run_loop(config.clone(), mining_stats, cuckoo_size as u32, proof_size); - }); - } - /// Start a minimal "stratum" mining service on a separate thread - pub fn start_stratum_server(&self, config: pow::types::MinerConfig) { + pub fn start_stratum_server(&self, config: StratumServerConfig) { let cuckoo_size = global::sizeshift(); let proof_size = global::proofsize(); let currently_syncing = self.currently_syncing.clone(); @@ -305,19 +277,54 @@ impl Server { let _ = thread::Builder::new() .name("stratum_server".to_string()) .spawn(move || { - let secs_5 = time::Duration::from_secs(5); - while currently_syncing.load(Ordering::Relaxed) { - thread::sleep(secs_5); - } stratum_server.run_loop( config.clone(), stratum_stats, cuckoo_size as u32, proof_size, + currently_syncing, ); }); } + /// Start mining for blocks internally on a separate thread. Relies on internal miner, + /// and should only be used for automated testing. Burns reward if wallet_listener_url + /// is 'None' + pub fn start_test_miner(&self, wallet_listener_url: Option) { + let currently_syncing = self.currently_syncing.clone(); + let config_wallet_url = match wallet_listener_url.clone() { + Some(u) => u, + None => String::from("http://127.0.0.1:13415"), + }; + + let config = StratumServerConfig { + attempt_time_per_block: 60, + burn_reward: false, + enable_stratum_server: None, + stratum_server_addr: None, + wallet_listener_url: config_wallet_url, + }; + + let mut miner = Miner::new( + config.clone(), + self.chain.clone(), + self.tx_pool.clone(), + self.stop.clone(), + ); + miner.set_debug_output_id(format!("Port {}", self.config.p2p_config.port)); + let _ = thread::Builder::new() + .name("test_miner".to_string()) + .spawn(move || { + // TODO push this down in the run loop so miner gets paused anytime we + // decide to sync again + let secs_5 = time::Duration::from_secs(5); + while currently_syncing.load(Ordering::Relaxed) { + thread::sleep(secs_5); + } + miner.run_loop(wallet_listener_url); + }); + } + /// The chain head pub fn head(&self) -> chain::Tip { self.chain.head().unwrap() @@ -334,7 +341,6 @@ impl Server { /// other /// consumers pub fn get_server_stats(&self) -> Result { - let mining_stats = self.state_info.mining_stats.read().unwrap().clone(); let stratum_stats = self.state_info.stratum_stats.read().unwrap().clone(); let awaiting_peers = self.state_info.awaiting_peers.load(Ordering::Relaxed); @@ -402,7 +408,6 @@ impl Server { header_head: self.header_head(), is_syncing: self.currently_syncing.load(Ordering::Relaxed), awaiting_peers: awaiting_peers, - mining_stats: mining_stats, stratum_stats: stratum_stats, peer_stats: peer_stats, diff_stats: diff_stats, diff --git a/servers/src/lib.rs b/servers/src/lib.rs index 18adfaa73..92db29429 100644 --- a/servers/src/lib.rs +++ b/servers/src/lib.rs @@ -40,15 +40,14 @@ extern crate grin_core as core; extern crate grin_keychain as keychain; extern crate grin_p2p as p2p; extern crate grin_pool as pool; -extern crate grin_pow as pow; extern crate grin_store as store; extern crate grin_util as util; extern crate grin_wallet as wallet; -mod common; +pub mod common; mod grin; mod mining; pub use grin::server::Server; -pub use common::types::{Seeding, ServerConfig}; -pub use common::stats::{PeerStats, ServerStats, DiffBlock}; +pub use common::types::{Seeding, ServerConfig, StratumServerConfig}; +pub use common::stats::{DiffBlock, PeerStats, ServerStats, StratumStats, WorkerStats}; diff --git a/servers/src/mining/mine_block.rs b/servers/src/mining/mine_block.rs index 8c7a9063a..56a8f1c5b 100644 --- a/servers/src/mining/mine_block.rs +++ b/servers/src/mining/mine_block.rs @@ -22,7 +22,7 @@ use std::time::Duration; use rand::{self, Rng}; use itertools::Itertools; -use core::ser::{AsFixedBytes}; +use core::ser::AsFixedBytes; use chain; use pool; use core::consensus; @@ -41,39 +41,39 @@ use common::adapters::PoolToChainAdapter; /// including the nonce (last 8 bytes) that can be sent off /// to the miner to mutate at will pub struct HeaderPrePowWriter { - pub pre_pow: Vec, + pub pre_pow: Vec, } impl Default for HeaderPrePowWriter { - fn default() -> HeaderPrePowWriter { - HeaderPrePowWriter { - pre_pow: Vec::new(), - } - } + fn default() -> HeaderPrePowWriter { + HeaderPrePowWriter { + pre_pow: Vec::new(), + } + } } impl HeaderPrePowWriter { - pub fn as_hex_string(&self, include_nonce: bool) -> String { - let mut result = String::from(format!("{:02x}", self.pre_pow.iter().format(""))); - if !include_nonce { - let l = result.len() - 16; - result.truncate(l); - } - result - } + pub fn as_hex_string(&self, include_nonce: bool) -> String { + let mut result = String::from(format!("{:02x}", self.pre_pow.iter().format(""))); + if !include_nonce { + let l = result.len() - 16; + result.truncate(l); + } + result + } } impl ser::Writer for HeaderPrePowWriter { - fn serialization_mode(&self) -> ser::SerializationMode { - ser::SerializationMode::Full - } + fn serialization_mode(&self) -> ser::SerializationMode { + ser::SerializationMode::Full + } - fn write_fixed_bytes(&mut self, bytes_in: &T) -> Result<(), ser::Error> { - for i in 0..bytes_in.len() { - self.pre_pow.push(bytes_in.as_ref()[i]) - } - Ok(()) - } + fn write_fixed_bytes(&mut self, bytes_in: &T) -> Result<(), ser::Error> { + for i in 0..bytes_in.len() { + self.pre_pow.push(bytes_in.as_ref()[i]) + } + Ok(()) + } } // Ensure a block suitable for mining is built and returned diff --git a/servers/src/mining/miner.rs b/servers/src/mining/miner.rs deleted file mode 100644 index 976aa5dde..000000000 --- a/servers/src/mining/miner.rs +++ /dev/null @@ -1,544 +0,0 @@ -// Copyright 2018 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. - -//! Mining service, gets a block to mine, and based on mining configuration chooses -//! a version of the cuckoo miner to mine the block and produce a valid header with -//! its proof-of-work. Any valid mined blocks are submitted to the network. - -use std::sync::{Arc, RwLock}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::thread; -use std::time::Duration; -use time; - -use common::adapters::PoolToChainAdapter; -use core::consensus; -use core::core::Proof; -use core::core::{Block, BlockHeader}; -use core::core::hash::{Hash, Hashed}; -use pow::{cuckoo, MiningWorker}; -use pow::types::MinerConfig; -use pow::plugin::PluginMiner; -use core::global; -use util::LOGGER; -use common::stats::MiningStats; - -use chain; -use pool; -use mining::mine_block; - -// Max number of transactions this miner will assemble in a block -const MAX_TX: u32 = 5000; - -pub struct Miner { - config: MinerConfig, - chain: Arc, - tx_pool: Arc>>, - stop: Arc, - - // Just to hold the port we're on, so this miner can be identified - // while watching debug output - debug_output_id: String, -} - -impl Miner { - /// Creates a new Miner. Needs references to the chain state and its - /// storage. - pub fn new( - config: MinerConfig, - chain_ref: Arc, - tx_pool: Arc>>, - stop: Arc, - ) -> Miner { - Miner { - config: config, - chain: chain_ref, - tx_pool: tx_pool, - debug_output_id: String::from("none"), - stop: stop, - } - } - - /// Keeping this optional so setting in a separate function - /// instead of in the new function - pub fn set_debug_output_id(&mut self, debug_output_id: String) { - self.debug_output_id = debug_output_id; - } - - /// Inner part of the mining loop for cuckoo-miner async mode - pub fn inner_loop_async( - &self, - plugin_miner: &mut PluginMiner, - b: &mut Block, - cuckoo_size: u32, - head: &BlockHeader, - latest_hash: &mut Hash, - attempt_time_per_block: u32, - mining_stats: Arc>, - ) -> Option { - debug!( - LOGGER, - "(Server ID: {}) Mining Cuckoo{} for max {}s on {} @ {} [{}].", - self.debug_output_id, - cuckoo_size, - attempt_time_per_block, - b.header.total_difficulty, - b.header.height, - b.header.hash() - ); - - // look for a pow for at most attempt_time_per_block sec on the - // same block (to give a chance to new - // transactions) and as long as the head hasn't changed - // Will change this to something else at some point - let deadline = time::get_time().sec + attempt_time_per_block as i64; - - // how often to output stats - let stat_output_interval = 2; - let mut next_stat_output = time::get_time().sec + stat_output_interval; - - // Get parts of the header - let mut pre_pow_writer = mine_block::HeaderPrePowWriter::default(); - b.header.write_pre_pow(&mut pre_pow_writer).unwrap(); - let pre_pow = pre_pow_writer.as_hex_string(false); - - // Start the miner working - let miner = plugin_miner.get_consumable(); - let job_handle = miner.notify(1, &pre_pow, "", 0).unwrap(); - - let mut sol = None; - - while head.hash() == *latest_hash && time::get_time().sec < deadline { - if let Some(s) = job_handle.get_solution() { - let proof = Proof::new(s.solution_nonces.to_vec()); - let proof_diff = proof.clone().to_difficulty(); - debug!( - LOGGER, - "Found cuckoo solution! nonce {} gave difficulty {} (block diff {})", - s.get_nonce_as_u64(), - proof_diff.into_num(), - (b.header.total_difficulty.clone() - head.total_difficulty.clone()).into_num() - ); - if proof_diff >= (b.header.total_difficulty.clone() - head.total_difficulty.clone()) - { - sol = Some(proof); - b.header.nonce = s.get_nonce_as_u64(); - break; - } - } - if time::get_time().sec > next_stat_output { - let mut sps_total = 0.0; - for i in 0..plugin_miner.loaded_plugin_count() { - let stats = job_handle.get_stats(i); - if let Ok(stat_vec) = stats { - for s in stat_vec { - if s.in_use == 0 { - continue; - } - let last_solution_time_secs = - s.last_solution_time as f64 / 1000000000.0; - let last_hashes_per_sec = 1.0 / last_solution_time_secs; - let status = match s.has_errored { - 0 => "OK", - _ => "ERRORED", - }; - debug!( - LOGGER, - "Mining: Plugin {} - Device {} ({}) Status: {} : Last Graph time: {}s; \ - Graphs per second: {:.*} - Total Attempts: {}", - i, - s.device_id, - s.device_name, - status, - last_solution_time_secs, - 3, - last_hashes_per_sec, - s.iterations_completed - ); - if last_hashes_per_sec.is_finite() { - sps_total += last_hashes_per_sec; - } - } - } - } - info!( - LOGGER, - "Mining: Cuckoo{} at {} gps (graphs per second)", cuckoo_size, sps_total - ); - if sps_total.is_finite() { - let mut mining_stats = mining_stats.write().unwrap(); - mining_stats.combined_gps = sps_total; - let mut device_vec = vec![]; - for i in 0..plugin_miner.loaded_plugin_count() { - device_vec.push(job_handle.get_stats(i).unwrap()); - } - mining_stats.device_stats = Some(device_vec); - } - next_stat_output = time::get_time().sec + stat_output_interval; - } - // avoid busy wait - thread::sleep(Duration::from_millis(100)); - - *latest_hash = self.chain.head().unwrap().last_block_h; - } - if sol == None { - debug!( - LOGGER, - "(Server ID: {}) No solution found after {} seconds, continuing...", - self.debug_output_id, - attempt_time_per_block - ); - } - - job_handle.stop_jobs(); - sol - } - - /// The inner part of mining loop for cuckoo miner sync mode - pub fn inner_loop_sync_plugin( - &self, - plugin_miner: &mut PluginMiner, - b: &mut Block, - cuckoo_size: u32, - head: &BlockHeader, - attempt_time_per_block: u32, - latest_hash: &mut Hash, - mining_stats: Arc>, - ) -> Option { - // look for a pow for at most attempt_time_per_block sec on the same block (to - // give a chance to new - // transactions) and as long as the head hasn't changed - let deadline = time::get_time().sec + attempt_time_per_block as i64; - let stat_check_interval = 3; - let mut next_stat_check = time::get_time().sec + stat_check_interval; - - debug!( - LOGGER, - "(Server ID: {}) Mining Cuckoo{} for max {}s (will wait for last solution) \ - on {} @ {} [{}].", - self.debug_output_id, - cuckoo_size, - attempt_time_per_block, - b.header.total_difficulty, - b.header.height, - latest_hash - ); - let mut iter_count = 0; - - if self.config.slow_down_in_millis != None && self.config.slow_down_in_millis.unwrap() > 0 { - debug!( - LOGGER, - "(Server ID: {}) Artificially slowing down loop by {}ms per iteration.", - self.debug_output_id, - self.config.slow_down_in_millis.unwrap() - ); - } - - let mut sol = None; - while head.hash() == *latest_hash && time::get_time().sec < deadline { - let pow_hash = b.header.pre_pow_hash(); - if let Ok(proof) = plugin_miner.mine(&pow_hash[..]) { - let proof_diff = proof.clone().to_difficulty(); - debug!( - LOGGER, - "Found cuckoo solution for nonce {} of difficulty {} (cumulative diff {})", - b.header.nonce, - proof_diff.into_num(), - b.header.total_difficulty.into_num() - ); - if proof_diff >= (b.header.total_difficulty.clone() - head.total_difficulty.clone()) - { - sol = Some(proof); - break; - } - } - - if time::get_time().sec >= next_stat_check { - let stats_vec = plugin_miner.get_stats(0).unwrap(); - for s in stats_vec.into_iter() { - if s.in_use == 0 { - continue; - } - let last_solution_time_secs = s.last_solution_time as f64 / 1000000000.0; - let last_hashes_per_sec = 1.0 / last_solution_time_secs; - let status = match s.has_errored { - 0 => "OK", - _ => "ERRORED", - }; - debug!( - LOGGER, - "Plugin 0 - Device {} ({}) Status: {} - Last Graph time: {}; Graphs per second: {:.*}", - s.device_id, - s.device_name, - status, - last_solution_time_secs, - 3, - last_hashes_per_sec - ); - info!( - LOGGER, - "Mining at {} graphs per second", last_hashes_per_sec - ); - if last_hashes_per_sec.is_finite() { - let mut mining_stats = mining_stats.write().unwrap(); - mining_stats.combined_gps = last_hashes_per_sec; - let mut device_vec = vec![]; - device_vec.push(plugin_miner.get_stats(0).unwrap()); - mining_stats.device_stats = Some(device_vec); - } - } - next_stat_check = time::get_time().sec + stat_check_interval; - } - - b.header.nonce += 1; - *latest_hash = self.chain.head().unwrap().last_block_h; - iter_count += 1; - - // Artificial slow down - if self.config.slow_down_in_millis != None - && self.config.slow_down_in_millis.unwrap() > 0 - { - thread::sleep(Duration::from_millis( - self.config.slow_down_in_millis.unwrap(), - )); - } - } - - if sol == None { - debug!( - LOGGER, - "(Server ID: {}) No solution found after {} iterations, continuing...", - self.debug_output_id, - iter_count - ) - } - - sol - } - - /// The inner part of mining loop for the internal miner - /// kept around mostly for automated testing purposes - pub fn inner_loop_sync_internal( - &self, - miner: &mut T, - b: &mut Block, - cuckoo_size: u32, - head: &BlockHeader, - attempt_time_per_block: u32, - latest_hash: &mut Hash, - ) -> Option { - // look for a pow for at most 2 sec on the same block (to give a chance to new - // transactions) and as long as the head hasn't changed - let deadline = time::get_time().sec + attempt_time_per_block as i64; - - debug!( - LOGGER, - "(Server ID: {}) Mining Cuckoo{} for max {}s on {} @ {} [{}].", - self.debug_output_id, - cuckoo_size, - attempt_time_per_block, - b.header.total_difficulty, - b.header.height, - latest_hash - ); - let mut iter_count = 0; - - if self.config.slow_down_in_millis != None && self.config.slow_down_in_millis.unwrap() > 0 { - debug!( - LOGGER, - "(Server ID: {}) Artificially slowing down loop by {}ms per iteration.", - self.debug_output_id, - self.config.slow_down_in_millis.unwrap() - ); - } - - let mut sol = None; - while head.hash() == *latest_hash && time::get_time().sec < deadline { - let pow_hash = b.header.pre_pow_hash(); - if let Ok(proof) = miner.mine(&pow_hash[..]) { - let proof_diff = proof.clone().to_difficulty(); - if proof_diff >= (b.header.total_difficulty.clone() - head.total_difficulty.clone()) - { - sol = Some(proof); - break; - } - } - - b.header.nonce += 1; - *latest_hash = self.chain.head().unwrap().last_block_h; - iter_count += 1; - - // Artificial slow down - if self.config.slow_down_in_millis != None - && self.config.slow_down_in_millis.unwrap() > 0 - { - thread::sleep(Duration::from_millis( - self.config.slow_down_in_millis.unwrap(), - )); - } - } - - if sol == None { - debug!( - LOGGER, - "(Server ID: {}) No solution found after {} iterations, continuing...", - self.debug_output_id, - iter_count - ) - } - - sol - } - - /// Starts the mining loop, building a new block on top of the existing - /// chain anytime required and looking for PoW solution. - pub fn run_loop( - &self, - miner_config: MinerConfig, - mining_stats: Arc>, - cuckoo_size: u32, - proof_size: usize, - ) { - info!( - LOGGER, - "(Server ID: {}) Starting miner loop.", self.debug_output_id - ); - - let mut plugin_miner = None; - let mut miner = None; - if !global::is_automated_testing_mode() { - plugin_miner = Some(PluginMiner::new( - consensus::EASINESS, - cuckoo_size, - proof_size, - )); - plugin_miner.as_mut().unwrap().init(miner_config.clone()); - } else { - miner = Some(cuckoo::Miner::new( - consensus::EASINESS, - cuckoo_size, - proof_size, - )); - } - - // iteration, we keep the returned derivation to provide it back when - // nothing has changed. We only want to create a new key_id for each new block. - let mut key_id = None; - - { - let mut mining_stats = mining_stats.write().unwrap(); - mining_stats.is_mining = true; - mining_stats.cuckoo_size = cuckoo_size as u16; - } - - loop { - trace!(LOGGER, "in miner loop. key_id: {:?}", key_id); - - // get the latest chain state and build a block on top of it - let head = self.chain.head_header().unwrap(); - let mut latest_hash = self.chain.head().unwrap().last_block_h; - let mut wallet_listener_url: Option = None; - if !self.config.burn_reward { - wallet_listener_url = Some(self.config.wallet_listener_url.clone()); - } - - let (mut b, block_fees) = mine_block::get_block( - &self.chain, - &self.tx_pool, - key_id.clone(), - MAX_TX.clone(), - wallet_listener_url, - ); - { - let mut mining_stats = mining_stats.write().unwrap(); - mining_stats.block_height = b.header.height; - mining_stats.network_difficulty = - (b.header.total_difficulty.clone() - head.total_difficulty.clone()).into_num(); - } - - let mut sol = None; - let mut use_async = false; - if let Some(c) = self.config.miner_async_mode { - if c { - use_async = true; - } - } - if let Some(mut p) = plugin_miner.as_mut() { - if use_async { - sol = self.inner_loop_async( - &mut p, - &mut b, - cuckoo_size, - &head, - &mut latest_hash, - miner_config.attempt_time_per_block, - mining_stats.clone(), - ); - } else { - sol = self.inner_loop_sync_plugin( - p, - &mut b, - cuckoo_size, - &head, - miner_config.attempt_time_per_block, - &mut latest_hash, - mining_stats.clone(), - ); - } - } - if let Some(m) = miner.as_mut() { - sol = self.inner_loop_sync_internal( - m, - &mut b, - cuckoo_size, - &head, - miner_config.attempt_time_per_block, - &mut latest_hash, - ); - } - - // we found a solution, push our block through the chain processing pipeline - if let Some(proof) = sol { - b.header.pow = proof; - info!( - LOGGER, - "(Server ID: {}) Found valid proof of work, adding block {}.", - self.debug_output_id, - b.hash() - ); - let res = self.chain.process_block(b, chain::Options::MINE); - if let Err(e) = res { - error!( - LOGGER, - "(Server ID: {}) Error validating mined block: {:?}", - self.debug_output_id, - e - ); - } - trace!(LOGGER, "resetting key_id in miner to None"); - key_id = None; - } else { - debug!( - LOGGER, - "setting pubkey in miner to pubkey from block_fees - {:?}", block_fees - ); - key_id = block_fees.key_id(); - } - - if self.stop.load(Ordering::Relaxed) { - break; - } - } - } -} diff --git a/servers/src/mining/mod.rs b/servers/src/mining/mod.rs index 6b367bd98..2dcf3caa9 100644 --- a/servers/src/mining/mod.rs +++ b/servers/src/mining/mod.rs @@ -14,6 +14,6 @@ //! Mining + Mining server -pub mod miner; +pub mod test_miner; pub mod stratumserver; mod mine_block; diff --git a/servers/src/mining/stratumserver.rs b/servers/src/mining/stratumserver.rs index f678e04ea..b05d47e8e 100644 --- a/servers/src/mining/stratumserver.rs +++ b/servers/src/mining/stratumserver.rs @@ -18,6 +18,7 @@ use std::time::Duration; use std::net::{TcpListener, TcpStream}; use std::io::{ErrorKind, Write}; use std::error::Error; +use std::sync::atomic::{AtomicBool, Ordering}; use time; use util::LOGGER; use std::io::BufRead; @@ -28,7 +29,7 @@ use std::time::SystemTime; use common::adapters::PoolToChainAdapter; use core::core::{Block, BlockHeader}; -use pow::types::MinerConfig; +use common::types::StratumServerConfig; use mining::mine_block; use chain; use pool; @@ -222,18 +223,19 @@ impl Worker { pub struct StratumServer { id: String, - config: MinerConfig, + config: StratumServerConfig, chain: Arc, tx_pool: Arc>>, current_block: Block, current_difficulty: u64, workers: Arc>>, + currently_syncing: Arc, } impl StratumServer { /// Creates a new Stratum Server. pub fn new( - config: MinerConfig, + config: StratumServerConfig, chain_ref: Arc, tx_pool: Arc>>, ) -> StratumServer { @@ -245,6 +247,7 @@ impl StratumServer { current_block: Block::default(), current_difficulty: ::max_value(), workers: Arc::new(Mutex::new(Vec::new())), + currently_syncing: Arc::new(AtomicBool::new(false)), } } @@ -309,8 +312,14 @@ impl StratumServer { ), "keepalive" => self.handle_keepalive(), "getjobtemplate" => { - let b = self.current_block.header.clone(); - self.handle_getjobtemplate(b) + if self.currently_syncing.load(Ordering::Relaxed) { + let e = r#"{"code": -32701, "message": "Node is syncing - Please wait"}"#; + let err = e.to_string(); + (err, true) + } else { + let b = self.current_block.header.clone(); + self.handle_getjobtemplate(b) + } } "status" => { self.handle_status(&stratum_stats.worker_stats[worker_stats_id]) @@ -530,10 +539,11 @@ impl StratumServer { /// be submitted. pub fn run_loop( &mut self, - miner_config: MinerConfig, + miner_config: StratumServerConfig, stratum_stats: Arc>, cuckoo_size: u32, proof_size: usize, + currently_syncing: Arc, ) { info!( LOGGER, @@ -543,6 +553,8 @@ impl StratumServer { proof_size ); + self.currently_syncing = currently_syncing; + // "globals" for this function let attempt_time_per_block = miner_config.attempt_time_per_block; let mut deadline: i64 = 0; @@ -579,6 +591,10 @@ impl StratumServer { // Main Loop loop { + // If we're fallen into sync mode, (or are just starting up, + // tell connected clients to stop what they're doing + let mining_stopped = self.currently_syncing.load(Ordering::Relaxed); + // Remove workers with failed connections self.clean_workers(&mut stratum_stats.clone()); @@ -589,7 +605,8 @@ impl StratumServer { // Build a new block if: // There is a new block on the chain // or We are rebuilding the current one to include new transactions - if current_hash != latest_hash || time::get_time().sec >= deadline { + // and we're not synching + if current_hash != latest_hash || time::get_time().sec >= deadline && !mining_stopped { if current_hash != latest_hash { // A brand new block, so we will generate a new key_id key_id = None; diff --git a/servers/src/mining/test_miner.rs b/servers/src/mining/test_miner.rs new file mode 100644 index 000000000..fcf4fbef4 --- /dev/null +++ b/servers/src/mining/test_miner.rs @@ -0,0 +1,203 @@ +// Copyright 2018 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. + +//! Mining service, gets a block to mine, and based on mining configuration +//! chooses a version of the cuckoo miner to mine the block and produce a valid +//! header with its proof-of-work. Any valid mined blocks are submitted to the +//! network. + +use std::sync::{Arc, RwLock}; +use std::sync::atomic::{AtomicBool, Ordering}; +use time; + +use common::adapters::PoolToChainAdapter; +use core::consensus; +use core::core::Proof; +use core::core::{Block, BlockHeader}; +use core::core::hash::{Hash, Hashed}; +use core::pow::cuckoo; +use common::types::StratumServerConfig; +use util::LOGGER; + +use chain; +use pool; +use mining::mine_block; +use core::global; + +// Max number of transactions this miner will assemble in a block +const MAX_TX: u32 = 5000; + +pub struct Miner { + config: StratumServerConfig, + chain: Arc, + tx_pool: Arc>>, + stop: Arc, + + // Just to hold the port we're on, so this miner can be identified + // while watching debug output + debug_output_id: String, +} + +impl Miner { + /// Creates a new Miner. Needs references to the chain state and its + /// storage. + pub fn new( + config: StratumServerConfig, + chain_ref: Arc, + tx_pool: Arc>>, + stop: Arc, + ) -> Miner { + Miner { + config: config, + chain: chain_ref, + tx_pool: tx_pool, + debug_output_id: String::from("none"), + stop: stop, + } + } + + /// Keeping this optional so setting in a separate function + /// instead of in the new function + pub fn set_debug_output_id(&mut self, debug_output_id: String) { + self.debug_output_id = debug_output_id; + } + + /// The inner part of mining loop for the internal miner + /// kept around mostly for automated testing purposes + pub fn inner_mining_loop( + &self, + b: &mut Block, + head: &BlockHeader, + attempt_time_per_block: u32, + latest_hash: &mut Hash, + ) -> Option { + // look for a pow for at most 2 sec on the same block (to give a chance to new + // transactions) and as long as the head hasn't changed + let deadline = time::get_time().sec + attempt_time_per_block as i64; + + debug!( + LOGGER, + "(Server ID: {}) Mining Cuckoo{} for max {}s on {} @ {} [{}].", + self.debug_output_id, + global::sizeshift(), + attempt_time_per_block, + b.header.total_difficulty, + b.header.height, + latest_hash + ); + let mut iter_count = 0; + + let mut sol = None; + while head.hash() == *latest_hash && time::get_time().sec < deadline { + let pow_hash = b.header.pre_pow_hash(); + if let Ok(proof) = cuckoo::Miner::new( + &pow_hash[..], + consensus::EASINESS, + global::proofsize(), + global::sizeshift(), + ).mine() + { + let proof_diff = proof.clone().to_difficulty(); + if proof_diff >= (b.header.total_difficulty.clone() - head.total_difficulty.clone()) + { + sol = Some(proof); + break; + } + } + + b.header.nonce += 1; + *latest_hash = self.chain.head().unwrap().last_block_h; + iter_count += 1; + } + + if sol == None { + debug!( + LOGGER, + "(Server ID: {}) No solution found after {} iterations, continuing...", + self.debug_output_id, + iter_count + ) + } + + sol + } + + /// Starts the mining loop, building a new block on top of the existing + /// chain anytime required and looking for PoW solution. + pub fn run_loop(&self, wallet_listener_url: Option) { + info!( + LOGGER, + "(Server ID: {}) Starting test miner loop.", self.debug_output_id + ); + + // iteration, we keep the returned derivation to provide it back when + // nothing has changed. We only want to create a new key_id for each new block. + let mut key_id = None; + + loop { + trace!(LOGGER, "in miner loop. key_id: {:?}", key_id); + + // get the latest chain state and build a block on top of it + let head = self.chain.head_header().unwrap(); + let mut latest_hash = self.chain.head().unwrap().last_block_h; + + let (mut b, block_fees) = mine_block::get_block( + &self.chain, + &self.tx_pool, + key_id.clone(), + MAX_TX.clone(), + wallet_listener_url.clone(), + ); + + let sol = self.inner_mining_loop( + &mut b, + &head, + self.config.attempt_time_per_block, + &mut latest_hash, + ); + + // we found a solution, push our block through the chain processing pipeline + if let Some(proof) = sol { + b.header.pow = proof; + info!( + LOGGER, + "(Server ID: {}) Found valid proof of work, adding block {}.", + self.debug_output_id, + b.hash() + ); + let res = self.chain.process_block(b, chain::Options::MINE); + if let Err(e) = res { + error!( + LOGGER, + "(Server ID: {}) Error validating mined block: {:?}", + self.debug_output_id, + e + ); + } + trace!(LOGGER, "resetting key_id in miner to None"); + key_id = None; + } else { + debug!( + LOGGER, + "setting pubkey in miner to pubkey from block_fees - {:?}", block_fees + ); + key_id = block_fees.key_id(); + } + + if self.stop.load(Ordering::Relaxed) { + break; + } + } + } +} diff --git a/servers/tests/api.rs b/servers/tests/api.rs index 2a35e2fc0..082bc53f3 100644 --- a/servers/tests/api.rs +++ b/servers/tests/api.rs @@ -19,9 +19,8 @@ extern crate grin_api as api; extern crate grin_chain as chain; extern crate grin_config as config; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; diff --git a/servers/tests/dandelion.rs b/servers/tests/dandelion.rs index 94eed8b7e..3f7d91f6e 100644 --- a/servers/tests/dandelion.rs +++ b/servers/tests/dandelion.rs @@ -20,9 +20,8 @@ extern crate grin_api as api; extern crate grin_chain as chain; extern crate grin_config as config; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; diff --git a/servers/tests/framework/mod.rs b/servers/tests/framework/mod.rs index 45bef2a9e..b5d908e81 100644 --- a/servers/tests/framework/mod.rs +++ b/servers/tests/framework/mod.rs @@ -15,10 +15,9 @@ extern crate grin_api as api; extern crate grin_chain as chain; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_keychain as keychain; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; @@ -189,22 +188,6 @@ impl LocalServerContainer { seeds = vec![self.config.seed_addr.to_string()]; } - let mut plugin_config = pow::types::CuckooMinerPluginConfig::default(); - let mut plugin_config_vec: Vec = Vec::new(); - plugin_config.type_filter = String::from("mean_cpu"); - plugin_config_vec.push(plugin_config); - - let miner_config = pow::types::MinerConfig { - enable_mining: self.config.start_miner, - burn_reward: self.config.burn_mining_rewards, - miner_async_mode: Some(false), - miner_plugin_dir: None, - miner_plugin_config: Some(plugin_config_vec), - wallet_listener_url: self.config.coinbase_wallet_address.clone(), - slow_down_in_millis: Some(self.config.miner_slowdown_in_millis.clone()), - ..Default::default() - }; - let s = servers::Server::new(servers::ServerConfig { api_http_addr: api_addr, db_root: format!("{}/.grin", self.working_dir), @@ -216,21 +199,30 @@ impl LocalServerContainer { seeding_type: seeding_type, chain_type: core::global::ChainTypes::AutomatedTesting, skip_sync_wait: Some(true), - mining_config: Some(miner_config.clone()), + stratum_mining_config: None, ..Default::default() }).unwrap(); self.p2p_server_stats = Some(s.get_server_stats().unwrap()); + let mut wallet_url = None; + if self.config.start_wallet == true { self.run_wallet(duration_in_seconds + 5); // give a second to start wallet before continuing thread::sleep(time::Duration::from_millis(1000)); + wallet_url = Some(format!( + "http://{}:{}", + self.config.base_addr, self.config.wallet_port + )); } if self.config.start_miner == true { - println!("starting Miner on port {}", self.config.p2p_server_port); - s.start_miner(miner_config); + println!( + "starting test Miner on port {}", + self.config.p2p_server_port + ); + s.start_test_miner(wallet_url); } for p in &mut self.peer_list { @@ -576,19 +568,13 @@ pub fn config(n: u16, test_name_dir: &str, seed_n: u16) -> servers::ServerConfig } } -/// Create and return a MinerConfig -pub fn miner_config() -> pow::types::MinerConfig { - let mut plugin_config = pow::types::CuckooMinerPluginConfig::default(); - let mut plugin_config_vec: Vec = Vec::new(); - plugin_config.type_filter = String::from("mean_cpu"); - plugin_config_vec.push(plugin_config); - - pow::types::MinerConfig { - enable_mining: true, - burn_reward: true, - miner_async_mode: Some(false), - miner_plugin_dir: None, - miner_plugin_config: Some(plugin_config_vec), - ..Default::default() +/// return stratum mining config +pub fn stratum_config() -> servers::common::types::StratumServerConfig { + servers::common::types::StratumServerConfig { + enable_stratum_server: Some(true), + stratum_server_addr: Some(String::from("127.0.0.1:13416")), + attempt_time_per_block: 60, + wallet_listener_url: String::from("http://127.0.0.1:13415"), + burn_reward: false, } } diff --git a/servers/tests/simulnet.rs b/servers/tests/simulnet.rs index 9ed640518..34ff0301e 100644 --- a/servers/tests/simulnet.rs +++ b/servers/tests/simulnet.rs @@ -15,9 +15,8 @@ extern crate grin_api as api; extern crate grin_chain as chain; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; @@ -32,8 +31,8 @@ use std::default::Default; use core::global; use core::global::ChainTypes; -use framework::{LocalServerContainerConfig, LocalServerContainerPool, - LocalServerContainerPoolConfig, config, miner_config}; +use framework::{config, stratum_config, LocalServerContainerConfig, LocalServerContainerPool, + LocalServerContainerPoolConfig}; /// Testing the frameworks by starting a fresh server, creating a genesis /// Block and mining into a wallet for a bit @@ -194,7 +193,7 @@ fn simulate_block_propagation() { } // start mining - servers[0].start_miner(miner_config()); + servers[0].start_test_miner(None); let _original_height = servers[0].head().height; // monitor for a change of head on a different server and check whether @@ -230,7 +229,7 @@ fn simulate_full_sync() { let s1 = servers::Server::new(framework::config(1000, "grin-sync", 1000)).unwrap(); // mine a few blocks on server 1 - s1.start_miner(miner_config()); + s1.start_test_miner(None); thread::sleep(time::Duration::from_secs(8)); #[ignore(unused_mut)] // mut needed? @@ -257,7 +256,7 @@ fn simulate_fast_sync() { let s1 = servers::Server::new(framework::config(2000, "grin-fast", 2000)).unwrap(); // mine a few blocks on server 1 - s1.start_miner(miner_config()); + s1.start_test_miner(None); thread::sleep(time::Duration::from_secs(8)); let mut conf = config(2001, "grin-fast", 2000); @@ -284,7 +283,7 @@ fn simulate_fast_sync_double() { let s1 = servers::Server::new(framework::config(3000, "grin-double-fast1", 3000)).unwrap(); // mine a few blocks on server 1 - s1.start_miner(miner_config()); + s1.start_test_miner(None); thread::sleep(time::Duration::from_secs(8)); { diff --git a/servers/tests/stratum.rs b/servers/tests/stratum.rs index 2c28fdcf1..98e033305 100644 --- a/servers/tests/stratum.rs +++ b/servers/tests/stratum.rs @@ -15,9 +15,8 @@ extern crate grin_api as api; extern crate grin_chain as chain; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; @@ -37,7 +36,7 @@ use std::time; use core::global; use core::global::ChainTypes; -use framework::{config, miner_config}; +use framework::{config, stratum_config}; // Create a grin server, and a stratum server. // Simulate a few JSONRpc requests and verify the results. @@ -55,14 +54,14 @@ fn basic_stratum_server() { let s = servers::Server::new(config(4000, test_name_dir, 0)).unwrap(); // Get mining config with stratumserver enabled - let mut miner_cfg = miner_config(); - miner_cfg.enable_mining = false; - miner_cfg.attempt_time_per_block = 999; - miner_cfg.enable_stratum_server = Some(true); - miner_cfg.stratum_server_addr = Some(String::from("127.0.0.1:11101")); + let mut stratum_cfg = stratum_config(); + stratum_cfg.burn_reward = true; + stratum_cfg.attempt_time_per_block = 999; + stratum_cfg.enable_stratum_server = Some(true); + stratum_cfg.stratum_server_addr = Some(String::from("127.0.0.1:11101")); // Start stratum server - s.start_stratum_server(miner_cfg); + s.start_stratum_server(stratum_cfg); // Wait for stratum server to start and // Verify stratum server accepts connections @@ -142,7 +141,7 @@ fn basic_stratum_server() { assert_eq!(stats.stratum_stats.worker_stats[1].is_connected, true); // Start mining blocks - s.start_miner(miner_config()); + s.start_test_miner(None); // Simulate a worker lost connection workers.remove(1); diff --git a/servers/tests/wallet.rs b/servers/tests/wallet.rs index 8a14826b4..ac1f14c1c 100644 --- a/servers/tests/wallet.rs +++ b/servers/tests/wallet.rs @@ -20,9 +20,8 @@ extern crate grin_api as api; extern crate grin_chain as chain; extern crate grin_config as config; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_p2p as p2p; -extern crate grin_pow as pow; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; diff --git a/src/bin/grin.rs b/src/bin/grin.rs index d4aef23de..90951e6b7 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -28,9 +28,9 @@ extern crate time; extern crate grin_api as api; extern crate grin_config as config; extern crate grin_core as core; -extern crate grin_servers as servers; extern crate grin_keychain as keychain; extern crate grin_p2p as p2p; +extern crate grin_servers as servers; extern crate grin_util as util; extern crate grin_wallet as wallet; @@ -139,10 +139,6 @@ fn main() { .long("seed") .help("Override seed node(s) to connect to") .takes_value(true)) - .arg(Arg::with_name("mine") - .short("m") - .long("mine") - .help("Starts the debugging mining loop")) .arg(Arg::with_name("wallet_url") .short("w") .long("wallet_url") @@ -399,13 +395,9 @@ fn server_command(server_args: Option<&ArgMatches>, mut global_config: GlobalCon server_config.api_http_addr = format!("{}:{}", default_ip, api_port); } - if a.is_present("mine") { - server_config.mining_config.as_mut().unwrap().enable_mining = true; - } - if let Some(wallet_url) = a.value_of("wallet_url") { server_config - .mining_config + .stratum_mining_config .as_mut() .unwrap() .wallet_listener_url = wallet_url.to_string(); diff --git a/src/bin/tui/mining.rs b/src/bin/tui/mining.rs index 8249ec909..7ab18fed7 100644 --- a/src/bin/tui/mining.rs +++ b/src/bin/tui/mining.rs @@ -29,81 +29,71 @@ use tui::chrono::prelude::*; use tui::constants::*; use tui::types::*; -use servers::{ServerStats, DiffBlock}; -use tui::pow::cuckoo_miner::CuckooMinerDeviceStats; +use servers::{DiffBlock, ServerStats, WorkerStats}; use tui::table::{TableView, TableViewItem}; #[derive(Copy, Clone, PartialEq, Eq, Hash)] -enum MiningDeviceColumn { - PluginId, - DeviceId, - DeviceName, - InUse, - ErrorStatus, - LastGraphTime, - GraphsPerSecond, +enum StratumWorkerColumn { + Id, + IsConnected, + LastSeen, + PowDifficulty, + NumAccepted, + NumRejected, + NumStale, } -impl MiningDeviceColumn { +impl StratumWorkerColumn { fn _as_str(&self) -> &str { match *self { - MiningDeviceColumn::PluginId => "Plugin ID", - MiningDeviceColumn::DeviceId => "Device ID", - MiningDeviceColumn::DeviceName => "Name", - MiningDeviceColumn::InUse => "In Use", - MiningDeviceColumn::ErrorStatus => "Status", - MiningDeviceColumn::LastGraphTime => "Last Graph Time", - MiningDeviceColumn::GraphsPerSecond => "GPS", + StratumWorkerColumn::Id => "Worker ID", + StratumWorkerColumn::IsConnected => "Connected", + StratumWorkerColumn::LastSeen => "Last Seen", + StratumWorkerColumn::PowDifficulty => "PowDifficulty", + StratumWorkerColumn::NumAccepted => "Num Accepted", + StratumWorkerColumn::NumRejected => "Num Rejected", + StratumWorkerColumn::NumStale => "Num Stale", } } } -impl TableViewItem for CuckooMinerDeviceStats { - fn to_column(&self, column: MiningDeviceColumn) -> String { - let last_solution_time_secs = self.last_solution_time as f64 / 1000000000.0; +impl TableViewItem for WorkerStats { + fn to_column(&self, column: StratumWorkerColumn) -> String { + let naive_datetime = NaiveDateTime::from_timestamp( + self.last_seen + .duration_since(time::UNIX_EPOCH) + .unwrap() + .as_secs() as i64, + 0, + ); + let datetime: DateTime = DateTime::from_utc(naive_datetime, Utc); + match column { - MiningDeviceColumn::PluginId => String::from("TBD"), - MiningDeviceColumn::DeviceId => self.device_id.clone(), - MiningDeviceColumn::DeviceName => self.device_name.clone(), - MiningDeviceColumn::InUse => match self.in_use { - 1 => String::from("Yes"), - _ => String::from("No"), - }, - MiningDeviceColumn::ErrorStatus => match self.has_errored { - 0 => String::from("OK"), - _ => String::from("Errored"), - }, - MiningDeviceColumn::LastGraphTime => { - String::from(format!("{}s", last_solution_time_secs)) - } - MiningDeviceColumn::GraphsPerSecond => { - String::from(format!("{:.*}", 4, 1.0 / last_solution_time_secs)) - } + StratumWorkerColumn::Id => self.id.clone(), + StratumWorkerColumn::IsConnected => self.is_connected.to_string(), + StratumWorkerColumn::LastSeen => datetime.to_string(), + StratumWorkerColumn::PowDifficulty => self.pow_difficulty.to_string(), + StratumWorkerColumn::NumAccepted => self.num_accepted.to_string(), + StratumWorkerColumn::NumRejected => self.num_rejected.to_string(), + StratumWorkerColumn::NumStale => self.num_stale.to_string(), } } - fn cmp(&self, other: &Self, column: MiningDeviceColumn) -> Ordering + fn cmp(&self, _other: &Self, column: StratumWorkerColumn) -> Ordering where Self: Sized, { - let last_solution_time_secs_self = self.last_solution_time as f64 / 1000000000.0; - let gps_self = 1.0 / last_solution_time_secs_self; - let last_solution_time_secs_other = other.last_solution_time as f64 / 1000000000.0; - let gps_other = 1.0 / last_solution_time_secs_other; match column { - MiningDeviceColumn::PluginId => Ordering::Equal, - MiningDeviceColumn::DeviceId => self.device_id.cmp(&other.device_id), - MiningDeviceColumn::DeviceName => self.device_name.cmp(&other.device_name), - MiningDeviceColumn::InUse => self.in_use.cmp(&other.in_use), - MiningDeviceColumn::ErrorStatus => self.has_errored.cmp(&other.has_errored), - MiningDeviceColumn::LastGraphTime => { - self.last_solution_time.cmp(&other.last_solution_time) - } - MiningDeviceColumn::GraphsPerSecond => gps_self.partial_cmp(&gps_other).unwrap(), + StratumWorkerColumn::Id => Ordering::Equal, + StratumWorkerColumn::IsConnected => Ordering::Equal, + StratumWorkerColumn::LastSeen => Ordering::Equal, + StratumWorkerColumn::PowDifficulty => Ordering::Equal, + StratumWorkerColumn::NumAccepted => Ordering::Equal, + StratumWorkerColumn::NumRejected => Ordering::Equal, + StratumWorkerColumn::NumStale => Ordering::Equal, } } } - #[derive(Copy, Clone, PartialEq, Eq, Hash)] enum DiffColumn { BlockNumber, @@ -154,7 +144,7 @@ pub struct TUIMiningView; impl TUIStatusListener for TUIMiningView { /// Create the mining view fn create() -> Box { - let devices_button = Button::new_raw("Status / Devices", |s| { + let devices_button = Button::new_raw("Mining Server Status", |s| { let _ = s.call_on_id("mining_stack_view", |sv: &mut StackView| { let pos = sv.find_layer_from_id("mining_device_view").unwrap(); sv.move_to_front(pos); @@ -174,47 +164,60 @@ impl TUIStatusListener for TUIMiningView { let _ = c.focus_id(MAIN_MENU); }); - let table_view = - TableView::::new() - .column(MiningDeviceColumn::PluginId, "Plugin ID", |c| { - c.width_percent(10) - }) - .column(MiningDeviceColumn::DeviceId, "Device ID", |c| { - c.width_percent(10) - }) - .column(MiningDeviceColumn::DeviceName, "Device Name", |c| { - c.width_percent(20) - }) - .column(MiningDeviceColumn::InUse, "In Use", |c| c.width_percent(10)) - .column(MiningDeviceColumn::ErrorStatus, "Status", |c| { - c.width_percent(10) - }) - .column(MiningDeviceColumn::LastGraphTime, "Graph Time", |c| { - c.width_percent(10) - }) - .column(MiningDeviceColumn::GraphsPerSecond, "GPS", |c| { - c.width_percent(10) - }); + let table_view = TableView::::new() + .column(StratumWorkerColumn::Id, "Worker ID", |c| { + c.width_percent(10) + }) + .column(StratumWorkerColumn::IsConnected, "Connected", |c| { + c.width_percent(10) + }) + .column(StratumWorkerColumn::LastSeen, "Last Seen", |c| { + c.width_percent(20) + }) + .column(StratumWorkerColumn::PowDifficulty, "Pow Difficulty", |c| { + c.width_percent(10) + }) + .column(StratumWorkerColumn::NumAccepted, "Num Accepted", |c| { + c.width_percent(10) + }) + .column(StratumWorkerColumn::NumRejected, "Num Rejected", |c| { + c.width_percent(10) + }) + .column(StratumWorkerColumn::NumStale, "Num Stale", |c| { + c.width_percent(10) + }); let status_view = LinearLayout::new(Orientation::Vertical) .child( LinearLayout::new(Orientation::Horizontal) - .child(TextView::new(" ").with_id("mining_config_status")), + .child(TextView::new(" ").with_id("stratum_config_status")), ) .child( LinearLayout::new(Orientation::Horizontal) - .child(TextView::new(" ").with_id("mining_status")), + .child(TextView::new(" ").with_id("stratum_is_running_status")), ) .child( LinearLayout::new(Orientation::Horizontal) - .child(TextView::new(" ").with_id("network_info")), + .child(TextView::new(" ").with_id("stratum_num_workers_status")), + ) + .child( + LinearLayout::new(Orientation::Horizontal) + .child(TextView::new(" ").with_id("stratum_block_height_status")), + ) + .child( + LinearLayout::new(Orientation::Horizontal) + .child(TextView::new(" ").with_id("stratum_network_difficulty_status")), + ) + .child( + LinearLayout::new(Orientation::Horizontal) + .child(TextView::new(" ").with_id("stratum_cuckoo_size_status")), ); let mining_device_view = LinearLayout::new(Orientation::Vertical) .child(status_view) .child(BoxView::with_full_screen( Dialog::around(table_view.with_id(TABLE_MINING_STATUS).min_size((50, 20))) - .title("Mining Devices"), + .title("Mining Workers"), )) .with_id("mining_device_view"); @@ -275,55 +278,6 @@ impl TUIStatusListener for TUIMiningView { /// update fn update(c: &mut Cursive, stats: &ServerStats) { - let basic_mining_config_status = { - if stats.mining_stats.is_enabled { - "Configured as mining node" - } else { - "Configured as validating node only (not mining)" - } - }; - let (basic_mining_status, basic_network_info) = { - if stats.mining_stats.is_enabled { - if stats.is_syncing { - ( - "Mining Status: Paused while syncing".to_string(), - " ".to_string(), - ) - } else if stats.mining_stats.combined_gps == 0.0 { - ( - "Mining Status: Starting miner and awaiting first solution...".to_string(), - " ".to_string(), - ) - } else { - ( - format!( - "Mining Status: Mining at height {} at {:.*} GPS", - stats.mining_stats.block_height, 4, stats.mining_stats.combined_gps - ), - format!( - "Cuckoo {} - Network Difficulty {}", - stats.mining_stats.cuckoo_size, - stats.mining_stats.network_difficulty.to_string() - ), - ) - } - } else { - (" ".to_string(), " ".to_string()) - } - }; - - // device - c.call_on_id("mining_config_status", |t: &mut TextView| { - t.set_content(basic_mining_config_status); - }); - c.call_on_id("mining_status", |t: &mut TextView| { - t.set_content(basic_mining_status); - }); - c.call_on_id("network_info", |t: &mut TextView| { - t.set_content(basic_network_info); - }); - - //diff stats c.call_on_id("diff_cur_height", |t: &mut TextView| { t.set_content(stats.diff_stats.height.to_string()); }); @@ -338,8 +292,6 @@ impl TUIStatusListener for TUIMiningView { t.set_content(stats.diff_stats.average_difficulty.to_string()); }); - let mining_stats = stats.mining_stats.clone(); - let device_stats = mining_stats.device_stats; let mut diff_stats = stats.diff_stats.last_blocks.clone(); diff_stats.reverse(); let _ = c.call_on_id( @@ -348,22 +300,38 @@ impl TUIStatusListener for TUIMiningView { t.set_items(diff_stats); }, ); + let stratum_stats = stats.stratum_stats.clone(); + let worker_stats = stratum_stats.worker_stats; + let stratum_enabled = format!("Mining server enabled: {}", stratum_stats.is_enabled); + let stratum_is_running = format!("Mining server running: {}", stratum_stats.is_running); + let stratum_num_workers = format!("Number of workers: {}", stratum_stats.num_workers); + let stratum_block_height = format!("Solving Block Height: {}", stratum_stats.block_height); + let stratum_network_difficulty = + format!("Network Difficulty: {}", stratum_stats.network_difficulty); + let stratum_cuckoo_size = format!("Cuckoo Size: {}", stratum_stats.cuckoo_size); - if device_stats.is_none() { - return; - } - let device_stats = device_stats.unwrap(); - let mut flattened_device_stats = vec![]; - for p in device_stats.into_iter() { - for d in p.into_iter() { - flattened_device_stats.push(d); - } - } - + c.call_on_id("stratum_config_status", |t: &mut TextView| { + t.set_content(stratum_enabled); + }); + c.call_on_id("stratum_is_running_status", |t: &mut TextView| { + t.set_content(stratum_is_running); + }); + c.call_on_id("stratum_num_workers_status", |t: &mut TextView| { + t.set_content(stratum_num_workers); + }); + c.call_on_id("stratum_block_height_status", |t: &mut TextView| { + t.set_content(stratum_block_height); + }); + c.call_on_id("stratum_network_difficulty_status", |t: &mut TextView| { + t.set_content(stratum_network_difficulty); + }); + c.call_on_id("stratum_cuckoo_size_status", |t: &mut TextView| { + t.set_content(stratum_cuckoo_size); + }); let _ = c.call_on_id( TABLE_MINING_STATUS, - |t: &mut TableView| { - t.set_items(flattened_device_stats); + |t: &mut TableView| { + t.set_items(worker_stats); }, ); } diff --git a/src/bin/tui/mod.rs b/src/bin/tui/mod.rs index 27ad011e5..04316cd8c 100644 --- a/src/bin/tui/mod.rs +++ b/src/bin/tui/mod.rs @@ -14,7 +14,6 @@ //! Grin TUI extern crate chrono; -extern crate grin_pow as pow; pub mod ui; pub mod table; diff --git a/src/bin/tui/status.rs b/src/bin/tui/status.rs index aaca22aba..66f56ccdb 100644 --- a/src/bin/tui/status.rs +++ b/src/bin/tui/status.rs @@ -86,7 +86,7 @@ impl TUIStatusListener for TUIStatusView { "Running".to_string() } }; - let basic_mining_config_status = { + /*let basic_mining_config_status = { if stats.mining_stats.is_enabled { "Configured as mining node" } else { @@ -121,7 +121,7 @@ impl TUIStatusListener for TUIStatusView { } else { (" ".to_string(), " ".to_string()) } - }; + };*/ c.call_on_id("basic_current_status", |t: &mut TextView| { t.set_content(basic_status); }); @@ -134,7 +134,7 @@ impl TUIStatusListener for TUIStatusView { c.call_on_id("basic_total_difficulty", |t: &mut TextView| { t.set_content(stats.head.total_difficulty.to_string()); }); - c.call_on_id("basic_mining_config_status", |t: &mut TextView| { + /*c.call_on_id("basic_mining_config_status", |t: &mut TextView| { t.set_content(basic_mining_config_status); }); c.call_on_id("basic_mining_status", |t: &mut TextView| { @@ -142,6 +142,6 @@ impl TUIStatusListener for TUIStatusView { }); c.call_on_id("basic_network_info", |t: &mut TextView| { t.set_content(basic_network_info); - }); + });*/ } } diff --git a/src/bin/tui/table.rs b/src/bin/tui/table.rs index b8de142f7..1bc88791d 100644 --- a/src/bin/tui/table.rs +++ b/src/bin/tui/table.rs @@ -287,9 +287,7 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView /// # Example /// /// ```norun - /// table.set_on_sort(|siv: &mut Cursive, column: BasicColumn, order: Ordering| { - /// - /// }); + /// rt(|siv: &mut Cursive, column: BasicColumn, order: Ordering| {}); /// ``` pub fn set_on_sort(&mut self, cb: F) where @@ -306,9 +304,7 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView /// # Example /// /// ```norun - /// table.on_sort(|siv: &mut Cursive, column: BasicColumn, order: Ordering| { - /// - /// }); + /// siv: &mut Cursive, column: BasicColumn, order: Ordering| {}); /// ``` pub fn on_sort(self, cb: F) -> Self where @@ -326,9 +322,7 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView /// # Example /// /// ```norun - /// table.set_on_submit(|siv: &mut Cursive, row: usize, index: usize| { - /// - /// }); + /// bmit(|siv: &mut Cursive, row: usize, index: usize| {}); /// ``` pub fn set_on_submit(&mut self, cb: F) where @@ -348,9 +342,7 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView /// # Example /// /// ```norun - /// table.on_submit(|siv: &mut Cursive, row: usize, index: usize| { - /// - /// }); + /// (|siv: &mut Cursive, row: usize, index: usize| {}); /// ``` pub fn on_submit(self, cb: F) -> Self where @@ -367,9 +359,7 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView /// # Example /// /// ```norun - /// table.set_on_select(|siv: &mut Cursive, row: usize, index: usize| { - /// - /// }); + /// lect(|siv: &mut Cursive, row: usize, index: usize| {}); /// ``` pub fn set_on_select(&mut self, cb: F) where @@ -388,9 +378,7 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView /// # Example /// /// ```norun - /// table.on_select(|siv: &mut Cursive, row: usize, index: usize| { - /// - /// }); + /// (|siv: &mut Cursive, row: usize, index: usize| {}); /// ``` pub fn on_select(self, cb: F) -> Self where @@ -693,7 +681,8 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView } impl + 'static, H: Eq + Hash + Copy + Clone + 'static> View - for TableView { + for TableView +{ fn draw(&self, printer: &Printer) { self.draw_columns(printer, "╷ ", |printer, column| { let color = if column.order != Ordering::Equal || column.selected {