From 14a44aa718048b0792766718b2fcbe8645335260 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Mon, 16 Sep 2024 17:37:34 +0300 Subject: [PATCH 01/10] Remove unused fn --- roles/tests-integration/tests/common/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/roles/tests-integration/tests/common/mod.rs b/roles/tests-integration/tests/common/mod.rs index 5d37b39d5..acf99f494 100644 --- a/roles/tests-integration/tests/common/mod.rs +++ b/roles/tests-integration/tests/common/mod.rs @@ -147,8 +147,4 @@ impl TemplateProvider { .generate_to_address(n, &mining_address) .unwrap(); } - - pub fn get_block_count(&self) -> u64 { - self.bitcoind.client.get_block_count().unwrap() - } } From 261e8185269bf15577ab7bb60273b2c73880ab92 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Tue, 3 Sep 2024 12:39:08 +0300 Subject: [PATCH 02/10] Add error handling to `PoolSv2::start` Handle errors in `start` function for better user experience and to be able to catch errors in test environment, for example without introducing error handling, we do not get a proper response if the provided `coinbase_output` in the config is valid. --- roles/pool/src/lib/mod.rs | 31 +++++++++++-------------------- roles/pool/src/main.rs | 2 +- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index d7d483a5c..2603695f8 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -5,12 +5,14 @@ pub mod template_receiver; use async_channel::{bounded, unbounded}; +use error::PoolError; use mining_pool::{get_coinbase_output, Configuration, Pool}; use template_receiver::TemplateRx; use tracing::{error, info, warn}; use tokio::select; +#[derive(Debug, Clone)] pub struct PoolSv2 { config: Configuration, } @@ -19,7 +21,8 @@ impl PoolSv2 { pub fn new(config: Configuration) -> PoolSv2 { PoolSv2 { config } } - pub async fn start(self) { + + pub async fn start(&self) -> Result<(), PoolError> { let config = self.config.clone(); let (status_tx, status_rx) = unbounded(); let (s_new_t, r_new_t) = bounded(10); @@ -27,15 +30,9 @@ impl PoolSv2 { let (s_solution, r_solution) = bounded(10); let (s_message_recv_signal, r_message_recv_signal) = bounded(10); let coinbase_output_result = get_coinbase_output(&config); - let coinbase_output_len = match coinbase_output_result { - Ok(coinbase_output) => coinbase_output.len() as u32, - Err(err) => { - error!("Failed to get Coinbase output: {:?}", err); - return; - } - }; + let coinbase_output_len = coinbase_output_result?.len() as u32; let tp_authority_public_key = config.tp_authority_public_key; - let template_rx_res = TemplateRx::connect( + TemplateRx::connect( config.tp_address.parse().unwrap(), s_new_t, s_prev_hash, @@ -45,13 +42,7 @@ impl PoolSv2 { coinbase_output_len, tp_authority_public_key, ) - .await; - - if let Err(e) = template_rx_res { - error!("Could not connect to Template Provider: {}", e); - return; - } - + .await?; let pool = Pool::start( config.clone(), r_new_t, @@ -76,7 +67,7 @@ impl PoolSv2 { // we also shut down in case of error }, } - break; + break Ok(()); } }; let task_status: status::Status = task_status.unwrap(); @@ -88,11 +79,11 @@ impl PoolSv2 { "SHUTDOWN from Downstream: {}\nTry to restart the downstream listener", err ); - break; + break Ok(()); } status::State::TemplateProviderShutdown(err) => { error!("SHUTDOWN from Upstream: {}\nTry to reconnecting or connecting to a new upstream", err); - break; + break Ok(()); } status::State::Healthy(msg) => { info!("HEALTHY message: {}", msg); @@ -103,7 +94,7 @@ impl PoolSv2 { .safe_lock(|p| p.remove_downstream(downstream_id)) .is_err() { - break; + break Ok(()); } } } diff --git a/roles/pool/src/main.rs b/roles/pool/src/main.rs index 512968439..34f5983e5 100644 --- a/roles/pool/src/main.rs +++ b/roles/pool/src/main.rs @@ -99,5 +99,5 @@ async fn main() { return; } }; - PoolSv2::new(config).start().await; + let _ = PoolSv2::new(config).start().await; } From ac99a062a24adb758e03b00bcd2f9bce39de35c0 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Mon, 2 Sep 2024 15:50:16 +0300 Subject: [PATCH 03/10] Add `PoolSv2::state` Adds a new property `state` to the pool struct. The main goal is providing abilities to mutate the state internally, i.e. only by the role itself, and abilities to view the state by the role runner. --- roles/pool/src/lib/mod.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index 2603695f8..7e68fc1a7 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -3,23 +3,36 @@ pub mod mining_pool; pub mod status; pub mod template_receiver; +use std::sync::Arc; + use async_channel::{bounded, unbounded}; use error::PoolError; use mining_pool::{get_coinbase_output, Configuration, Pool}; +use roles_logic_sv2::utils::Mutex; use template_receiver::TemplateRx; use tracing::{error, info, warn}; use tokio::select; +#[derive(Debug, Clone, PartialEq)] +pub enum PoolState { + Initial, + Running, +} + #[derive(Debug, Clone)] pub struct PoolSv2 { config: Configuration, + state: Arc>, } impl PoolSv2 { pub fn new(config: Configuration) -> PoolSv2 { - PoolSv2 { config } + PoolSv2 { + config, + state: Arc::new(Mutex::new(PoolState::Initial)), + } } pub async fn start(&self) -> Result<(), PoolError> { @@ -51,6 +64,8 @@ impl PoolSv2 { s_message_recv_signal, status::Sender::DownstreamListener(status_tx), ); + // Set the state to running + let _ = self.state.safe_lock(|s| *s = PoolState::Running); // Start the error handling loop // See `./status.rs` and `utils/error_handling` for information on how this operates @@ -100,4 +115,8 @@ impl PoolSv2 { } } } + + pub async fn state(&self) -> Arc> { + self.state.clone() + } } From a4033af8ffbe75d931d0c2ea91d4de4e6e514b58 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Wed, 4 Sep 2024 13:26:13 +0300 Subject: [PATCH 04/10] Add networking/port test utils fn(s) --- roles/Cargo.lock | 7 +++--- roles/tests-integration/Cargo.toml | 1 + roles/tests-integration/tests/common/mod.rs | 27 +++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/roles/Cargo.lock b/roles/Cargo.lock index af5f8304f..dc6557615 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -1443,6 +1443,7 @@ dependencies = [ "bitcoind", "flate2", "minreq", + "once_cell", "tar", ] @@ -1841,9 +1842,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "33ea5043e58958ee56f3e15a90aee535795cd7dfd319846288d93c5b57d85cbe" [[package]] name = "opaque-debug" @@ -2360,7 +2361,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes 0.14.0", "rand", "secp256k1-sys 0.10.0", "serde", diff --git a/roles/tests-integration/Cargo.toml b/roles/tests-integration/Cargo.toml index 00eab65fa..496f4f31e 100644 --- a/roles/tests-integration/Cargo.toml +++ b/roles/tests-integration/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" bitcoind = "0.36.0" flate2 = "1.0.32" minreq = { version = "2.12.0", features = ["https"] } +once_cell = "1.20.0" tar = "0.4.41" [lib] diff --git a/roles/tests-integration/tests/common/mod.rs b/roles/tests-integration/tests/common/mod.rs index acf99f494..56edbc3b0 100644 --- a/roles/tests-integration/tests/common/mod.rs +++ b/roles/tests-integration/tests/common/mod.rs @@ -1,13 +1,20 @@ use bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD, Conf}; use flate2::read::GzDecoder; +use once_cell::sync::Lazy; use std::{ + collections::HashSet, env, fs::{create_dir_all, File}, io::{BufReader, Read}, + net::TcpListener, path::{Path, PathBuf}, + sync::Mutex, }; use tar::Archive; +// prevents get_available_port from ever returning the same port twice +static UNIQUE_PORTS: Lazy>> = Lazy::new(|| Mutex::new(HashSet::new())); + const VERSION_TP: &str = "0.1.7"; fn download_bitcoind_tarball(download_url: &str) -> Vec { @@ -148,3 +155,23 @@ impl TemplateProvider { .unwrap(); } } + +pub fn is_port_open(address: std::net::SocketAddr) -> bool { + TcpListener::bind(address).is_err() +} + +pub fn get_available_port() -> u16 { + let mut unique_ports = UNIQUE_PORTS.lock().unwrap(); + + loop { + let port = TcpListener::bind("127.0.0.1:0") + .unwrap() + .local_addr() + .unwrap() + .port(); + if !unique_ports.contains(&port) { + unique_ports.insert(port); + return port; + } + } +} From 02c4dc3d19a380cd5b10958769a3712c70bea749 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Wed, 4 Sep 2024 13:30:09 +0300 Subject: [PATCH 05/10] Add `TestPoolSv2` test module A utility struct that wraps the original `PoolSv2` and provide some utility to start the pool role in testing env. --- roles/Cargo.lock | 860 ++++++++------------ roles/tests-integration/Cargo.toml | 3 + roles/tests-integration/tests/common/mod.rs | 111 ++- 3 files changed, 447 insertions(+), 527 deletions(-) diff --git a/roles/Cargo.lock b/roles/Cargo.lock index dc6557615..19c49ee8b 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -4,19 +4,13 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" @@ -80,9 +74,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -95,33 +89,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -129,9 +123,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arrayvec" @@ -162,22 +156,21 @@ dependencies = [ [[package]] name = "async-channel" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136d4d23bcc79e27423727b36823d86233aad06dfea531837b038394d11e9928" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" dependencies = [ "concurrent-queue", - "event-listener 5.3.0", - "event-listener-strategy 0.5.2", + "event-listener-strategy", "futures-core", "pin-project-lite", ] [[package]] name = "async-compat" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f68a707c1feb095d8c07f8a65b9f506b117d30af431cab89374357de7c11461b" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" dependencies = [ "futures-core", "futures-io", @@ -188,14 +181,14 @@ dependencies = [ [[package]] name = "async-executor" -version = "1.11.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b10202063978b3351199d68f8b22c4e47e4b1b822f8d43fd862d5ea8c006b29a" +checksum = "30ca9a001c1e8ba5149f91a74362376cc6bc5b919d92d988668657bd570bdcec" dependencies = [ "async-task", "concurrent-queue", - "fastrand 2.1.0", - "futures-lite 2.3.0", + "fastrand", + "futures-lite", "slab", ] @@ -205,71 +198,42 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" dependencies = [ - "async-channel 2.2.1", + "async-channel 2.3.1", "async-executor", - "async-io 2.3.2", - "async-lock 3.3.0", + "async-io", + "async-lock", "blocking", - "futures-lite 2.3.0", + "futures-lite", "once_cell", ] [[package]] name = "async-io" -version = "1.13.0" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ - "async-lock 2.8.0", - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-lite 1.13.0", - "log", - "parking", - "polling 2.8.0", - "rustix 0.37.27", - "slab", - "socket2 0.4.10", - "waker-fn", -] - -[[package]] -name = "async-io" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcccb0f599cfa2f8ace422d3555572f47424da5648a4382a9dd0310ff8210884" -dependencies = [ - "async-lock 3.3.0", + "async-lock", "cfg-if", "concurrent-queue", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "parking", - "polling 3.7.0", - "rustix 0.38.34", + "polling", + "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "async-lock" -version = "2.8.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" dependencies = [ - "event-listener 2.5.3", -] - -[[package]] -name = "async-lock" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b" -dependencies = [ - "event-listener 4.0.3", - "event-listener-strategy 0.4.0", + "event-listener 5.3.1", + "event-listener-strategy", "pin-project-lite", ] @@ -292,25 +256,25 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] name = "async-std" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +checksum = "c634475f29802fde2b8f0b505b1bd00dfe4df7d4a000f0b36f7671197d5c3615" dependencies = [ "async-attributes", "async-channel 1.9.0", "async-global-executor", - "async-io 1.13.0", - "async-lock 2.8.0", + "async-io", + "async-lock", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-lite 1.13.0", + "futures-lite", "gloo-timers", "kv-log-macro", "log", @@ -330,13 +294,13 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] @@ -364,17 +328,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.2", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets", ] [[package]] @@ -454,7 +418,7 @@ dependencies = [ "bitcoin_hashes 0.14.0", "hex-conservative 0.2.1", "hex_lit", - "secp256k1 0.29.0", + "secp256k1 0.29.1", "serde", ] @@ -511,7 +475,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ "bitcoin-internals 0.2.0", - "hex-conservative 0.1.1", + "hex-conservative 0.1.2", ] [[package]] @@ -564,15 +528,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" dependencies = [ "serde", ] @@ -597,15 +555,14 @@ dependencies = [ [[package]] name = "blocking" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "495f7104e962b7356f0aeb34247aca1fe7d2e783b346582db7f2904cb5717e88" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" dependencies = [ - "async-channel 2.2.1", - "async-lock 3.3.0", + "async-channel 2.3.1", "async-task", "futures-io", - "futures-lite 2.3.0", + "futures-lite", "piper", ] @@ -640,15 +597,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.0.97" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -693,9 +653,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -703,9 +663,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -715,21 +675,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "codec_sv2" @@ -746,9 +706,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "common_messages_sv2" @@ -825,9 +785,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -843,9 +803,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -935,9 +895,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -955,71 +915,41 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "event-listener" -version = "4.0.3" +version = "5.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b215c49b2b248c855fb73579eb1f4f26c38ffdc12973e20e07b91d78d5646e" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d9944b8ca13534cdfb2800775f8dd4902ff3fc75a50101466decadfdf322a24" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" dependencies = [ "concurrent-queue", "parking", "pin-project-lite", ] -[[package]] -name = "event-listener-strategy" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958e4d70b6d5e81971bebec42271ec641e7ff4e170a6fa605f2b8a8b65cb97d3" -dependencies = [ - "event-listener 4.0.3", - "pin-project-lite", -] - [[package]] name = "event-listener-strategy" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" dependencies = [ - "event-listener 5.3.0", + "event-listener 5.3.1", "pin-project-lite", ] [[package]] name = "fastrand" -version = "1.9.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -1029,7 +959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -1096,28 +1026,13 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" -[[package]] -name = "futures-lite" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" -dependencies = [ - "fastrand 1.9.0", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - [[package]] name = "futures-lite" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" dependencies = [ - "fastrand 2.1.0", + "fastrand", "futures-core", "futures-io", "parking", @@ -1132,7 +1047,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] @@ -1198,15 +1113,15 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" [[package]] name = "gloo-timers" -version = "0.2.6" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" dependencies = [ "futures-channel", "futures-core", @@ -1216,15 +1131,15 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816ec7294445779408f36fe57bc5b7fc1cf59664059096c65f905c1c61f58069" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", "http", "indexmap", "slab", @@ -1276,6 +1191,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + [[package]] name = "hex" version = "0.4.3" @@ -1284,9 +1205,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hex-conservative" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" [[package]] name = "hex-conservative" @@ -1325,9 +1246,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", "http", @@ -1335,12 +1256,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", - "futures-core", + "futures-util", "http", "http-body", "pin-project-lite", @@ -1348,9 +1269,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.8.0" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -1369,9 +1290,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.3.1" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" dependencies = [ "bytes", "futures-channel", @@ -1390,9 +1311,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.3" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" dependencies = [ "bytes", "futures-channel", @@ -1401,7 +1322,7 @@ dependencies = [ "http-body", "hyper", "pin-project-lite", - "socket2 0.5.7", + "socket2", "tokio", "tower", "tower-service", @@ -1410,9 +1331,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1427,42 +1348,25 @@ dependencies = [ "generic-array", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "integration-test" version = "0.1.0" dependencies = [ "bitcoind", "flate2", + "key-utils", "minreq", "once_cell", + "pool_sv2", "tar", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.9", - "libc", - "windows-sys 0.48.0", + "tokio", ] [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" @@ -1532,9 +1436,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1582,33 +1486,38 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags", + "libc", + "redox_syscall", +] [[package]] -name = "linux-raw-sys" -version = "0.3.8" +name = "linked-hash-map" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -1622,18 +1531,18 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" dependencies = [ "value-bag", ] [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" @@ -1696,15 +1605,6 @@ dependencies = [ "const_sv2", ] -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -1731,13 +1631,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi 0.3.9", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1795,9 +1696,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", @@ -1821,21 +1722,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi 0.3.9", - "libc", -] - [[package]] name = "object" -version = "0.32.2" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -1870,15 +1761,15 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "parking" -version = "2.2.0" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -1892,9 +1783,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets", ] [[package]] @@ -1905,9 +1796,9 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "pest" -version = "2.7.11" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "9c73c26c01b8c87956cea613c907c9d6ecffd8d18a2a5908e5de0adfaa185cea" dependencies = [ "memchr", "thiserror", @@ -1916,9 +1807,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "664d22978e2815783adbdd2c588b455b1bd625299ce36b2a99881ac9627e6d8d" dependencies = [ "pest", "pest_generator", @@ -1926,22 +1817,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "a2d5487022d5d33f4c30d91c22afa240ce2a644e87fe08caad974d4eab6badbe" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "0091754bbd0ea592c4deb3a122ce8ecbb0753b738aa82bc055fcc2eccc8d8174" dependencies = [ "once_cell", "pest", @@ -1965,7 +1856,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] @@ -1982,44 +1873,28 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "piper" -version = "0.2.1" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" dependencies = [ "atomic-waker", - "fastrand 2.1.0", + "fastrand", "futures-io", ] [[package]] name = "polling" -version = "2.8.0" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ - "autocfg", - "bitflags 1.3.2", "cfg-if", "concurrent-queue", - "libc", - "log", - "pin-project-lite", - "windows-sys 0.48.0", -] - -[[package]] -name = "polling" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645493cf344456ef24219d02a768cf1fb92ddf8c92161679ae3d91b91a637be3" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "pin-project-lite", - "rustix 0.38.34", + "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2073,9 +1948,12 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "pretty_env_logger" @@ -2089,9 +1967,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -2104,9 +1982,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2143,27 +2021,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", + "bitflags", ] [[package]] name = "regex" -version = "1.10.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -2173,9 +2042,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -2184,9 +2053,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "ring" @@ -2228,7 +2097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.5.0", + "bitflags", "serde", "serde_derive", ] @@ -2265,28 +2134,14 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "0.37.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" -dependencies = [ - "bitflags 1.3.2", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys 0.3.8", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", - "linux-raw-sys 0.4.13", + "linux-raw-sys", "windows-sys 0.52.0", ] @@ -2357,13 +2212,13 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0cc0f1cf93f4969faf3ea1c7d8a9faed25918d96affa959720823dfe86d4f3" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "bitcoin_hashes 0.14.0", "rand", - "secp256k1-sys 0.10.0", + "secp256k1-sys 0.10.1", "serde", ] @@ -2387,40 +2242,41 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1433bd67156263443f14d603720b082dd3121779323fce20cba2aa07b874bc1b" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] [[package]] name = "serde" -version = "1.0.200" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.200" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.116" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -2475,6 +2331,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -2505,16 +2367,6 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "socket2" version = "0.5.7" @@ -2547,9 +2399,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "sv1-mining-device" @@ -2594,9 +2446,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.61" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -2616,15 +2468,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", - "fastrand 2.1.0", + "fastrand", "once_cell", - "rustix 0.38.34", - "windows-sys 0.52.0", + "rustix", + "windows-sys 0.59.0", ] [[package]] @@ -2661,7 +2513,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] @@ -2685,39 +2537,38 @@ dependencies = [ [[package]] name = "tokio" -version = "1.38.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.7", + "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] name = "tokio-util" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" dependencies = [ "bytes", "futures-core", @@ -2773,20 +2624,19 @@ dependencies = [ "tokio", "tower-layer", "tower-service", - "tracing", ] [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2794,7 +2644,6 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2808,7 +2657,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", ] [[package]] @@ -2897,15 +2746,15 @@ checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "universal-hash" @@ -2925,9 +2774,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" @@ -2943,15 +2792,9 @@ checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "waker-fn" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "want" @@ -2970,34 +2813,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -3007,9 +2851,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3017,28 +2861,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -3059,7 +2903,7 @@ dependencies = [ "either", "home", "once_cell", - "rustix 0.38.34", + "rustix", ] [[package]] @@ -3080,11 +2924,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3093,144 +2937,87 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-targets", ] [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -3248,8 +3035,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", - "linux-raw-sys 0.4.13", - "rustix 0.38.34", + "linux-raw-sys", + "rustix", ] [[package]] @@ -3261,8 +3048,29 @@ dependencies = [ "linked-hash-map", ] +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/roles/tests-integration/Cargo.toml b/roles/tests-integration/Cargo.toml index 496f4f31e..a1d17847f 100644 --- a/roles/tests-integration/Cargo.toml +++ b/roles/tests-integration/Cargo.toml @@ -9,6 +9,9 @@ flate2 = "1.0.32" minreq = { version = "2.12.0", features = ["https"] } once_cell = "1.20.0" tar = "0.4.41" +pool_sv2 = { version = "0.1.0", path = "../pool" } +key-utils = { version = "1.0.0", path = "../../utils/key-utils" } +tokio = { version = "1.16.1", features = ["full"] } [lib] path = "tests/common/mod.rs" diff --git a/roles/tests-integration/tests/common/mod.rs b/roles/tests-integration/tests/common/mod.rs index 56edbc3b0..85f8412f7 100644 --- a/roles/tests-integration/tests/common/mod.rs +++ b/roles/tests-integration/tests/common/mod.rs @@ -1,14 +1,18 @@ use bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD, Conf}; use flate2::read::GzDecoder; +use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; use once_cell::sync::Lazy; +use pool_sv2::PoolSv2; use std::{ collections::HashSet, env, fs::{create_dir_all, File}, io::{BufReader, Read}, - net::TcpListener, + net::{SocketAddr, TcpListener}, path::{Path, PathBuf}, + str::FromStr, sync::Mutex, + time::Duration, }; use tar::Archive; @@ -175,3 +179,108 @@ pub fn get_available_port() -> u16 { } } } + +#[derive(Debug)] +pub struct TestPoolSv2 { + pub pool: PoolSv2, + pub port: u16, +} + +impl TestPoolSv2 { + pub fn new( + listening_address: Option, + coinbase_outputs: Option>, + template_provider_address: Option, + ) -> Self { + use pool_sv2::mining_pool::{CoinbaseOutput, Configuration}; + let pool_port = get_available_port(); + let listening_address = listening_address + .unwrap_or(SocketAddr::from_str(&format!("127.0.0.1:{}", pool_port)).unwrap()); + let is_pool_port_open = is_port_open(listening_address); + assert_eq!(is_pool_port_open, false); + let authority_public_key = Secp256k1PublicKey::try_from( + "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72".to_string(), + ) + .expect("failed"); + let authority_secret_key = Secp256k1SecretKey::try_from( + "mkDLTBBRxdBv998612qipDYoTK3YUrqLe8uWw7gu3iXbSrn2n".to_string(), + ) + .expect("failed"); + let cert_validity_sec = 3600; + let coinbase_outputs = if let Some(cb_outs) = coinbase_outputs { + cb_outs + } else { + vec![CoinbaseOutput::new( + "P2WPKH".to_string(), + "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075".to_string(), + )] + }; + let pool_signature = "Stratum v2 SRI Pool".to_string(); + let tp_address = if let Some(tp_add) = template_provider_address { + tp_add.to_string() + } else { + "127.0.0.1:8442".to_string() + }; + let connection_config = pool_sv2::mining_pool::ConnectionConfig::new( + listening_address.to_string(), + cert_validity_sec, + pool_signature, + ); + let template_provider_config = + pool_sv2::mining_pool::TemplateProviderConfig::new(tp_address, None); + let authority_config = + pool_sv2::mining_pool::AuthorityConfig::new(authority_public_key, authority_secret_key); + let config = Configuration::new( + connection_config, + template_provider_config, + authority_config, + coinbase_outputs, + ); + let pool = PoolSv2::new(config); + + Self { + pool, + port: pool_port, + } + } +} + +pub async fn start_template_provider() -> (TemplateProvider, u16) { + let template_provider_port = get_available_port(); + let template_provider = TemplateProvider::start(template_provider_port); + template_provider.generate_blocks(16); + (template_provider, template_provider_port) +} + +pub async fn start_template_provider_and_pool() -> Result<(PoolSv2, u16, TemplateProvider, u16), ()> +{ + let (template_provider, template_provider_port) = start_template_provider().await; + let template_provider_address = + SocketAddr::from_str(&format!("127.0.0.1:{}", template_provider_port)).unwrap(); + let test_pool = TestPoolSv2::new(None, None, Some(template_provider_address)); + let pool = test_pool.pool.clone(); + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + assert_eq!(state, pool_sv2::PoolState::Initial); + let _pool = pool.clone(); + tokio::task::spawn(async move { + assert!(_pool.start().await.is_ok()); + }); + // Wait for the pool to start. + tokio::time::sleep(Duration::from_secs(1)).await; + let pool_listening_address = + SocketAddr::from_str(&format!("127.0.0.1:{}", test_pool.port)).unwrap(); + loop { + if is_port_open(pool_listening_address) { + break; + } + } + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + assert_eq!(state, pool_sv2::PoolState::Running); + template_provider.stop(); + Ok(( + pool, + test_pool.port, + template_provider, + template_provider_port, + )) +} From 3a80407e13f8449f87fcdc8b394fef7766b936a2 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Wed, 4 Sep 2024 13:32:23 +0300 Subject: [PATCH 06/10] Add integration test for `PoolSv2` --- .github/workflows/test.yaml | 4 +++ .../tests/pool_integration.rs | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 roles/tests-integration/tests/pool_integration.rs diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 5b669ebc0..a2f63deb4 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -40,6 +40,10 @@ jobs: cargo build --manifest-path=roles/Cargo.toml cargo build --manifest-path=utils/Cargo.toml + - name: Roles Integration Tests + run: | + cargo test --manifest-path=roles/Cargo.toml --verbose --test '*' -- --nocapture + - name: Run sv1-client-and-server example run: | cargo run --manifest-path=examples/sv1-client-and-server/Cargo.toml --bin client_and_server -- 60 diff --git a/roles/tests-integration/tests/pool_integration.rs b/roles/tests-integration/tests/pool_integration.rs new file mode 100644 index 000000000..4e9fc123a --- /dev/null +++ b/roles/tests-integration/tests/pool_integration.rs @@ -0,0 +1,31 @@ +use std::str::FromStr; + +mod common; + +#[tokio::test] +async fn success_pool_template_provider_connection() { + assert!(common::start_template_provider_and_pool().await.is_ok()); +} + +#[tokio::test] +async fn pool_bad_coinbase_output() { + let (template_provider, template_provider_port) = common::start_template_provider().await; + let invalid_coinbase_output = vec![pool_sv2::mining_pool::CoinbaseOutput::new( + "P2PK".to_string(), + "04466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276728176c3c6431f8eeda4538dc37c865e2784f3a9e77d044f33e407797e1278".to_string(), + )]; + let template_provider_address = + std::net::SocketAddr::from_str(&format!("127.0.0.1:{}", template_provider_port)).unwrap(); + let test_pool = common::TestPoolSv2::new( + None, + Some(invalid_coinbase_output), + Some(template_provider_address), + ); + let pool = test_pool.pool.clone(); + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + assert_eq!(state, pool_sv2::PoolState::Initial); + assert!(pool.start().await.is_err()); + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + assert_eq!(state, pool_sv2::PoolState::Initial); + template_provider.stop(); +} From e23fbe6be650dfdc156ca22ea075f7d424657090 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Thu, 12 Sep 2024 16:42:57 +0300 Subject: [PATCH 07/10] Separate `lib` code from `bin` in `mining-device` Isolating the library code into a `lib/mod.rs` and consume it in `main.rs`. --- roles/Cargo.lock | 2 +- roles/test-utils/mining-device/Cargo.toml | 10 +- roles/test-utils/mining-device/src/lib/mod.rs | 712 +++++++++++++++++ roles/test-utils/mining-device/src/main.rs | 718 +----------------- 4 files changed, 728 insertions(+), 714 deletions(-) create mode 100644 roles/test-utils/mining-device/src/lib/mod.rs diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 19c49ee8b..2e9ee5b98 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -1551,7 +1551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] -name = "mining-device" +name = "mining_device" version = "0.1.1" dependencies = [ "async-channel 1.9.0", diff --git a/roles/test-utils/mining-device/Cargo.toml b/roles/test-utils/mining-device/Cargo.toml index a59719504..6c9d6c35e 100644 --- a/roles/test-utils/mining-device/Cargo.toml +++ b/roles/test-utils/mining-device/Cargo.toml @@ -1,11 +1,16 @@ [package] -name = "mining-device" +name = "mining_device" version = "0.1.1" edition = "2018" publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "mining_device" +path = "src/lib/mod.rs" + + [dependencies] stratum-common = { version = "1.0.0", path = "../../../common" } codec_sv2 = { version = "^1.0.1", path = "../../../protocols/v2/codec-sv2", features=["noise_sv2"] } @@ -24,3 +29,6 @@ tracing = { version = "0.1" } tracing-subscriber = "0.3" sha2 = "0.10.6" tokio = "^1.38.0" + +[features] +abort_mining = [] diff --git a/roles/test-utils/mining-device/src/lib/mod.rs b/roles/test-utils/mining-device/src/lib/mod.rs new file mode 100644 index 000000000..01d0505b0 --- /dev/null +++ b/roles/test-utils/mining-device/src/lib/mod.rs @@ -0,0 +1,712 @@ +#![allow(clippy::option_map_unit_fn)] +use key_utils::Secp256k1PublicKey; +use network_helpers_sv2::noise_connection_tokio::Connection; +use roles_logic_sv2::utils::Id; +use std::{ + net::{SocketAddr, ToSocketAddrs}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + time::Duration, +}; +use tokio::net::TcpStream; + +use async_channel::{Receiver, Sender}; +use binary_sv2::u256_from_int; +use codec_sv2::{Initiator, StandardEitherFrame, StandardSv2Frame}; +use rand::{thread_rng, Rng}; +use roles_logic_sv2::{ + common_messages_sv2::{Protocol, SetupConnection, SetupConnectionSuccess}, + common_properties::{IsMiningUpstream, IsUpstream}, + errors::Error, + handlers::{ + common::ParseUpstreamCommonMessages, + mining::{ParseUpstreamMiningMessages, SendTo, SupportedChannelTypes}, + }, + mining_sv2::*, + parsers::{Mining, MiningDeviceMessages}, + routing_logic::{CommonRoutingLogic, MiningRoutingLogic, NoRouting}, + selectors::NullDownstreamMiningSelector, + utils::Mutex, +}; +use std::time::Instant; +use stratum_common::bitcoin::{ + blockdata::block::BlockHeader, hash_types::BlockHash, hashes::Hash, util::uint::Uint256, +}; +use tracing::{error, info}; + +pub async fn connect( + address: String, + pub_key: Option, + device_id: Option, + user_id: Option, + handicap: u32, +) -> Result<(), Error> { + let address = address + .clone() + .to_socket_addrs() + .expect("Invalid pool address, use one of this formats: ip:port, domain:port") + .next() + .expect("Invalid pool address, use one of this formats: ip:port, domain:port"); + let socket = loop { + let pool = tokio::time::timeout(Duration::from_secs(5), TcpStream::connect(address)).await; + match pool { + Ok(result) => match result { + Ok(socket) => break socket, + Err(e) => { + error!( + "Failed to connect to Upstream role at {}, retrying in 5s: {}", + address, e + ); + tokio::time::sleep(Duration::from_secs(5)).await; + } + }, + Err(_) => { + error!("Pool is unresponsive, terminating"); + std::process::exit(1); + } + } + }; + info!("Pool tcp connection established at {}", address); + let address = socket.peer_addr().unwrap(); + let initiator = Initiator::new(pub_key.map(|e| e.0)); + let (receiver, sender, _, _): (Receiver, Sender, _, _) = + Connection::new(socket, codec_sv2::HandshakeRole::Initiator(initiator)) + .await + .unwrap(); + info!("Pool noise connection established at {}", address); + Device::start(receiver, sender, address, device_id, user_id, handicap).await +} + +pub type Message = MiningDeviceMessages<'static>; +pub type StdFrame = StandardSv2Frame; +pub type EitherFrame = StandardEitherFrame; + +struct SetupConnectionHandler {} +use std::convert::TryInto; + +impl SetupConnectionHandler { + pub fn new() -> Self { + SetupConnectionHandler {} + } + fn get_setup_connection_message( + address: SocketAddr, + device_id: Option, + ) -> SetupConnection<'static> { + let endpoint_host = address.ip().to_string().into_bytes().try_into().unwrap(); + let vendor = String::new().try_into().unwrap(); + let hardware_version = String::new().try_into().unwrap(); + let firmware = String::new().try_into().unwrap(); + let device_id = device_id.unwrap_or_default(); + info!( + "Creating SetupConnection message with device id: {:?}", + device_id + ); + SetupConnection { + protocol: Protocol::MiningProtocol, + min_version: 2, + max_version: 2, + flags: 0b0000_0000_0000_0000_0000_0000_0000_0001, + endpoint_host, + endpoint_port: address.port(), + vendor, + hardware_version, + firmware, + device_id: device_id.try_into().unwrap(), + } + } + pub async fn setup( + self_: Arc>, + receiver: &mut Receiver, + sender: &mut Sender, + device_id: Option, + address: SocketAddr, + ) { + let setup_connection = Self::get_setup_connection_message(address, device_id); + + let sv2_frame: StdFrame = MiningDeviceMessages::Common(setup_connection.into()) + .try_into() + .unwrap(); + let sv2_frame = sv2_frame.into(); + sender.send(sv2_frame).await.unwrap(); + info!("Setup connection sent to {}", address); + + let mut incoming: StdFrame = receiver.recv().await.unwrap().try_into().unwrap(); + let message_type = incoming.get_header().unwrap().msg_type(); + let payload = incoming.payload(); + ParseUpstreamCommonMessages::handle_message_common( + self_, + message_type, + payload, + CommonRoutingLogic::None, + ) + .unwrap(); + } +} + +impl ParseUpstreamCommonMessages for SetupConnectionHandler { + fn handle_setup_connection_success( + &mut self, + _: SetupConnectionSuccess, + ) -> Result { + use roles_logic_sv2::handlers::common::SendTo; + info!("Setup connection success"); + Ok(SendTo::None(None)) + } + + fn handle_setup_connection_error( + &mut self, + _: roles_logic_sv2::common_messages_sv2::SetupConnectionError, + ) -> Result { + error!("Setup connection error"); + todo!() + } + + fn handle_channel_endpoint_changed( + &mut self, + _: roles_logic_sv2::common_messages_sv2::ChannelEndpointChanged, + ) -> Result { + todo!() + } +} + +#[derive(Debug, Clone)] +struct NewWorkNotifier { + should_send: bool, + sender: Sender<()>, +} + +#[derive(Debug)] +pub struct Device { + #[allow(dead_code)] + receiver: Receiver, + sender: Sender, + #[allow(dead_code)] + channel_opened: bool, + channel_id: Option, + miner: Arc>, + jobs: Vec>, + prev_hash: Option>, + sequence_numbers: Id, + notify_changes_to_mining_thread: NewWorkNotifier, +} + +fn open_channel(device_id: Option) -> OpenStandardMiningChannel<'static> { + let user_identity = device_id.unwrap_or_default().try_into().unwrap(); + let id: u32 = 10; + info!("Measuring CPU hashrate"); + let p = std::thread::available_parallelism().unwrap().get() as u32 - 3; + let nominal_hash_rate = measure_hashrate(5) as f32 * p as f32; + info!("Pc hashrate is {}", nominal_hash_rate); + info!("MINING DEVICE: send open channel with request id {}", id); + OpenStandardMiningChannel { + request_id: id.into(), + user_identity, + nominal_hash_rate, + max_target: u256_from_int(567_u64), + } +} + +impl Device { + async fn start( + mut receiver: Receiver, + mut sender: Sender, + addr: SocketAddr, + device_id: Option, + user_id: Option, + handicap: u32, + ) -> Result<(), Error> { + let setup_connection_handler = Arc::new(Mutex::new(SetupConnectionHandler::new())); + SetupConnectionHandler::setup( + setup_connection_handler, + &mut receiver, + &mut sender, + device_id, + addr, + ) + .await; + info!("Pool sv2 connection established at {}", addr); + let miner = Arc::new(Mutex::new(Miner::new(handicap))); + let (notify_changes_to_mining_thread, update_miners) = async_channel::unbounded(); + let self_ = Self { + channel_opened: false, + receiver: receiver.clone(), + sender: sender.clone(), + miner: miner.clone(), + jobs: Vec::new(), + prev_hash: None, + channel_id: None, + sequence_numbers: Id::new(), + notify_changes_to_mining_thread: NewWorkNotifier { + should_send: true, + sender: notify_changes_to_mining_thread, + }, + }; + let open_channel = + MiningDeviceMessages::Mining(Mining::OpenStandardMiningChannel(open_channel(user_id))); + let frame: StdFrame = open_channel.try_into().unwrap(); + self_.sender.send(frame.into()).await.unwrap(); + let self_mutex = std::sync::Arc::new(Mutex::new(self_)); + let cloned = self_mutex.clone(); + + let (share_send, share_recv) = async_channel::unbounded(); + + #[cfg(not(feature = "abort_mining"))] + start_mining_threads(update_miners, miner, share_send); + + tokio::task::spawn(async move { + let recv = share_recv.clone(); + loop { + let (nonce, job_id, version, ntime) = recv.recv().await.unwrap(); + Self::send_share(cloned.clone(), nonce, job_id, version, ntime).await; + } + }); + + info!("Mining device started"); + loop { + let incoming = receiver.recv().await.unwrap(); + let mut incoming: StdFrame = incoming.try_into().unwrap(); + let message_type = incoming.get_header().unwrap().msg_type(); + let payload = incoming.payload(); + let next = Device::handle_message_mining( + self_mutex.clone(), + message_type, + payload, + MiningRoutingLogic::None, + )?; + let msg: Result = (message_type, payload).try_into(); + info!("Mining device received message: {:?}", msg); + let mut notify_changes_to_mining_thread = self_mutex + .safe_lock(|s| s.notify_changes_to_mining_thread.clone()) + .unwrap(); + if notify_changes_to_mining_thread.should_send + && (message_type == const_sv2::MESSAGE_TYPE_NEW_MINING_JOB + || message_type == const_sv2::MESSAGE_TYPE_SET_NEW_PREV_HASH + || message_type == const_sv2::MESSAGE_TYPE_SET_TARGET) + { + notify_changes_to_mining_thread + .sender + .send(()) + .await + .unwrap(); + notify_changes_to_mining_thread.should_send = false; + }; + match next { + SendTo::RelayNewMessageToRemote(_, m) => { + let sv2_frame: StdFrame = MiningDeviceMessages::Mining(m).try_into().unwrap(); + let either_frame: EitherFrame = sv2_frame.into(); + sender.send(either_frame).await.unwrap(); + } + SendTo::None(_) => (), + _ => panic!(), + } + } + } + + async fn send_share( + self_mutex: Arc>, + nonce: u32, + job_id: u32, + version: u32, + ntime: u32, + ) { + let share = + MiningDeviceMessages::Mining(Mining::SubmitSharesStandard(SubmitSharesStandard { + channel_id: self_mutex.safe_lock(|s| s.channel_id.unwrap()).unwrap(), + sequence_number: self_mutex.safe_lock(|s| s.sequence_numbers.next()).unwrap(), + job_id, + nonce, + ntime, + version, + })); + let frame: StdFrame = share.try_into().unwrap(); + let sender = self_mutex.safe_lock(|s| s.sender.clone()).unwrap(); + sender.send(frame.into()).await.unwrap(); + } +} + +impl IsUpstream<(), NullDownstreamMiningSelector> for Device { + fn get_version(&self) -> u16 { + todo!() + } + + fn get_flags(&self) -> u32 { + todo!() + } + + fn get_supported_protocols(&self) -> Vec { + todo!() + } + + fn get_id(&self) -> u32 { + todo!() + } + + fn get_mapper(&mut self) -> Option<&mut roles_logic_sv2::common_properties::RequestIdMapper> { + todo!() + } + + fn get_remote_selector(&mut self) -> &mut NullDownstreamMiningSelector { + todo!() + } +} + +impl IsMiningUpstream<(), NullDownstreamMiningSelector> for Device { + fn total_hash_rate(&self) -> u64 { + todo!() + } + + fn add_hash_rate(&mut self, _to_add: u64) { + todo!() + } + fn get_opened_channels( + &mut self, + ) -> &mut Vec { + todo!() + } + + fn update_channels(&mut self, _: roles_logic_sv2::common_properties::UpstreamChannel) { + todo!() + } +} + +impl ParseUpstreamMiningMessages<(), NullDownstreamMiningSelector, NoRouting> for Device { + fn get_channel_type(&self) -> SupportedChannelTypes { + SupportedChannelTypes::Standard + } + + fn is_work_selection_enabled(&self) -> bool { + false + } + + fn handle_open_standard_mining_channel_success( + &mut self, + m: OpenStandardMiningChannelSuccess, + _: Option>>, + ) -> Result, Error> { + self.channel_opened = true; + self.channel_id = Some(m.channel_id); + let req_id = m.get_request_id_as_u32(); + self.miner + .safe_lock(|miner| miner.new_target(m.target.to_vec())) + .unwrap(); + self.notify_changes_to_mining_thread.should_send = true; + Ok(SendTo::None(None)) + } + + fn handle_open_extended_mining_channel_success( + &mut self, + _: OpenExtendedMiningChannelSuccess, + ) -> Result, Error> { + unreachable!() + } + + fn handle_open_mining_channel_error( + &mut self, + _: OpenMiningChannelError, + ) -> Result, Error> { + todo!() + } + + fn handle_update_channel_error(&mut self, _: UpdateChannelError) -> Result, Error> { + todo!() + } + + fn handle_close_channel(&mut self, _: CloseChannel) -> Result, Error> { + todo!() + } + + fn handle_set_extranonce_prefix( + &mut self, + _: SetExtranoncePrefix, + ) -> Result, Error> { + todo!() + } + + fn handle_submit_shares_success( + &mut self, + m: SubmitSharesSuccess, + ) -> Result, Error> { + info!("SUCCESS {:?}", m); + Ok(SendTo::None(None)) + } + + fn handle_submit_shares_error(&mut self, _: SubmitSharesError) -> Result, Error> { + info!("Submit shares error"); + Ok(SendTo::None(None)) + } + + fn handle_new_mining_job(&mut self, m: NewMiningJob) -> Result, Error> { + match (m.is_future(), self.prev_hash.as_ref()) { + (false, Some(p_h)) => { + self.miner + .safe_lock(|miner| miner.new_header(p_h, &m)) + .unwrap(); + self.jobs = vec![m.as_static()]; + self.notify_changes_to_mining_thread.should_send = true; + } + (true, _) => self.jobs.push(m.as_static()), + (false, None) => { + panic!() + } + } + Ok(SendTo::None(None)) + } + + fn handle_new_extended_mining_job( + &mut self, + _: NewExtendedMiningJob, + ) -> Result, Error> { + todo!() + } + + fn handle_set_new_prev_hash(&mut self, m: SetNewPrevHash) -> Result, Error> { + let jobs: Vec<&NewMiningJob<'static>> = self + .jobs + .iter() + .filter(|j| j.job_id == m.job_id && j.is_future()) + .collect(); + match jobs.len() { + 0 => { + self.prev_hash = Some(m.as_static()); + } + 1 => { + self.miner + .safe_lock(|miner| miner.new_header(&m, jobs[0])) + .unwrap(); + self.jobs = vec![jobs[0].clone()]; + self.prev_hash = Some(m.as_static()); + self.notify_changes_to_mining_thread.should_send = true; + } + _ => panic!(), + } + Ok(SendTo::None(None)) + } + + fn handle_set_custom_mining_job_success( + &mut self, + _: SetCustomMiningJobSuccess, + ) -> Result, Error> { + todo!() + } + + fn handle_set_custom_mining_job_error( + &mut self, + _: SetCustomMiningJobError, + ) -> Result, Error> { + todo!() + } + + fn handle_set_target(&mut self, m: SetTarget) -> Result, Error> { + self.miner + .safe_lock(|miner| miner.new_target(m.maximum_target.to_vec())) + .unwrap(); + self.notify_changes_to_mining_thread.should_send = true; + Ok(SendTo::None(None)) + } + + fn handle_reconnect(&mut self, _: Reconnect) -> Result, Error> { + todo!() + } +} + +#[derive(Debug, Clone)] +struct Miner { + header: Option, + target: Option, + job_id: Option, + version: Option, + handicap: u32, +} + +impl Miner { + fn new(handicap: u32) -> Self { + Self { + target: None, + header: None, + job_id: None, + version: None, + handicap, + } + } + + fn new_target(&mut self, mut target: Vec) { + // target is sent in LE and comparisons in this file are done in BE + target.reverse(); + let hex_string = target + .iter() + .fold("".to_string(), |acc, b| acc + format!("{:02x}", b).as_str()); + info!("Set target to {}", hex_string); + self.target = Some(Uint256::from_be_bytes(target.try_into().unwrap())); + } + + fn new_header(&mut self, set_new_prev_hash: &SetNewPrevHash, new_job: &NewMiningJob) { + self.job_id = Some(new_job.job_id); + self.version = Some(new_job.version); + let prev_hash: [u8; 32] = set_new_prev_hash.prev_hash.to_vec().try_into().unwrap(); + let prev_hash = Hash::from_inner(prev_hash); + let merkle_root: [u8; 32] = new_job.merkle_root.to_vec().try_into().unwrap(); + let merkle_root = Hash::from_inner(merkle_root); + // fields need to be added as BE and the are converted to LE in the background before hashing + let header = BlockHeader { + version: new_job.version as i32, + prev_blockhash: BlockHash::from_hash(prev_hash), + merkle_root, + time: std::time::SystemTime::now() + .duration_since( + std::time::SystemTime::UNIX_EPOCH - std::time::Duration::from_secs(60), + ) + .unwrap() + .as_secs() as u32, + bits: set_new_prev_hash.nbits, + nonce: 0, + }; + self.header = Some(header); + } + pub fn next_share(&mut self) -> NextShareOutcome { + if let Some(header) = self.header.as_ref() { + let mut hash = header.block_hash().as_hash().into_inner(); + hash.reverse(); + let hash = Uint256::from_be_bytes(hash); + if hash < *self.target.as_ref().unwrap() { + info!( + "Found share with nonce: {}, for target: {:?}, with hash: {:?}", + header.nonce, self.target, hash, + ); + NextShareOutcome::ValidShare + } else { + NextShareOutcome::InvalidShare + } + } else { + std::thread::yield_now(); + NextShareOutcome::InvalidShare + } + } +} + +enum NextShareOutcome { + ValidShare, + InvalidShare, +} + +impl NextShareOutcome { + pub fn is_valid(&self) -> bool { + matches!(self, NextShareOutcome::ValidShare) + } +} + +// returns hashrate based on how fast the device hashes over the given duration +fn measure_hashrate(duration_secs: u64) -> f64 { + let mut rng = thread_rng(); + let prev_hash: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap(); + let prev_hash = Hash::from_inner(prev_hash); + // We create a random block that we can hash, we are only interested in knowing how many hashes + // per unit of time we can do + let merkle_root: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap(); + let merkle_root = Hash::from_inner(merkle_root); + let header = BlockHeader { + version: rng.gen(), + prev_blockhash: BlockHash::from_hash(prev_hash), + merkle_root, + time: std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH - std::time::Duration::from_secs(60)) + .unwrap() + .as_secs() as u32, + bits: rng.gen(), + nonce: 0, + }; + let start_time = Instant::now(); + let mut hashes: u64 = 0; + let duration = Duration::from_secs(duration_secs); + let mut miner = Miner::new(0); + // We put the target to 0 we are only interested in how many hashes per unit of time we can do + // and do not want to be botherd by messages about valid shares found. + miner.new_target(vec![0_u8; 32]); + miner.header = Some(header); + + while start_time.elapsed() < duration { + miner.next_share(); + hashes += 1; + } + + let elapsed_secs = start_time.elapsed().as_secs_f64(); + hashes as f64 / elapsed_secs +} +fn generate_random_32_byte_array() -> [u8; 32] { + let mut rng = thread_rng(); + let mut arr = [0u8; 32]; + rng.fill(&mut arr[..]); + arr +} + +fn start_mining_threads( + have_new_job: Receiver<()>, + miner: Arc>, + share_send: Sender<(u32, u32, u32, u32)>, +) { + tokio::task::spawn(async move { + let mut killers: Vec> = vec![]; + loop { + let available_parallelism = u32::max( + 2, + std::thread::available_parallelism().unwrap().get() as u32, + ); + let p = available_parallelism - 1; + let unit = u32::MAX / p; + while have_new_job.recv().await.is_ok() { + while let Some(killer) = killers.pop() { + killer.store(true, Ordering::Relaxed); + } + let miner = miner.safe_lock(|m| m.clone()).unwrap(); + for i in 0..p { + let mut miner = miner.clone(); + let share_send = share_send.clone(); + let killer = Arc::new(AtomicBool::new(false)); + miner.header.as_mut().map(|h| h.nonce = i * unit); + killers.push(killer.clone()); + std::thread::spawn(move || { + mine(miner, share_send, killer); + }); + } + } + } + }); +} + +fn mine(mut miner: Miner, share_send: Sender<(u32, u32, u32, u32)>, kill: Arc) { + if miner.handicap != 0 { + loop { + if kill.load(Ordering::Relaxed) { + break; + } + std::thread::sleep(std::time::Duration::from_micros(miner.handicap.into())); + if miner.next_share().is_valid() { + let nonce = miner.header.unwrap().nonce; + let time = miner.header.unwrap().time; + let job_id = miner.job_id.unwrap(); + let version = miner.version; + share_send + .try_send((nonce, job_id, version.unwrap(), time)) + .unwrap(); + } + miner.header.as_mut().map(|h| h.nonce += 1); + } + } else { + loop { + if miner.next_share().is_valid() { + if kill.load(Ordering::Relaxed) { + break; + } + let nonce = miner.header.unwrap().nonce; + let time = miner.header.unwrap().time; + let job_id = miner.job_id.unwrap(); + let version = miner.version; + share_send + .try_send((nonce, job_id, version.unwrap(), time)) + .unwrap(); + } + miner.header.as_mut().map(|h| h.nonce += 1); + } + } +} diff --git a/roles/test-utils/mining-device/src/main.rs b/roles/test-utils/mining-device/src/main.rs index 35a31d56a..02a19c12f 100644 --- a/roles/test-utils/mining-device/src/main.rs +++ b/roles/test-utils/mining-device/src/main.rs @@ -1,24 +1,11 @@ +#![allow(special_module_name)] #![allow(clippy::option_map_unit_fn)] use key_utils::Secp256k1PublicKey; -use network_helpers_sv2::noise_connection_tokio::Connection; -use roles_logic_sv2::utils::Id; -use std::{ - net::{SocketAddr, ToSocketAddrs}, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - time::Duration, -}; -use tokio::net::TcpStream; use clap::Parser; -use rand::{thread_rng, Rng}; -use std::time::Instant; -use stratum_common::bitcoin::{ - blockdata::block::BlockHeader, hash_types::BlockHash, hashes::Hash, util::uint::Uint256, -}; -use tracing::{error, info}; +use tracing::info; + +pub mod lib; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] @@ -54,710 +41,17 @@ struct Args { id_user: Option, } -async fn connect( - address: String, - pub_key: Option, - device_id: Option, - user_id: Option, - handicap: u32, -) { - let address = address - .clone() - .to_socket_addrs() - .expect("Invalid pool address, use one of this formats: ip:port, domain:port") - .next() - .expect("Invalid pool address, use one of this formats: ip:port, domain:port"); - info!("Connecting to pool at {}", address); - let socket = loop { - let pool = tokio::time::timeout(Duration::from_secs(5), TcpStream::connect(address)).await; - match pool { - Ok(result) => match result { - Ok(socket) => break socket, - Err(e) => { - error!( - "Failed to connect to Upstream role at {}, retrying in 5s: {}", - address, e - ); - tokio::time::sleep(Duration::from_secs(5)).await; - } - }, - Err(_) => { - error!("Pool is unresponsive, terminating"); - std::process::exit(1); - } - } - }; - info!("Pool tcp connection established at {}", address); - let address = socket.peer_addr().unwrap(); - let initiator = Initiator::new(pub_key.map(|e| e.0)); - let (receiver, sender, _, _): (Receiver, Sender, _, _) = - Connection::new(socket, codec_sv2::HandshakeRole::Initiator(initiator)) - .await - .unwrap(); - info!("Pool noise connection established at {}", address); - Device::start(receiver, sender, address, device_id, user_id, handicap).await -} - #[tokio::main(flavor = "current_thread")] async fn main() { let args = Args::parse(); tracing_subscriber::fmt::init(); info!("start"); - connect( + let _ = lib::connect( args.address_pool, args.pubkey_pool, args.id_device, args.id_user, args.handicap, ) - .await -} - -use async_channel::{Receiver, Sender}; -use binary_sv2::u256_from_int; -use codec_sv2::{Initiator, StandardEitherFrame, StandardSv2Frame}; -use roles_logic_sv2::{ - common_messages_sv2::{Protocol, SetupConnection, SetupConnectionSuccess}, - common_properties::{IsMiningUpstream, IsUpstream}, - errors::Error, - handlers::{ - common::ParseUpstreamCommonMessages, - mining::{ParseUpstreamMiningMessages, SendTo, SupportedChannelTypes}, - }, - mining_sv2::*, - parsers::{Mining, MiningDeviceMessages}, - routing_logic::{CommonRoutingLogic, MiningRoutingLogic, NoRouting}, - selectors::NullDownstreamMiningSelector, - utils::Mutex, -}; - -pub type Message = MiningDeviceMessages<'static>; -pub type StdFrame = StandardSv2Frame; -pub type EitherFrame = StandardEitherFrame; - -struct SetupConnectionHandler {} -use std::convert::TryInto; - -impl SetupConnectionHandler { - pub fn new() -> Self { - SetupConnectionHandler {} - } - fn get_setup_connection_message( - address: SocketAddr, - device_id: Option, - ) -> SetupConnection<'static> { - let endpoint_host = address.ip().to_string().into_bytes().try_into().unwrap(); - let vendor = String::new().try_into().unwrap(); - let hardware_version = String::new().try_into().unwrap(); - let firmware = String::new().try_into().unwrap(); - let device_id = device_id.unwrap_or_default(); - info!( - "Creating SetupConnection message with device id: {:?}", - device_id - ); - SetupConnection { - protocol: Protocol::MiningProtocol, - min_version: 2, - max_version: 2, - flags: 0b0000_0000_0000_0000_0000_0000_0000_0001, - endpoint_host, - endpoint_port: address.port(), - vendor, - hardware_version, - firmware, - device_id: device_id.try_into().unwrap(), - } - } - pub async fn setup( - self_: Arc>, - receiver: &mut Receiver, - sender: &mut Sender, - device_id: Option, - address: SocketAddr, - ) { - let setup_connection = Self::get_setup_connection_message(address, device_id); - - let sv2_frame: StdFrame = MiningDeviceMessages::Common(setup_connection.into()) - .try_into() - .unwrap(); - let sv2_frame = sv2_frame.into(); - sender.send(sv2_frame).await.unwrap(); - info!("Setup connection sent to {}", address); - - let mut incoming: StdFrame = receiver.recv().await.unwrap().try_into().unwrap(); - let message_type = incoming.get_header().unwrap().msg_type(); - let payload = incoming.payload(); - ParseUpstreamCommonMessages::handle_message_common( - self_, - message_type, - payload, - CommonRoutingLogic::None, - ) - .unwrap(); - } -} - -impl ParseUpstreamCommonMessages for SetupConnectionHandler { - fn handle_setup_connection_success( - &mut self, - _: SetupConnectionSuccess, - ) -> Result { - use roles_logic_sv2::handlers::common::SendTo; - info!("Setup connection success"); - Ok(SendTo::None(None)) - } - - fn handle_setup_connection_error( - &mut self, - _: roles_logic_sv2::common_messages_sv2::SetupConnectionError, - ) -> Result { - error!("Setup connection error"); - todo!() - } - - fn handle_channel_endpoint_changed( - &mut self, - _: roles_logic_sv2::common_messages_sv2::ChannelEndpointChanged, - ) -> Result { - todo!() - } -} - -#[derive(Debug, Clone)] -struct NewWorkNotifier { - should_send: bool, - sender: Sender<()>, -} - -#[derive(Debug)] -pub struct Device { - #[allow(dead_code)] - receiver: Receiver, - sender: Sender, - #[allow(dead_code)] - channel_opened: bool, - channel_id: Option, - miner: Arc>, - jobs: Vec>, - prev_hash: Option>, - sequence_numbers: Id, - notify_changes_to_mining_thread: NewWorkNotifier, -} - -fn open_channel(device_id: Option) -> OpenStandardMiningChannel<'static> { - let user_identity = device_id.unwrap_or_default().try_into().unwrap(); - let id: u32 = 10; - info!("Measuring CPU hashrate"); - let p = std::thread::available_parallelism().unwrap().get() as u32 - 3; - let nominal_hash_rate = measure_hashrate(5) as f32 * p as f32; - info!("Pc hashrate is {}", nominal_hash_rate); - info!("MINING DEVICE: send open channel with request id {}", id); - OpenStandardMiningChannel { - request_id: id.into(), - user_identity, - nominal_hash_rate, - max_target: u256_from_int(567_u64), - } -} - -impl Device { - async fn start( - mut receiver: Receiver, - mut sender: Sender, - addr: SocketAddr, - device_id: Option, - user_id: Option, - handicap: u32, - ) { - let setup_connection_handler = Arc::new(Mutex::new(SetupConnectionHandler::new())); - SetupConnectionHandler::setup( - setup_connection_handler, - &mut receiver, - &mut sender, - device_id, - addr, - ) - .await; - info!("Pool sv2 connection established at {}", addr); - let miner = Arc::new(Mutex::new(Miner::new(handicap))); - let (notify_changes_to_mining_thread, update_miners) = async_channel::unbounded(); - let self_ = Self { - channel_opened: false, - receiver: receiver.clone(), - sender: sender.clone(), - miner: miner.clone(), - jobs: Vec::new(), - prev_hash: None, - channel_id: None, - sequence_numbers: Id::new(), - notify_changes_to_mining_thread: NewWorkNotifier { - should_send: true, - sender: notify_changes_to_mining_thread, - }, - }; - let open_channel = - MiningDeviceMessages::Mining(Mining::OpenStandardMiningChannel(open_channel(user_id))); - let frame: StdFrame = open_channel.try_into().unwrap(); - self_.sender.send(frame.into()).await.unwrap(); - let self_mutex = std::sync::Arc::new(Mutex::new(self_)); - let cloned = self_mutex.clone(); - - let (share_send, share_recv) = async_channel::unbounded(); - - start_mining_threads(update_miners, miner, share_send); - tokio::task::spawn(async move { - let recv = share_recv.clone(); - loop { - let (nonce, job_id, version, ntime) = recv.recv().await.unwrap(); - Self::send_share(cloned.clone(), nonce, job_id, version, ntime).await; - } - }); - - loop { - let mut incoming: StdFrame = receiver.recv().await.unwrap().try_into().unwrap(); - let message_type = incoming.get_header().unwrap().msg_type(); - let payload = incoming.payload(); - let next = Device::handle_message_mining( - self_mutex.clone(), - message_type, - payload, - MiningRoutingLogic::None, - ) - .unwrap(); - let mut notify_changes_to_mining_thread = self_mutex - .safe_lock(|s| s.notify_changes_to_mining_thread.clone()) - .unwrap(); - if notify_changes_to_mining_thread.should_send - && (message_type == const_sv2::MESSAGE_TYPE_NEW_MINING_JOB - || message_type == const_sv2::MESSAGE_TYPE_SET_NEW_PREV_HASH - || message_type == const_sv2::MESSAGE_TYPE_SET_TARGET) - { - notify_changes_to_mining_thread - .sender - .send(()) - .await - .unwrap(); - notify_changes_to_mining_thread.should_send = false; - }; - match next { - SendTo::RelayNewMessageToRemote(_, m) => { - let sv2_frame: StdFrame = MiningDeviceMessages::Mining(m).try_into().unwrap(); - let either_frame: EitherFrame = sv2_frame.into(); - sender.send(either_frame).await.unwrap(); - } - SendTo::None(_) => (), - _ => panic!(), - } - } - } - - async fn send_share( - self_mutex: Arc>, - nonce: u32, - job_id: u32, - version: u32, - ntime: u32, - ) { - let share = - MiningDeviceMessages::Mining(Mining::SubmitSharesStandard(SubmitSharesStandard { - channel_id: self_mutex.safe_lock(|s| s.channel_id.unwrap()).unwrap(), - sequence_number: self_mutex.safe_lock(|s| s.sequence_numbers.next()).unwrap(), - job_id, - nonce, - ntime, - version, - })); - let frame: StdFrame = share.try_into().unwrap(); - let sender = self_mutex.safe_lock(|s| s.sender.clone()).unwrap(); - sender.send(frame.into()).await.unwrap(); - } -} - -impl IsUpstream<(), NullDownstreamMiningSelector> for Device { - fn get_version(&self) -> u16 { - todo!() - } - - fn get_flags(&self) -> u32 { - todo!() - } - - fn get_supported_protocols(&self) -> Vec { - todo!() - } - - fn get_id(&self) -> u32 { - todo!() - } - - fn get_mapper(&mut self) -> Option<&mut roles_logic_sv2::common_properties::RequestIdMapper> { - todo!() - } - - fn get_remote_selector(&mut self) -> &mut NullDownstreamMiningSelector { - todo!() - } -} - -impl IsMiningUpstream<(), NullDownstreamMiningSelector> for Device { - fn total_hash_rate(&self) -> u64 { - todo!() - } - - fn add_hash_rate(&mut self, _to_add: u64) { - todo!() - } - fn get_opened_channels( - &mut self, - ) -> &mut Vec { - todo!() - } - - fn update_channels(&mut self, _: roles_logic_sv2::common_properties::UpstreamChannel) { - todo!() - } -} - -impl ParseUpstreamMiningMessages<(), NullDownstreamMiningSelector, NoRouting> for Device { - fn get_channel_type(&self) -> SupportedChannelTypes { - SupportedChannelTypes::Standard - } - - fn is_work_selection_enabled(&self) -> bool { - false - } - - fn handle_open_standard_mining_channel_success( - &mut self, - m: OpenStandardMiningChannelSuccess, - _: Option>>, - ) -> Result, Error> { - self.channel_opened = true; - self.channel_id = Some(m.channel_id); - let req_id = m.get_request_id_as_u32(); - info!( - "MINING DEVICE: channel opened with: group id {}, channel id {}, request id {}", - m.group_channel_id, m.channel_id, req_id - ); - self.miner - .safe_lock(|miner| miner.new_target(m.target.to_vec())) - .unwrap(); - self.notify_changes_to_mining_thread.should_send = true; - Ok(SendTo::None(None)) - } - - fn handle_open_extended_mining_channel_success( - &mut self, - _: OpenExtendedMiningChannelSuccess, - ) -> Result, Error> { - unreachable!() - } - - fn handle_open_mining_channel_error( - &mut self, - _: OpenMiningChannelError, - ) -> Result, Error> { - todo!() - } - - fn handle_update_channel_error(&mut self, _: UpdateChannelError) -> Result, Error> { - todo!() - } - - fn handle_close_channel(&mut self, _: CloseChannel) -> Result, Error> { - todo!() - } - - fn handle_set_extranonce_prefix( - &mut self, - _: SetExtranoncePrefix, - ) -> Result, Error> { - todo!() - } - - fn handle_submit_shares_success( - &mut self, - m: SubmitSharesSuccess, - ) -> Result, Error> { - info!("SUCCESS {:?}", m); - Ok(SendTo::None(None)) - } - - fn handle_submit_shares_error(&mut self, _: SubmitSharesError) -> Result, Error> { - info!("Submit shares error"); - Ok(SendTo::None(None)) - } - - fn handle_new_mining_job(&mut self, m: NewMiningJob) -> Result, Error> { - match (m.is_future(), self.prev_hash.as_ref()) { - (false, Some(p_h)) => { - self.miner - .safe_lock(|miner| miner.new_header(p_h, &m)) - .unwrap(); - self.jobs = vec![m.as_static()]; - self.notify_changes_to_mining_thread.should_send = true; - } - (true, _) => self.jobs.push(m.as_static()), - (false, None) => { - panic!() - } - } - Ok(SendTo::None(None)) - } - - fn handle_new_extended_mining_job( - &mut self, - _: NewExtendedMiningJob, - ) -> Result, Error> { - todo!() - } - - fn handle_set_new_prev_hash(&mut self, m: SetNewPrevHash) -> Result, Error> { - let jobs: Vec<&NewMiningJob<'static>> = self - .jobs - .iter() - .filter(|j| j.job_id == m.job_id && j.is_future()) - .collect(); - match jobs.len() { - 0 => { - self.prev_hash = Some(m.as_static()); - } - 1 => { - self.miner - .safe_lock(|miner| miner.new_header(&m, jobs[0])) - .unwrap(); - self.jobs = vec![jobs[0].clone()]; - self.prev_hash = Some(m.as_static()); - self.notify_changes_to_mining_thread.should_send = true; - } - _ => panic!(), - } - Ok(SendTo::None(None)) - } - - fn handle_set_custom_mining_job_success( - &mut self, - _: SetCustomMiningJobSuccess, - ) -> Result, Error> { - todo!() - } - - fn handle_set_custom_mining_job_error( - &mut self, - _: SetCustomMiningJobError, - ) -> Result, Error> { - todo!() - } - - fn handle_set_target(&mut self, m: SetTarget) -> Result, Error> { - self.miner - .safe_lock(|miner| miner.new_target(m.maximum_target.to_vec())) - .unwrap(); - self.notify_changes_to_mining_thread.should_send = true; - Ok(SendTo::None(None)) - } - - fn handle_reconnect(&mut self, _: Reconnect) -> Result, Error> { - todo!() - } -} - -#[derive(Debug, Clone)] -struct Miner { - header: Option, - target: Option, - job_id: Option, - version: Option, - handicap: u32, -} - -impl Miner { - fn new(handicap: u32) -> Self { - Self { - target: None, - header: None, - job_id: None, - version: None, - handicap, - } - } - - fn new_target(&mut self, mut target: Vec) { - // target is sent in LE and comparisons in this file are done in BE - target.reverse(); - let hex_string = target - .iter() - .fold("".to_string(), |acc, b| acc + format!("{:02x}", b).as_str()); - info!("Set target to {}", hex_string); - self.target = Some(Uint256::from_be_bytes(target.try_into().unwrap())); - } - - fn new_header(&mut self, set_new_prev_hash: &SetNewPrevHash, new_job: &NewMiningJob) { - self.job_id = Some(new_job.job_id); - self.version = Some(new_job.version); - let prev_hash: [u8; 32] = set_new_prev_hash.prev_hash.to_vec().try_into().unwrap(); - let prev_hash = Hash::from_inner(prev_hash); - let merkle_root: [u8; 32] = new_job.merkle_root.to_vec().try_into().unwrap(); - let merkle_root = Hash::from_inner(merkle_root); - // fields need to be added as BE and the are converted to LE in the background before hashing - let header = BlockHeader { - version: new_job.version as i32, - prev_blockhash: BlockHash::from_hash(prev_hash), - merkle_root, - time: std::time::SystemTime::now() - .duration_since( - std::time::SystemTime::UNIX_EPOCH - std::time::Duration::from_secs(60), - ) - .unwrap() - .as_secs() as u32, - bits: set_new_prev_hash.nbits, - nonce: 0, - }; - self.header = Some(header); - } - pub fn next_share(&mut self) -> NextShareOutcome { - if let Some(header) = self.header.as_ref() { - let mut hash = header.block_hash().as_hash().into_inner(); - hash.reverse(); - let hash = Uint256::from_be_bytes(hash); - if hash < *self.target.as_ref().unwrap() { - info!( - "Found share with nonce: {}, for target: {:?}, with hash: {:?}", - header.nonce, self.target, hash, - ); - NextShareOutcome::ValidShare - } else { - NextShareOutcome::InvalidShare - } - } else { - std::thread::yield_now(); - NextShareOutcome::InvalidShare - } - } -} - -enum NextShareOutcome { - ValidShare, - InvalidShare, -} - -impl NextShareOutcome { - pub fn is_valid(&self) -> bool { - matches!(self, NextShareOutcome::ValidShare) - } -} - -// returns hashrate based on how fast the device hashes over the given duration -fn measure_hashrate(duration_secs: u64) -> f64 { - let mut rng = thread_rng(); - let prev_hash: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap(); - let prev_hash = Hash::from_inner(prev_hash); - // We create a random block that we can hash, we are only interested in knowing how many hashes - // per unit of time we can do - let merkle_root: [u8; 32] = generate_random_32_byte_array().to_vec().try_into().unwrap(); - let merkle_root = Hash::from_inner(merkle_root); - let header = BlockHeader { - version: rng.gen(), - prev_blockhash: BlockHash::from_hash(prev_hash), - merkle_root, - time: std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH - std::time::Duration::from_secs(60)) - .unwrap() - .as_secs() as u32, - bits: rng.gen(), - nonce: 0, - }; - let start_time = Instant::now(); - let mut hashes: u64 = 0; - let duration = Duration::from_secs(duration_secs); - let mut miner = Miner::new(0); - // We put the target to 0 we are only interested in how many hashes per unit of time we can do - // and do not want to be botherd by messages about valid shares found. - miner.new_target(vec![0_u8; 32]); - miner.header = Some(header); - - while start_time.elapsed() < duration { - miner.next_share(); - hashes += 1; - } - - let elapsed_secs = start_time.elapsed().as_secs_f64(); - hashes as f64 / elapsed_secs -} -fn generate_random_32_byte_array() -> [u8; 32] { - let mut rng = thread_rng(); - let mut arr = [0u8; 32]; - rng.fill(&mut arr[..]); - arr -} - -fn start_mining_threads( - have_new_job: Receiver<()>, - miner: Arc>, - share_send: Sender<(u32, u32, u32, u32)>, -) { - tokio::task::spawn(async move { - let mut killers: Vec> = vec![]; - loop { - let available_parallelism = u32::max( - 2, - std::thread::available_parallelism().unwrap().get() as u32, - ); - let p = available_parallelism - 1; - let unit = u32::MAX / p; - while have_new_job.recv().await.is_ok() { - while let Some(killer) = killers.pop() { - killer.store(true, Ordering::Relaxed); - } - let miner = miner.safe_lock(|m| m.clone()).unwrap(); - for i in 0..p { - let mut miner = miner.clone(); - let share_send = share_send.clone(); - let killer = Arc::new(AtomicBool::new(false)); - miner.header.as_mut().map(|h| h.nonce = i * unit); - killers.push(killer.clone()); - std::thread::spawn(move || { - mine(miner, share_send, killer); - }); - } - } - } - }); -} - -fn mine(mut miner: Miner, share_send: Sender<(u32, u32, u32, u32)>, kill: Arc) { - if miner.handicap != 0 { - loop { - if kill.load(Ordering::Relaxed) { - break; - } - std::thread::sleep(std::time::Duration::from_micros(miner.handicap.into())); - if miner.next_share().is_valid() { - let nonce = miner.header.unwrap().nonce; - let time = miner.header.unwrap().time; - let job_id = miner.job_id.unwrap(); - let version = miner.version; - share_send - .try_send((nonce, job_id, version.unwrap(), time)) - .unwrap(); - } - miner.header.as_mut().map(|h| h.nonce += 1); - } - } else { - loop { - if miner.next_share().is_valid() { - if kill.load(Ordering::Relaxed) { - break; - } - let nonce = miner.header.unwrap().nonce; - let time = miner.header.unwrap().time; - let job_id = miner.job_id.unwrap(); - let version = miner.version; - share_send - .try_send((nonce, job_id, version.unwrap(), time)) - .unwrap(); - } - miner.header.as_mut().map(|h| h.nonce += 1); - } - } + .await; } From b49416c2964e549147eacbd7c27523110b1f3d19 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Thu, 12 Sep 2024 16:50:09 +0300 Subject: [PATCH 08/10] Handle `mining_device` open channel error case .. just return the error to the user to give an indication that an error occurd. --- protocols/v2/roles-logic-sv2/src/errors.rs | 2 ++ roles/test-utils/mining-device/src/lib/mod.rs | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/protocols/v2/roles-logic-sv2/src/errors.rs b/protocols/v2/roles-logic-sv2/src/errors.rs index 20c4bcd55..c4b3305ec 100644 --- a/protocols/v2/roles-logic-sv2/src/errors.rs +++ b/protocols/v2/roles-logic-sv2/src/errors.rs @@ -61,6 +61,7 @@ pub enum Error { HashrateError(InputError), LogicErrorMessage(std::boxed::Box>), JDSMissingTransactions, + MiningChannelError(u32), } impl From for Error { @@ -153,6 +154,7 @@ impl Display for Error { HashrateError(e) => write!(f, "Impossible to get Hashrate: {:?}", e), LogicErrorMessage(e) => write!(f, "Message is well formatted but can not be handled: {:?}", e), JDSMissingTransactions => write!(f, "JD server cannot propagate the block: missing transactions"), + MiningChannelError(e) => write!(f, "Mining channel error: {:?}", e), } } } diff --git a/roles/test-utils/mining-device/src/lib/mod.rs b/roles/test-utils/mining-device/src/lib/mod.rs index 01d0505b0..95e795c45 100644 --- a/roles/test-utils/mining-device/src/lib/mod.rs +++ b/roles/test-utils/mining-device/src/lib/mod.rs @@ -404,9 +404,9 @@ impl ParseUpstreamMiningMessages<(), NullDownstreamMiningSelector, NoRouting> fo fn handle_open_mining_channel_error( &mut self, - _: OpenMiningChannelError, + e: OpenMiningChannelError, ) -> Result, Error> { - todo!() + return Err(Error::MiningChannelError(e.request_id)); } fn handle_update_channel_error(&mut self, _: UpdateChannelError) -> Result, Error> { From 08afc096219a93a5a43103a86f76b07695579689 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Thu, 12 Sep 2024 16:48:23 +0300 Subject: [PATCH 09/10] Save dropped `PoolSv2` downstreams This commit adds a new property to the `Running` state called `DroppedDownstreams` that saves a vector of `Vec`, u32 referring to the `downstream_id`. --- roles/pool/src/lib/mod.rs | 47 ++++++++++++++++++++- roles/tests-integration/tests/common/mod.rs | 5 ++- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index 7e68fc1a7..217f1db7c 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -15,10 +15,23 @@ use tracing::{error, info, warn}; use tokio::select; +#[derive(Debug, Clone, PartialEq)] +pub struct DroppedDownstreams(Vec); + +impl DroppedDownstreams { + pub fn new() -> DroppedDownstreams { + DroppedDownstreams(vec![]) + } + pub fn push(&mut self, id: u32) { + self.0.push(id); + } +} + #[derive(Debug, Clone, PartialEq)] pub enum PoolState { Initial, - Running, + Running(DroppedDownstreams), + DownstreamInstanceDropped, } #[derive(Debug, Clone)] @@ -65,10 +78,13 @@ impl PoolSv2 { status::Sender::DownstreamListener(status_tx), ); // Set the state to running - let _ = self.state.safe_lock(|s| *s = PoolState::Running); + let _ = self + .state + .safe_lock(|s| *s = PoolState::Running(DroppedDownstreams(vec![]))); // Start the error handling loop // See `./status.rs` and `utils/error_handling` for information on how this operates + let internal_state = self.state.clone(); loop { let task_status = select! { task_status = status_rx.recv() => task_status, @@ -109,8 +125,35 @@ impl PoolSv2 { .safe_lock(|p| p.remove_downstream(downstream_id)) .is_err() { + error!( + "Failed to remove downstream instance {}, shutting down.", + downstream_id + ); break Ok(()); } + // Add the downstream id to the list of removed downstreams + internal_state + .safe_lock(|s| { + let mut current = s.clone(); + match current { + PoolState::Running(ref mut removed) => { + let new = DroppedDownstreams( + removed + .0 + .iter() + .cloned() + .chain(std::iter::once(downstream_id)) + .collect(), + ); + *s = PoolState::Running(new); + } + _ => { + // This should.. never happen + warn!("Downstream instance dropped but pool is not running"); + } + } + }) + .expect("Failed to set state to DownstreamInstanceDropped"); } } } diff --git a/roles/tests-integration/tests/common/mod.rs b/roles/tests-integration/tests/common/mod.rs index 85f8412f7..1691021f3 100644 --- a/roles/tests-integration/tests/common/mod.rs +++ b/roles/tests-integration/tests/common/mod.rs @@ -275,7 +275,10 @@ pub async fn start_template_provider_and_pool() -> Result<(PoolSv2, u16, Templat } } let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); - assert_eq!(state, pool_sv2::PoolState::Running); + assert_eq!( + state, + pool_sv2::PoolState::Running(pool_sv2::DroppedDownstreams::new()) + ); template_provider.stop(); Ok(( pool, From 4ae960873c4e5407883e59dc92047c58a610d658 Mon Sep 17 00:00:00 2001 From: jbesraa Date: Thu, 12 Sep 2024 16:51:25 +0300 Subject: [PATCH 10/10] Add integration test for mining device auth.. failure with a pool. This test run a `TemplateProvider`, `PoolSv2` and a `mining_device` with the auth-failure flag enable which will result in the `PoolSv2` to reject the `mining_device`. --- roles/Cargo.lock | 1 + roles/tests-integration/Cargo.toml | 4 ++ roles/tests-integration/tests/common/mod.rs | 10 ++++ .../tests/pool_integration.rs | 46 +++++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 2e9ee5b98..f86606280 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -1355,6 +1355,7 @@ dependencies = [ "bitcoind", "flate2", "key-utils", + "mining_device", "minreq", "once_cell", "pool_sv2", diff --git a/roles/tests-integration/Cargo.toml b/roles/tests-integration/Cargo.toml index a1d17847f..b10daf0dd 100644 --- a/roles/tests-integration/Cargo.toml +++ b/roles/tests-integration/Cargo.toml @@ -12,6 +12,10 @@ tar = "0.4.41" pool_sv2 = { version = "0.1.0", path = "../pool" } key-utils = { version = "1.0.0", path = "../../utils/key-utils" } tokio = { version = "1.16.1", features = ["full"] } +mining_device = { version = "0.1.1", path = "../test-utils/mining-device" } [lib] path = "tests/common/mod.rs" + +[features] +mining_device_reject_auth = ["pool_sv2/MG_reject_auth", "mining_device/abort_mining"] diff --git a/roles/tests-integration/tests/common/mod.rs b/roles/tests-integration/tests/common/mod.rs index 1691021f3..7bf8d7273 100644 --- a/roles/tests-integration/tests/common/mod.rs +++ b/roles/tests-integration/tests/common/mod.rs @@ -287,3 +287,13 @@ pub async fn start_template_provider_and_pool() -> Result<(PoolSv2, u16, Templat template_provider_port, )) } + +pub struct TestMiningDevice; + +impl TestMiningDevice { + pub async fn start(pool_address: SocketAddr) -> Result<(), pool_sv2::error::PoolError> { + mining_device::connect(pool_address.to_string(), None, None, None, 0) + .await + .map_err(|e| e.into()) + } +} diff --git a/roles/tests-integration/tests/pool_integration.rs b/roles/tests-integration/tests/pool_integration.rs index 4e9fc123a..f73cf7751 100644 --- a/roles/tests-integration/tests/pool_integration.rs +++ b/roles/tests-integration/tests/pool_integration.rs @@ -1,5 +1,7 @@ use std::str::FromStr; +use common::is_port_open; + mod common; #[tokio::test] @@ -29,3 +31,47 @@ async fn pool_bad_coinbase_output() { assert_eq!(state, pool_sv2::PoolState::Initial); template_provider.stop(); } + +#[cfg(feature = "mining_device_reject_auth")] +#[tokio::test] +async fn pool_remove_downstream_after_bad_auth() { + let (template_provider, template_provider_port) = common::start_template_provider().await; + let test_pool = common::TestPoolSv2::new( + None, + None, + Some( + std::net::SocketAddr::from_str(&format!("127.0.0.1:{}", template_provider_port)) + .unwrap(), + ), + ); + let pool = test_pool.pool.clone(); + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + assert_eq!(state, pool_sv2::PoolState::Initial); + let _pool = pool.clone(); + tokio::task::spawn(async move { + let _ = _pool.start().await; + }); + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + // Wait for the pool to start. + let pool_port = test_pool.port; + let pool_listening_address = + std::net::SocketAddr::from_str(&format!("127.0.0.1:{}", pool_port)).unwrap(); + loop { + if is_port_open(pool_listening_address) { + break; + } + } + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + assert_eq!( + state, + pool_sv2::PoolState::Running(pool_sv2::DroppedDownstreams::new()) + ); + assert!(common::TestMiningDevice::start(pool_listening_address) + .await + .is_err()); + let state = pool.state().await.safe_lock(|s| s.clone()).unwrap(); + let mut dropped_downstreams = pool_sv2::DroppedDownstreams::new(); + dropped_downstreams.push(1); + assert_eq!(state, pool_sv2::PoolState::Running(dropped_downstreams)); + template_provider.stop(); +}