mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21: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=wallet
|
||||||
- TEST_DIR=p2p
|
- TEST_DIR=p2p
|
||||||
- TEST_DIR=api
|
- TEST_DIR=api
|
||||||
- TEST_DIR=pow
|
|
||||||
- TEST_DIR=keychain
|
- TEST_DIR=keychain
|
||||||
- TEST_DIR=core
|
- TEST_DIR=core
|
||||||
- TEST_DIR=util
|
- 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)",
|
"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]]
|
[[package]]
|
||||||
name = "cursive"
|
name = "cursive"
|
||||||
version = "0.8.2-alpha.0"
|
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)",
|
"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]]
|
[[package]]
|
||||||
name = "fuchsia-zircon"
|
name = "fuchsia-zircon"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
|
@ -615,7 +587,6 @@ dependencies = [
|
||||||
"grin_core 0.2.0",
|
"grin_core 0.2.0",
|
||||||
"grin_keychain 0.2.0",
|
"grin_keychain 0.2.0",
|
||||||
"grin_p2p 0.2.0",
|
"grin_p2p 0.2.0",
|
||||||
"grin_pow 0.2.0",
|
|
||||||
"grin_servers 0.2.0",
|
"grin_servers 0.2.0",
|
||||||
"grin_util 0.2.0",
|
"grin_util 0.2.0",
|
||||||
"grin_wallet 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)",
|
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"grin_core 0.2.0",
|
"grin_core 0.2.0",
|
||||||
"grin_keychain 0.2.0",
|
"grin_keychain 0.2.0",
|
||||||
"grin_pow 0.2.0",
|
|
||||||
"grin_store 0.2.0",
|
"grin_store 0.2.0",
|
||||||
"grin_util 0.2.0",
|
"grin_util 0.2.0",
|
||||||
"lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"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"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"grin_p2p 0.2.0",
|
"grin_p2p 0.2.0",
|
||||||
"grin_pow 0.2.0",
|
|
||||||
"grin_servers 0.2.0",
|
"grin_servers 0.2.0",
|
||||||
"grin_util 0.2.0",
|
"grin_util 0.2.0",
|
||||||
"grin_wallet 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)",
|
"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]]
|
[[package]]
|
||||||
name = "grin_servers"
|
name = "grin_servers"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
@ -782,7 +735,6 @@ dependencies = [
|
||||||
"grin_keychain 0.2.0",
|
"grin_keychain 0.2.0",
|
||||||
"grin_p2p 0.2.0",
|
"grin_p2p 0.2.0",
|
||||||
"grin_pool 0.2.0",
|
"grin_pool 0.2.0",
|
||||||
"grin_pow 0.2.0",
|
|
||||||
"grin_store 0.2.0",
|
"grin_store 0.2.0",
|
||||||
"grin_util 0.2.0",
|
"grin_util 0.2.0",
|
||||||
"grin_wallet 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)",
|
"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]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.7"
|
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.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 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 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 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 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"
|
"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 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 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 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 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 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"
|
"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 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 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 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-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 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"
|
"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_core = { path = "./core" }
|
||||||
grin_keychain = { path = "./keychain" }
|
grin_keychain = { path = "./keychain" }
|
||||||
grin_p2p = { path = "./p2p"}
|
grin_p2p = { path = "./p2p"}
|
||||||
grin_pow = { path = "./pow"}
|
|
||||||
grin_servers = { path = "./servers" }
|
grin_servers = { path = "./servers" }
|
||||||
grin_util = { path = "./util"}
|
grin_util = { path = "./util"}
|
||||||
grin_wallet = { path = "./wallet" }
|
grin_wallet = { path = "./wallet" }
|
||||||
|
|
|
@ -22,5 +22,3 @@ grin_util = { path = "../util" }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
|
|
||||||
grin_pow = { path = "../pow" }
|
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub struct Chain {
|
||||||
txhashset: Arc<RwLock<txhashset::TxHashSet>>,
|
txhashset: Arc<RwLock<txhashset::TxHashSet>>,
|
||||||
|
|
||||||
// POW verification function
|
// POW verification function
|
||||||
pow_verifier: fn(&BlockHeader, u32) -> bool,
|
pow_verifier: fn(&BlockHeader, u8) -> bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Sync for Chain {}
|
unsafe impl Sync for Chain {}
|
||||||
|
@ -157,7 +157,7 @@ impl Chain {
|
||||||
db_root: String,
|
db_root: String,
|
||||||
adapter: Arc<ChainAdapter>,
|
adapter: Arc<ChainAdapter>,
|
||||||
genesis: Block,
|
genesis: Block,
|
||||||
pow_verifier: fn(&BlockHeader, u32) -> bool,
|
pow_verifier: fn(&BlockHeader, u8) -> bool,
|
||||||
) -> Result<Chain, Error> {
|
) -> Result<Chain, Error> {
|
||||||
let chain_store = store::ChainKVStore::new(db_root.clone())?;
|
let chain_store = store::ChainKVStore::new(db_root.clone())?;
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ pub struct BlockContext {
|
||||||
/// The head
|
/// The head
|
||||||
pub head: Tip,
|
pub head: Tip,
|
||||||
/// The POW verification function
|
/// The POW verification function
|
||||||
pub pow_verifier: fn(&BlockHeader, u32) -> bool,
|
pub pow_verifier: fn(&BlockHeader, u8) -> bool,
|
||||||
/// MMR sum tree states
|
/// MMR sum tree states
|
||||||
pub txhashset: Arc<RwLock<txhashset::TxHashSet>>,
|
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) {
|
if !ctx.opts.contains(Options::SKIP_POW) {
|
||||||
let n = global::sizeshift() as u32;
|
let n = global::sizeshift();
|
||||||
if !(ctx.pow_verifier)(header, n) {
|
if !(ctx.pow_verifier)(header, n) {
|
||||||
error!(
|
error!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate env_logger;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_pow as pow;
|
|
||||||
extern crate grin_util as util;
|
extern crate grin_util as util;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
@ -34,7 +33,7 @@ use core::global::ChainTypes;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::Keychain;
|
||||||
|
|
||||||
use pow::{cuckoo, types, MiningWorker};
|
use core::pow;
|
||||||
|
|
||||||
fn clean_output_dir(dir_name: &str) {
|
fn clean_output_dir(dir_name: &str) {
|
||||||
let _ = fs::remove_dir_all(dir_name);
|
let _ = fs::remove_dir_all(dir_name);
|
||||||
|
@ -44,7 +43,7 @@ fn setup(dir_name: &str) -> Chain {
|
||||||
util::init_test_logger();
|
util::init_test_logger();
|
||||||
clean_output_dir(dir_name);
|
clean_output_dir(dir_name);
|
||||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
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(
|
chain::Chain::init(
|
||||||
dir_name.to_string(),
|
dir_name.to_string(),
|
||||||
Arc::new(NoopAdapter {}),
|
Arc::new(NoopAdapter {}),
|
||||||
|
@ -70,19 +69,6 @@ fn data_files() {
|
||||||
let chain = setup(chain_dir);
|
let chain = setup(chain_dir);
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
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 {
|
for n in 1..4 {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let difficulty = consensus::next_difficulty(chain.difficulty_iter()).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();
|
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||||
|
|
||||||
pow::pow_size(
|
pow::pow_size(
|
||||||
&mut cuckoo_miner,
|
|
||||||
&mut b.header,
|
&mut b.header,
|
||||||
difficulty,
|
difficulty,
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
// let prev_bhash = b.header.previous;
|
// let prev_bhash = b.header.previous;
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate env_logger;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_pow as pow;
|
|
||||||
extern crate grin_util as util;
|
extern crate grin_util as util;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
@ -35,7 +34,7 @@ use core::global::ChainTypes;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::Keychain;
|
||||||
|
|
||||||
use pow::{cuckoo, types, MiningWorker};
|
use core::pow;
|
||||||
|
|
||||||
fn clean_output_dir(dir_name: &str) {
|
fn clean_output_dir(dir_name: &str) {
|
||||||
let _ = fs::remove_dir_all(dir_name);
|
let _ = fs::remove_dir_all(dir_name);
|
||||||
|
@ -45,7 +44,7 @@ fn setup(dir_name: &str) -> Chain {
|
||||||
let _ = env_logger::init();
|
let _ = env_logger::init();
|
||||||
clean_output_dir(dir_name);
|
clean_output_dir(dir_name);
|
||||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
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(
|
chain::Chain::init(
|
||||||
dir_name.to_string(),
|
dir_name.to_string(),
|
||||||
Arc::new(NoopAdapter {}),
|
Arc::new(NoopAdapter {}),
|
||||||
|
@ -59,19 +58,6 @@ fn mine_empty_chain() {
|
||||||
let chain = setup(".grin");
|
let chain = setup(".grin");
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
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 {
|
for n in 1..4 {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let difficulty = consensus::next_difficulty(chain.difficulty_iter()).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();
|
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||||
|
|
||||||
pow::pow_size(
|
pow::pow_size(
|
||||||
&mut cuckoo_miner,
|
|
||||||
&mut b.header,
|
&mut b.header,
|
||||||
difficulty,
|
difficulty,
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let bhash = b.hash();
|
let bhash = b.hash();
|
||||||
|
@ -438,7 +424,7 @@ fn prepare_block_nosum(
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn actual_diff_iter_output() {
|
fn actual_diff_iter_output() {
|
||||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
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(
|
let chain = chain::Chain::init(
|
||||||
"../.grin".to_string(),
|
"../.grin".to_string(),
|
||||||
Arc::new(NoopAdapter {}),
|
Arc::new(NoopAdapter {}),
|
||||||
|
|
|
@ -16,7 +16,6 @@ extern crate env_logger;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_pow as pow;
|
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -29,6 +28,7 @@ use core::core::target::Difficulty;
|
||||||
use keychain::Keychain;
|
use keychain::Keychain;
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
|
use core::pow;
|
||||||
|
|
||||||
fn clean_output_dir(dir_name: &str) {
|
fn clean_output_dir(dir_name: &str) {
|
||||||
let _ = fs::remove_dir_all(dir_name);
|
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;
|
&chain::store::ChainKVStore::new(chain_dir.to_string()).unwrap() as &ChainStore;
|
||||||
|
|
||||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
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.save_block(&genesis).unwrap();
|
||||||
chain_store
|
chain_store
|
||||||
.setup_height(&genesis.header, &Tip::new(genesis.hash()))
|
.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_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_pow as pow;
|
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
|
@ -34,7 +33,7 @@ use core::global::ChainTypes;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::Keychain;
|
||||||
|
|
||||||
use pow::{cuckoo, types, MiningWorker};
|
use core::pow;
|
||||||
|
|
||||||
fn clean_output_dir(dir_name: &str) {
|
fn clean_output_dir(dir_name: &str) {
|
||||||
let _ = fs::remove_dir_all(dir_name);
|
let _ = fs::remove_dir_all(dir_name);
|
||||||
|
@ -46,7 +45,7 @@ fn test_coinbase_maturity() {
|
||||||
clean_output_dir(".grin");
|
clean_output_dir(".grin");
|
||||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
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(
|
let chain = chain::Chain::init(
|
||||||
".grin".to_string(),
|
".grin".to_string(),
|
||||||
|
@ -55,19 +54,6 @@ fn test_coinbase_maturity() {
|
||||||
pow::verify_size,
|
pow::verify_size,
|
||||||
).unwrap();
|
).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 prev = chain.head_header().unwrap();
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = Keychain::from_random_seed().unwrap();
|
||||||
|
@ -85,10 +71,10 @@ fn test_coinbase_maturity() {
|
||||||
chain.set_txhashset_roots(&mut block, false).unwrap();
|
chain.set_txhashset_roots(&mut block, false).unwrap();
|
||||||
|
|
||||||
pow::pow_size(
|
pow::pow_size(
|
||||||
&mut cuckoo_miner,
|
|
||||||
&mut block.header,
|
&mut block.header,
|
||||||
difficulty,
|
difficulty,
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
assert_eq!(block.outputs.len(), 1);
|
assert_eq!(block.outputs.len(), 1);
|
||||||
|
@ -145,10 +131,10 @@ fn test_coinbase_maturity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pow::pow_size(
|
pow::pow_size(
|
||||||
&mut cuckoo_miner,
|
|
||||||
&mut block.header,
|
&mut block.header,
|
||||||
difficulty,
|
difficulty,
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
// mine enough blocks to increase the height sufficiently for
|
// 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();
|
chain.set_txhashset_roots(&mut block, false).unwrap();
|
||||||
|
|
||||||
pow::pow_size(
|
pow::pow_size(
|
||||||
&mut cuckoo_miner,
|
|
||||||
&mut block.header,
|
&mut block.header,
|
||||||
difficulty,
|
difficulty,
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
chain.process_block(block, chain::Options::MINE).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();
|
chain.set_txhashset_roots(&mut block, false).unwrap();
|
||||||
|
|
||||||
pow::pow_size(
|
pow::pow_size(
|
||||||
&mut cuckoo_miner,
|
|
||||||
&mut block.header,
|
&mut block.header,
|
||||||
difficulty,
|
difficulty,
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let result = chain.process_block(block, chain::Options::MINE);
|
let result = chain.process_block(block, chain::Options::MINE);
|
||||||
|
|
|
@ -12,6 +12,5 @@ toml = "0.4"
|
||||||
|
|
||||||
grin_servers = { path = "../servers" }
|
grin_servers = { path = "../servers" }
|
||||||
grin_p2p = { path = "../p2p" }
|
grin_p2p = { path = "../p2p" }
|
||||||
grin_pow = { path = "../pow"}
|
|
||||||
grin_util = { path = "../util" }
|
grin_util = { path = "../util" }
|
||||||
grin_wallet = { path = "../wallet"}
|
grin_wallet = { path = "../wallet"}
|
||||||
|
|
|
@ -20,8 +20,7 @@ use std::path::PathBuf;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use toml;
|
use toml;
|
||||||
use servers::ServerConfig;
|
use servers::{ServerConfig, StratumServerConfig};
|
||||||
use pow::types::MinerConfig;
|
|
||||||
use util::LoggingConfig;
|
use util::LoggingConfig;
|
||||||
use types::{ConfigError, ConfigMembers, GlobalConfig};
|
use types::{ConfigError, ConfigMembers, GlobalConfig};
|
||||||
use wallet::WalletConfig;
|
use wallet::WalletConfig;
|
||||||
|
@ -38,7 +37,7 @@ impl Default for ConfigMembers {
|
||||||
fn default() -> ConfigMembers {
|
fn default() -> ConfigMembers {
|
||||||
ConfigMembers {
|
ConfigMembers {
|
||||||
server: ServerConfig::default(),
|
server: ServerConfig::default(),
|
||||||
mining: Some(MinerConfig::default()),
|
mining_server: Some(StratumServerConfig::default()),
|
||||||
logging: Some(LoggingConfig::default()),
|
logging: Some(LoggingConfig::default()),
|
||||||
wallet: WalletConfig::default(),
|
wallet: WalletConfig::default(),
|
||||||
}
|
}
|
||||||
|
@ -136,7 +135,7 @@ impl GlobalConfig {
|
||||||
Ok(mut gc) => {
|
Ok(mut gc) => {
|
||||||
// Put the struct back together, because the config
|
// Put the struct back together, because the config
|
||||||
// file was flattened a bit
|
// 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.using_config_file = true;
|
||||||
self.members = Some(gc);
|
self.members = Some(gc);
|
||||||
return Ok(self);
|
return Ok(self);
|
||||||
|
@ -177,13 +176,14 @@ impl GlobalConfig {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/// Enable mining
|
/// Enable mining
|
||||||
pub fn mining_enabled(&mut self) -> bool {
|
pub fn stratum_enabled(&mut self) -> bool {
|
||||||
return self.members
|
return self.members
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.mining
|
.mining_server
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.enable_mining;
|
.enable_stratum_server
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,8 @@ extern crate serde;
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate toml;
|
extern crate toml;
|
||||||
|
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@ use std::path::PathBuf;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use servers::ServerConfig;
|
use servers::{ServerConfig, StratumServerConfig};
|
||||||
use pow::types::MinerConfig;
|
|
||||||
use util::LoggingConfig;
|
use util::LoggingConfig;
|
||||||
use wallet::WalletConfig;
|
use wallet::WalletConfig;
|
||||||
|
|
||||||
|
@ -98,7 +97,7 @@ pub struct ConfigMembers {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub server: ServerConfig,
|
pub server: ServerConfig,
|
||||||
/// Mining config
|
/// Mining config
|
||||||
pub mining: Option<MinerConfig>,
|
pub mining_server: Option<StratumServerConfig>,
|
||||||
/// Logging config
|
/// Logging config
|
||||||
pub logging: Option<LoggingConfig>,
|
pub logging: Option<LoggingConfig>,
|
||||||
|
|
||||||
|
|
|
@ -1079,6 +1079,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn block_10_tx_serialized_size() {
|
fn block_10_tx_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = Keychain::from_random_seed().unwrap();
|
||||||
|
global::set_mining_mode(global::ChainTypes::Mainnet);
|
||||||
|
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
|
|
|
@ -234,7 +234,7 @@ mod test {
|
||||||
use core::block::Error::KernelLockHeight;
|
use core::block::Error::KernelLockHeight;
|
||||||
use ser;
|
use ser;
|
||||||
use keychain;
|
use keychain;
|
||||||
use keychain::{BlindingFactor, Keychain};
|
use keychain::Keychain;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_amount_to_hr() {
|
pub fn test_amount_to_hr() {
|
||||||
|
|
|
@ -47,3 +47,4 @@ pub mod core;
|
||||||
pub mod genesis;
|
pub mod genesis;
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
pub mod global;
|
pub mod global;
|
||||||
|
pub mod pow;
|
||||||
|
|
|
@ -22,9 +22,8 @@ use std::cmp;
|
||||||
|
|
||||||
use blake2;
|
use blake2;
|
||||||
|
|
||||||
use core::core::Proof;
|
use core::Proof;
|
||||||
use siphash::siphash24;
|
use pow::siphash::siphash24;
|
||||||
use MiningWorker;
|
|
||||||
|
|
||||||
const MAXPATHLEN: usize = 8192;
|
const MAXPATHLEN: usize = 8192;
|
||||||
|
|
||||||
|
@ -55,7 +54,7 @@ impl Cuckoo {
|
||||||
/// Initializes a new Cuckoo Cycle setup, using the provided byte array to
|
/// 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
|
/// generate a seed. In practice for PoW applications the byte array is a
|
||||||
/// serialized block header.
|
/// serialized block header.
|
||||||
pub fn new(header: &[u8], sizeshift: u32) -> Cuckoo {
|
pub fn new(header: &[u8], sizeshift: u8) -> Cuckoo {
|
||||||
let size = 1 << sizeshift;
|
let size = 1 << sizeshift;
|
||||||
let hashed = blake2::blake2b::blake2b(32, &[], header);
|
let hashed = blake2::blake2b::blake2b(32, &[], header);
|
||||||
let hashed = hashed.as_bytes();
|
let hashed = hashed.as_bytes();
|
||||||
|
@ -148,32 +147,8 @@ impl Cuckoo {
|
||||||
pub struct Miner {
|
pub struct Miner {
|
||||||
easiness: u64,
|
easiness: u64,
|
||||||
proof_size: usize,
|
proof_size: usize,
|
||||||
cuckoo: Option<Cuckoo>,
|
cuckoo: Cuckoo,
|
||||||
graph: Vec<u32>,
|
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?
|
/// What type of cycle we have found?
|
||||||
|
@ -187,13 +162,27 @@ enum CycleSol {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Miner {
|
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
|
/// 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 us = [0; MAXPATHLEN];
|
||||||
let mut vs = [0; MAXPATHLEN];
|
let mut vs = [0; MAXPATHLEN];
|
||||||
for nonce in 0..self.easiness {
|
for nonce in 0..self.easiness {
|
||||||
us[0] = self.cuckoo.as_mut().unwrap().new_node(nonce, 0) as u32;
|
us[0] = self.cuckoo.new_node(nonce, 0) as u32;
|
||||||
vs[0] = self.cuckoo.as_mut().unwrap().new_node(nonce, 1) as u32;
|
vs[0] = self.cuckoo.new_node(nonce, 1) as u32;
|
||||||
let u = self.graph[us[0] as usize];
|
let u = self.graph[us[0] as usize];
|
||||||
let v = self.graph[vs[0] as usize];
|
let v = self.graph[vs[0] as usize];
|
||||||
if us[0] == 0 {
|
if us[0] == 0 {
|
||||||
|
@ -292,7 +281,7 @@ impl Miner {
|
||||||
let mut n = 0;
|
let mut n = 0;
|
||||||
let mut sol = vec![0; self.proof_size];
|
let mut sol = vec![0; self.proof_size];
|
||||||
for nonce in 0..self.easiness {
|
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) {
|
if cycle.contains(&edge) {
|
||||||
sol[n] = nonce as u32;
|
sol[n] = nonce as u32;
|
||||||
n += 1;
|
n += 1;
|
||||||
|
@ -317,7 +306,7 @@ fn u8_to_u64(p: &[u8], i: usize) -> u64 {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::core::Proof;
|
use core::Proof;
|
||||||
|
|
||||||
static V1: [u32; 42] = [
|
static V1: [u32; 42] = [
|
||||||
0x3bbd, 0x4e96, 0x1013b, 0x1172b, 0x1371b, 0x13e6a, 0x1aaa6, 0x1b575, 0x1e237, 0x1ee88,
|
0x3bbd, 0x4e96, 0x1013b, 0x1172b, 0x1371b, 0x13e6a, 0x1aaa6, 0x1b575, 0x1e237, 0x1ee88,
|
||||||
|
@ -355,13 +344,13 @@ mod test {
|
||||||
/// generated by other implementations.
|
/// generated by other implementations.
|
||||||
#[test]
|
#[test]
|
||||||
fn mine20_vectors() {
|
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);
|
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);
|
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);
|
assert_eq!(Proof::new(V3.to_vec()), nonces3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,13 +388,13 @@ mod test {
|
||||||
// cuckoo20
|
// cuckoo20
|
||||||
for n in 1..5 {
|
for n in 1..5 {
|
||||||
let h = [n; 32];
|
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));
|
assert!(Cuckoo::new(&h, 20).verify(nonces, 75));
|
||||||
}
|
}
|
||||||
// cuckoo18
|
// cuckoo18
|
||||||
for n in 1..5 {
|
for n in 1..5 {
|
||||||
let h = [n; 32];
|
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));
|
assert!(Cuckoo::new(&h, 18).verify(nonces, 75));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -29,62 +29,31 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate blake2_rfc as blake2;
|
extern crate blake2_rfc as blake2;
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
|
||||||
extern crate serde_derive;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate slog;
|
|
||||||
extern crate time;
|
extern crate time;
|
||||||
|
|
||||||
extern crate grin_core as core;
|
|
||||||
extern crate grin_util as util;
|
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;
|
mod siphash;
|
||||||
pub mod plugin;
|
|
||||||
pub mod cuckoo;
|
pub mod cuckoo;
|
||||||
pub mod types;
|
|
||||||
|
|
||||||
use core::consensus;
|
use consensus;
|
||||||
use core::core::BlockHeader;
|
use core::{Block, BlockHeader};
|
||||||
use core::core::Proof;
|
use core::target::Difficulty;
|
||||||
use core::core::target::Difficulty;
|
use global;
|
||||||
use core::global;
|
use genesis;
|
||||||
use core::genesis;
|
use pow::cuckoo::{Cuckoo, Error};
|
||||||
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>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Validates the proof of work of a given header, and that the proof of work
|
/// Validates the proof of work of a given header, and that the proof of work
|
||||||
/// satisfies the requirements of the header.
|
/// 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)
|
Cuckoo::new(&bh.pre_pow_hash()[..], cuckoo_sz)
|
||||||
.verify(bh.pow.clone(), consensus::EASINESS as u64)
|
.verify(bh.pow.clone(), consensus::EASINESS as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mines a genesis block, using the config specified miner if specified.
|
/// Mines a genesis block using the internal miner
|
||||||
/// Otherwise, uses the internal miner
|
pub fn mine_genesis_block() -> Result<Block, Error> {
|
||||||
pub fn mine_genesis_block(
|
|
||||||
miner_config: Option<types::MinerConfig>,
|
|
||||||
) -> Result<core::core::Block, Error> {
|
|
||||||
let mut gen = genesis::genesis_testnet2();
|
let mut gen = genesis::genesis_testnet2();
|
||||||
if global::is_user_testing_mode() || global::is_automated_testing_mode() {
|
if global::is_user_testing_mode() || global::is_automated_testing_mode() {
|
||||||
gen = genesis::genesis_dev();
|
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
|
// total_difficulty on the genesis header *is* the difficulty of that block
|
||||||
let genesis_difficulty = gen.header.total_difficulty.clone();
|
let genesis_difficulty = gen.header.total_difficulty.clone();
|
||||||
|
|
||||||
let sz = global::sizeshift() as u32;
|
let sz = global::sizeshift();
|
||||||
let proof_size = global::proofsize();
|
let proof_size = global::proofsize();
|
||||||
|
|
||||||
let mut miner: Box<MiningWorker> = match miner_config {
|
pow_size(&mut gen.header, genesis_difficulty, proof_size, sz).unwrap();
|
||||||
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();
|
|
||||||
Ok(gen)
|
Ok(gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs a proof of work computation over the provided block using the provided
|
/// 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
|
/// Mining Worker, until the required difficulty target is reached. May take a
|
||||||
/// while for a low target...
|
/// while for a low target...
|
||||||
pub fn pow_size<T: MiningWorker + ?Sized>(
|
pub fn pow_size(
|
||||||
miner: &mut T,
|
|
||||||
bh: &mut BlockHeader,
|
bh: &mut BlockHeader,
|
||||||
diff: Difficulty,
|
diff: Difficulty,
|
||||||
_: u32,
|
proof_size: usize,
|
||||||
|
sz: u8,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let start_nonce = bh.nonce;
|
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
|
// if we found a cycle (not guaranteed) and the proof hash is higher that the
|
||||||
// diff, we're all good
|
// 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 {
|
if proof.clone().to_difficulty() >= diff {
|
||||||
bh.pow = proof.clone();
|
bh.pow = proof.clone();
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -157,28 +118,24 @@ pub fn pow_size<T: MiningWorker + ?Sized>(
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use global;
|
use global;
|
||||||
use core::core::target::Difficulty;
|
use core::target::Difficulty;
|
||||||
use core::genesis;
|
use genesis;
|
||||||
use core::global::ChainTypes;
|
use global::ChainTypes;
|
||||||
|
|
||||||
|
/// We'll be generating genesis blocks differently
|
||||||
|
#[ignore]
|
||||||
#[test]
|
#[test]
|
||||||
fn genesis_pow() {
|
fn genesis_pow() {
|
||||||
global::set_mining_mode(ChainTypes::AutomatedTesting);
|
|
||||||
let mut b = genesis::genesis_dev();
|
let mut b = genesis::genesis_dev();
|
||||||
b.header.nonce = 485;
|
b.header.nonce = 485;
|
||||||
let mut internal_miner = cuckoo::Miner::new(
|
|
||||||
consensus::EASINESS,
|
|
||||||
global::sizeshift() as u32,
|
|
||||||
global::proofsize(),
|
|
||||||
);
|
|
||||||
pow_size(
|
pow_size(
|
||||||
&mut internal_miner,
|
|
||||||
&mut b.header,
|
&mut b.header,
|
||||||
Difficulty::one(),
|
Difficulty::one(),
|
||||||
global::sizeshift() as u32,
|
global::proofsize(),
|
||||||
|
global::sizeshift(),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
assert!(b.header.nonce != 310);
|
assert!(b.header.nonce != 310);
|
||||||
assert!(b.header.pow.clone().to_difficulty() >= Difficulty::one());
|
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]
|
* Linux x86_64 and MacOS [grin + mining + development]
|
||||||
* Not Windows 10 yet [grin kind-of builds. No mining yet. Help wanted!]
|
* 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
|
## 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`)
|
- 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:
|
- rocksdb + libs for compiling rocksdb:
|
||||||
- clang (clanglib or clang-devel or libclang-dev)
|
- clang (clanglib or clang-devel or libclang-dev)
|
||||||
- llvm (Fedora llvm-devel, Debian llvm-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,
|
To cross-compile `grin` on a x86 Linux platform and produce ARM binaries,
|
||||||
say, for a Raspberry Pi.
|
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
|
### Build errors
|
||||||
|
|
||||||
See [Troubleshooting](https://github.com/mimblewimble/docs/wiki/Troubleshooting)
|
See [Troubleshooting](https://github.com/mimblewimble/docs/wiki/Troubleshooting)
|
||||||
|
|
175
grin.toml
175
grin.toml
|
@ -56,7 +56,7 @@ chain_type = "Testnet2"
|
||||||
capabilities = [7]
|
capabilities = [7]
|
||||||
|
|
||||||
#skip waiting for sync on startup, (optional param, mostly for testing)
|
#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
|
#whether to run the ncurses TUI. Ncurses must be installed and this
|
||||||
#will also disable logging to stdout
|
#will also disable logging to stdout
|
||||||
|
@ -65,6 +65,14 @@ run_tui = true
|
||||||
#Whether to run the wallet listener with the server by default
|
#Whether to run the wallet listener with the server by default
|
||||||
run_wallet_listener = true
|
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
|
#The P2P server details (i.e. the server that communicates with other
|
||||||
#grin server nodes
|
#grin server nodes
|
||||||
|
|
||||||
|
@ -91,6 +99,27 @@ port = 13414
|
||||||
#until we get to at least this number
|
#until we get to at least this number
|
||||||
#peer_min_preferred_count = 8
|
#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 ###
|
### 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)
|
# Whether to append to the log file (true), or replace it on every run (false)
|
||||||
log_file_append = true
|
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_keychain = { path = "../keychain" }
|
||||||
grin_p2p = { path = "../p2p" }
|
grin_p2p = { path = "../p2p" }
|
||||||
grin_pool = { path = "../pool" }
|
grin_pool = { path = "../pool" }
|
||||||
grin_pow = { path = "../pow" }
|
|
||||||
grin_store = { path = "../store" }
|
grin_store = { path = "../store" }
|
||||||
grin_util = { path = "../util" }
|
grin_util = { path = "../util" }
|
||||||
grin_wallet = { path = "../wallet" }
|
grin_wallet = { path = "../wallet" }
|
||||||
|
|
|
@ -21,7 +21,6 @@ use std::time::SystemTime;
|
||||||
|
|
||||||
use chain;
|
use chain;
|
||||||
use p2p;
|
use p2p;
|
||||||
use pow;
|
|
||||||
|
|
||||||
/// Server state info collection struct, to be passed around into internals
|
/// Server state info collection struct, to be passed around into internals
|
||||||
/// and populated when required
|
/// and populated when required
|
||||||
|
@ -29,8 +28,6 @@ use pow;
|
||||||
pub struct ServerStateInfo {
|
pub struct ServerStateInfo {
|
||||||
/// whether we're in a state of waiting for peers at startup
|
/// whether we're in a state of waiting for peers at startup
|
||||||
pub awaiting_peers: Arc<AtomicBool>,
|
pub awaiting_peers: Arc<AtomicBool>,
|
||||||
/// Mining stats
|
|
||||||
pub mining_stats: Arc<RwLock<MiningStats>>,
|
|
||||||
/// Stratum stats
|
/// Stratum stats
|
||||||
pub stratum_stats: Arc<RwLock<StratumStats>>,
|
pub stratum_stats: Arc<RwLock<StratumStats>>,
|
||||||
}
|
}
|
||||||
|
@ -39,7 +36,6 @@ impl Default for ServerStateInfo {
|
||||||
fn default() -> ServerStateInfo {
|
fn default() -> ServerStateInfo {
|
||||||
ServerStateInfo {
|
ServerStateInfo {
|
||||||
awaiting_peers: Arc::new(AtomicBool::new(false)),
|
awaiting_peers: Arc::new(AtomicBool::new(false)),
|
||||||
mining_stats: Arc::new(RwLock::new(MiningStats::default())),
|
|
||||||
stratum_stats: Arc::new(RwLock::new(StratumStats::default())),
|
stratum_stats: Arc::new(RwLock::new(StratumStats::default())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,8 +54,6 @@ pub struct ServerStats {
|
||||||
pub is_syncing: bool,
|
pub is_syncing: bool,
|
||||||
/// Whether we're awaiting peers
|
/// Whether we're awaiting peers
|
||||||
pub awaiting_peers: bool,
|
pub awaiting_peers: bool,
|
||||||
/// Handle to current mining stats
|
|
||||||
pub mining_stats: MiningStats,
|
|
||||||
/// Handle to current stratum server stats
|
/// Handle to current stratum server stats
|
||||||
pub stratum_stats: StratumStats,
|
pub stratum_stats: StratumStats,
|
||||||
/// Peer stats
|
/// Peer stats
|
||||||
|
@ -68,26 +62,6 @@ pub struct ServerStats {
|
||||||
pub diff_stats: DiffStats,
|
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
|
/// Struct to return relevant information about stratum workers
|
||||||
#[derive(Clone, Serialize, Debug)]
|
#[derive(Clone, Serialize, Debug)]
|
||||||
pub struct WorkerStats {
|
pub struct WorkerStats {
|
||||||
|
@ -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 {
|
impl Default for WorkerStats {
|
||||||
fn default() -> WorkerStats {
|
fn default() -> WorkerStats {
|
||||||
WorkerStats {
|
WorkerStats {
|
||||||
|
|
|
@ -22,9 +22,9 @@ use core::core;
|
||||||
use p2p;
|
use p2p;
|
||||||
use pool;
|
use pool;
|
||||||
use store;
|
use store;
|
||||||
use pow;
|
|
||||||
use wallet;
|
use wallet;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
|
use core::pow;
|
||||||
|
|
||||||
/// Error type wrapping underlying module errors.
|
/// Error type wrapping underlying module errors.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -161,7 +161,7 @@ pub struct ServerConfig {
|
||||||
pub p2p_config: p2p::P2PConfig,
|
pub p2p_config: p2p::P2PConfig,
|
||||||
|
|
||||||
/// Configuration for the mining daemon
|
/// Configuration for the mining daemon
|
||||||
pub mining_config: Option<pow::types::MinerConfig>,
|
pub stratum_mining_config: Option<StratumServerConfig>,
|
||||||
|
|
||||||
/// Transaction pool configuration
|
/// Transaction pool configuration
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -177,6 +177,12 @@ pub struct ServerConfig {
|
||||||
|
|
||||||
/// Whether to run the wallet listener with the server by default
|
/// Whether to run the wallet listener with the server by default
|
||||||
pub run_wallet_listener: Option<bool>,
|
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 {
|
impl Default for ServerConfig {
|
||||||
|
@ -188,7 +194,7 @@ impl Default for ServerConfig {
|
||||||
seeding_type: Seeding::default(),
|
seeding_type: Seeding::default(),
|
||||||
seeds: None,
|
seeds: None,
|
||||||
p2p_config: p2p::P2PConfig::default(),
|
p2p_config: p2p::P2PConfig::default(),
|
||||||
mining_config: Some(pow::types::MinerConfig::default()),
|
stratum_mining_config: Some(StratumServerConfig::default()),
|
||||||
chain_type: ChainTypes::default(),
|
chain_type: ChainTypes::default(),
|
||||||
archive_mode: None,
|
archive_mode: None,
|
||||||
chain_validation_mode: ChainValidationMode::default(),
|
chain_validation_mode: ChainValidationMode::default(),
|
||||||
|
@ -196,6 +202,42 @@ impl Default for ServerConfig {
|
||||||
skip_sync_wait: None,
|
skip_sync_wait: None,
|
||||||
run_tui: None,
|
run_tui: None,
|
||||||
run_wallet_listener: Some(false),
|
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 common::adapters::*;
|
||||||
use api;
|
use api;
|
||||||
use chain;
|
use chain;
|
||||||
use core::{consensus, genesis, global};
|
use core::{consensus, genesis, global, pow};
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
use core::core::hash::Hashed;
|
use core::core::hash::Hashed;
|
||||||
use grin::dandelion_monitor;
|
use grin::dandelion_monitor;
|
||||||
use mining::miner;
|
|
||||||
use mining::stratumserver;
|
use mining::stratumserver;
|
||||||
use p2p;
|
use p2p;
|
||||||
use pool;
|
use pool;
|
||||||
|
@ -37,8 +36,8 @@ use grin::seed;
|
||||||
use grin::sync;
|
use grin::sync;
|
||||||
use common::types::*;
|
use common::types::*;
|
||||||
use common::stats::*;
|
use common::stats::*;
|
||||||
use pow;
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use mining::test_miner::Miner;
|
||||||
|
|
||||||
/// Grin server holding internal structures.
|
/// Grin server holding internal structures.
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
|
@ -66,16 +65,11 @@ impl Server {
|
||||||
where
|
where
|
||||||
F: FnMut(Arc<Server>),
|
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)?);
|
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;
|
let enable_stratum_server = mining_config.as_mut().unwrap().enable_stratum_server;
|
||||||
if let Some(s) = enable_stratum_server {
|
if let Some(s) = enable_stratum_server {
|
||||||
if s {
|
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());
|
info_callback(serv.clone());
|
||||||
loop {
|
loop {
|
||||||
thread::sleep(time::Duration::from_secs(1));
|
thread::sleep(time::Duration::from_secs(1));
|
||||||
|
@ -127,7 +127,7 @@ impl Server {
|
||||||
global::ChainTypes::Testnet2 => genesis::genesis_testnet2(),
|
global::ChainTypes::Testnet2 => genesis::genesis_testnet2(),
|
||||||
global::ChainTypes::AutomatedTesting => genesis::genesis_dev(),
|
global::ChainTypes::AutomatedTesting => genesis::genesis_dev(),
|
||||||
global::ChainTypes::UserTesting => 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());
|
info!(LOGGER, "Starting server, genesis block: {}", genesis.hash());
|
||||||
|
@ -262,36 +262,8 @@ impl Server {
|
||||||
self.p2p.peers.peer_count()
|
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
|
/// 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 cuckoo_size = global::sizeshift();
|
||||||
let proof_size = global::proofsize();
|
let proof_size = global::proofsize();
|
||||||
let currently_syncing = self.currently_syncing.clone();
|
let currently_syncing = self.currently_syncing.clone();
|
||||||
|
@ -305,19 +277,54 @@ impl Server {
|
||||||
let _ = thread::Builder::new()
|
let _ = thread::Builder::new()
|
||||||
.name("stratum_server".to_string())
|
.name("stratum_server".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
let secs_5 = time::Duration::from_secs(5);
|
|
||||||
while currently_syncing.load(Ordering::Relaxed) {
|
|
||||||
thread::sleep(secs_5);
|
|
||||||
}
|
|
||||||
stratum_server.run_loop(
|
stratum_server.run_loop(
|
||||||
config.clone(),
|
config.clone(),
|
||||||
stratum_stats,
|
stratum_stats,
|
||||||
cuckoo_size as u32,
|
cuckoo_size as u32,
|
||||||
proof_size,
|
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
|
/// The chain head
|
||||||
pub fn head(&self) -> chain::Tip {
|
pub fn head(&self) -> chain::Tip {
|
||||||
self.chain.head().unwrap()
|
self.chain.head().unwrap()
|
||||||
|
@ -334,7 +341,6 @@ impl Server {
|
||||||
/// other
|
/// other
|
||||||
/// consumers
|
/// consumers
|
||||||
pub fn get_server_stats(&self) -> Result<ServerStats, Error> {
|
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 stratum_stats = self.state_info.stratum_stats.read().unwrap().clone();
|
||||||
let awaiting_peers = self.state_info.awaiting_peers.load(Ordering::Relaxed);
|
let awaiting_peers = self.state_info.awaiting_peers.load(Ordering::Relaxed);
|
||||||
|
|
||||||
|
@ -402,7 +408,6 @@ impl Server {
|
||||||
header_head: self.header_head(),
|
header_head: self.header_head(),
|
||||||
is_syncing: self.currently_syncing.load(Ordering::Relaxed),
|
is_syncing: self.currently_syncing.load(Ordering::Relaxed),
|
||||||
awaiting_peers: awaiting_peers,
|
awaiting_peers: awaiting_peers,
|
||||||
mining_stats: mining_stats,
|
|
||||||
stratum_stats: stratum_stats,
|
stratum_stats: stratum_stats,
|
||||||
peer_stats: peer_stats,
|
peer_stats: peer_stats,
|
||||||
diff_stats: diff_stats,
|
diff_stats: diff_stats,
|
||||||
|
|
|
@ -40,15 +40,14 @@ extern crate grin_core as core;
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_p2p as p2p;
|
extern crate grin_p2p as p2p;
|
||||||
extern crate grin_pool as pool;
|
extern crate grin_pool as pool;
|
||||||
extern crate grin_pow as pow;
|
|
||||||
extern crate grin_store as store;
|
extern crate grin_store as store;
|
||||||
extern crate grin_util as util;
|
extern crate grin_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
mod common;
|
pub mod common;
|
||||||
mod grin;
|
mod grin;
|
||||||
mod mining;
|
mod mining;
|
||||||
|
|
||||||
pub use grin::server::Server;
|
pub use grin::server::Server;
|
||||||
pub use common::types::{Seeding, ServerConfig};
|
pub use common::types::{Seeding, ServerConfig, StratumServerConfig};
|
||||||
pub use common::stats::{PeerStats, ServerStats, DiffBlock};
|
pub use common::stats::{DiffBlock, PeerStats, ServerStats, StratumStats, WorkerStats};
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::time::Duration;
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use core::ser::{AsFixedBytes};
|
use core::ser::AsFixedBytes;
|
||||||
use chain;
|
use chain;
|
||||||
use pool;
|
use pool;
|
||||||
use core::consensus;
|
use core::consensus;
|
||||||
|
|
|
@ -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
|
//! Mining + Mining server
|
||||||
|
|
||||||
pub mod miner;
|
pub mod test_miner;
|
||||||
pub mod stratumserver;
|
pub mod stratumserver;
|
||||||
mod mine_block;
|
mod mine_block;
|
||||||
|
|
|
@ -18,6 +18,7 @@ use std::time::Duration;
|
||||||
use std::net::{TcpListener, TcpStream};
|
use std::net::{TcpListener, TcpStream};
|
||||||
use std::io::{ErrorKind, Write};
|
use std::io::{ErrorKind, Write};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use time;
|
use time;
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
|
@ -28,7 +29,7 @@ use std::time::SystemTime;
|
||||||
|
|
||||||
use common::adapters::PoolToChainAdapter;
|
use common::adapters::PoolToChainAdapter;
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::{Block, BlockHeader};
|
||||||
use pow::types::MinerConfig;
|
use common::types::StratumServerConfig;
|
||||||
use mining::mine_block;
|
use mining::mine_block;
|
||||||
use chain;
|
use chain;
|
||||||
use pool;
|
use pool;
|
||||||
|
@ -222,18 +223,19 @@ impl Worker {
|
||||||
|
|
||||||
pub struct StratumServer {
|
pub struct StratumServer {
|
||||||
id: String,
|
id: String,
|
||||||
config: MinerConfig,
|
config: StratumServerConfig,
|
||||||
chain: Arc<chain::Chain>,
|
chain: Arc<chain::Chain>,
|
||||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||||
current_block: Block,
|
current_block: Block,
|
||||||
current_difficulty: u64,
|
current_difficulty: u64,
|
||||||
workers: Arc<Mutex<Vec<Worker>>>,
|
workers: Arc<Mutex<Vec<Worker>>>,
|
||||||
|
currently_syncing: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StratumServer {
|
impl StratumServer {
|
||||||
/// Creates a new Stratum Server.
|
/// Creates a new Stratum Server.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config: MinerConfig,
|
config: StratumServerConfig,
|
||||||
chain_ref: Arc<chain::Chain>,
|
chain_ref: Arc<chain::Chain>,
|
||||||
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
tx_pool: Arc<RwLock<pool::TransactionPool<PoolToChainAdapter>>>,
|
||||||
) -> StratumServer {
|
) -> StratumServer {
|
||||||
|
@ -245,6 +247,7 @@ impl StratumServer {
|
||||||
current_block: Block::default(),
|
current_block: Block::default(),
|
||||||
current_difficulty: <u64>::max_value(),
|
current_difficulty: <u64>::max_value(),
|
||||||
workers: Arc::new(Mutex::new(Vec::new())),
|
workers: Arc::new(Mutex::new(Vec::new())),
|
||||||
|
currently_syncing: Arc::new(AtomicBool::new(false)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,9 +312,15 @@ impl StratumServer {
|
||||||
),
|
),
|
||||||
"keepalive" => self.handle_keepalive(),
|
"keepalive" => self.handle_keepalive(),
|
||||||
"getjobtemplate" => {
|
"getjobtemplate" => {
|
||||||
|
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();
|
let b = self.current_block.header.clone();
|
||||||
self.handle_getjobtemplate(b)
|
self.handle_getjobtemplate(b)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"status" => {
|
"status" => {
|
||||||
self.handle_status(&stratum_stats.worker_stats[worker_stats_id])
|
self.handle_status(&stratum_stats.worker_stats[worker_stats_id])
|
||||||
}
|
}
|
||||||
|
@ -530,10 +539,11 @@ impl StratumServer {
|
||||||
/// be submitted.
|
/// be submitted.
|
||||||
pub fn run_loop(
|
pub fn run_loop(
|
||||||
&mut self,
|
&mut self,
|
||||||
miner_config: MinerConfig,
|
miner_config: StratumServerConfig,
|
||||||
stratum_stats: Arc<RwLock<StratumStats>>,
|
stratum_stats: Arc<RwLock<StratumStats>>,
|
||||||
cuckoo_size: u32,
|
cuckoo_size: u32,
|
||||||
proof_size: usize,
|
proof_size: usize,
|
||||||
|
currently_syncing: Arc<AtomicBool>,
|
||||||
) {
|
) {
|
||||||
info!(
|
info!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
|
@ -543,6 +553,8 @@ impl StratumServer {
|
||||||
proof_size
|
proof_size
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.currently_syncing = currently_syncing;
|
||||||
|
|
||||||
// "globals" for this function
|
// "globals" for this function
|
||||||
let attempt_time_per_block = miner_config.attempt_time_per_block;
|
let attempt_time_per_block = miner_config.attempt_time_per_block;
|
||||||
let mut deadline: i64 = 0;
|
let mut deadline: i64 = 0;
|
||||||
|
@ -579,6 +591,10 @@ impl StratumServer {
|
||||||
|
|
||||||
// Main Loop
|
// Main Loop
|
||||||
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
|
// Remove workers with failed connections
|
||||||
self.clean_workers(&mut stratum_stats.clone());
|
self.clean_workers(&mut stratum_stats.clone());
|
||||||
|
|
||||||
|
@ -589,7 +605,8 @@ impl StratumServer {
|
||||||
// Build a new block if:
|
// Build a new block if:
|
||||||
// There is a new block on the chain
|
// There is a new block on the chain
|
||||||
// or We are rebuilding the current one to include new transactions
|
// 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 {
|
if current_hash != latest_hash {
|
||||||
// A brand new block, so we will generate a new key_id
|
// A brand new block, so we will generate a new key_id
|
||||||
key_id = None;
|
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_chain as chain;
|
||||||
extern crate grin_config as config;
|
extern crate grin_config as config;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
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_chain as chain;
|
||||||
extern crate grin_config as config;
|
extern crate grin_config as config;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,9 @@
|
||||||
extern crate grin_api as api;
|
extern crate grin_api as api;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
@ -189,22 +188,6 @@ impl LocalServerContainer {
|
||||||
seeds = vec![self.config.seed_addr.to_string()];
|
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 {
|
let s = servers::Server::new(servers::ServerConfig {
|
||||||
api_http_addr: api_addr,
|
api_http_addr: api_addr,
|
||||||
db_root: format!("{}/.grin", self.working_dir),
|
db_root: format!("{}/.grin", self.working_dir),
|
||||||
|
@ -216,21 +199,30 @@ impl LocalServerContainer {
|
||||||
seeding_type: seeding_type,
|
seeding_type: seeding_type,
|
||||||
chain_type: core::global::ChainTypes::AutomatedTesting,
|
chain_type: core::global::ChainTypes::AutomatedTesting,
|
||||||
skip_sync_wait: Some(true),
|
skip_sync_wait: Some(true),
|
||||||
mining_config: Some(miner_config.clone()),
|
stratum_mining_config: None,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|
||||||
self.p2p_server_stats = Some(s.get_server_stats().unwrap());
|
self.p2p_server_stats = Some(s.get_server_stats().unwrap());
|
||||||
|
|
||||||
|
let mut wallet_url = None;
|
||||||
|
|
||||||
if self.config.start_wallet == true {
|
if self.config.start_wallet == true {
|
||||||
self.run_wallet(duration_in_seconds + 5);
|
self.run_wallet(duration_in_seconds + 5);
|
||||||
// give a second to start wallet before continuing
|
// give a second to start wallet before continuing
|
||||||
thread::sleep(time::Duration::from_millis(1000));
|
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 {
|
if self.config.start_miner == true {
|
||||||
println!("starting Miner on port {}", self.config.p2p_server_port);
|
println!(
|
||||||
s.start_miner(miner_config);
|
"starting test Miner on port {}",
|
||||||
|
self.config.p2p_server_port
|
||||||
|
);
|
||||||
|
s.start_test_miner(wallet_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in &mut self.peer_list {
|
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
|
/// return stratum mining config
|
||||||
pub fn miner_config() -> pow::types::MinerConfig {
|
pub fn stratum_config() -> servers::common::types::StratumServerConfig {
|
||||||
let mut plugin_config = pow::types::CuckooMinerPluginConfig::default();
|
servers::common::types::StratumServerConfig {
|
||||||
let mut plugin_config_vec: Vec<pow::types::CuckooMinerPluginConfig> = Vec::new();
|
enable_stratum_server: Some(true),
|
||||||
plugin_config.type_filter = String::from("mean_cpu");
|
stratum_server_addr: Some(String::from("127.0.0.1:13416")),
|
||||||
plugin_config_vec.push(plugin_config);
|
attempt_time_per_block: 60,
|
||||||
|
wallet_listener_url: String::from("http://127.0.0.1:13415"),
|
||||||
pow::types::MinerConfig {
|
burn_reward: false,
|
||||||
enable_mining: true,
|
|
||||||
burn_reward: true,
|
|
||||||
miner_async_mode: Some(false),
|
|
||||||
miner_plugin_dir: None,
|
|
||||||
miner_plugin_config: Some(plugin_config_vec),
|
|
||||||
..Default::default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
extern crate grin_api as api;
|
extern crate grin_api as api;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
@ -32,8 +31,8 @@ use std::default::Default;
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
|
|
||||||
use framework::{LocalServerContainerConfig, LocalServerContainerPool,
|
use framework::{config, stratum_config, LocalServerContainerConfig, LocalServerContainerPool,
|
||||||
LocalServerContainerPoolConfig, config, miner_config};
|
LocalServerContainerPoolConfig};
|
||||||
|
|
||||||
/// Testing the frameworks by starting a fresh server, creating a genesis
|
/// Testing the frameworks by starting a fresh server, creating a genesis
|
||||||
/// Block and mining into a wallet for a bit
|
/// Block and mining into a wallet for a bit
|
||||||
|
@ -194,7 +193,7 @@ fn simulate_block_propagation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// start mining
|
// start mining
|
||||||
servers[0].start_miner(miner_config());
|
servers[0].start_test_miner(None);
|
||||||
let _original_height = servers[0].head().height;
|
let _original_height = servers[0].head().height;
|
||||||
|
|
||||||
// monitor for a change of head on a different server and check whether
|
// 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();
|
let s1 = servers::Server::new(framework::config(1000, "grin-sync", 1000)).unwrap();
|
||||||
// mine a few blocks on server 1
|
// mine a few blocks on server 1
|
||||||
s1.start_miner(miner_config());
|
s1.start_test_miner(None);
|
||||||
thread::sleep(time::Duration::from_secs(8));
|
thread::sleep(time::Duration::from_secs(8));
|
||||||
|
|
||||||
#[ignore(unused_mut)] // mut needed?
|
#[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();
|
let s1 = servers::Server::new(framework::config(2000, "grin-fast", 2000)).unwrap();
|
||||||
// mine a few blocks on server 1
|
// mine a few blocks on server 1
|
||||||
s1.start_miner(miner_config());
|
s1.start_test_miner(None);
|
||||||
thread::sleep(time::Duration::from_secs(8));
|
thread::sleep(time::Duration::from_secs(8));
|
||||||
|
|
||||||
let mut conf = config(2001, "grin-fast", 2000);
|
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();
|
let s1 = servers::Server::new(framework::config(3000, "grin-double-fast1", 3000)).unwrap();
|
||||||
// mine a few blocks on server 1
|
// mine a few blocks on server 1
|
||||||
s1.start_miner(miner_config());
|
s1.start_test_miner(None);
|
||||||
thread::sleep(time::Duration::from_secs(8));
|
thread::sleep(time::Duration::from_secs(8));
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
extern crate grin_api as api;
|
extern crate grin_api as api;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
@ -37,7 +36,7 @@ use std::time;
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
|
|
||||||
use framework::{config, miner_config};
|
use framework::{config, stratum_config};
|
||||||
|
|
||||||
// Create a grin server, and a stratum server.
|
// Create a grin server, and a stratum server.
|
||||||
// Simulate a few JSONRpc requests and verify the results.
|
// 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();
|
let s = servers::Server::new(config(4000, test_name_dir, 0)).unwrap();
|
||||||
|
|
||||||
// Get mining config with stratumserver enabled
|
// Get mining config with stratumserver enabled
|
||||||
let mut miner_cfg = miner_config();
|
let mut stratum_cfg = stratum_config();
|
||||||
miner_cfg.enable_mining = false;
|
stratum_cfg.burn_reward = true;
|
||||||
miner_cfg.attempt_time_per_block = 999;
|
stratum_cfg.attempt_time_per_block = 999;
|
||||||
miner_cfg.enable_stratum_server = Some(true);
|
stratum_cfg.enable_stratum_server = Some(true);
|
||||||
miner_cfg.stratum_server_addr = Some(String::from("127.0.0.1:11101"));
|
stratum_cfg.stratum_server_addr = Some(String::from("127.0.0.1:11101"));
|
||||||
|
|
||||||
// Start stratum server
|
// Start stratum server
|
||||||
s.start_stratum_server(miner_cfg);
|
s.start_stratum_server(stratum_cfg);
|
||||||
|
|
||||||
// Wait for stratum server to start and
|
// Wait for stratum server to start and
|
||||||
// Verify stratum server accepts connections
|
// Verify stratum server accepts connections
|
||||||
|
@ -142,7 +141,7 @@ fn basic_stratum_server() {
|
||||||
assert_eq!(stats.stratum_stats.worker_stats[1].is_connected, true);
|
assert_eq!(stats.stratum_stats.worker_stats[1].is_connected, true);
|
||||||
|
|
||||||
// Start mining blocks
|
// Start mining blocks
|
||||||
s.start_miner(miner_config());
|
s.start_test_miner(None);
|
||||||
|
|
||||||
// Simulate a worker lost connection
|
// Simulate a worker lost connection
|
||||||
workers.remove(1);
|
workers.remove(1);
|
||||||
|
|
|
@ -20,9 +20,8 @@ extern crate grin_api as api;
|
||||||
extern crate grin_chain as chain;
|
extern crate grin_chain as chain;
|
||||||
extern crate grin_config as config;
|
extern crate grin_config as config;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_p2p as p2p;
|
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_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,9 @@ extern crate time;
|
||||||
extern crate grin_api as api;
|
extern crate grin_api as api;
|
||||||
extern crate grin_config as config;
|
extern crate grin_config as config;
|
||||||
extern crate grin_core as core;
|
extern crate grin_core as core;
|
||||||
extern crate grin_servers as servers;
|
|
||||||
extern crate grin_keychain as keychain;
|
extern crate grin_keychain as keychain;
|
||||||
extern crate grin_p2p as p2p;
|
extern crate grin_p2p as p2p;
|
||||||
|
extern crate grin_servers as servers;
|
||||||
extern crate grin_util as util;
|
extern crate grin_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
@ -139,10 +139,6 @@ fn main() {
|
||||||
.long("seed")
|
.long("seed")
|
||||||
.help("Override seed node(s) to connect to")
|
.help("Override seed node(s) to connect to")
|
||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
.arg(Arg::with_name("mine")
|
|
||||||
.short("m")
|
|
||||||
.long("mine")
|
|
||||||
.help("Starts the debugging mining loop"))
|
|
||||||
.arg(Arg::with_name("wallet_url")
|
.arg(Arg::with_name("wallet_url")
|
||||||
.short("w")
|
.short("w")
|
||||||
.long("wallet_url")
|
.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);
|
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") {
|
if let Some(wallet_url) = a.value_of("wallet_url") {
|
||||||
server_config
|
server_config
|
||||||
.mining_config
|
.stratum_mining_config
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.wallet_listener_url = wallet_url.to_string();
|
.wallet_listener_url = wallet_url.to_string();
|
||||||
|
|
|
@ -29,81 +29,71 @@ use tui::chrono::prelude::*;
|
||||||
use tui::constants::*;
|
use tui::constants::*;
|
||||||
use tui::types::*;
|
use tui::types::*;
|
||||||
|
|
||||||
use servers::{ServerStats, DiffBlock};
|
use servers::{DiffBlock, ServerStats, WorkerStats};
|
||||||
use tui::pow::cuckoo_miner::CuckooMinerDeviceStats;
|
|
||||||
use tui::table::{TableView, TableViewItem};
|
use tui::table::{TableView, TableViewItem};
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
enum MiningDeviceColumn {
|
enum StratumWorkerColumn {
|
||||||
PluginId,
|
Id,
|
||||||
DeviceId,
|
IsConnected,
|
||||||
DeviceName,
|
LastSeen,
|
||||||
InUse,
|
PowDifficulty,
|
||||||
ErrorStatus,
|
NumAccepted,
|
||||||
LastGraphTime,
|
NumRejected,
|
||||||
GraphsPerSecond,
|
NumStale,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MiningDeviceColumn {
|
impl StratumWorkerColumn {
|
||||||
fn _as_str(&self) -> &str {
|
fn _as_str(&self) -> &str {
|
||||||
match *self {
|
match *self {
|
||||||
MiningDeviceColumn::PluginId => "Plugin ID",
|
StratumWorkerColumn::Id => "Worker ID",
|
||||||
MiningDeviceColumn::DeviceId => "Device ID",
|
StratumWorkerColumn::IsConnected => "Connected",
|
||||||
MiningDeviceColumn::DeviceName => "Name",
|
StratumWorkerColumn::LastSeen => "Last Seen",
|
||||||
MiningDeviceColumn::InUse => "In Use",
|
StratumWorkerColumn::PowDifficulty => "PowDifficulty",
|
||||||
MiningDeviceColumn::ErrorStatus => "Status",
|
StratumWorkerColumn::NumAccepted => "Num Accepted",
|
||||||
MiningDeviceColumn::LastGraphTime => "Last Graph Time",
|
StratumWorkerColumn::NumRejected => "Num Rejected",
|
||||||
MiningDeviceColumn::GraphsPerSecond => "GPS",
|
StratumWorkerColumn::NumStale => "Num Stale",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TableViewItem<MiningDeviceColumn> for CuckooMinerDeviceStats {
|
impl TableViewItem<StratumWorkerColumn> for WorkerStats {
|
||||||
fn to_column(&self, column: MiningDeviceColumn) -> String {
|
fn to_column(&self, column: StratumWorkerColumn) -> String {
|
||||||
let last_solution_time_secs = self.last_solution_time as f64 / 1000000000.0;
|
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 {
|
match column {
|
||||||
MiningDeviceColumn::PluginId => String::from("TBD"),
|
StratumWorkerColumn::Id => self.id.clone(),
|
||||||
MiningDeviceColumn::DeviceId => self.device_id.clone(),
|
StratumWorkerColumn::IsConnected => self.is_connected.to_string(),
|
||||||
MiningDeviceColumn::DeviceName => self.device_name.clone(),
|
StratumWorkerColumn::LastSeen => datetime.to_string(),
|
||||||
MiningDeviceColumn::InUse => match self.in_use {
|
StratumWorkerColumn::PowDifficulty => self.pow_difficulty.to_string(),
|
||||||
1 => String::from("Yes"),
|
StratumWorkerColumn::NumAccepted => self.num_accepted.to_string(),
|
||||||
_ => String::from("No"),
|
StratumWorkerColumn::NumRejected => self.num_rejected.to_string(),
|
||||||
},
|
StratumWorkerColumn::NumStale => self.num_stale.to_string(),
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmp(&self, other: &Self, column: MiningDeviceColumn) -> Ordering
|
fn cmp(&self, _other: &Self, column: StratumWorkerColumn) -> Ordering
|
||||||
where
|
where
|
||||||
Self: Sized,
|
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 {
|
match column {
|
||||||
MiningDeviceColumn::PluginId => Ordering::Equal,
|
StratumWorkerColumn::Id => Ordering::Equal,
|
||||||
MiningDeviceColumn::DeviceId => self.device_id.cmp(&other.device_id),
|
StratumWorkerColumn::IsConnected => Ordering::Equal,
|
||||||
MiningDeviceColumn::DeviceName => self.device_name.cmp(&other.device_name),
|
StratumWorkerColumn::LastSeen => Ordering::Equal,
|
||||||
MiningDeviceColumn::InUse => self.in_use.cmp(&other.in_use),
|
StratumWorkerColumn::PowDifficulty => Ordering::Equal,
|
||||||
MiningDeviceColumn::ErrorStatus => self.has_errored.cmp(&other.has_errored),
|
StratumWorkerColumn::NumAccepted => Ordering::Equal,
|
||||||
MiningDeviceColumn::LastGraphTime => {
|
StratumWorkerColumn::NumRejected => Ordering::Equal,
|
||||||
self.last_solution_time.cmp(&other.last_solution_time)
|
StratumWorkerColumn::NumStale => Ordering::Equal,
|
||||||
}
|
|
||||||
MiningDeviceColumn::GraphsPerSecond => gps_self.partial_cmp(&gps_other).unwrap(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
enum DiffColumn {
|
enum DiffColumn {
|
||||||
BlockNumber,
|
BlockNumber,
|
||||||
|
@ -154,7 +144,7 @@ pub struct TUIMiningView;
|
||||||
impl TUIStatusListener for TUIMiningView {
|
impl TUIStatusListener for TUIMiningView {
|
||||||
/// Create the mining view
|
/// Create the mining view
|
||||||
fn create() -> Box<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 _ = s.call_on_id("mining_stack_view", |sv: &mut StackView| {
|
||||||
let pos = sv.find_layer_from_id("mining_device_view").unwrap();
|
let pos = sv.find_layer_from_id("mining_device_view").unwrap();
|
||||||
sv.move_to_front(pos);
|
sv.move_to_front(pos);
|
||||||
|
@ -174,47 +164,60 @@ impl TUIStatusListener for TUIMiningView {
|
||||||
let _ = c.focus_id(MAIN_MENU);
|
let _ = c.focus_id(MAIN_MENU);
|
||||||
});
|
});
|
||||||
|
|
||||||
let table_view =
|
let table_view = TableView::<WorkerStats, StratumWorkerColumn>::new()
|
||||||
TableView::<CuckooMinerDeviceStats, MiningDeviceColumn>::new()
|
.column(StratumWorkerColumn::Id, "Worker ID", |c| {
|
||||||
.column(MiningDeviceColumn::PluginId, "Plugin ID", |c| {
|
|
||||||
c.width_percent(10)
|
c.width_percent(10)
|
||||||
})
|
})
|
||||||
.column(MiningDeviceColumn::DeviceId, "Device ID", |c| {
|
.column(StratumWorkerColumn::IsConnected, "Connected", |c| {
|
||||||
c.width_percent(10)
|
c.width_percent(10)
|
||||||
})
|
})
|
||||||
.column(MiningDeviceColumn::DeviceName, "Device Name", |c| {
|
.column(StratumWorkerColumn::LastSeen, "Last Seen", |c| {
|
||||||
c.width_percent(20)
|
c.width_percent(20)
|
||||||
})
|
})
|
||||||
.column(MiningDeviceColumn::InUse, "In Use", |c| c.width_percent(10))
|
.column(StratumWorkerColumn::PowDifficulty, "Pow Difficulty", |c| {
|
||||||
.column(MiningDeviceColumn::ErrorStatus, "Status", |c| {
|
|
||||||
c.width_percent(10)
|
c.width_percent(10)
|
||||||
})
|
})
|
||||||
.column(MiningDeviceColumn::LastGraphTime, "Graph Time", |c| {
|
.column(StratumWorkerColumn::NumAccepted, "Num Accepted", |c| {
|
||||||
c.width_percent(10)
|
c.width_percent(10)
|
||||||
})
|
})
|
||||||
.column(MiningDeviceColumn::GraphsPerSecond, "GPS", |c| {
|
.column(StratumWorkerColumn::NumRejected, "Num Rejected", |c| {
|
||||||
|
c.width_percent(10)
|
||||||
|
})
|
||||||
|
.column(StratumWorkerColumn::NumStale, "Num Stale", |c| {
|
||||||
c.width_percent(10)
|
c.width_percent(10)
|
||||||
});
|
});
|
||||||
|
|
||||||
let status_view = LinearLayout::new(Orientation::Vertical)
|
let status_view = LinearLayout::new(Orientation::Vertical)
|
||||||
.child(
|
.child(
|
||||||
LinearLayout::new(Orientation::Horizontal)
|
LinearLayout::new(Orientation::Horizontal)
|
||||||
.child(TextView::new(" ").with_id("mining_config_status")),
|
.child(TextView::new(" ").with_id("stratum_config_status")),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
LinearLayout::new(Orientation::Horizontal)
|
LinearLayout::new(Orientation::Horizontal)
|
||||||
.child(TextView::new(" ").with_id("mining_status")),
|
.child(TextView::new(" ").with_id("stratum_is_running_status")),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
LinearLayout::new(Orientation::Horizontal)
|
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)
|
let mining_device_view = LinearLayout::new(Orientation::Vertical)
|
||||||
.child(status_view)
|
.child(status_view)
|
||||||
.child(BoxView::with_full_screen(
|
.child(BoxView::with_full_screen(
|
||||||
Dialog::around(table_view.with_id(TABLE_MINING_STATUS).min_size((50, 20)))
|
Dialog::around(table_view.with_id(TABLE_MINING_STATUS).min_size((50, 20)))
|
||||||
.title("Mining Devices"),
|
.title("Mining Workers"),
|
||||||
))
|
))
|
||||||
.with_id("mining_device_view");
|
.with_id("mining_device_view");
|
||||||
|
|
||||||
|
@ -275,55 +278,6 @@ impl TUIStatusListener for TUIMiningView {
|
||||||
|
|
||||||
/// update
|
/// update
|
||||||
fn update(c: &mut Cursive, stats: &ServerStats) {
|
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| {
|
c.call_on_id("diff_cur_height", |t: &mut TextView| {
|
||||||
t.set_content(stats.diff_stats.height.to_string());
|
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());
|
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();
|
let mut diff_stats = stats.diff_stats.last_blocks.clone();
|
||||||
diff_stats.reverse();
|
diff_stats.reverse();
|
||||||
let _ = c.call_on_id(
|
let _ = c.call_on_id(
|
||||||
|
@ -348,22 +300,38 @@ impl TUIStatusListener for TUIMiningView {
|
||||||
t.set_items(diff_stats);
|
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() {
|
c.call_on_id("stratum_config_status", |t: &mut TextView| {
|
||||||
return;
|
t.set_content(stratum_enabled);
|
||||||
}
|
});
|
||||||
let device_stats = device_stats.unwrap();
|
c.call_on_id("stratum_is_running_status", |t: &mut TextView| {
|
||||||
let mut flattened_device_stats = vec![];
|
t.set_content(stratum_is_running);
|
||||||
for p in device_stats.into_iter() {
|
});
|
||||||
for d in p.into_iter() {
|
c.call_on_id("stratum_num_workers_status", |t: &mut TextView| {
|
||||||
flattened_device_stats.push(d);
|
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(
|
let _ = c.call_on_id(
|
||||||
TABLE_MINING_STATUS,
|
TABLE_MINING_STATUS,
|
||||||
|t: &mut TableView<CuckooMinerDeviceStats, MiningDeviceColumn>| {
|
|t: &mut TableView<WorkerStats, StratumWorkerColumn>| {
|
||||||
t.set_items(flattened_device_stats);
|
t.set_items(worker_stats);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
//! Grin TUI
|
//! Grin TUI
|
||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
extern crate grin_pow as pow;
|
|
||||||
|
|
||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod table;
|
pub mod table;
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl TUIStatusListener for TUIStatusView {
|
||||||
"Running".to_string()
|
"Running".to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let basic_mining_config_status = {
|
/*let basic_mining_config_status = {
|
||||||
if stats.mining_stats.is_enabled {
|
if stats.mining_stats.is_enabled {
|
||||||
"Configured as mining node"
|
"Configured as mining node"
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,7 +121,7 @@ impl TUIStatusListener for TUIStatusView {
|
||||||
} else {
|
} else {
|
||||||
(" ".to_string(), " ".to_string())
|
(" ".to_string(), " ".to_string())
|
||||||
}
|
}
|
||||||
};
|
};*/
|
||||||
c.call_on_id("basic_current_status", |t: &mut TextView| {
|
c.call_on_id("basic_current_status", |t: &mut TextView| {
|
||||||
t.set_content(basic_status);
|
t.set_content(basic_status);
|
||||||
});
|
});
|
||||||
|
@ -134,7 +134,7 @@ impl TUIStatusListener for TUIStatusView {
|
||||||
c.call_on_id("basic_total_difficulty", |t: &mut TextView| {
|
c.call_on_id("basic_total_difficulty", |t: &mut TextView| {
|
||||||
t.set_content(stats.head.total_difficulty.to_string());
|
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);
|
t.set_content(basic_mining_config_status);
|
||||||
});
|
});
|
||||||
c.call_on_id("basic_mining_status", |t: &mut TextView| {
|
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| {
|
c.call_on_id("basic_network_info", |t: &mut TextView| {
|
||||||
t.set_content(basic_network_info);
|
t.set_content(basic_network_info);
|
||||||
});
|
});*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,9 +287,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```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)
|
pub fn set_on_sort<F>(&mut self, cb: F)
|
||||||
where
|
where
|
||||||
|
@ -306,9 +304,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```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
|
pub fn on_sort<F>(self, cb: F) -> Self
|
||||||
where
|
where
|
||||||
|
@ -326,9 +322,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```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)
|
pub fn set_on_submit<F>(&mut self, cb: F)
|
||||||
where
|
where
|
||||||
|
@ -348,9 +342,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```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
|
pub fn on_submit<F>(self, cb: F) -> Self
|
||||||
where
|
where
|
||||||
|
@ -367,9 +359,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```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)
|
pub fn set_on_select<F>(&mut self, cb: F)
|
||||||
where
|
where
|
||||||
|
@ -388,9 +378,7 @@ impl<T: TableViewItem<H>, H: Eq + Hash + Copy + Clone + 'static> TableView<T, H>
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```norun
|
/// ```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
|
pub fn on_select<F>(self, cb: F) -> Self
|
||||||
where
|
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
|
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) {
|
fn draw(&self, printer: &Printer) {
|
||||||
self.draw_columns(printer, "╷ ", |printer, column| {
|
self.draw_columns(printer, "╷ ", |printer, column| {
|
||||||
let color = if column.order != Ordering::Equal || column.selected {
|
let color = if column.order != Ordering::Equal || column.selected {
|
||||||
|
|
Loading…
Reference in a new issue