mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
[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
This commit is contained in:
parent
46a7245ec1
commit
4c6a193e01
46 changed files with 661 additions and 1684 deletions
|
@ -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
|
||||
|
|
63
Cargo.lock
generated
63
Cargo.lock
generated
|
@ -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)" = "<none>"
|
||||
"checksum cursive 0.8.2-alpha.0 (git+https://github.com/yeastplume/Cursive?tag=grin_integration_1)" = "<none>"
|
||||
"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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -22,5 +22,3 @@ grin_util = { path = "../util" }
|
|||
[dev-dependencies]
|
||||
env_logger = "0.3"
|
||||
rand = "0.3"
|
||||
|
||||
grin_pow = { path = "../pow" }
|
||||
|
|
|
@ -131,7 +131,7 @@ pub struct Chain {
|
|||
txhashset: Arc<RwLock<txhashset::TxHashSet>>,
|
||||
|
||||
// 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<ChainAdapter>,
|
||||
genesis: Block,
|
||||
pow_verifier: fn(&BlockHeader, u32) -> bool,
|
||||
pow_verifier: fn(&BlockHeader, u8) -> bool,
|
||||
) -> Result<Chain, Error> {
|
||||
let chain_store = store::ChainKVStore::new(db_root.clone())?;
|
||||
|
||||
|
|
|
@ -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<RwLock<txhashset::TxHashSet>>,
|
||||
}
|
||||
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {}),
|
||||
|
|
|
@ -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()))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<MinerConfig>,
|
||||
pub mining_server: Option<StratumServerConfig>,
|
||||
/// Logging config
|
||||
pub logging: Option<LoggingConfig>,
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -47,3 +47,4 @@ pub mod core;
|
|||
pub mod genesis;
|
||||
pub mod ser;
|
||||
pub mod global;
|
||||
pub mod pow;
|
||||
|
|
|
@ -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: Cuckoo,
|
||||
graph: Vec<u32>,
|
||||
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<Proof, Error> {
|
||||
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<Proof, Error> {
|
||||
pub fn mine(&mut self) -> Result<Proof, Error> {
|
||||
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));
|
||||
}
|
||||
}
|
|
@ -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<Proof, Error>;
|
||||
}
|
||||
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<types::MinerConfig>,
|
||||
) -> Result<core::core::Block, Error> {
|
||||
/// Mines a genesis block using the internal miner
|
||||
pub fn mine_genesis_block() -> Result<Block, Error> {
|
||||
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<MiningWorker> = 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<T: MiningWorker + ?Sized>(
|
||||
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<T: MiningWorker + ?Sized>(
|
|||
|
||||
// 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<T: MiningWorker + ?Sized>(
|
|||
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()));
|
||||
}
|
||||
}
|
21
doc/build.md
21
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)
|
||||
|
|
175
grin.toml
175
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
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
[package]
|
||||
name = "grin_pow"
|
||||
version = "0.2.0"
|
||||
|
||||
authors = ["Grin Developers <mimblewimble@lists.launchpad.net>"]
|
||||
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"]
|
|
@ -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<Option<Vec<CuckooMinerConfig>>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
/// plugin miner
|
||||
pub struct PluginMiner {
|
||||
/// the miner
|
||||
pub miner: Option<CuckooMiner>,
|
||||
last_solution: CuckooMinerSolution,
|
||||
config: Vec<CuckooMinerConfig>,
|
||||
}
|
||||
|
||||
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::<u32>() {
|
||||
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<Vec<CuckooMinerDeviceStats>, 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<Proof, cuckoo::Error> {
|
||||
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)
|
||||
}
|
||||
}
|
|
@ -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<HashMap<String, HashMap<String, u32>>>,
|
||||
}
|
||||
|
||||
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<bool>,
|
||||
|
||||
/// plugin dir
|
||||
pub miner_plugin_dir: Option<String>,
|
||||
|
||||
/// Cuckoo miner plugin configuration, one for each plugin
|
||||
pub miner_plugin_config: Option<Vec<CuckooMinerPluginConfig>>,
|
||||
|
||||
/// 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<u64>,
|
||||
|
||||
/// Run a stratum mining server rather than mining locally in-process
|
||||
pub enable_stratum_server: Option<bool>,
|
||||
|
||||
/// If enabled, the address and port to listen on
|
||||
pub stratum_server_addr: Option<String>,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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" }
|
||||
|
|
|
@ -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<AtomicBool>,
|
||||
/// Mining stats
|
||||
pub mining_stats: Arc<RwLock<MiningStats>>,
|
||||
/// Stratum stats
|
||||
pub stratum_stats: Arc<RwLock<StratumStats>>,
|
||||
}
|
||||
|
@ -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<Vec<Vec<pow::cuckoo_miner::CuckooMinerDeviceStats>>>,
|
||||
}
|
||||
|
||||
/// 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<WorkerStats>,
|
||||
/// 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<WorkerStats>,
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
|
|
|
@ -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<pow::types::MinerConfig>,
|
||||
pub stratum_mining_config: Option<StratumServerConfig>,
|
||||
|
||||
/// 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<bool>,
|
||||
|
||||
/// Whether to run the test miner (internal, cuckoo 16)
|
||||
pub run_test_miner: Option<bool>,
|
||||
|
||||
/// Test miner wallet URL
|
||||
pub test_miner_wallet_url: Option<String>,
|
||||
}
|
||||
|
||||
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<bool>,
|
||||
|
||||
/// If enabled, the address and port to listen on
|
||||
pub stratum_server_addr: Option<String>,
|
||||
|
||||
/// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Server>),
|
||||
{
|
||||
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<String>) {
|
||||
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<ServerStats, Error> {
|
||||
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,
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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<u8>,
|
||||
pub pre_pow: Vec<u8>,
|
||||
}
|
||||
|
||||
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<T: AsFixedBytes>(&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<T: AsFixedBytes>(&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
|
||||
|
|
|
@ -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<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
stop: Arc<AtomicBool>,
|
||||
|
||||
// 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<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
stop: Arc<AtomicBool>,
|
||||
) -> 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<RwLock<MiningStats>>,
|
||||
) -> Option<Proof> {
|
||||
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<RwLock<MiningStats>>,
|
||||
) -> Option<Proof> {
|
||||
// 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<T: MiningWorker>(
|
||||
&self,
|
||||
miner: &mut T,
|
||||
b: &mut Block,
|
||||
cuckoo_size: u32,
|
||||
head: &BlockHeader,
|
||||
attempt_time_per_block: u32,
|
||||
latest_hash: &mut Hash,
|
||||
) -> Option<Proof> {
|
||||
// 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<RwLock<MiningStats>>,
|
||||
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<String> = 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,6 @@
|
|||
|
||||
//! Mining + Mining server
|
||||
|
||||
pub mod miner;
|
||||
pub mod test_miner;
|
||||
pub mod stratumserver;
|
||||
mod mine_block;
|
||||
|
|
|
@ -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<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
current_block: Block,
|
||||
current_difficulty: u64,
|
||||
workers: Arc<Mutex<Vec<Worker>>>,
|
||||
currently_syncing: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl StratumServer {
|
||||
/// Creates a new Stratum Server.
|
||||
pub fn new(
|
||||
config: MinerConfig,
|
||||
config: StratumServerConfig,
|
||||
chain_ref: Arc<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
) -> StratumServer {
|
||||
|
@ -245,6 +247,7 @@ impl StratumServer {
|
|||
current_block: Block::default(),
|
||||
current_difficulty: <u64>::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<RwLock<StratumStats>>,
|
||||
cuckoo_size: u32,
|
||||
proof_size: usize,
|
||||
currently_syncing: Arc<AtomicBool>,
|
||||
) {
|
||||
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;
|
||||
|
|
203
servers/src/mining/test_miner.rs
Normal file
203
servers/src/mining/test_miner.rs
Normal file
|
@ -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<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
stop: Arc<AtomicBool>,
|
||||
|
||||
// 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<chain::Chain>,
|
||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||
stop: Arc<AtomicBool>,
|
||||
) -> 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<Proof> {
|
||||
// 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<String>) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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<pow::types::CuckooMinerPluginConfig> = 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<pow::types::CuckooMinerPluginConfig> = 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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<MiningDeviceColumn> for CuckooMinerDeviceStats {
|
||||
fn to_column(&self, column: MiningDeviceColumn) -> String {
|
||||
let last_solution_time_secs = self.last_solution_time as f64 / 1000000000.0;
|
||||
impl TableViewItem<StratumWorkerColumn> 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<Utc> = 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<View> {
|
||||
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::<CuckooMinerDeviceStats, MiningDeviceColumn>::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::<WorkerStats, StratumWorkerColumn>::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<CuckooMinerDeviceStats, MiningDeviceColumn>| {
|
||||
t.set_items(flattened_device_stats);
|
||||
|t: &mut TableView<WorkerStats, StratumWorkerColumn>| {
|
||||
t.set_items(worker_stats);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
//! Grin TUI
|
||||
extern crate chrono;
|
||||
extern crate grin_pow as pow;
|
||||
|
||||
pub mod ui;
|
||||
pub mod table;
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,9 +287,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// # 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<F>(&mut self, cb: F)
|
||||
where
|
||||
|
@ -306,9 +304,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// # Example
|
||||
///
|
||||
/// ```norun
|
||||
/// table.on_sort(|siv: &mut Cursive, column: BasicColumn, order: Ordering| {
|
||||
///
|
||||
/// });
|
||||
/// siv: &mut Cursive, column: BasicColumn, order: Ordering| {});
|
||||
/// ```
|
||||
pub fn on_sort<F>(self, cb: F) -> Self
|
||||
where
|
||||
|
@ -326,9 +322,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// # 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<F>(&mut self, cb: F)
|
||||
where
|
||||
|
@ -348,9 +342,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// # Example
|
||||
///
|
||||
/// ```norun
|
||||
/// table.on_submit(|siv: &mut Cursive, row: usize, index: usize| {
|
||||
///
|
||||
/// });
|
||||
/// (|siv: &mut Cursive, row: usize, index: usize| {});
|
||||
/// ```
|
||||
pub fn on_submit<F>(self, cb: F) -> Self
|
||||
where
|
||||
|
@ -367,9 +359,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// # 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<F>(&mut self, cb: F)
|
||||
where
|
||||
|
@ -388,9 +378,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
/// # Example
|
||||
///
|
||||
/// ```norun
|
||||
/// table.on_select(|siv: &mut Cursive, row: usize, index: usize| {
|
||||
///
|
||||
/// });
|
||||
/// (|siv: &mut Cursive, row: usize, index: usize| {});
|
||||
/// ```
|
||||
pub fn on_select<F>(self, cb: F) -> Self
|
||||
where
|
||||
|
@ -693,7 +681,8 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
|||
}
|
||||
|
||||
impl<T: TableViewItem<H> + 'static, H: Eq + Hash + Copy + Clone + 'static> View
|
||||
for TableView<T, H> {
|
||||
for TableView<T, H>
|
||||
{
|
||||
fn draw(&self, printer: &Printer) {
|
||||
self.draw_columns(printer, "╷ ", |printer, column| {
|
||||
let color = if column.order != Ordering::Equal || column.selected {
|
||||
|
|
Loading…
Reference in a new issue