From e94f73c4ccfe4c200a44f0df057ff2ad89562e6d Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 28 Aug 2024 17:06:45 +0200 Subject: [PATCH 01/32] Add scaffold for randomx_miner --- Cargo.lock | 16 ++ Cargo.toml | 1 + applications/randomx_miner/Cargo.toml | 26 +++ applications/randomx_miner/README.md | 0 applications/randomx_miner/build.rs | 20 +++ applications/randomx_miner/log4rs_sample.yml | 171 +++++++++++++++++++ applications/randomx_miner/src/cli.rs | 54 ++++++ applications/randomx_miner/src/config.rs | 109 ++++++++++++ applications/randomx_miner/src/lib.rs | 38 +++++ applications/randomx_miner/src/main.rs | 66 +++++++ applications/randomx_miner/src/run_miner.rs | 37 ++++ 11 files changed, 538 insertions(+) create mode 100644 applications/randomx_miner/Cargo.toml create mode 100644 applications/randomx_miner/README.md create mode 100644 applications/randomx_miner/build.rs create mode 100644 applications/randomx_miner/log4rs_sample.yml create mode 100644 applications/randomx_miner/src/cli.rs create mode 100644 applications/randomx_miner/src/config.rs create mode 100644 applications/randomx_miner/src/lib.rs create mode 100644 applications/randomx_miner/src/main.rs create mode 100644 applications/randomx_miner/src/run_miner.rs diff --git a/Cargo.lock b/Cargo.lock index 0d9e861b8d..087572df02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4853,6 +4853,22 @@ dependencies = [ "thiserror", ] +[[package]] +name = "randomx_miner" +version = "1.3.0-pre.0" +dependencies = [ + "clap 3.2.25", + "config", + "crossterm 0.25.0", + "log", + "minotari_app_utilities", + "serde", + "tari_common", + "tari_comms", + "tari_features", + "tokio", +] + [[package]] name = "rayon" version = "1.8.0" diff --git a/Cargo.toml b/Cargo.toml index 8fed89ad35..2919f82863 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,7 @@ members = [ "applications/minotari_miner", "applications/minotari_ledger_wallet/comms", "applications/minotari_ledger_wallet/common", + "applications/randomx_miner", "integration_tests", "hashing" ] diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml new file mode 100644 index 0000000000..51314ec59c --- /dev/null +++ b/applications/randomx_miner/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "randomx_miner" +authors = ["The Tari Development Community"] +description = "The Tari merge mining proxy for xmrig" +repository = "https://github.com/tari-project/tari" +license = "BSD-3-Clause" +version = "1.3.0-pre.0" +edition = "2018" + +[features] +default = [] + +[dependencies] +minotari_app_utilities = { path = "../minotari_app_utilities", features = ["miner_input"] } +tari_common = { path = "../../common" } +tari_comms = { path = "../../comms/core" } + +clap = { version = "3.2", features = ["derive", "env"] } +config = "0.14.0" +crossterm = { version = "0.25.0" } +log = { version = "0.4", features = ["std"] } +serde = { version = "1.0", default-features = false, features = ["derive"] } +tokio = { version = "1.36", default-features = false, features = ["rt-multi-thread"] } + +[build-dependencies] +tari_features = { path = "../../common/tari_features", version = "1.3.0-pre.0" } \ No newline at end of file diff --git a/applications/randomx_miner/README.md b/applications/randomx_miner/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/applications/randomx_miner/build.rs b/applications/randomx_miner/build.rs new file mode 100644 index 0000000000..f4bfd85de7 --- /dev/null +++ b/applications/randomx_miner/build.rs @@ -0,0 +1,20 @@ +// Copyright 2024 The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use tari_features::resolver::build_features; + +#[cfg(windows)] +fn main() { + build_features(); + use std::env; + println!("cargo:rerun-if-changed=icon.res"); + let mut path = env::current_dir().unwrap(); + path.push("icon.res"); + println!("cargo:rustc-link-arg={}", path.into_os_string().into_string().unwrap()); +} + +#[cfg(not(windows))] +pub fn main() { + build_features(); + // Build as usual +} diff --git a/applications/randomx_miner/log4rs_sample.yml b/applications/randomx_miner/log4rs_sample.yml new file mode 100644 index 0000000000..fe0b3cbfee --- /dev/null +++ b/applications/randomx_miner/log4rs_sample.yml @@ -0,0 +1,171 @@ +# A sample log configuration file for running in release mode. By default, this configuration splits up log messages to +# three destinations: +# * Console: For log messages with level INFO and higher +# * log/randomx_miner/network.log: INFO-level logs related to the comms crate. This file will be quite busy since there +# are lots of P2P debug messages, and so this traffic is segregated from the application log messages +# * log/randomx_miner/base_layer.log: Non-comms related INFO-level messages and higher are logged into this file +# * log/randomx_miner/other.log: Third-party crates' messages will be logged here at an ERROR level +# +# See https://docs.rs/log4rs/0.8.3/log4rs/encode/pattern/index.html for deciphering the log pattern. The log format +# used in this sample configuration prints messages as: +# timestamp [target] LEVEL message +refresh_rate: 30 seconds +appenders: + # An appender named "stdout" that writes to file. + stdout: + kind: rolling_file + path: "{{log_dir}}/log/randomx_miner/stdout.log" + append: false + encoder: + pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {h({l}):5} {m}{n}" + filters: + - kind: threshold + level: info + policy: + kind: compound + trigger: + kind: size + limit: 10mb + roller: + kind: delete + + # An appender named "network" that writes to a file with a custom pattern encoder + network: + kind: rolling_file + path: "{{log_dir}}/log/randomx_miner/network.log" + policy: + kind: compound + trigger: + kind: size + limit: 10mb + roller: + kind: fixed_window + base: 1 + count: 5 + pattern: "{{log_dir}}/log/randomx_miner/network.{}.log" + encoder: + pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" + + # An appender named "base_layer" that writes to a file with a custom pattern encoder + base_layer: + kind: rolling_file + path: "{{log_dir}}/log/randomx_miner/base_layer.log" + policy: + kind: compound + trigger: + kind: size + limit: 10mb + roller: + kind: fixed_window + base: 1 + count: 5 + pattern: "{{log_dir}}/log/randomx_miner/base_layer.{}.log" + encoder: + pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" + + # An appender named "base_layer" that writes to a file with a custom pattern encoder + other: + kind: rolling_file + path: "{{log_dir}}/log/randomx_miner/other.log" + policy: + kind: compound + trigger: + kind: size + limit: 10mb + roller: + kind: fixed_window + base: 1 + count: 5 + pattern: "{{log_dir}}/log/randomx_miner/other.{}.log" + encoder: + pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" + + # An appender named "contacts" that writes to a file with a custom pattern encoder + contacts: + kind: rolling_file + path: "{{log_dir}}/log/randomx_miner/contacts.log" + policy: + kind: compound + trigger: + kind: size + limit: 10mb + roller: + kind: fixed_window + base: 1 + count: 5 + pattern: "{{log_dir}}/log/randomx_miner/contacts.{}.log" + encoder: + pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" + +# root (to base_layer) +root: + level: debug + appenders: + - other + +loggers: + # base_layer + randomx_miner: + level: debug + appenders: + - base_layer + - stdout + additive: false + # other + h2: + level: info + appenders: + - other + additive: false + hyper: + level: info + appenders: + - other + additive: false + tokio_util: + level: error + appenders: + - other + additive: false + # network + comms: + level: info + appenders: + - network + additive: false + contacts: + level: info + appenders: + - contacts + additive: false + comms::noise: + level: error + appenders: + - network + additive: false + p2p: + level: info + appenders: + - network + # Route log events sent to the "mio" logger to the "other" appender + mio: + level: error + appenders: + - network + additive: false + yamux: + level: error + appenders: + - network + additive: false + tracing: + level: error + appenders: + - network + additive: false + # Route R2D2 log events + r2d2: + level: warn + appenders: + - other + additive: false diff --git a/applications/randomx_miner/src/cli.rs b/applications/randomx_miner/src/cli.rs new file mode 100644 index 0000000000..3e2ea9063a --- /dev/null +++ b/applications/randomx_miner/src/cli.rs @@ -0,0 +1,54 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::fmt::Debug; + +use clap::Parser; +use minotari_app_utilities::common_cli_args::CommonCliArgs; +use tari_common::configuration::{ConfigOverrideProvider, Network}; + +#[derive(Parser, Debug)] +#[clap(author, version, about, long_about = None)] +#[clap(propagate_version = true)] +pub struct Cli { + #[clap(flatten)] + pub common: CommonCliArgs, + #[clap(long, alias = "mine-until-height")] + pub mine_until_height: Option, + #[clap(long, alias = "max-blocks")] + pub miner_max_blocks: Option, + #[clap(long, alias = "min-difficulty")] + pub miner_min_diff: Option, + #[clap(long, alias = "max-difficulty")] + pub miner_max_diff: Option, + #[clap(short, long, alias = "non-interactive", env = "TARI_NON_INTERACTIVE")] + pub non_interactive_mode: bool, +} + +impl ConfigOverrideProvider for Cli { + fn get_config_property_overrides(&self, network: &mut Network) -> Vec<(String, String)> { + let mut overrides = self.common.get_config_property_overrides(network); + *network = self.common.network.unwrap_or(*network); + overrides.push(("randomx_miner.network".to_string(), network.to_string())); + overrides + } +} diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs new file mode 100644 index 0000000000..a15fff27d7 --- /dev/null +++ b/applications/randomx_miner/src/config.rs @@ -0,0 +1,109 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Minotari Miner Node derives all +// configuration management + +use std::path::{Path, PathBuf}; + +use serde::{Deserialize, Serialize}; +use tari_common::{configuration::Network, SubConfigPath}; +use tari_comms::multiaddr::Multiaddr; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(deny_unknown_fields)] +pub struct RandomXMinerConfig { + /// The address for the monero node, or merge mining proxy + pub monero_base_node_address: Option, + /// Monero wallet address + pub monero_wallet_address: Option, + /// An address to post hash results too + pub universe_address: Option, + /// What mode to run in, eco or max + pub mode: MiningMode, + /// Selected network + pub network: Network, + /// The relative path to store persistent config + pub config_dir: PathBuf, +} + +#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] +pub enum MiningMode { + #[default] + Eco, + Max, +} + +impl SubConfigPath for RandomXMinerConfig { + fn main_key_prefix() -> &'static str { + "randomx_miner" + } +} + +impl Default for RandomXMinerConfig { + fn default() -> Self { + Self { + monero_base_node_address: None, + monero_wallet_address: None, + universe_address: None, + mode: Default::default(), + network: Default::default(), + config_dir: PathBuf::from("config/randomx_miner"), + } + } +} + +impl RandomXMinerConfig { + pub fn set_base_path>(&mut self, base_path: P) { + if !self.config_dir.is_absolute() { + self.config_dir = base_path.as_ref().join(self.config_dir.as_path()); + } + } +} + +#[cfg(test)] +mod test { + use config::Config; + use tari_common::DefaultConfigLoader; + + use crate::config::{MiningMode, RandomXMinerConfig}; + + #[test] + fn miner_configuration() { + const CONFIG: &str = r#" +[miner] +monero_wallet_address="44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A" +mode = "eco" +"#; + let mut cfg: Config = Config::default(); + #[allow(deprecated)] + cfg.merge(config::File::from_str(CONFIG, config::FileFormat::Toml)) + .unwrap(); + let config = RandomXMinerConfig::load_from(&cfg).expect("Failed to load config"); + assert_eq!(config.mode, MiningMode::Eco); + assert_eq!( + config.monero_wallet_address, + Some( + "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A" + .to_string() + ) + ); + } +} diff --git a/applications/randomx_miner/src/lib.rs b/applications/randomx_miner/src/lib.rs new file mode 100644 index 0000000000..29c5195dc1 --- /dev/null +++ b/applications/randomx_miner/src/lib.rs @@ -0,0 +1,38 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +mod cli; +use cli::Cli; +mod config; +mod run_miner; +use run_miner::start_miner; +use tari_common::exit_codes::ExitError; + +pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; +pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; + +// non-64-bit not supported +minotari_app_utilities::deny_non_64_bit_archs!(); + +pub async fn run_miner(cli: Cli) -> Result<(), ExitError> { + start_miner(cli).await +} diff --git a/applications/randomx_miner/src/main.rs b/applications/randomx_miner/src/main.rs new file mode 100644 index 0000000000..c69a9a1782 --- /dev/null +++ b/applications/randomx_miner/src/main.rs @@ -0,0 +1,66 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::io::stdout; + +use clap::Parser; +use crossterm::{execute, terminal::SetTitle}; +use log::*; +use minotari_app_utilities::consts; +use tari_common::{exit_codes::ExitError, initialize_logging}; + +pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; +pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; + +mod cli; +use cli::Cli; +mod run_miner; +use run_miner::start_miner; + +mod config; + +#[tokio::main] +async fn main() { + let terminal_title = format!("RandomX- Version {}", consts::APP_VERSION); + if let Err(e) = execute!(stdout(), SetTitle(terminal_title.as_str())) { + println!("Error setting terminal title. {}", e) + } + match main_inner().await { + Ok(_) => std::process::exit(0), + Err(err) => { + error!(target: LOG_TARGET, "Fatal error: {:?}", err); + let exit_code = err.exit_code; + error!(target: LOG_TARGET, "Exiting with code: {:?}", exit_code); + std::process::exit(exit_code as i32) + }, + } +} + +async fn main_inner() -> Result<(), ExitError> { + let cli = Cli::parse(); + initialize_logging( + &cli.common.log_config_path("randomx_miner"), + &cli.common.get_base_path(), + include_str!("../log4rs_sample.yml"), + )?; + start_miner(cli).await +} diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs new file mode 100644 index 0000000000..284dd90275 --- /dev/null +++ b/applications/randomx_miner/src/run_miner.rs @@ -0,0 +1,37 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use tari_common::{exit_codes::ExitError, load_configuration, DefaultConfigLoader}; + +use crate::{cli::Cli, config::RandomXMinerConfig}; + +pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; +pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; + +pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { + let config_path = cli.common.config_path(); + let cfg = load_configuration(config_path.as_path(), true, cli.non_interactive_mode, &cli)?; + let mut config = RandomXMinerConfig::load_from(&cfg).expect("Failed to load config"); + config.set_base_path(cli.common.get_base_path()); + + Ok(()) +} From 63e0d2fdf53e287d1aade1cef0c5b23be9684e14 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 29 Aug 2024 19:30:31 +0200 Subject: [PATCH 02/32] Communicate with monero node over proxy --- Cargo.lock | 454 +++++++++++++++--- applications/randomx_miner/Cargo.toml | 3 + applications/randomx_miner/log4rs_sample.yml | 147 +----- applications/randomx_miner/src/config.rs | 4 +- applications/randomx_miner/src/error.rs | 53 ++ .../randomx_miner/src/json_rpc/mod.rs | 73 +++ applications/randomx_miner/src/lib.rs | 10 +- applications/randomx_miner/src/main.rs | 8 +- applications/randomx_miner/src/run_miner.rs | 95 +++- 9 files changed, 636 insertions(+), 211 deletions(-) create mode 100644 applications/randomx_miner/src/error.rs create mode 100644 applications/randomx_miner/src/json_rpc/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 087572df02..9c8c8c9e80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,6 +211,12 @@ dependencies = [ "syn 2.0.74", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" @@ -248,9 +254,9 @@ dependencies = [ "bitflags 1.3.2", "bytes 1.5.0", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "itoa", "matchit", "memchr", @@ -259,7 +265,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower", "tower-layer", "tower-service", @@ -274,8 +280,8 @@ dependencies = [ "async-trait", "bytes 1.5.0", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "mime", "rustversion", "tower-layer", @@ -333,6 +339,12 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64-compat" version = "1.0.0" @@ -2282,7 +2294,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util 0.7.10", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes 1.5.0", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", "indexmap 2.1.0", "slab", "tokio", @@ -2336,7 +2367,7 @@ dependencies = [ "base64 0.21.5", "bytes 1.5.0", "headers-core", - "http", + "http 0.2.9", "httpdate", "mime", "sha1 0.10.6", @@ -2348,7 +2379,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http", + "http 0.2.9", ] [[package]] @@ -2463,6 +2494,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes 1.5.0", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.5" @@ -2470,7 +2512,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.5.0", - "http", + "http 0.2.9", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes 1.5.0", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes 1.5.0", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -2511,9 +2576,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -2525,13 +2590,50 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes 1.5.0", + "futures-channel", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.12", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.27", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2544,12 +2646,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes 1.5.0", - "hyper", + "hyper 0.14.27", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes 1.5.0", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes 1.5.0", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2 0.5.5", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3320,7 +3458,7 @@ dependencies = [ "qrcode", "rand", "regex", - "reqwest", + "reqwest 0.11.22", "rpassword", "rustyline", "serde", @@ -3396,7 +3534,7 @@ dependencies = [ "crossterm 0.25.0", "futures 0.3.29", "hex", - "hyper", + "hyper 0.14.27", "jsonrpc", "log", "markup5ever", @@ -3405,7 +3543,7 @@ dependencies = [ "minotari_node_grpc_client", "minotari_wallet_grpc_client", "monero", - "reqwest", + "reqwest 0.11.22", "scraper", "serde", "serde_json", @@ -4862,10 +5000,13 @@ dependencies = [ "crossterm 0.25.0", "log", "minotari_app_utilities", + "reqwest 0.12.7", "serde", + "serde_json", "tari_common", "tari_comms", "tari_features", + "thiserror", "tokio", ] @@ -4991,11 +5132,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", + "h2 0.3.26", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", @@ -5007,7 +5148,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "system-configuration", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", "tower-service", @@ -5018,6 +5159,49 @@ dependencies = [ "winreg", ] +[[package]] +name = "reqwest" +version = "0.12.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" +dependencies = [ + "base64 0.22.1", + "bytes 1.5.0", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls", + "hyper-tls 0.6.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 2.1.3", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-registry", +] + [[package]] name = "rfc6979" version = "0.4.0" @@ -5164,6 +5348,19 @@ dependencies = [ "webpki", ] +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -5194,6 +5391,33 @@ dependencies = [ "base64 0.21.5", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.102.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" +dependencies = [ + "ring 0.17.5", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.14" @@ -5604,9 +5828,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smart-default" @@ -5867,6 +6091,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -5920,7 +6153,18 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.4.1", + "core-foundation", + "system-configuration-sys 0.6.0", ] [[package]] @@ -5933,6 +6177,16 @@ dependencies = [ "libc", ] +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tap" version = "1.0.1" @@ -6342,7 +6596,7 @@ dependencies = [ "minotari_wallet_ffi", "minotari_wallet_grpc_client", "rand", - "reqwest", + "reqwest 0.11.22", "serde_json", "tari_chat_client", "tari_common", @@ -6432,7 +6686,7 @@ dependencies = [ "log", "once_cell", "prometheus", - "reqwest", + "reqwest 0.11.22", "thiserror", "tokio", "warp", @@ -6470,8 +6724,8 @@ dependencies = [ "pgp", "prost", "rand", - "reqwest", - "rustls", + "reqwest 0.11.22", + "rustls 0.20.9", "semver", "serde", "tari_common", @@ -6645,18 +6899,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.50" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.50" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -6824,11 +7078,22 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.9", "tokio", "webpki", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.12", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -6962,10 +7227,10 @@ dependencies = [ "bytes 1.5.0", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.26", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-timeout", "percent-encoding", "pin-project 1.1.3", @@ -6974,7 +7239,7 @@ dependencies = [ "rustls-native-certs", "rustls-pemfile 1.0.3", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.4", "tokio-stream", "tokio-util 0.7.10", "tower", @@ -6996,10 +7261,10 @@ dependencies = [ "bytes 1.5.0", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", + "h2 0.3.26", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-timeout", "percent-encoding", "pin-project 1.1.3", @@ -7144,7 +7409,7 @@ dependencies = [ "radix_trie", "rand", "ring 0.16.20", - "rustls", + "rustls 0.20.9", "thiserror", "time", "tokio", @@ -7171,13 +7436,13 @@ dependencies = [ "log", "rand", "ring 0.16.20", - "rustls", + "rustls 0.20.9", "rustls-pemfile 0.3.0", "smallvec", "thiserror", "tinyvec", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.4", "url", "webpki", ] @@ -7459,8 +7724,8 @@ dependencies = [ "futures-channel", "futures-util", "headers", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "log", "mime", "mime_guess", @@ -7622,6 +7887,36 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.45.0" @@ -7646,7 +7941,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -7681,17 +7976,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -7708,9 +8004,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -7726,9 +8022,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -7744,9 +8040,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -7762,9 +8064,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -7780,9 +8082,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -7798,9 +8100,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -7816,9 +8118,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -7916,9 +8218,9 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index 51314ec59c..863708a5c3 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -19,7 +19,10 @@ clap = { version = "3.2", features = ["derive", "env"] } config = "0.14.0" crossterm = { version = "0.25.0" } log = { version = "0.4", features = ["std"] } +reqwest = { version = "0.12.7", features = ["json"] } serde = { version = "1.0", default-features = false, features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0.63" tokio = { version = "1.36", default-features = false, features = ["rt-multi-thread"] } [build-dependencies] diff --git a/applications/randomx_miner/log4rs_sample.yml b/applications/randomx_miner/log4rs_sample.yml index fe0b3cbfee..01b6630c1c 100644 --- a/applications/randomx_miner/log4rs_sample.yml +++ b/applications/randomx_miner/log4rs_sample.yml @@ -13,159 +13,52 @@ refresh_rate: 30 seconds appenders: # An appender named "stdout" that writes to file. stdout: - kind: rolling_file - path: "{{log_dir}}/log/randomx_miner/stdout.log" - append: false + kind: console encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {h({l}):5} {m}{n}" + pattern: "{d(%H:%M)} {h({l}):5} {m}{n}" filters: - kind: threshold - level: info - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: delete - - # An appender named "network" that writes to a file with a custom pattern encoder - network: - kind: rolling_file - path: "{{log_dir}}/log/randomx_miner/network.log" - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: fixed_window - base: 1 - count: 5 - pattern: "{{log_dir}}/log/randomx_miner/network.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" - - # An appender named "base_layer" that writes to a file with a custom pattern encoder - base_layer: - kind: rolling_file - path: "{{log_dir}}/log/randomx_miner/base_layer.log" - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: fixed_window - base: 1 - count: 5 - pattern: "{{log_dir}}/log/randomx_miner/base_layer.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" + level: debug - # An appender named "base_layer" that writes to a file with a custom pattern encoder - other: - kind: rolling_file - path: "{{log_dir}}/log/randomx_miner/other.log" - policy: - kind: compound - trigger: - kind: size - limit: 10mb - roller: - kind: fixed_window - base: 1 - count: 5 - pattern: "{{log_dir}}/log/randomx_miner/other.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" - - # An appender named "contacts" that writes to a file with a custom pattern encoder - contacts: + randomx_miner: kind: rolling_file - path: "{{log_dir}}/log/randomx_miner/contacts.log" + path: "{{log_dir}}/log/randomx_miner/randomx_miner.log" policy: kind: compound trigger: kind: size - limit: 10mb + limit: 200mb roller: kind: fixed_window base: 1 - count: 5 - pattern: "{{log_dir}}/log/randomx_miner/contacts.{}.log" + count: 50 + pattern: "{{log_dir}}/log/randomx_miner/randomx_miner.{}.log" encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] [Thread:{I}] {l:5} {m}{n}" + pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {l:5} {m}{n}" -# root (to base_layer) +# root root: level: debug appenders: - - other + - stdout + - randomx_miner loggers: - # base_layer - randomx_miner: - level: debug - appenders: - - base_layer - - stdout - additive: false - # other h2: level: info appenders: - - other + - stdout + - randomx_miner additive: false hyper: level: info appenders: - - other - additive: false - tokio_util: - level: error - appenders: - - other - additive: false - # network - comms: - level: info - appenders: - - network - additive: false - contacts: - level: info - appenders: - - contacts - additive: false - comms::noise: - level: error - appenders: - - network - additive: false - p2p: - level: info - appenders: - - network - # Route log events sent to the "mio" logger to the "other" appender - mio: - level: error - appenders: - - network - additive: false - yamux: - level: error - appenders: - - network + - stdout + - randomx_miner additive: false - tracing: + selectors: level: error appenders: - - network - additive: false - # Route R2D2 log events - r2d2: - level: warn - appenders: - - other - additive: false + - stdout + - randomx_miner + additive: false \ No newline at end of file diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs index a15fff27d7..71b6bd4b25 100644 --- a/applications/randomx_miner/src/config.rs +++ b/applications/randomx_miner/src/config.rs @@ -31,11 +31,11 @@ use tari_comms::multiaddr::Multiaddr; #[serde(deny_unknown_fields)] pub struct RandomXMinerConfig { /// The address for the monero node, or merge mining proxy - pub monero_base_node_address: Option, + pub monero_base_node_address: Option, /// Monero wallet address pub monero_wallet_address: Option, /// An address to post hash results too - pub universe_address: Option, + pub universe_address: Option, /// What mode to run in, eco or max pub mode: MiningMode, /// Selected network diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs new file mode 100644 index 0000000000..5622ea9387 --- /dev/null +++ b/applications/randomx_miner/src/error.rs @@ -0,0 +1,53 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("Config error: {0}")] + Config(#[from] ConfigError), + #[error("Common config error: {0}")] + CommonConfig(#[from] tari_common::configuration::error::ConfigError), + #[error("Reqwest error: {0}")] + Reqwest(#[from] reqwest::Error), + #[error("General error: {0}")] + General(String), + #[error("Request error: {0}")] + Request(#[from] RequestError), +} + +#[derive(Debug, thiserror::Error)] +pub enum ConfigError { + #[error("Missing base node or proxy address")] + MissingBaseNode, + #[error("Missing monero wallet address")] + MissingMoneroWalletAddress, + #[error("Common config error: {0}")] + CommonConfig(#[from] tari_common::configuration::error::ConfigError), +} + +#[derive(Debug, thiserror::Error)] +pub enum RequestError { + #[error("Failed to process request `get_block_count`: {0}")] + GetBlockCount(String), + #[error("Failed to process request `get_block_template`: {0}")] + GetBlockTemplate(String), +} diff --git a/applications/randomx_miner/src/json_rpc/mod.rs b/applications/randomx_miner/src/json_rpc/mod.rs new file mode 100644 index 0000000000..8fd1be8a14 --- /dev/null +++ b/applications/randomx_miner/src/json_rpc/mod.rs @@ -0,0 +1,73 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize)] +pub struct Request<'a> { + jsonrpc: &'a str, + id: &'a str, + method: &'a str, + params: serde_json::Value, +} + +impl Request<'_> { + pub fn new(method: &str, params: serde_json::Value) -> Request { + Request { + jsonrpc: "2.0", + id: "0", + method, + params, + } + } +} + +#[derive(Deserialize, Debug)] +pub struct GetBlockCountResponse { + jsonrpc: String, + id: String, + pub result: GetBlockCountResult, +} + +#[derive(Deserialize, Debug)] +pub struct GetBlockCountResult { + pub count: u64, + pub status: String, +} + +#[derive(Deserialize, Debug)] +pub struct GetBlockTemplateResponse { + jsonrpc: String, + id: String, + pub result: GetBlockTemplateResult, +} + +#[derive(Deserialize, Debug)] +pub struct GetBlockTemplateResult { + pub blocktemplate_blob: String, + pub blockhashing_blob: String, + pub difficulty: u64, + pub height: u64, + pub prev_hash: String, + pub reserved_offset: u64, + pub status: String, +} diff --git a/applications/randomx_miner/src/lib.rs b/applications/randomx_miner/src/lib.rs index 29c5195dc1..370ea88c41 100644 --- a/applications/randomx_miner/src/lib.rs +++ b/applications/randomx_miner/src/lib.rs @@ -23,9 +23,13 @@ mod cli; use cli::Cli; mod config; +mod error; +pub use error::{ConfigError, Error}; +mod json_rpc; +pub use json_rpc::Request; mod run_miner; use run_miner::start_miner; -use tari_common::exit_codes::ExitError; +use tari_common::exit_codes::{ExitCode, ExitError}; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; @@ -34,5 +38,7 @@ pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; minotari_app_utilities::deny_non_64_bit_archs!(); pub async fn run_miner(cli: Cli) -> Result<(), ExitError> { - start_miner(cli).await + start_miner(cli) + .await + .map_err(|e| ExitError::new(ExitCode::UnknownError, e.to_string())) } diff --git a/applications/randomx_miner/src/main.rs b/applications/randomx_miner/src/main.rs index c69a9a1782..5ece9813af 100644 --- a/applications/randomx_miner/src/main.rs +++ b/applications/randomx_miner/src/main.rs @@ -35,6 +35,10 @@ mod cli; use cli::Cli; mod run_miner; use run_miner::start_miner; +mod error; +use tari_common::exit_codes::ExitCode; +mod json_rpc; +use json_rpc::Request; mod config; @@ -62,5 +66,7 @@ async fn main_inner() -> Result<(), ExitError> { &cli.common.get_base_path(), include_str!("../log4rs_sample.yml"), )?; - start_miner(cli).await + start_miner(cli) + .await + .map_err(|e| ExitError::new(ExitCode::UnknownError, e.to_string())) } diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 284dd90275..60c2bb20f9 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -20,18 +20,107 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use tari_common::{exit_codes::ExitError, load_configuration, DefaultConfigLoader}; +use std::{sync::Arc, time::Duration}; -use crate::{cli::Cli, config::RandomXMinerConfig}; +use log::{debug, error, info}; +use minotari_app_utilities::parse_miner_input::wallet_payment_address; +use reqwest::Client; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use tari_common::{load_configuration, DefaultConfigLoader}; +use tokio::{sync::Mutex, time::sleep}; + +use crate::{ + cli::Cli, + config::RandomXMinerConfig, + error::{ConfigError, Error, RequestError}, + json_rpc::{GetBlockCountResponse, GetBlockTemplateResponse, Request}, +}; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; -pub async fn start_miner(cli: Cli) -> Result<(), ExitError> { +pub async fn start_miner(cli: Cli) -> Result<(), Error> { let config_path = cli.common.config_path(); let cfg = load_configuration(config_path.as_path(), true, cli.non_interactive_mode, &cli)?; let mut config = RandomXMinerConfig::load_from(&cfg).expect("Failed to load config"); config.set_base_path(cli.common.get_base_path()); + let node_address = config.monero_base_node_address.ok_or(ConfigError::MissingBaseNode)?; + info!(target: LOG_TARGET, "Using Monero node address: {}", node_address); + + let monero_wallet_address = config + .monero_wallet_address + .ok_or(ConfigError::MissingMoneroWalletAddress)?; + info!(target: LOG_TARGET, "Mining to Monero wallet address: {}", &monero_wallet_address); + + let client = Client::new(); + + let mut tip = Arc::new(Mutex::new(0u64)); + let mut blocks_found: u64 = 0; + loop { + info!(target: LOG_TARGET, "Starting new mining cycle"); + + get_tip_info(&client, &node_address, tip.clone()).await?; + get_block_template(&client, &node_address, &monero_wallet_address).await?; + sleep(Duration::from_secs(15)).await + } +} + +async fn get_tip_info(client: &Client, node_address: &String, tip: Arc>) -> Result<(), Error> { + let response = client + .post(format!("{}/json_rpc", &node_address.to_string())) // Replace with your node's address + .json(&Request::new("get_block_count", serde_json::Value::Null)) + .send().await.map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + Error::from(RequestError::GetBlockCount(e.to_string())) + })? + .json::().await?; + debug!(target: LOG_TARGET, "`get_block_count` Response: {:?}", response); + + if response.result.status == "OK" { + debug!(target: LOG_TARGET, "`get_block_count` Blockchain tip (block height): {}", response.result.count); + *tip.lock().await = response.result.count; + } else { + debug!(target: LOG_TARGET, "Failed to get the block count. Status: {}", response.result.status); + return Err(RequestError::GetBlockCount(format!( + "Failed to get the block count. Status: {}", + response.result.status + )) + .into()); + } + + Ok(()) +} + +async fn get_block_template( + client: &Client, + node_address: &String, + monero_wallet_address: &String, +) -> Result<(), Error> { + let response = client + .post(format!("{}/json_rpc", &node_address.to_string())) // Replace with your node's address + .json(&Request::new("get_block_template", json!({ + "wallet_address": monero_wallet_address, + "reserve_size": 60, + }))) + .send().await.map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + Error::from(RequestError::GetBlockTemplate(e.to_string())) + })? + .json::().await?; + debug!(target: LOG_TARGET, "`get_block_template` Response: {:?}", response); + + if response.result.status == "OK" { + debug!(target: LOG_TARGET, "`get_block_template` Block template: {:?}", response.result); + } else { + debug!(target: LOG_TARGET, "Failed to get the block template. Status: {}", response.result.status); + return Err(RequestError::GetBlockCount(format!( + "Failed to get the block template. Status: {}", + response.result.status + )) + .into()); + } + Ok(()) } From 5ac4dd9e1fba50642d69912fb18ee4faf82726a3 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 30 Aug 2024 10:20:36 +0200 Subject: [PATCH 03/32] refactor requests to the proxy --- applications/randomx_miner/src/config.rs | 1 - applications/randomx_miner/src/error.rs | 2 - .../src/json_rpc/get_block_count.rs | 78 ++++++++++++++++ .../src/json_rpc/get_block_template.rs | 89 +++++++++++++++++++ .../randomx_miner/src/json_rpc/mod.rs | 38 ++------ applications/randomx_miner/src/run_miner.rs | 73 ++------------- 6 files changed, 179 insertions(+), 102 deletions(-) create mode 100644 applications/randomx_miner/src/json_rpc/get_block_count.rs create mode 100644 applications/randomx_miner/src/json_rpc/get_block_template.rs diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs index 71b6bd4b25..ceebbe6224 100644 --- a/applications/randomx_miner/src/config.rs +++ b/applications/randomx_miner/src/config.rs @@ -25,7 +25,6 @@ use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; use tari_common::{configuration::Network, SubConfigPath}; -use tari_comms::multiaddr::Multiaddr; #[derive(Serialize, Deserialize, Debug)] #[serde(deny_unknown_fields)] diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 5622ea9387..34d4ea72e0 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -28,8 +28,6 @@ pub enum Error { CommonConfig(#[from] tari_common::configuration::error::ConfigError), #[error("Reqwest error: {0}")] Reqwest(#[from] reqwest::Error), - #[error("General error: {0}")] - General(String), #[error("Request error: {0}")] Request(#[from] RequestError), } diff --git a/applications/randomx_miner/src/json_rpc/get_block_count.rs b/applications/randomx_miner/src/json_rpc/get_block_count.rs new file mode 100644 index 0000000000..bd0af965b1 --- /dev/null +++ b/applications/randomx_miner/src/json_rpc/get_block_count.rs @@ -0,0 +1,78 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::sync::Arc; + +use log::{debug, error}; +use reqwest::Client; +use serde::Deserialize; +use tokio::sync::Mutex; + +use crate::{ + error::{Error, RequestError}, + Request, +}; + +pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::get_block_count"; + +#[allow(dead_code)] // jsonrpc and id fields +#[derive(Deserialize, Debug)] +pub struct GetBlockCountResponse { + jsonrpc: String, + id: String, + pub result: BlockCount, +} + +#[derive(Deserialize, Debug)] +pub struct BlockCount { + pub count: u64, + pub status: String, +} + +pub async fn get_block_count(client: &Client, node_address: &String, tip: Arc>) -> Result<(), Error> { + let response = client + .post(format!("{}/json_rpc", &node_address.to_string())) + .json(&Request::new("get_block_count", serde_json::Value::Null)) + .send() + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + Error::from(RequestError::GetBlockCount(e.to_string())) + })? + .json::() + .await?; + debug!(target: LOG_TARGET, "`get_block_count` Response: {:?}", response); + + if response.result.status == "OK" { + debug!(target: LOG_TARGET, "`get_block_count` Blockchain tip (block height): {}", response.result.count); + *tip.lock().await = response.result.count; + } else { + debug!(target: LOG_TARGET, "Failed to get the block count. Status: {}", response.result.status); + return Err(RequestError::GetBlockCount(format!( + "Failed to get the block count. Status: {}", + response.result.status + )) + .into()); + } + + Ok(()) +} diff --git a/applications/randomx_miner/src/json_rpc/get_block_template.rs b/applications/randomx_miner/src/json_rpc/get_block_template.rs new file mode 100644 index 0000000000..ca267d93a9 --- /dev/null +++ b/applications/randomx_miner/src/json_rpc/get_block_template.rs @@ -0,0 +1,89 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use log::{debug, error}; +use reqwest::Client; +use serde::Deserialize; +use serde_json::json; + +use crate::{ + error::{Error, RequestError}, + Request, +}; + +pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::get_block_template"; + +#[allow(dead_code)] // jsonrpc and id fields +#[derive(Deserialize, Debug)] +pub struct GetBlockTemplateResponse { + jsonrpc: String, + id: String, + pub result: BlockTemplate, +} + +#[allow(dead_code)] // not all fields are used currently +#[derive(Deserialize, Debug)] +pub struct BlockTemplate { + pub blocktemplate_blob: String, + pub blockhashing_blob: String, + pub difficulty: u64, + pub height: u64, + pub prev_hash: String, + pub reserved_offset: u64, + pub status: String, +} + +pub async fn get_block_template( + client: &Client, + node_address: &String, + monero_wallet_address: &String, +) -> Result { + let response = client + .post(format!("{}/json_rpc", &node_address.to_string())) + .json(&Request::new( + "get_block_template", + json!({ + "wallet_address": monero_wallet_address, + "reserve_size": 60, + }), + )) + .send() + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + Error::from(RequestError::GetBlockTemplate(e.to_string())) + })? + .json::() + .await?; + debug!(target: LOG_TARGET, "`get_block_template` Response: {:?}", response); + + if response.result.status == "OK" { + Ok(response.result) + } else { + debug!(target: LOG_TARGET, "Failed to get the block template. Status: {}", response.result.status); + Err(RequestError::GetBlockCount(format!( + "Failed to get the block template. Status: {}", + response.result.status + )) + .into()) + } +} diff --git a/applications/randomx_miner/src/json_rpc/mod.rs b/applications/randomx_miner/src/json_rpc/mod.rs index 8fd1be8a14..6407dc4896 100644 --- a/applications/randomx_miner/src/json_rpc/mod.rs +++ b/applications/randomx_miner/src/json_rpc/mod.rs @@ -20,7 +20,12 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use serde::{Deserialize, Serialize}; +use serde::Serialize; + +mod get_block_count; +mod get_block_template; +pub use get_block_count::get_block_count; +pub use get_block_template::get_block_template; #[derive(Serialize)] pub struct Request<'a> { @@ -40,34 +45,3 @@ impl Request<'_> { } } } - -#[derive(Deserialize, Debug)] -pub struct GetBlockCountResponse { - jsonrpc: String, - id: String, - pub result: GetBlockCountResult, -} - -#[derive(Deserialize, Debug)] -pub struct GetBlockCountResult { - pub count: u64, - pub status: String, -} - -#[derive(Deserialize, Debug)] -pub struct GetBlockTemplateResponse { - jsonrpc: String, - id: String, - pub result: GetBlockTemplateResult, -} - -#[derive(Deserialize, Debug)] -pub struct GetBlockTemplateResult { - pub blocktemplate_blob: String, - pub blockhashing_blob: String, - pub difficulty: u64, - pub height: u64, - pub prev_hash: String, - pub reserved_offset: u64, - pub status: String, -} diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 60c2bb20f9..e99a711ef8 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -22,23 +22,19 @@ use std::{sync::Arc, time::Duration}; -use log::{debug, error, info}; -use minotari_app_utilities::parse_miner_input::wallet_payment_address; +use log::info; use reqwest::Client; -use serde::{Deserialize, Serialize}; -use serde_json::json; use tari_common::{load_configuration, DefaultConfigLoader}; use tokio::{sync::Mutex, time::sleep}; use crate::{ cli::Cli, config::RandomXMinerConfig, - error::{ConfigError, Error, RequestError}, - json_rpc::{GetBlockCountResponse, GetBlockTemplateResponse, Request}, + error::{ConfigError, Error}, + json_rpc::{get_block_count, get_block_template}, }; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; -pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; pub async fn start_miner(cli: Cli) -> Result<(), Error> { let config_path = cli.common.config_path(); @@ -61,66 +57,9 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { loop { info!(target: LOG_TARGET, "Starting new mining cycle"); - get_tip_info(&client, &node_address, tip.clone()).await?; - get_block_template(&client, &node_address, &monero_wallet_address).await?; - sleep(Duration::from_secs(15)).await - } -} - -async fn get_tip_info(client: &Client, node_address: &String, tip: Arc>) -> Result<(), Error> { - let response = client - .post(format!("{}/json_rpc", &node_address.to_string())) // Replace with your node's address - .json(&Request::new("get_block_count", serde_json::Value::Null)) - .send().await.map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - Error::from(RequestError::GetBlockCount(e.to_string())) - })? - .json::().await?; - debug!(target: LOG_TARGET, "`get_block_count` Response: {:?}", response); - - if response.result.status == "OK" { - debug!(target: LOG_TARGET, "`get_block_count` Blockchain tip (block height): {}", response.result.count); - *tip.lock().await = response.result.count; - } else { - debug!(target: LOG_TARGET, "Failed to get the block count. Status: {}", response.result.status); - return Err(RequestError::GetBlockCount(format!( - "Failed to get the block count. Status: {}", - response.result.status - )) - .into()); - } + get_block_count(&client, &node_address, tip.clone()).await?; + let block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; - Ok(()) -} - -async fn get_block_template( - client: &Client, - node_address: &String, - monero_wallet_address: &String, -) -> Result<(), Error> { - let response = client - .post(format!("{}/json_rpc", &node_address.to_string())) // Replace with your node's address - .json(&Request::new("get_block_template", json!({ - "wallet_address": monero_wallet_address, - "reserve_size": 60, - }))) - .send().await.map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - Error::from(RequestError::GetBlockTemplate(e.to_string())) - })? - .json::().await?; - debug!(target: LOG_TARGET, "`get_block_template` Response: {:?}", response); - - if response.result.status == "OK" { - debug!(target: LOG_TARGET, "`get_block_template` Block template: {:?}", response.result); - } else { - debug!(target: LOG_TARGET, "Failed to get the block template. Status: {}", response.result.status); - return Err(RequestError::GetBlockCount(format!( - "Failed to get the block template. Status: {}", - response.result.status - )) - .into()); + sleep(Duration::from_secs(15)).await } - - Ok(()) } From 14f2c3b4fc2279443d7e7f946392ba0ecc193803 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 30 Aug 2024 16:15:15 +0200 Subject: [PATCH 04/32] Calculate the hash --- Cargo.lock | 5 ++ applications/randomx_miner/Cargo.toml | 5 ++ applications/randomx_miner/src/error.rs | 18 ++++++ .../src/json_rpc/get_block_template.rs | 2 +- .../randomx_miner/src/json_rpc/mod.rs | 6 +- applications/randomx_miner/src/run_miner.rs | 61 +++++++++++++++++-- .../src/proof_of_work/monero_rx/pow_data.rs | 2 +- 7 files changed, 89 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c8c8c9e80..423274860e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4998,14 +4998,19 @@ dependencies = [ "clap 3.2.25", "config", "crossterm 0.25.0", + "hex", "log", "minotari_app_utilities", + "monero", + "randomx-rs", "reqwest 0.12.7", "serde", "serde_json", "tari_common", "tari_comms", + "tari_core", "tari_features", + "tari_utilities", "thiserror", "tokio", ] diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index 863708a5c3..fdaf40e4bb 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -14,11 +14,16 @@ default = [] minotari_app_utilities = { path = "../minotari_app_utilities", features = ["miner_input"] } tari_common = { path = "../../common" } tari_comms = { path = "../../comms/core" } +tari_core = { path = "../../base_layer/core" } +tari_utilities = "0.7.0" clap = { version = "3.2", features = ["derive", "env"] } config = "0.14.0" crossterm = { version = "0.25.0" } +hex = "0.4.3" log = { version = "0.4", features = ["std"] } +monero = { version = "0.21.0" } +randomx-rs = { version = "1.3.0" } reqwest = { version = "0.12.7", features = ["json"] } serde = { version = "1.0", default-features = false, features = ["derive"] } serde_json = "1.0" diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 34d4ea72e0..6ba296b057 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -20,6 +20,8 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +use tari_core::proof_of_work::monero_rx::MergeMineError; + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Config error: {0}")] @@ -30,6 +32,8 @@ pub enum Error { Reqwest(#[from] reqwest::Error), #[error("Request error: {0}")] Request(#[from] RequestError), + #[error("Mining cycle error: {0}")] + Mining(#[from] MiningError), } #[derive(Debug, thiserror::Error)] @@ -49,3 +53,17 @@ pub enum RequestError { #[error("Failed to process request `get_block_template`: {0}")] GetBlockTemplate(String), } + +#[derive(Debug, thiserror::Error)] +pub enum MiningError { + #[error("DifficultyError`: {0}")] + Difficulty(#[from] tari_core::proof_of_work::DifficultyError), + #[error("RandomXVMFactoryError`: {0}")] + RandomXVMFactory(#[from] tari_core::proof_of_work::randomx_factory::RandomXVMFactoryError), + #[error("HexError`: {0}")] + Hex(#[from] tari_utilities::hex::HexError), + #[error("FromHexError`: {0}")] + FromHex(#[from] hex::FromHexError), + #[error("MergeMineError`: {0}")] + MergeMine(#[from] MergeMineError), +} diff --git a/applications/randomx_miner/src/json_rpc/get_block_template.rs b/applications/randomx_miner/src/json_rpc/get_block_template.rs index ca267d93a9..735a0579e0 100644 --- a/applications/randomx_miner/src/json_rpc/get_block_template.rs +++ b/applications/randomx_miner/src/json_rpc/get_block_template.rs @@ -41,7 +41,7 @@ pub struct GetBlockTemplateResponse { } #[allow(dead_code)] // not all fields are used currently -#[derive(Deserialize, Debug)] +#[derive(Deserialize, Debug, Clone)] pub struct BlockTemplate { pub blocktemplate_blob: String, pub blockhashing_blob: String, diff --git a/applications/randomx_miner/src/json_rpc/mod.rs b/applications/randomx_miner/src/json_rpc/mod.rs index 6407dc4896..edba6d38bc 100644 --- a/applications/randomx_miner/src/json_rpc/mod.rs +++ b/applications/randomx_miner/src/json_rpc/mod.rs @@ -22,10 +22,8 @@ use serde::Serialize; -mod get_block_count; -mod get_block_template; -pub use get_block_count::get_block_count; -pub use get_block_template::get_block_template; +pub mod get_block_count; +pub mod get_block_template; #[derive(Serialize)] pub struct Request<'a> { diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index e99a711ef8..f75ccbf4c5 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -22,16 +22,25 @@ use std::{sync::Arc, time::Duration}; -use log::info; +use log::{debug, info}; use reqwest::Client; use tari_common::{load_configuration, DefaultConfigLoader}; +use tari_core::proof_of_work::{ + monero_rx::deserialize_monero_block_from_hex, + randomx_factory::RandomXFactory, + Difficulty, +}; +use tari_utilities::hex::{from_hex, to_hex}; use tokio::{sync::Mutex, time::sleep}; use crate::{ cli::Cli, config::RandomXMinerConfig, - error::{ConfigError, Error}, - json_rpc::{get_block_count, get_block_template}, + error::{ConfigError, Error, MiningError}, + json_rpc::{ + get_block_count::get_block_count, + get_block_template::{get_block_template, BlockTemplate}, + }, }; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; @@ -52,7 +61,7 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let client = Client::new(); - let mut tip = Arc::new(Mutex::new(0u64)); + let tip = Arc::new(Mutex::new(0u64)); let mut blocks_found: u64 = 0; loop { info!(target: LOG_TARGET, "Starting new mining cycle"); @@ -60,6 +69,50 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { get_block_count(&client, &node_address, tip.clone()).await?; let block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; + loop { + mining_cycle(block_template.clone())?; + } + sleep(Duration::from_secs(15)).await } } + +fn mining_cycle(block_template: BlockTemplate) -> Result<(Difficulty, Vec), MiningError> { + let randomx_factory = RandomXFactory::default(); + + // Assign these flags later + // let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; + + let key = hex::decode(&block_template.prev_hash)?; + let vm = randomx_factory.create(&key)?; + + let block = deserialize_monero_block_from_hex(&block_template.blocktemplate_blob)?; + let bytes = hex::decode(block_template.blockhashing_blob).unwrap(); + + let versions = "0c0c"; + + let input = &format!( + "{}{}{}{}{}{}", + versions, + to_hex(&block.header.timestamp.to_le_bytes()), + to_hex(&block.header.prev_id.to_bytes()), + to_hex(&block.header.nonce.to_le_bytes()), + to_hex(&block.tx_hashes[0].to_bytes()), + to_hex(&block_template.height.to_le_bytes()) + ); + debug!(target: LOG_TARGET, "Input: {}", input); + let input = from_hex(input)?; + + let hash = vm.calculate_hash(&input)?; + debug!(target: LOG_TARGET, "RandomX Hash: {:?}", hash); + let difficulty = Difficulty::little_endian_difficulty(&hash)?; + debug!(target: LOG_TARGET, "Difficulty: {}", difficulty); + + if difficulty.as_u64() >= block_template.difficulty { + println!("Valid block found!"); + } else { + println!("Keep mining..."); + } + + Ok((difficulty, hash)) +} diff --git a/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs b/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs index 14ebf802e0..23b9131967 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/pow_data.rs @@ -47,7 +47,7 @@ use crate::{ proof_of_work::monero_rx::helpers::create_block_hashing_blob, }; -/// This is a struct to deserialize the data from he pow field into data required for the randomX Monero merged mine +/// This is a struct to deserialize the data from the pow field into data required for the randomX Monero merged mine /// pow. #[derive(Clone, Debug)] pub struct MoneroPowData { From ac56f125187dd8e54441b94ea5b300240e6b7fa1 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 30 Aug 2024 17:30:17 +0200 Subject: [PATCH 05/32] increment the blockhashing blog nonce --- applications/randomx_miner/src/run_miner.rs | 49 +++++++++------------ 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index f75ccbf4c5..ba50adaca7 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -20,11 +20,12 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{sync::Arc, time::Duration}; +use std::{convert::TryInto, sync::Arc, time::Duration}; use log::{debug, info}; use reqwest::Client; use tari_common::{load_configuration, DefaultConfigLoader}; +use tari_comms::message::MessageExt; use tari_core::proof_of_work::{ monero_rx::deserialize_monero_block_from_hex, randomx_factory::RandomXFactory, @@ -63,21 +64,20 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let tip = Arc::new(Mutex::new(0u64)); let mut blocks_found: u64 = 0; - loop { - info!(target: LOG_TARGET, "Starting new mining cycle"); - get_block_count(&client, &node_address, tip.clone()).await?; - let block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; + info!(target: LOG_TARGET, "Starting new mining cycle"); - loop { - mining_cycle(block_template.clone())?; - } + get_block_count(&client, &node_address, tip.clone()).await?; + let block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; - sleep(Duration::from_secs(15)).await + let mut count = 0u32; + loop { + mining_cycle(block_template.clone(), count)?; + count += 1; } } -fn mining_cycle(block_template: BlockTemplate) -> Result<(Difficulty, Vec), MiningError> { +fn mining_cycle(block_template: BlockTemplate, count: u32) -> Result<(Difficulty, Vec), MiningError> { let randomx_factory = RandomXFactory::default(); // Assign these flags later @@ -87,23 +87,18 @@ fn mining_cycle(block_template: BlockTemplate) -> Result<(Difficulty, Vec), let vm = randomx_factory.create(&key)?; let block = deserialize_monero_block_from_hex(&block_template.blocktemplate_blob)?; - let bytes = hex::decode(block_template.blockhashing_blob).unwrap(); - - let versions = "0c0c"; - - let input = &format!( - "{}{}{}{}{}{}", - versions, - to_hex(&block.header.timestamp.to_le_bytes()), - to_hex(&block.header.prev_id.to_bytes()), - to_hex(&block.header.nonce.to_le_bytes()), - to_hex(&block.tx_hashes[0].to_bytes()), - to_hex(&block_template.height.to_le_bytes()) - ); - debug!(target: LOG_TARGET, "Input: {}", input); - let input = from_hex(input)?; - - let hash = vm.calculate_hash(&input)?; + let mut bytes = hex::decode(block_template.blockhashing_blob)?; + + let nonce_position = 38; + let nonce_bytes: [u8; 4] = bytes[nonce_position..nonce_position + 4] + .try_into() + .expect("Slice with incorrect length"); // Remove this expect + let mut nonce = u32::from_le_bytes(nonce_bytes); + debug!(target: LOG_TARGET, "Nonce bytes: {:?}", nonce); + + bytes[nonce_position..nonce_position + 4].copy_from_slice(&count.to_le_bytes()); + + let hash = vm.calculate_hash(&bytes)?; debug!(target: LOG_TARGET, "RandomX Hash: {:?}", hash); let difficulty = Difficulty::little_endian_difficulty(&hash)?; debug!(target: LOG_TARGET, "Difficulty: {}", difficulty); From bf6bf0580a5f8031e9f1a0d42c2752d4d46fad1b Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 2 Sep 2024 14:39:14 +0200 Subject: [PATCH 06/32] Error refactoring --- applications/randomx_miner/src/error.rs | 4 +++ .../src/json_rpc/get_block_count.rs | 27 ++++++++----------- .../src/json_rpc/get_block_template.rs | 18 ++++++------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 6ba296b057..43546b7825 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -66,4 +66,8 @@ pub enum MiningError { FromHex(#[from] hex::FromHexError), #[error("MergeMineError`: {0}")] MergeMine(#[from] MergeMineError), + #[error("Request error: {0}")] + Request(#[from] RequestError), + #[error("RandomXError: {0}")] + RandomX(#[from] randomx_rs::RandomXError), } diff --git a/applications/randomx_miner/src/json_rpc/get_block_count.rs b/applications/randomx_miner/src/json_rpc/get_block_count.rs index bd0af965b1..5a96960048 100644 --- a/applications/randomx_miner/src/json_rpc/get_block_count.rs +++ b/applications/randomx_miner/src/json_rpc/get_block_count.rs @@ -20,17 +20,11 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::sync::Arc; - use log::{debug, error}; use reqwest::Client; use serde::Deserialize; -use tokio::sync::Mutex; -use crate::{ - error::{Error, RequestError}, - Request, -}; +use crate::{error::RequestError, Request}; pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::get_block_count"; @@ -48,7 +42,7 @@ pub struct BlockCount { pub status: String, } -pub async fn get_block_count(client: &Client, node_address: &String, tip: Arc>) -> Result<(), Error> { +pub async fn get_block_count(client: &Client, node_address: &String) -> Result { let response = client .post(format!("{}/json_rpc", &node_address.to_string())) .json(&Request::new("get_block_count", serde_json::Value::Null)) @@ -56,23 +50,24 @@ pub async fn get_block_count(client: &Client, node_address: &String, tip: Arc() - .await?; + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + RequestError::GetBlockCount(e.to_string()) + })?; debug!(target: LOG_TARGET, "`get_block_count` Response: {:?}", response); if response.result.status == "OK" { debug!(target: LOG_TARGET, "`get_block_count` Blockchain tip (block height): {}", response.result.count); - *tip.lock().await = response.result.count; + Ok(response.result.count) } else { debug!(target: LOG_TARGET, "Failed to get the block count. Status: {}", response.result.status); - return Err(RequestError::GetBlockCount(format!( + Err(RequestError::GetBlockCount(format!( "Failed to get the block count. Status: {}", response.result.status - )) - .into()); + ))) } - - Ok(()) } diff --git a/applications/randomx_miner/src/json_rpc/get_block_template.rs b/applications/randomx_miner/src/json_rpc/get_block_template.rs index 735a0579e0..454b271c2f 100644 --- a/applications/randomx_miner/src/json_rpc/get_block_template.rs +++ b/applications/randomx_miner/src/json_rpc/get_block_template.rs @@ -25,10 +25,7 @@ use reqwest::Client; use serde::Deserialize; use serde_json::json; -use crate::{ - error::{Error, RequestError}, - Request, -}; +use crate::{error::RequestError, Request}; pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::get_block_template"; @@ -56,7 +53,7 @@ pub async fn get_block_template( client: &Client, node_address: &String, monero_wallet_address: &String, -) -> Result { +) -> Result { let response = client .post(format!("{}/json_rpc", &node_address.to_string())) .json(&Request::new( @@ -70,10 +67,14 @@ pub async fn get_block_template( .await .map_err(|e| { error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - Error::from(RequestError::GetBlockTemplate(e.to_string())) + RequestError::GetBlockTemplate(e.to_string()) })? .json::() - .await?; + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + RequestError::GetBlockTemplate(e.to_string()) + })?; debug!(target: LOG_TARGET, "`get_block_template` Response: {:?}", response); if response.result.status == "OK" { @@ -83,7 +84,6 @@ pub async fn get_block_template( Err(RequestError::GetBlockCount(format!( "Failed to get the block template. Status: {}", response.result.status - )) - .into()) + ))) } } From 74c3cc93fd0a458e8127d6699c604350d9878e49 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 2 Sep 2024 14:41:28 +0200 Subject: [PATCH 07/32] Allow the RandomX factory to accept params Specifically the cache and dataset needed for max mode mining. --- applications/randomx_miner/src/run_miner.rs | 157 +++++++++++++----- .../src/proof_of_work/monero_rx/helpers.rs | 4 +- .../proof_of_work/monero_rx/merkle_tree.rs | 2 +- .../core/src/proof_of_work/randomx_factory.rs | 70 +++++--- 4 files changed, 163 insertions(+), 70 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index ba50adaca7..7bb05b08bb 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -20,32 +20,35 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use std::{convert::TryInto, sync::Arc, time::Duration}; +use std::{ + cmp::max, + collections::HashMap, + sync::Arc, + time::{Duration, Instant}, +}; -use log::{debug, info}; +use log::{debug, info, warn}; +use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; use reqwest::Client; use tari_common::{load_configuration, DefaultConfigLoader}; -use tari_comms::message::MessageExt; use tari_core::proof_of_work::{ - monero_rx::deserialize_monero_block_from_hex, - randomx_factory::RandomXFactory, + randomx_factory::{RandomXFactory, RandomXVMInstance}, Difficulty, }; -use tari_utilities::hex::{from_hex, to_hex}; -use tokio::{sync::Mutex, time::sleep}; +use tokio::sync::RwLock; use crate::{ cli::Cli, config::RandomXMinerConfig, error::{ConfigError, Error, MiningError}, - json_rpc::{ - get_block_count::get_block_count, - get_block_template::{get_block_template, BlockTemplate}, - }, + json_rpc::{get_block_count::get_block_count, get_block_template::get_block_template}, }; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; +type SafeRandomXCache = Arc, RandomXCache>>>; +type SafeRandomXDataset = Arc, RandomXDataset>>>; + pub async fn start_miner(cli: Cli) -> Result<(), Error> { let config_path = cli.common.config_path(); let cfg = load_configuration(config_path.as_path(), true, cli.non_interactive_mode, &cli)?; @@ -61,53 +64,125 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { info!(target: LOG_TARGET, "Mining to Monero wallet address: {}", &monero_wallet_address); let client = Client::new(); - - let tip = Arc::new(Mutex::new(0u64)); let mut blocks_found: u64 = 0; info!(target: LOG_TARGET, "Starting new mining cycle"); - get_block_count(&client, &node_address, tip.clone()).await?; - let block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; + let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; + let randomx_factory = RandomXFactory::new_with_flags(2, flags); + + let caches: SafeRandomXCache = Default::default(); + let datasets: SafeRandomXDataset = Default::default(); - let mut count = 0u32; loop { - mining_cycle(block_template.clone(), count)?; - count += 1; + thread_work( + &client, + &node_address, + &monero_wallet_address, + &randomx_factory, + caches.clone(), + datasets.clone(), + ) + .await?; } } -fn mining_cycle(block_template: BlockTemplate, count: u32) -> Result<(Difficulty, Vec), MiningError> { - let randomx_factory = RandomXFactory::default(); - - // Assign these flags later - // let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; +async fn thread_work( + client: &Client, + node_address: &String, + monero_wallet_address: &String, + randomx_factory: &RandomXFactory, + caches: SafeRandomXCache, + datasets: SafeRandomXDataset, +) -> Result<(), MiningError> { + let flags = randomx_factory.get_flags()?; + let current_height = get_block_count(client, node_address).await?; + let block_template = get_block_template(client, node_address, monero_wallet_address).await?; + let blockhashing_bytes = hex::decode(block_template.blockhashing_blob)?; let key = hex::decode(&block_template.prev_hash)?; - let vm = randomx_factory.create(&key)?; - let block = deserialize_monero_block_from_hex(&block_template.blocktemplate_blob)?; - let mut bytes = hex::decode(block_template.blockhashing_blob)?; + debug!(target: LOG_TARGET, "Initializing cache"); + let read_lock = caches.read().await; + let (flags, cache) = match read_lock.get(&key) { + Some(cache) => (flags, cache.clone()), + None => match RandomXCache::new(flags, &key) { + Ok(cache) => (flags, cache), + Err(err) => { + drop(read_lock); + warn!( + target: LOG_TARGET, + "Error initializing RandomX cache with flags {:?}. {:?}. Fallback to default flags", flags, err + ); + // This is informed by how RandomX falls back on any cache allocation failure + // https://github.com/xmrig/xmrig/blob/02b2b87bb685ab83b132267aa3c2de0766f16b8b/src/crypto/rx/RxCache.cpp#L88 + let flags = RandomXFlag::FLAG_DEFAULT; + let cache = RandomXCache::new(flags, &key)?; + caches.write().await.insert(key.to_vec(), cache.clone()); + (flags, cache) + }, + }, + }; + debug!(target: LOG_TARGET, "Initializing dataset"); + let read_lock = datasets.read().await; + let dataset = match read_lock.get(&key) { + Some(dataset) => dataset.clone(), + None => { + drop(read_lock); + let d = RandomXDataset::new(RandomXFlag::FLAG_DEFAULT, cache.clone(), 0)?; + datasets.write().await.insert(key.to_vec(), d.clone()); + d + }, + }; + + let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; + let mut count = 0u32; + let start_time = Instant::now(); + let mut last_check_time = start_time; + let mut max_difficulty_reached = 0; + debug!(target: LOG_TARGET, "Mining now"); + loop { + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone()).await?; + count += 1; - let nonce_position = 38; - let nonce_bytes: [u8; 4] = bytes[nonce_position..nonce_position + 4] - .try_into() - .expect("Slice with incorrect length"); // Remove this expect - let mut nonce = u32::from_le_bytes(nonce_bytes); - debug!(target: LOG_TARGET, "Nonce bytes: {:?}", nonce); + // Check the hash rate every second + let now = Instant::now(); + let elapsed_since_last_check = now.duration_since(last_check_time); - bytes[nonce_position..nonce_position + 4].copy_from_slice(&count.to_le_bytes()); + if elapsed_since_last_check >= Duration::from_secs(10) { + let total_elapsed_time = now.duration_since(start_time).as_secs_f64(); + let hash_rate = count as f64 / total_elapsed_time; - let hash = vm.calculate_hash(&bytes)?; - debug!(target: LOG_TARGET, "RandomX Hash: {:?}", hash); - let difficulty = Difficulty::little_endian_difficulty(&hash)?; - debug!(target: LOG_TARGET, "Difficulty: {}", difficulty); + println!("Hash Rate: {:.2} H/s", hash_rate); + + last_check_time = now; // Reset the last check time + } - if difficulty.as_u64() >= block_template.difficulty { - println!("Valid block found!"); - } else { - println!("Keep mining..."); + unsafe { + if difficulty.as_u64() > max_difficulty_reached { + max_difficulty_reached = difficulty.as_u64(); + println!("New max difficulty reached: {}", max_difficulty_reached); + } + } + + if difficulty.as_u64() >= block_template.difficulty { + println!("Valid block found!"); + return Ok(()); + } } +} + +async fn mining_cycle( + mut blockhashing_bytes: Vec, + count: u32, + vm: RandomXVMInstance, +) -> Result<(Difficulty, Vec), MiningError> { + let nonce_position = 38; + blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&count.to_le_bytes()); + + let hash = vm.calculate_hash(&blockhashing_bytes)?; + // Check last byte of hash and see if it's over difficulty + let difficulty = Difficulty::little_endian_difficulty(&hash)?; Ok((difficulty, hash)) } diff --git a/base_layer/core/src/proof_of_work/monero_rx/helpers.rs b/base_layer/core/src/proof_of_work/monero_rx/helpers.rs index 5b0dae7ea6..100e09c4b7 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/helpers.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/helpers.rs @@ -65,7 +65,7 @@ pub fn randomx_difficulty( let monero_pow_data = verify_header(header, genesis_block_hash, consensus)?; trace!(target: LOG_TARGET, "Valid Monero data: {}", monero_pow_data); let blockhashing_blob = monero_pow_data.to_blockhashing_blob(); - let vm = randomx_factory.create(monero_pow_data.randomx_key())?; + let vm = randomx_factory.create(monero_pow_data.randomx_key(), None, None)?; get_random_x_difficulty(&blockhashing_blob, &vm).map(|(diff, _)| diff) } @@ -1245,7 +1245,7 @@ mod test { let key = from_hex("2aca6501719a5c7ab7d4acbc7cc5d277b57ad8c27c6830788c2d5a596308e5b1").unwrap(); let rx = RandomXFactory::default(); - let (difficulty, hash) = get_random_x_difficulty(&input, &rx.create(&key).unwrap()).unwrap(); + let (difficulty, hash) = get_random_x_difficulty(&input, &rx.create(&key, None, None).unwrap()).unwrap(); assert_eq!( hash.to_hex(), "f68fbc8cc85bde856cd1323e9f8e6f024483038d728835de2f8c014ff6260000" diff --git a/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs b/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs index faaeeba537..93184fa968 100644 --- a/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs +++ b/base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs @@ -423,7 +423,7 @@ mod test { fn randomx_hash(input: &[u8], key: &str) -> String { let key = from_hex(key).unwrap(); RandomXFactory::default() - .create(&key) + .create(&key, None, None) .unwrap() .calculate_hash(input) .unwrap() diff --git a/base_layer/core/src/proof_of_work/randomx_factory.rs b/base_layer/core/src/proof_of_work/randomx_factory.rs index fb4889d3fa..dbb0a3d8ed 100644 --- a/base_layer/core/src/proof_of_work/randomx_factory.rs +++ b/base_layer/core/src/proof_of_work/randomx_factory.rs @@ -9,7 +9,7 @@ use std::{ }; use log::*; -use randomx_rs::{RandomXCache, RandomXError, RandomXFlag, RandomXVM}; +use randomx_rs::{RandomXCache, RandomXDataset, RandomXError, RandomXFlag, RandomXVM}; const LOG_TARGET: &str = "c::pow::randomx_factory"; @@ -35,24 +35,14 @@ pub struct RandomXVMInstance { } impl RandomXVMInstance { - fn create(key: &[u8], flags: RandomXFlag) -> Result { - let (flags, cache) = match RandomXCache::new(flags, key) { - Ok(cache) => (flags, cache), - Err(err) => { - warn!( - target: LOG_TARGET, - "Error initializing RandomX cache with flags {:?}. {:?}. Fallback to default flags", flags, err - ); - // This is informed by how RandomX falls back on any cache allocation failure - // https://github.com/xmrig/xmrig/blob/02b2b87bb685ab83b132267aa3c2de0766f16b8b/src/crypto/rx/RxCache.cpp#L88 - let flags = RandomXFlag::FLAG_DEFAULT; - let cache = RandomXCache::new(flags, key)?; - (flags, cache) - }, - }; - + fn create( + key: &[u8], + flags: RandomXFlag, + cache: Option, + dataset: Option, + ) -> Result { // Note: Memory required per VM in light mode is 256MB - let vm = RandomXVM::new(flags, Some(cache), None)?; + let vm = RandomXVM::new(flags, cache, dataset)?; // Note: No dataset is initialized here because we want to run in light mode. Only a cache // is required by the VM for verification, giving it a dataset will only make the VM @@ -106,15 +96,26 @@ impl RandomXFactory { } } + pub fn new_with_flags(max_vms: usize, flags: RandomXFlag) -> Self { + Self { + inner: Arc::new(RwLock::new(RandomXFactoryInner::new_with_flags(max_vms, flags))), + } + } + /// Create a new RandomX VM instance with the specified key - pub fn create(&self, key: &[u8]) -> Result { + pub fn create( + &self, + key: &[u8], + cache: Option, + dataset: Option, + ) -> Result { let res; { let mut inner = self .inner .write() .map_err(|_| RandomXVMFactoryError::PoisonedLockError)?; - res = inner.create(key)?; + res = inner.create(key, cache, dataset)?; } Ok(res) } @@ -158,8 +159,25 @@ impl RandomXFactoryInner { } } + pub(crate) fn new_with_flags(max_vms: usize, flags: RandomXFlag) -> Self { + debug!( + target: LOG_TARGET, + "RandomX factory started with {} max VMs and recommended flags = {:?}", max_vms, flags + ); + Self { + flags, + vms: Default::default(), + max_vms, + } + } + /// Create a new RandomXVMInstance - pub(crate) fn create(&mut self, key: &[u8]) -> Result { + pub(crate) fn create( + &mut self, + key: &[u8], + cache: Option, + dataset: Option, + ) -> Result { if let Some(entry) = self.vms.get_mut(key) { let vm = entry.1.clone(); entry.0 = Instant::now(); @@ -180,7 +198,7 @@ impl RandomXFactoryInner { } } - let vm = RandomXVMInstance::create(key, self.flags)?; + let vm = RandomXVMInstance::create(key, self.flags, cache, dataset)?; self.vms.insert(Vec::from(key), (Instant::now(), vm.clone())); @@ -216,14 +234,14 @@ mod test { let factory = RandomXFactory::new(2); let key = b"some-key"; - let vm = factory.create(&key[..]).unwrap(); + let vm = factory.create(&key[..], None, None).unwrap(); let preimage = b"hashme"; let hash1 = vm.calculate_hash(&preimage[..]).unwrap(); - let vm = factory.create(&key[..]).unwrap(); + let vm = factory.create(&key[..], None, None).unwrap(); assert_eq!(vm.calculate_hash(&preimage[..]).unwrap(), hash1); let key = b"another-key"; - let vm = factory.create(&key[..]).unwrap(); + let vm = factory.create(&key[..], None, None).unwrap(); assert_ne!(vm.calculate_hash(&preimage[..]).unwrap(), hash1); } @@ -236,7 +254,7 @@ mod test { let factory = factory.clone(); threads.push(tokio::spawn(async move { let key = b"some-key"; - let vm = factory.create(&key[..]).unwrap(); + let vm = factory.create(&key[..], None, None).unwrap(); let preimage = b"hashme"; let _hash = vm.calculate_hash(&preimage[..]).unwrap(); })); From a177bd4c1e1751e4b4134e9e5335adb0f318f8c5 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 2 Sep 2024 16:12:50 +0200 Subject: [PATCH 08/32] Add to CI --- .github/workflows/build_binaries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_binaries.yml b/.github/workflows/build_binaries.yml index 58a851b540..112ed7d9eb 100644 --- a/.github/workflows/build_binaries.yml +++ b/.github/workflows/build_binaries.yml @@ -22,7 +22,7 @@ env: TS_BUNDLE_ID_BASE: "com.tarilabs" TS_SIG_FN: "sha256-unsigned.txt" ## Must be a JSon string - TS_FILES: '["minotari_node","minotari_console_wallet","minotari_miner","minotari_merge_mining_proxy"]' + TS_FILES: '["minotari_node","minotari_console_wallet","minotari_miner","minotari_merge_mining_proxy","randomx_miner"]' TS_FEATURES: "default, safe" TS_LIBRARIES: "minotari_mining_helper_ffi" # For debug builds From 0c4b9bf51d308ca13912a49f2adc61fa6b410997 Mon Sep 17 00:00:00 2001 From: brianp Date: Mon, 2 Sep 2024 17:38:50 +0200 Subject: [PATCH 09/32] submit the block with successful hash --- applications/randomx_miner/src/error.rs | 2 + .../randomx_miner/src/json_rpc/mod.rs | 1 + .../src/json_rpc/submit_block.rs | 53 +++++++++++++++++++ applications/randomx_miner/src/run_miner.rs | 28 +++++----- .../core/src/proof_of_work/randomx_factory.rs | 3 +- 5 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 applications/randomx_miner/src/json_rpc/submit_block.rs diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 43546b7825..4e0ff8c379 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -52,6 +52,8 @@ pub enum RequestError { GetBlockCount(String), #[error("Failed to process request `get_block_template`: {0}")] GetBlockTemplate(String), + #[error("Failed to process request `submit_block`: {0}")] + SubmitBlock(String), } #[derive(Debug, thiserror::Error)] diff --git a/applications/randomx_miner/src/json_rpc/mod.rs b/applications/randomx_miner/src/json_rpc/mod.rs index edba6d38bc..bf5ea473af 100644 --- a/applications/randomx_miner/src/json_rpc/mod.rs +++ b/applications/randomx_miner/src/json_rpc/mod.rs @@ -24,6 +24,7 @@ use serde::Serialize; pub mod get_block_count; pub mod get_block_template; +pub mod submit_block; #[derive(Serialize)] pub struct Request<'a> { diff --git a/applications/randomx_miner/src/json_rpc/submit_block.rs b/applications/randomx_miner/src/json_rpc/submit_block.rs new file mode 100644 index 0000000000..74da6e53b6 --- /dev/null +++ b/applications/randomx_miner/src/json_rpc/submit_block.rs @@ -0,0 +1,53 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use log::{debug, error}; +use reqwest::Client; +use serde::Deserialize; +use serde_json::json; + +use crate::{error::RequestError, json_rpc::Request}; + +pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::submit_block"; + +pub async fn submit_block(client: &Client, node_address: &String, block_hash: String) -> Result<(), RequestError> { + let response = client + .post(format!("{}/json_rpc", &node_address.to_string())) + .json(&Request::new("submitblock", json![block_hash])) + .send() + .await + .map_err(|e| { + error!(target: LOG_TARGET, "Reqwest error: {:?}", e); + RequestError::SubmitBlock(e.to_string()) + })?; + debug!(target: LOG_TARGET, "`submit_block` Response: {:?}", response); + + if response.status().is_success() { + Ok(()) + } else { + debug!(target: LOG_TARGET, "Failed to get the block template. {:?}", response); + Err(RequestError::SubmitBlock(format!( + "Failed to get the block template. Status: {:?}", + response + ))) + } +} diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 7bb05b08bb..f883c3c995 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -21,27 +21,29 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ - cmp::max, collections::HashMap, sync::Arc, time::{Duration, Instant}, }; use log::{debug, info, warn}; +use monero::VarInt; use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; use reqwest::Client; use tari_common::{load_configuration, DefaultConfigLoader}; use tari_core::proof_of_work::{ + monero_rx::{deserialize_monero_block_from_hex, serialize_monero_block_to_hex}, randomx_factory::{RandomXFactory, RandomXVMInstance}, Difficulty, }; +use tari_utilities::epoch_time::EpochTime; use tokio::sync::RwLock; use crate::{ cli::Cli, config::RandomXMinerConfig, error::{ConfigError, Error, MiningError}, - json_rpc::{get_block_count::get_block_count, get_block_template::get_block_template}, + json_rpc::{get_block_count::get_block_count, get_block_template::get_block_template, submit_block::submit_block}, }; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; @@ -129,7 +131,7 @@ async fn thread_work( Some(dataset) => dataset.clone(), None => { drop(read_lock); - let d = RandomXDataset::new(RandomXFlag::FLAG_DEFAULT, cache.clone(), 0)?; + let d = RandomXDataset::new(flags, cache.clone(), 0)?; datasets.write().await.insert(key.to_vec(), d.clone()); d }, @@ -142,10 +144,8 @@ async fn thread_work( let mut max_difficulty_reached = 0; debug!(target: LOG_TARGET, "Mining now"); loop { - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone()).await?; - count += 1; + let (difficulty, _) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone()).await?; - // Check the hash rate every second let now = Instant::now(); let elapsed_since_last_check = now.duration_since(last_check_time); @@ -155,20 +155,24 @@ async fn thread_work( println!("Hash Rate: {:.2} H/s", hash_rate); - last_check_time = now; // Reset the last check time + last_check_time = now; } - unsafe { - if difficulty.as_u64() > max_difficulty_reached { - max_difficulty_reached = difficulty.as_u64(); - println!("New max difficulty reached: {}", max_difficulty_reached); - } + if difficulty.as_u64() > max_difficulty_reached { + max_difficulty_reached = difficulty.as_u64(); + println!("New max difficulty reached: {}", max_difficulty_reached); } if difficulty.as_u64() >= block_template.difficulty { println!("Valid block found!"); + let mut block = deserialize_monero_block_from_hex(&block_template.blocktemplate_blob)?; + block.header.nonce = count; + block.header.timestamp = VarInt(EpochTime::now().as_u64()); + let block_hex = serialize_monero_block_to_hex(&block)?; + submit_block(client, node_address, block_hex).await?; return Ok(()); } + count += 1; } } diff --git a/base_layer/core/src/proof_of_work/randomx_factory.rs b/base_layer/core/src/proof_of_work/randomx_factory.rs index dbb0a3d8ed..2a623030d5 100644 --- a/base_layer/core/src/proof_of_work/randomx_factory.rs +++ b/base_layer/core/src/proof_of_work/randomx_factory.rs @@ -36,7 +36,6 @@ pub struct RandomXVMInstance { impl RandomXVMInstance { fn create( - key: &[u8], flags: RandomXFlag, cache: Option, dataset: Option, @@ -198,7 +197,7 @@ impl RandomXFactoryInner { } } - let vm = RandomXVMInstance::create(key, self.flags, cache, dataset)?; + let vm = RandomXVMInstance::create(self.flags, cache, dataset)?; self.vms.insert(Vec::from(key), (Instant::now(), vm.clone())); From 65223aef1b438744b7d336222786d2430cf7e1bb Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 3 Sep 2024 15:08:19 +0200 Subject: [PATCH 10/32] Update the mined block timestamp --- .../src/json_rpc/get_block_template.rs | 1 + .../src/json_rpc/submit_block.rs | 2 +- applications/randomx_miner/src/run_miner.rs | 31 ++++++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/applications/randomx_miner/src/json_rpc/get_block_template.rs b/applications/randomx_miner/src/json_rpc/get_block_template.rs index 454b271c2f..e83a1c95b9 100644 --- a/applications/randomx_miner/src/json_rpc/get_block_template.rs +++ b/applications/randomx_miner/src/json_rpc/get_block_template.rs @@ -46,6 +46,7 @@ pub struct BlockTemplate { pub height: u64, pub prev_hash: String, pub reserved_offset: u64, + pub seed_hash: String, pub status: String, } diff --git a/applications/randomx_miner/src/json_rpc/submit_block.rs b/applications/randomx_miner/src/json_rpc/submit_block.rs index 74da6e53b6..359e3746a9 100644 --- a/applications/randomx_miner/src/json_rpc/submit_block.rs +++ b/applications/randomx_miner/src/json_rpc/submit_block.rs @@ -32,7 +32,7 @@ pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::submit_block"; pub async fn submit_block(client: &Client, node_address: &String, block_hash: String) -> Result<(), RequestError> { let response = client .post(format!("{}/json_rpc", &node_address.to_string())) - .json(&Request::new("submitblock", json![block_hash])) + .json(&Request::new("submitblock", json!([block_hash]))) .send() .await .map_err(|e| { diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index f883c3c995..d829fbdd0d 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -100,9 +100,9 @@ async fn thread_work( let flags = randomx_factory.get_flags()?; let current_height = get_block_count(client, node_address).await?; let block_template = get_block_template(client, node_address, monero_wallet_address).await?; - let blockhashing_bytes = hex::decode(block_template.blockhashing_blob)?; + let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; - let key = hex::decode(&block_template.prev_hash)?; + let key = hex::decode(&block_template.seed_hash)?; debug!(target: LOG_TARGET, "Initializing cache"); let read_lock = caches.read().await; @@ -144,32 +144,35 @@ async fn thread_work( let mut max_difficulty_reached = 0; debug!(target: LOG_TARGET, "Mining now"); loop { - let (difficulty, _) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone()).await?; + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone()).await?; let now = Instant::now(); let elapsed_since_last_check = now.duration_since(last_check_time); - if elapsed_since_last_check >= Duration::from_secs(10) { + if elapsed_since_last_check >= Duration::from_secs(2) { let total_elapsed_time = now.duration_since(start_time).as_secs_f64(); let hash_rate = count as f64 / total_elapsed_time; - println!("Hash Rate: {:.2} H/s", hash_rate); + info!( + "Hash Rate: {:.2} H/s | Max difficulty reached: {}", + hash_rate, max_difficulty_reached + ); last_check_time = now; } if difficulty.as_u64() > max_difficulty_reached { max_difficulty_reached = difficulty.as_u64(); - println!("New max difficulty reached: {}", max_difficulty_reached); } if difficulty.as_u64() >= block_template.difficulty { - println!("Valid block found!"); - let mut block = deserialize_monero_block_from_hex(&block_template.blocktemplate_blob)?; - block.header.nonce = count; - block.header.timestamp = VarInt(EpochTime::now().as_u64()); - let block_hex = serialize_monero_block_to_hex(&block)?; + info!("Valid block found!"); + let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; + block_template_bytes[0..42].copy_from_slice(&hash[0..42]); + + let block_hex = hex::encode(block_template_bytes.clone()); submit_block(client, node_address, block_hex).await?; + return Ok(()); } count += 1; @@ -184,9 +187,13 @@ async fn mining_cycle( let nonce_position = 38; blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&count.to_le_bytes()); + let timestamp_position = 8; + let timestamp_bytes: [u8; 4] = (EpochTime::now().as_u64() as u32).to_le_bytes(); + blockhashing_bytes[timestamp_position..timestamp_position + 4].copy_from_slice(×tamp_bytes); + let hash = vm.calculate_hash(&blockhashing_bytes)?; // Check last byte of hash and see if it's over difficulty let difficulty = Difficulty::little_endian_difficulty(&hash)?; - Ok((difficulty, hash)) + Ok((difficulty, blockhashing_bytes)) } From fce301efcd4abf903af66e38c9ef59ffbdecc7c8 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 3 Sep 2024 15:08:59 +0200 Subject: [PATCH 11/32] Initialize empty caches on lite mode --- base_layer/core/src/proof_of_work/randomx_factory.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/base_layer/core/src/proof_of_work/randomx_factory.rs b/base_layer/core/src/proof_of_work/randomx_factory.rs index 2a623030d5..6ced8b201a 100644 --- a/base_layer/core/src/proof_of_work/randomx_factory.rs +++ b/base_layer/core/src/proof_of_work/randomx_factory.rs @@ -36,12 +36,17 @@ pub struct RandomXVMInstance { impl RandomXVMInstance { fn create( + key: &[u8], flags: RandomXFlag, cache: Option, dataset: Option, ) -> Result { // Note: Memory required per VM in light mode is 256MB - let vm = RandomXVM::new(flags, cache, dataset)?; + let cache = match cache { + Some(c) => c, + None => RandomXCache::new(flags, key)?, + }; + let vm = RandomXVM::new(flags, Some(cache), dataset)?; // Note: No dataset is initialized here because we want to run in light mode. Only a cache // is required by the VM for verification, giving it a dataset will only make the VM @@ -197,7 +202,7 @@ impl RandomXFactoryInner { } } - let vm = RandomXVMInstance::create(self.flags, cache, dataset)?; + let vm = RandomXVMInstance::create(key, self.flags, cache, dataset)?; self.vms.insert(Vec::from(key), (Instant::now(), vm.clone())); From 8876af8d8cd0f554980084f14ec8e25c89501a9d Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 3 Sep 2024 15:19:22 +0200 Subject: [PATCH 12/32] Add cli options for node and wallet address --- applications/randomx_miner/src/cli.rs | 4 ++++ applications/randomx_miner/src/error.rs | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/applications/randomx_miner/src/cli.rs b/applications/randomx_miner/src/cli.rs index 3e2ea9063a..2e4bdf1fd9 100644 --- a/applications/randomx_miner/src/cli.rs +++ b/applications/randomx_miner/src/cli.rs @@ -32,6 +32,10 @@ use tari_common::configuration::{ConfigOverrideProvider, Network}; pub struct Cli { #[clap(flatten)] pub common: CommonCliArgs, + #[clap(long, alias = "monero-base-node-address")] + pub monero_base_node_address: Option, + #[clap(long, alias = "monero-wallet-address")] + pub monero_wallet_address: Option, #[clap(long, alias = "mine-until-height")] pub mine_until_height: Option, #[clap(long, alias = "max-blocks")] diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 4e0ff8c379..617bd451ed 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -20,8 +20,6 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use tari_core::proof_of_work::monero_rx::MergeMineError; - #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Config error: {0}")] @@ -67,7 +65,7 @@ pub enum MiningError { #[error("FromHexError`: {0}")] FromHex(#[from] hex::FromHexError), #[error("MergeMineError`: {0}")] - MergeMine(#[from] MergeMineError), + MergeMine(#[from] tari_core::proof_of_work::monero_rx::MergeMineError), #[error("Request error: {0}")] Request(#[from] RequestError), #[error("RandomXError: {0}")] From a497ff9f2cbb41b0bf7ec9bff9e351ce56fd43ec Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 3 Sep 2024 15:25:28 +0200 Subject: [PATCH 13/32] Update config options --- common/config/presets/h_randomx_miner.toml | 13 +++++++++++++ .../{h_collectibles.toml => i_collectibles.toml} | 0 .../presets/{i_indexer.toml => j_indexer.toml} | 0 ..._wallet_daemon.toml => k_dan_wallet_daemon.toml} | 0 common/src/configuration/utils.rs | 6 +++--- 5 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 common/config/presets/h_randomx_miner.toml rename common/config/presets/{h_collectibles.toml => i_collectibles.toml} (100%) rename common/config/presets/{i_indexer.toml => j_indexer.toml} (100%) rename common/config/presets/{j_dan_wallet_daemon.toml => k_dan_wallet_daemon.toml} (100%) diff --git a/common/config/presets/h_randomx_miner.toml b/common/config/presets/h_randomx_miner.toml new file mode 100644 index 0000000000..ce8d978662 --- /dev/null +++ b/common/config/presets/h_randomx_miner.toml @@ -0,0 +1,13 @@ +######################################################################################################################## +# # +# RandomX Miner Configuration Options (RandomXMinerConfig) # +# # +######################################################################################################################## + +[randomx_miner] + +# Monero base node or Tari MergeMinerProxy address (default = "http://127.0.0.1:18081") +#monero_base_node_address = "http://127.0.0.1:18081" + +# Monero wallet address (default = "none") +#monero_wallet_address = "none" \ No newline at end of file diff --git a/common/config/presets/h_collectibles.toml b/common/config/presets/i_collectibles.toml similarity index 100% rename from common/config/presets/h_collectibles.toml rename to common/config/presets/i_collectibles.toml diff --git a/common/config/presets/i_indexer.toml b/common/config/presets/j_indexer.toml similarity index 100% rename from common/config/presets/i_indexer.toml rename to common/config/presets/j_indexer.toml diff --git a/common/config/presets/j_dan_wallet_daemon.toml b/common/config/presets/k_dan_wallet_daemon.toml similarity index 100% rename from common/config/presets/j_dan_wallet_daemon.toml rename to common/config/presets/k_dan_wallet_daemon.toml diff --git a/common/src/configuration/utils.rs b/common/src/configuration/utils.rs index cacd4cc0a6..9b0b300daf 100644 --- a/common/src/configuration/utils.rs +++ b/common/src/configuration/utils.rs @@ -136,9 +136,9 @@ pub fn get_default_config(use_mining_config: bool) -> [&'static str; 12] { include_str!("../../config/presets/g_miner.toml"), include_str!("../../config/presets/f_merge_mining_proxy.toml"), include_str!("../../config/presets/e_validator_node.toml"), - include_str!("../../config/presets/h_collectibles.toml"), - include_str!("../../config/presets/i_indexer.toml"), - include_str!("../../config/presets/j_dan_wallet_daemon.toml"), + include_str!("../../config/presets/i_collectibles.toml"), + include_str!("../../config/presets/j_indexer.toml"), + include_str!("../../config/presets/k_dan_wallet_daemon.toml"), ] } From 472720c86c51270907d52793c6bacec2a77c0955 Mon Sep 17 00:00:00 2001 From: brianp Date: Tue, 3 Sep 2024 16:23:36 +0200 Subject: [PATCH 14/32] Enhance the config options with more usability --- Cargo.lock | 2 + applications/randomx_miner/Cargo.toml | 2 + applications/randomx_miner/src/cli.rs | 2 + applications/randomx_miner/src/config.rs | 3 + .../src/json_rpc/submit_block.rs | 1 - applications/randomx_miner/src/run_miner.rs | 74 +++++++++++++++---- common/config/presets/h_randomx_miner.toml | 5 +- common/src/configuration/utils.rs | 5 +- 8 files changed, 75 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 423274860e..1c4328f51a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4998,10 +4998,12 @@ dependencies = [ "clap 3.2.25", "config", "crossterm 0.25.0", + "dialoguer 0.11.0", "hex", "log", "minotari_app_utilities", "monero", + "num_cpus", "randomx-rs", "reqwest 0.12.7", "serde", diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index fdaf40e4bb..0a54d44cf2 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -20,9 +20,11 @@ tari_utilities = "0.7.0" clap = { version = "3.2", features = ["derive", "env"] } config = "0.14.0" crossterm = { version = "0.25.0" } +dialoguer = { version = "0.11.0" } hex = "0.4.3" log = { version = "0.4", features = ["std"] } monero = { version = "0.21.0" } +num_cpus = "1.16" randomx-rs = { version = "1.3.0" } reqwest = { version = "0.12.7", features = ["json"] } serde = { version = "1.0", default-features = false, features = ["derive"] } diff --git a/applications/randomx_miner/src/cli.rs b/applications/randomx_miner/src/cli.rs index 2e4bdf1fd9..8c70827a54 100644 --- a/applications/randomx_miner/src/cli.rs +++ b/applications/randomx_miner/src/cli.rs @@ -46,6 +46,8 @@ pub struct Cli { pub miner_max_diff: Option, #[clap(short, long, alias = "non-interactive", env = "TARI_NON_INTERACTIVE")] pub non_interactive_mode: bool, + #[clap(short, long, alias = "num-mining-threads")] + pub num_mining_threads: Option, } impl ConfigOverrideProvider for Cli { diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs index ceebbe6224..a8016b225d 100644 --- a/applications/randomx_miner/src/config.rs +++ b/applications/randomx_miner/src/config.rs @@ -41,6 +41,8 @@ pub struct RandomXMinerConfig { pub network: Network, /// The relative path to store persistent config pub config_dir: PathBuf, + /// Number of mining threads + pub num_mining_threads: usize, } #[derive(Serialize, Deserialize, Debug, Default, PartialEq)] @@ -65,6 +67,7 @@ impl Default for RandomXMinerConfig { mode: Default::default(), network: Default::default(), config_dir: PathBuf::from("config/randomx_miner"), + num_mining_threads: num_cpus::get(), } } } diff --git a/applications/randomx_miner/src/json_rpc/submit_block.rs b/applications/randomx_miner/src/json_rpc/submit_block.rs index 359e3746a9..a5a388e505 100644 --- a/applications/randomx_miner/src/json_rpc/submit_block.rs +++ b/applications/randomx_miner/src/json_rpc/submit_block.rs @@ -22,7 +22,6 @@ use log::{debug, error}; use reqwest::Client; -use serde::Deserialize; use serde_json::json; use crate::{error::RequestError, json_rpc::Request}; diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index d829fbdd0d..5f9494b179 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -26,13 +26,13 @@ use std::{ time::{Duration, Instant}, }; +use dialoguer::Input as InputPrompt; use log::{debug, info, warn}; -use monero::VarInt; +use minotari_app_utilities::parse_miner_input::process_quit; use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; -use reqwest::Client; +use reqwest::Client as ReqwestClient; use tari_common::{load_configuration, DefaultConfigLoader}; use tari_core::proof_of_work::{ - monero_rx::{deserialize_monero_block_from_hex, serialize_monero_block_to_hex}, randomx_factory::{RandomXFactory, RandomXVMInstance}, Difficulty, }; @@ -57,21 +57,16 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let mut config = RandomXMinerConfig::load_from(&cfg).expect("Failed to load config"); config.set_base_path(cli.common.get_base_path()); - let node_address = config.monero_base_node_address.ok_or(ConfigError::MissingBaseNode)?; - info!(target: LOG_TARGET, "Using Monero node address: {}", node_address); + let node_address = monero_base_node_address(&cli, &config)?; + let monero_wallet_address = monero_wallet_address(&cli, &config)?; + let threads = cli.num_mining_threads.unwrap_or(config.num_mining_threads); - let monero_wallet_address = config - .monero_wallet_address - .ok_or(ConfigError::MissingMoneroWalletAddress)?; - info!(target: LOG_TARGET, "Mining to Monero wallet address: {}", &monero_wallet_address); - - let client = Client::new(); - let mut blocks_found: u64 = 0; + let client = ReqwestClient::new(); info!(target: LOG_TARGET, "Starting new mining cycle"); let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; - let randomx_factory = RandomXFactory::new_with_flags(2, flags); + let randomx_factory = RandomXFactory::new_with_flags(threads, flags); let caches: SafeRandomXCache = Default::default(); let datasets: SafeRandomXDataset = Default::default(); @@ -90,7 +85,7 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { } async fn thread_work( - client: &Client, + client: &ReqwestClient, node_address: &String, monero_wallet_address: &String, randomx_factory: &RandomXFactory, @@ -98,7 +93,6 @@ async fn thread_work( datasets: SafeRandomXDataset, ) -> Result<(), MiningError> { let flags = randomx_factory.get_flags()?; - let current_height = get_block_count(client, node_address).await?; let block_template = get_block_template(client, node_address, monero_wallet_address).await?; let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; @@ -197,3 +191,53 @@ async fn mining_cycle( Ok((difficulty, blockhashing_bytes)) } + +fn monero_base_node_address(cli: &Cli, config: &RandomXMinerConfig) -> Result { + let monero_base_node_address = cli + .monero_base_node_address + .as_ref() + .cloned() + .or_else(|| config.monero_base_node_address.as_ref().cloned()) + .or_else(|| { + if !cli.non_interactive_mode { + let base_node = InputPrompt::::new() + .with_prompt("Please enter the 'monero-base-node-address' ('quit' or 'exit' to quit) ") + .interact() + .unwrap(); + process_quit(&base_node); + Some(base_node.trim().to_string()) + } else { + None + } + }) + .ok_or(ConfigError::MissingBaseNode)?; + + info!(target: LOG_TARGET, "Using Monero node address: {}", &monero_base_node_address); + + Ok(monero_base_node_address) +} + +fn monero_wallet_address(cli: &Cli, config: &RandomXMinerConfig) -> Result { + let monero_wallet_address = cli + .monero_wallet_address + .as_ref() + .cloned() + .or_else(|| config.monero_wallet_address.as_ref().cloned()) + .or_else(|| { + if !cli.non_interactive_mode { + let address = InputPrompt::::new() + .with_prompt("Please enter the 'monero-wallet-address' ('quit' or 'exit' to quit) ") + .interact() + .unwrap(); + process_quit(&address); + Some(address.trim().to_string()) + } else { + None + } + }) + .ok_or(ConfigError::MissingMoneroWalletAddress)?; + + info!(target: LOG_TARGET, "Mining to Monero wallet address: {}", &monero_wallet_address); + + Ok(monero_wallet_address) +} diff --git a/common/config/presets/h_randomx_miner.toml b/common/config/presets/h_randomx_miner.toml index ce8d978662..1a202ce629 100644 --- a/common/config/presets/h_randomx_miner.toml +++ b/common/config/presets/h_randomx_miner.toml @@ -10,4 +10,7 @@ #monero_base_node_address = "http://127.0.0.1:18081" # Monero wallet address (default = "none") -#monero_wallet_address = "none" \ No newline at end of file +#monero_wallet_address = "none" + +# Number of mining threads (default: number of logical CPU cores) +#num_mining_threads = 8 \ No newline at end of file diff --git a/common/src/configuration/utils.rs b/common/src/configuration/utils.rs index 9b0b300daf..863c2efb32 100644 --- a/common/src/configuration/utils.rs +++ b/common/src/configuration/utils.rs @@ -108,7 +108,7 @@ pub fn load_configuration_with_overrides, TOverride: ConfigOverri /// Returns a new configuration file template in parts from the embedded presets. If non_interactive is false, the user /// is prompted to select if they would like to select a base node configuration that enables mining or not. /// Also includes the common configuration defined in `config/presets/common.toml`. -pub fn prompt_default_config() -> [&'static str; 12] { +pub fn prompt_default_config() -> [&'static str; 13] { let mine = prompt( "Node config does not exist.\nWould you like to mine (Y/n)?\nNOTE: this will enable additional gRPC methods \ that could be used to monitor and submit blocks from this node.", @@ -118,7 +118,7 @@ pub fn prompt_default_config() -> [&'static str; 12] { /// Returns the default configuration file template in parts from the embedded presets. If use_mining_config is true, /// the base node configuration that enables mining is returned, otherwise the non-mining configuration is returned. -pub fn get_default_config(use_mining_config: bool) -> [&'static str; 12] { +pub fn get_default_config(use_mining_config: bool) -> [&'static str; 13] { let base_node_allow_methods = if use_mining_config { include_str!("../../config/presets/c_base_node_b_mining_allow_methods.toml") } else { @@ -135,6 +135,7 @@ pub fn get_default_config(use_mining_config: bool) -> [&'static str; 12] { include_str!("../../config/presets/d_console_wallet.toml"), include_str!("../../config/presets/g_miner.toml"), include_str!("../../config/presets/f_merge_mining_proxy.toml"), + include_str!("../../config/presets/h_randomx_miner.toml"), include_str!("../../config/presets/e_validator_node.toml"), include_str!("../../config/presets/i_collectibles.toml"), include_str!("../../config/presets/j_indexer.toml"), From e29d5ae736695bc6e7f6194dcb52510b73a9d860 Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 4 Sep 2024 10:33:38 +0200 Subject: [PATCH 15/32] Re-write for better thread management --- Cargo.lock | 37 ++-- applications/randomx_miner/Cargo.toml | 1 + applications/randomx_miner/src/cli.rs | 2 +- applications/randomx_miner/src/error.rs | 16 ++ .../src/json_rpc/get_block_template.rs | 8 +- .../src/json_rpc/submit_block.rs | 2 +- applications/randomx_miner/src/run_miner.rs | 164 +++++++++--------- 7 files changed, 125 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1c4328f51a..6418adb616 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3430,7 +3430,7 @@ dependencies = [ "tari_contacts", "tari_crypto", "tari_p2p", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_utilities", "thiserror", "tokio", @@ -3479,7 +3479,7 @@ dependencies = [ "tari_max_size", "tari_p2p", "tari_script", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_utilities", "thiserror", "tokio", @@ -3658,7 +3658,7 @@ dependencies = [ "tari_metrics", "tari_p2p", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_storage", "tari_utilities", "thiserror", @@ -3716,7 +3716,7 @@ dependencies = [ "tari_p2p", "tari_script", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_test_utils", "tari_utilities", "tempfile", @@ -3758,7 +3758,7 @@ dependencies = [ "tari_p2p", "tari_script", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_test_utils", "tari_utilities", "tempfile", @@ -5012,6 +5012,7 @@ dependencies = [ "tari_comms", "tari_core", "tari_features", + "tari_shutdown 1.3.0-pre.0 (git+https://github.com/tari-project/tari.git?tag=v1.3.0-pre.0)", "tari_utilities", "thiserror", "tokio", @@ -6253,7 +6254,7 @@ dependencies = [ "tari_max_size", "tari_p2p", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_storage", "thiserror", ] @@ -6356,7 +6357,7 @@ dependencies = [ "tari_comms_rpc_macros", "tari_crypto", "tari_metrics", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6403,7 +6404,7 @@ dependencies = [ "tari_comms", "tari_comms_rpc_macros", "tari_crypto", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6454,7 +6455,7 @@ dependencies = [ "tari_max_size", "tari_p2p", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_test_utils", "tari_utilities", "tempfile", @@ -6527,7 +6528,7 @@ dependencies = [ "tari_p2p", "tari_script", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6616,7 +6617,7 @@ dependencies = [ "tari_key_manager", "tari_p2p", "tari_script", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_utilities", "tempfile", "thiserror", @@ -6740,7 +6741,7 @@ dependencies = [ "tari_comms_dht", "tari_crypto", "tari_service_framework", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6780,7 +6781,7 @@ dependencies = [ "futures 0.3.29", "futures-test", "log", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tari_test_utils", "thiserror", "tokio", @@ -6796,6 +6797,14 @@ dependencies = [ "tokio", ] +[[package]] +name = "tari_shutdown" +version = "1.3.0-pre.0" +source = "git+https://github.com/tari-project/tari.git?tag=v1.3.0-pre.0#e73426904901b24d6c752d8cf456782893e999c1" +dependencies = [ + "futures 0.3.29", +] + [[package]] name = "tari_storage" version = "1.4.0-pre.0" @@ -6817,7 +6826,7 @@ dependencies = [ "futures-test", "rand", "tari_comms", - "tari_shutdown", + "tari_shutdown 1.3.0-pre.0", "tempfile", "tokio", ] diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index 0a54d44cf2..2a0c0ab74e 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -29,6 +29,7 @@ randomx-rs = { version = "1.3.0" } reqwest = { version = "0.12.7", features = ["json"] } serde = { version = "1.0", default-features = false, features = ["derive"] } serde_json = "1.0" +tari_shutdown = { git = "https://github.com/tari-project/tari.git", tag = "v1.3.0-pre.0" } thiserror = "1.0.63" tokio = { version = "1.36", default-features = false, features = ["rt-multi-thread"] } diff --git a/applications/randomx_miner/src/cli.rs b/applications/randomx_miner/src/cli.rs index 8c70827a54..2acc556229 100644 --- a/applications/randomx_miner/src/cli.rs +++ b/applications/randomx_miner/src/cli.rs @@ -46,7 +46,7 @@ pub struct Cli { pub miner_max_diff: Option, #[clap(short, long, alias = "non-interactive", env = "TARI_NON_INTERACTIVE")] pub non_interactive_mode: bool, - #[clap(short, long, alias = "num-mining-threads")] + #[clap(short = 't', long, alias = "num-mining-threads")] pub num_mining_threads: Option, } diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 617bd451ed..530e39c551 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -20,6 +20,8 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +use randomx_rs::RandomXDataset; + #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Config error: {0}")] @@ -70,4 +72,18 @@ pub enum MiningError { Request(#[from] RequestError), #[error("RandomXError: {0}")] RandomX(#[from] randomx_rs::RandomXError), + #[error("Tokio runtime error: {0}")] + TokioRuntime(String), +} + +#[derive(Debug, thiserror::Error)] +pub enum DatasetError { + #[error("Failed to generate the cache")] + CacheCreation, + #[error("Failed to generate the dataset")] + DatasetCreation, + #[error("Could not acquire writelock for dataset")] + WriteLock, + #[error("Could not acquire readlock for dataset")] + ReadLock, } diff --git a/applications/randomx_miner/src/json_rpc/get_block_template.rs b/applications/randomx_miner/src/json_rpc/get_block_template.rs index e83a1c95b9..83b16d369d 100644 --- a/applications/randomx_miner/src/json_rpc/get_block_template.rs +++ b/applications/randomx_miner/src/json_rpc/get_block_template.rs @@ -50,13 +50,13 @@ pub struct BlockTemplate { pub status: String, } -pub async fn get_block_template( +pub async fn get_block_template<'a>( client: &Client, - node_address: &String, - monero_wallet_address: &String, + node_address: &'a str, + monero_wallet_address: &'a str, ) -> Result { let response = client - .post(format!("{}/json_rpc", &node_address.to_string())) + .post(format!("{}/json_rpc", node_address)) .json(&Request::new( "get_block_template", json!({ diff --git a/applications/randomx_miner/src/json_rpc/submit_block.rs b/applications/randomx_miner/src/json_rpc/submit_block.rs index a5a388e505..de1e09c9d5 100644 --- a/applications/randomx_miner/src/json_rpc/submit_block.rs +++ b/applications/randomx_miner/src/json_rpc/submit_block.rs @@ -28,7 +28,7 @@ use crate::{error::RequestError, json_rpc::Request}; pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::submit_block"; -pub async fn submit_block(client: &Client, node_address: &String, block_hash: String) -> Result<(), RequestError> { +pub async fn submit_block<'a>(client: &Client, node_address: &'a str, block_hash: String) -> Result<(), RequestError> { let response = client .post(format!("{}/json_rpc", &node_address.to_string())) .json(&Request::new("submitblock", json!([block_hash]))) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 5f9494b179..a079f89dc8 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -21,8 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ - collections::HashMap, - sync::Arc, + thread, time::{Duration, Instant}, }; @@ -36,21 +35,18 @@ use tari_core::proof_of_work::{ randomx_factory::{RandomXFactory, RandomXVMInstance}, Difficulty, }; +use tari_shutdown::Shutdown; use tari_utilities::epoch_time::EpochTime; -use tokio::sync::RwLock; use crate::{ cli::Cli, config::RandomXMinerConfig, - error::{ConfigError, Error, MiningError}, + error::{ConfigError, DatasetError, Error, MiningError, MiningError::TokioRuntime}, json_rpc::{get_block_count::get_block_count, get_block_template::get_block_template, submit_block::submit_block}, }; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; -type SafeRandomXCache = Arc, RandomXCache>>>; -type SafeRandomXDataset = Arc, RandomXDataset>>>; - pub async fn start_miner(cli: Cli) -> Result<(), Error> { let config_path = cli.common.config_path(); let cfg = load_configuration(config_path.as_path(), true, cli.non_interactive_mode, &cli)?; @@ -59,53 +55,57 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let node_address = monero_base_node_address(&cli, &config)?; let monero_wallet_address = monero_wallet_address(&cli, &config)?; - let threads = cli.num_mining_threads.unwrap_or(config.num_mining_threads); + let num_threads = cli.num_mining_threads.unwrap_or(config.num_mining_threads); + let mut shutdown = Shutdown::new(); let client = ReqwestClient::new(); - info!(target: LOG_TARGET, "Starting new mining cycle"); + debug!(target: LOG_TARGET, "Starting new mining cycle"); let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; - let randomx_factory = RandomXFactory::new_with_flags(threads, flags); - - let caches: SafeRandomXCache = Default::default(); - let datasets: SafeRandomXDataset = Default::default(); + let randomx_factory = RandomXFactory::new_with_flags(num_threads, flags); + + info!(target: LOG_TARGET, "Starting {} threads", num_threads); + let mut threads = vec![]; + + for i in 0..num_threads { + let rclient = client.clone(); + let node_address = node_address.clone(); + let monero_wallet_address = monero_wallet_address.clone(); + let randomx_factory = randomx_factory.clone(); + threads.push(thread::spawn(move || { + thread_work(&rclient, &node_address, &monero_wallet_address, &randomx_factory) + })); + } - loop { - thread_work( - &client, - &node_address, - &monero_wallet_address, - &randomx_factory, - caches.clone(), - datasets.clone(), - ) - .await?; + for t in threads { + t.join().unwrap()?; } + + shutdown.trigger(); + + Ok(()) } -async fn thread_work( +fn thread_work<'a>( client: &ReqwestClient, - node_address: &String, - monero_wallet_address: &String, + node_address: &'a str, + monero_wallet_address: &'a str, randomx_factory: &RandomXFactory, - caches: SafeRandomXCache, - datasets: SafeRandomXDataset, ) -> Result<(), MiningError> { + let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; let flags = randomx_factory.get_flags()?; - let block_template = get_block_template(client, node_address, monero_wallet_address).await?; - let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; - let key = hex::decode(&block_template.seed_hash)?; + loop { + let block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; + let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; + + let key = hex::decode(&block_template.seed_hash)?; - debug!(target: LOG_TARGET, "Initializing cache"); - let read_lock = caches.read().await; - let (flags, cache) = match read_lock.get(&key) { - Some(cache) => (flags, cache.clone()), - None => match RandomXCache::new(flags, &key) { + debug!(target: LOG_TARGET, "Initializing cache"); + let (flags, cache) = match RandomXCache::new(flags, &key) { Ok(cache) => (flags, cache), Err(err) => { - drop(read_lock); warn!( target: LOG_TARGET, "Error initializing RandomX cache with flags {:?}. {:?}. Fallback to default flags", flags, err @@ -114,66 +114,60 @@ async fn thread_work( // https://github.com/xmrig/xmrig/blob/02b2b87bb685ab83b132267aa3c2de0766f16b8b/src/crypto/rx/RxCache.cpp#L88 let flags = RandomXFlag::FLAG_DEFAULT; let cache = RandomXCache::new(flags, &key)?; - caches.write().await.insert(key.to_vec(), cache.clone()); (flags, cache) }, - }, - }; - debug!(target: LOG_TARGET, "Initializing dataset"); - let read_lock = datasets.read().await; - let dataset = match read_lock.get(&key) { - Some(dataset) => dataset.clone(), - None => { - drop(read_lock); - let d = RandomXDataset::new(flags, cache.clone(), 0)?; - datasets.write().await.insert(key.to_vec(), d.clone()); - d - }, - }; - - let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; - let mut count = 0u32; - let start_time = Instant::now(); - let mut last_check_time = start_time; - let mut max_difficulty_reached = 0; - debug!(target: LOG_TARGET, "Mining now"); - loop { - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone()).await?; - - let now = Instant::now(); - let elapsed_since_last_check = now.duration_since(last_check_time); - - if elapsed_since_last_check >= Duration::from_secs(2) { - let total_elapsed_time = now.duration_since(start_time).as_secs_f64(); - let hash_rate = count as f64 / total_elapsed_time; + }; + + debug!(target: LOG_TARGET, "Initializing dataset"); + let dataset = RandomXDataset::new(flags, cache.clone(), 0)?; + + let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; + let mut count = 0u32; + let start_time = Instant::now(); + let mut last_check_time = start_time; + let mut max_difficulty_reached = 0; + debug!(target: LOG_TARGET, "Mining now"); + loop { + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone())?; + + let now = Instant::now(); + let elapsed_since_last_check = now.duration_since(last_check_time); + + if elapsed_since_last_check >= Duration::from_secs(2) { + let total_elapsed_time = now.duration_since(start_time).as_secs_f64(); + let hash_rate = count as f64 / total_elapsed_time; + + info!( + "Hash Rate: {:.2} H/s | Max difficulty reached: {}", + hash_rate, max_difficulty_reached + ); - info!( - "Hash Rate: {:.2} H/s | Max difficulty reached: {}", - hash_rate, max_difficulty_reached - ); + last_check_time = now; + } - last_check_time = now; - } + if difficulty.as_u64() > max_difficulty_reached { + max_difficulty_reached = difficulty.as_u64(); + } - if difficulty.as_u64() > max_difficulty_reached { - max_difficulty_reached = difficulty.as_u64(); - } + if difficulty.as_u64() >= block_template.difficulty { + info!("Valid block found!"); + let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; + block_template_bytes[0..42].copy_from_slice(&hash[0..42]); - if difficulty.as_u64() >= block_template.difficulty { - info!("Valid block found!"); - let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; - block_template_bytes[0..42].copy_from_slice(&hash[0..42]); + let block_hex = hex::encode(block_template_bytes.clone()); - let block_hex = hex::encode(block_template_bytes.clone()); - submit_block(client, node_address, block_hex).await?; + runtime + .block_on(submit_block(client, node_address, block_hex)) + .map_err(MiningError::Request)?; - return Ok(()); + break; + } + count += 1; } - count += 1; } } -async fn mining_cycle( +fn mining_cycle( mut blockhashing_bytes: Vec, count: u32, vm: RandomXVMInstance, From a0b242fa3787e7a97e22794268dbcef2514b6f03 Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 4 Sep 2024 14:41:51 +0200 Subject: [PATCH 16/32] Add support for shared caches when multithreading --- applications/randomx_miner/src/error.rs | 22 +++-- applications/randomx_miner/src/lib.rs | 3 + applications/randomx_miner/src/main.rs | 2 + applications/randomx_miner/src/run_miner.rs | 76 +++++++-------- .../randomx_miner/src/shared_dataset.rs | 95 +++++++++++++++++++ applications/randomx_miner/src/stats_store.rs | 55 +++++++++++ 6 files changed, 205 insertions(+), 48 deletions(-) create mode 100644 applications/randomx_miner/src/shared_dataset.rs create mode 100644 applications/randomx_miner/src/stats_store.rs diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index 530e39c551..be088c0f42 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -20,8 +20,6 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use randomx_rs::RandomXDataset; - #[derive(Debug, thiserror::Error)] pub enum Error { #[error("Config error: {0}")] @@ -74,16 +72,20 @@ pub enum MiningError { RandomX(#[from] randomx_rs::RandomXError), #[error("Tokio runtime error: {0}")] TokioRuntime(String), + #[error("Dataset error: {0}")] + Dataset(#[from] DatasetError), } #[derive(Debug, thiserror::Error)] pub enum DatasetError { - #[error("Failed to generate the cache")] - CacheCreation, - #[error("Failed to generate the dataset")] - DatasetCreation, - #[error("Could not acquire writelock for dataset")] - WriteLock, - #[error("Could not acquire readlock for dataset")] - ReadLock, + #[error("Read lock error: {0}")] + ReadLock(String), + #[error("Write lock error: {0}")] + WriteLock(String), + #[error("RandomXError: {0}")] + RandomX(#[from] randomx_rs::RandomXError), + #[error("Dataset could not be found or created")] + DatasetNotFound, + #[error("FromHexError`: {0}")] + FromHex(#[from] hex::FromHexError), } diff --git a/applications/randomx_miner/src/lib.rs b/applications/randomx_miner/src/lib.rs index 370ea88c41..04a8861fef 100644 --- a/applications/randomx_miner/src/lib.rs +++ b/applications/randomx_miner/src/lib.rs @@ -28,6 +28,9 @@ pub use error::{ConfigError, Error}; mod json_rpc; pub use json_rpc::Request; mod run_miner; +mod shared_dataset; +mod stats_store; + use run_miner::start_miner; use tari_common::exit_codes::{ExitCode, ExitError}; diff --git a/applications/randomx_miner/src/main.rs b/applications/randomx_miner/src/main.rs index 5ece9813af..f990584541 100644 --- a/applications/randomx_miner/src/main.rs +++ b/applications/randomx_miner/src/main.rs @@ -39,6 +39,8 @@ mod error; use tari_common::exit_codes::ExitCode; mod json_rpc; use json_rpc::Request; +mod shared_dataset; +mod stats_store; mod config; diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index a079f89dc8..7b0ef682cb 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -21,14 +21,15 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ + sync::Arc, thread, time::{Duration, Instant}, }; use dialoguer::Input as InputPrompt; -use log::{debug, info, warn}; +use log::{debug, info}; use minotari_app_utilities::parse_miner_input::process_quit; -use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; +use randomx_rs::RandomXFlag; use reqwest::Client as ReqwestClient; use tari_common::{load_configuration, DefaultConfigLoader}; use tari_core::proof_of_work::{ @@ -41,8 +42,10 @@ use tari_utilities::epoch_time::EpochTime; use crate::{ cli::Cli, config::RandomXMinerConfig, - error::{ConfigError, DatasetError, Error, MiningError, MiningError::TokioRuntime}, + error::{ConfigError, Error, MiningError, MiningError::TokioRuntime}, json_rpc::{get_block_count::get_block_count, get_block_template::get_block_template, submit_block::submit_block}, + shared_dataset::SharedDataset, + stats_store::StatsStore, }; pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; @@ -64,6 +67,8 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; let randomx_factory = RandomXFactory::new_with_flags(num_threads, flags); + let shared_dataset = Arc::new(SharedDataset::default()); + let stats_store = Arc::new(StatsStore::new()); info!(target: LOG_TARGET, "Starting {} threads", num_threads); let mut threads = vec![]; @@ -73,8 +78,19 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let node_address = node_address.clone(); let monero_wallet_address = monero_wallet_address.clone(); let randomx_factory = randomx_factory.clone(); + let dataset = shared_dataset.clone(); + let ss = stats_store.clone(); threads.push(thread::spawn(move || { - thread_work(&rclient, &node_address, &monero_wallet_address, &randomx_factory) + thread_work( + num_threads, + i, + &rclient, + &node_address, + &monero_wallet_address, + &randomx_factory, + dataset, + ss, + ) })); } @@ -88,10 +104,14 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { } fn thread_work<'a>( + num_threads: usize, + thread_number: usize, client: &ReqwestClient, node_address: &'a str, monero_wallet_address: &'a str, randomx_factory: &RandomXFactory, + shared_dataset: Arc, + stats_store: Arc, ) -> Result<(), MiningError> { let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; let flags = randomx_factory.get_flags()?; @@ -102,47 +122,27 @@ fn thread_work<'a>( let key = hex::decode(&block_template.seed_hash)?; - debug!(target: LOG_TARGET, "Initializing cache"); - let (flags, cache) = match RandomXCache::new(flags, &key) { - Ok(cache) => (flags, cache), - Err(err) => { - warn!( - target: LOG_TARGET, - "Error initializing RandomX cache with flags {:?}. {:?}. Fallback to default flags", flags, err - ); - // This is informed by how RandomX falls back on any cache allocation failure - // https://github.com/xmrig/xmrig/blob/02b2b87bb685ab83b132267aa3c2de0766f16b8b/src/crypto/rx/RxCache.cpp#L88 - let flags = RandomXFlag::FLAG_DEFAULT; - let cache = RandomXCache::new(flags, &key)?; - (flags, cache) - }, - }; - - debug!(target: LOG_TARGET, "Initializing dataset"); - let dataset = RandomXDataset::new(flags, cache.clone(), 0)?; + debug!(target: LOG_TARGET, "Initializing dataset and cache"); + let (dataset, cache) = shared_dataset.fetch_or_create_dataset(hex::encode(&key), flags)?; let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; - let mut count = 0u32; - let start_time = Instant::now(); - let mut last_check_time = start_time; + let mut nonce = thread_number; + let mut last_check_time = Instant::now(); let mut max_difficulty_reached = 0; debug!(target: LOG_TARGET, "Mining now"); loop { - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), count, vm.clone())?; - - let now = Instant::now(); - let elapsed_since_last_check = now.duration_since(last_check_time); + stats_store.start(); + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), nonce as u32, vm.clone())?; + stats_store.inc_hashed_count(); + let elapsed_since_last_check = Instant::now().duration_since(last_check_time); if elapsed_since_last_check >= Duration::from_secs(2) { - let total_elapsed_time = now.duration_since(start_time).as_secs_f64(); - let hash_rate = count as f64 / total_elapsed_time; - info!( "Hash Rate: {:.2} H/s | Max difficulty reached: {}", - hash_rate, max_difficulty_reached + stats_store.hashes_per_second(), + max_difficulty_reached ); - - last_check_time = now; + last_check_time = Instant::now(); } if difficulty.as_u64() > max_difficulty_reached { @@ -162,18 +162,18 @@ fn thread_work<'a>( break; } - count += 1; + nonce += num_threads; } } } fn mining_cycle( mut blockhashing_bytes: Vec, - count: u32, + nonce: u32, vm: RandomXVMInstance, ) -> Result<(Difficulty, Vec), MiningError> { let nonce_position = 38; - blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&count.to_le_bytes()); + blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&nonce.to_le_bytes()); let timestamp_position = 8; let timestamp_bytes: [u8; 4] = (EpochTime::now().as_u64() as u32).to_le_bytes(); diff --git a/applications/randomx_miner/src/shared_dataset.rs b/applications/randomx_miner/src/shared_dataset.rs new file mode 100644 index 0000000000..e79769f5d9 --- /dev/null +++ b/applications/randomx_miner/src/shared_dataset.rs @@ -0,0 +1,95 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::sync::RwLock; + +use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; + +use crate::error::DatasetError; + +pub struct Dataset { + pub identifier: String, + pub dataset: RandomXDataset, + pub cache: RandomXCache, +} + +impl Dataset { + pub fn new(identifier: String, dataset: RandomXDataset, cache: RandomXCache) -> Self { + Self { + identifier, + dataset, + cache, + } + } +} + +// This allows us to share the randomx dataset across multiple threads. +#[derive(Default)] +pub struct SharedDataset { + pub inner: RwLock>, +} +unsafe impl Send for SharedDataset {} +unsafe impl Sync for SharedDataset {} + +impl SharedDataset { + pub fn fetch_or_create_dataset( + &self, + key: String, + flags: RandomXFlag, + ) -> Result<(RandomXDataset, RandomXCache), DatasetError> { + { + let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; + if let Some(existing_dataset) = read_guard.as_ref() { + if existing_dataset.identifier == key { + return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); + } + } + } // Read lock is released here + + { + let mut write_guard = self.inner.write().map_err(|e| DatasetError::WriteLock(e.to_string()))?; + + // Double-check the condition after acquiring the write lock to avoid race conditions. + if let Some(existing_dataset) = &*write_guard { + if existing_dataset.identifier == key { + return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); + } + } + + let cache = RandomXCache::new(flags, &hex::decode(key.clone())?)?; + let new_dataset = RandomXDataset::new(flags, cache.clone(), 0)?; + + // Step 4: Update the Option inside the RwLock with the new dataset. + *write_guard = Some(Dataset::new(key, new_dataset, cache)); + } + + // Step 5: Return the updated dataset wrapped in Arc. + { + let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; + if let Some(existing_dataset) = read_guard.as_ref() { + return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); + }; + } + + Err(DatasetError::DatasetNotFound) + } +} diff --git a/applications/randomx_miner/src/stats_store.rs b/applications/randomx_miner/src/stats_store.rs new file mode 100644 index 0000000000..4c6ea561d9 --- /dev/null +++ b/applications/randomx_miner/src/stats_store.rs @@ -0,0 +1,55 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use std::sync::atomic::{AtomicU64, Ordering}; + +use tari_utilities::epoch_time::EpochTime; + +/// Stats store stores statistics about running miner in memory. +pub struct StatsStore { + start_time: AtomicU64, + hashed_count: AtomicU64, +} + +impl StatsStore { + pub fn new() -> Self { + Self { + start_time: AtomicU64::new(0), + hashed_count: AtomicU64::new(0), + } + } + + pub fn start(&self) { + if self.start_time.load(Ordering::SeqCst) == 0 { + self.start_time.swap(EpochTime::now().as_u64(), Ordering::SeqCst); + } + } + + pub fn hashes_per_second(&self) -> u64 { + let elapsed = EpochTime::now().as_u64() - self.start_time.load(Ordering::SeqCst); + self.hashed_count.load(Ordering::SeqCst) / elapsed + } + + pub fn inc_hashed_count(&self) { + self.hashed_count.fetch_add(1, Ordering::SeqCst); + } +} From c9fc64f66594ba2eb240e901385f149449ad71ec Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 4 Sep 2024 17:35:05 +0200 Subject: [PATCH 17/32] Better bail out for new templates --- applications/randomx_miner/src/config.rs | 7 ++- applications/randomx_miner/src/run_miner.rs | 53 +++++++++++++-------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs index a8016b225d..4027ca1667 100644 --- a/applications/randomx_miner/src/config.rs +++ b/applications/randomx_miner/src/config.rs @@ -26,7 +26,7 @@ use std::path::{Path, PathBuf}; use serde::{Deserialize, Serialize}; use tari_common::{configuration::Network, SubConfigPath}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct RandomXMinerConfig { /// The address for the monero node, or merge mining proxy @@ -43,9 +43,11 @@ pub struct RandomXMinerConfig { pub config_dir: PathBuf, /// Number of mining threads pub num_mining_threads: usize, + /// How long to wait before checking for a new template in milliseconds + pub template_refresh_interval_ms: u64, } -#[derive(Serialize, Deserialize, Debug, Default, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Clone)] pub enum MiningMode { #[default] Eco, @@ -68,6 +70,7 @@ impl Default for RandomXMinerConfig { network: Default::default(), config_dir: PathBuf::from("config/randomx_miner"), num_mining_threads: num_cpus::get(), + template_refresh_interval_ms: 500, } } } diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 7b0ef682cb..8afeb717b0 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -68,28 +68,30 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; let randomx_factory = RandomXFactory::new_with_flags(num_threads, flags); let shared_dataset = Arc::new(SharedDataset::default()); - let stats_store = Arc::new(StatsStore::new()); + let stats_store = Arc::new(StatsStore::new(num_threads)); info!(target: LOG_TARGET, "Starting {} threads", num_threads); let mut threads = vec![]; - for i in 0..num_threads { + for thread_index in 0..num_threads { let rclient = client.clone(); let node_address = node_address.clone(); let monero_wallet_address = monero_wallet_address.clone(); let randomx_factory = randomx_factory.clone(); let dataset = shared_dataset.clone(); - let ss = stats_store.clone(); + let stats = stats_store.clone(); + let config = config.clone(); threads.push(thread::spawn(move || { thread_work( num_threads, - i, + thread_index, &rclient, &node_address, &monero_wallet_address, &randomx_factory, dataset, - ss, + stats, + config, ) })); } @@ -112,6 +114,7 @@ fn thread_work<'a>( randomx_factory: &RandomXFactory, shared_dataset: Arc, stats_store: Arc, + config: RandomXMinerConfig, ) -> Result<(), MiningError> { let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; let flags = randomx_factory.get_flags()?; @@ -122,35 +125,43 @@ fn thread_work<'a>( let key = hex::decode(&block_template.seed_hash)?; - debug!(target: LOG_TARGET, "Initializing dataset and cache"); - let (dataset, cache) = shared_dataset.fetch_or_create_dataset(hex::encode(&key), flags)?; + let (dataset, cache) = shared_dataset.fetch_or_create_dataset(hex::encode(&key), flags, thread_number)?; let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; let mut nonce = thread_number; - let mut last_check_time = Instant::now(); + let mut stats_last_check_time = Instant::now(); let mut max_difficulty_reached = 0; - debug!(target: LOG_TARGET, "Mining now"); + debug!(target: LOG_TARGET, "Thread {} ⛏️ Mining now", thread_number); + stats_store.start(); + let start = Instant::now(); loop { - stats_store.start(); - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), nonce as u32, vm.clone())?; - stats_store.inc_hashed_count(); - - let elapsed_since_last_check = Instant::now().duration_since(last_check_time); - if elapsed_since_last_check >= Duration::from_secs(2) { - info!( - "Hash Rate: {:.2} H/s | Max difficulty reached: {}", - stats_store.hashes_per_second(), - max_difficulty_reached + if start.elapsed().as_secs() >= config.template_refresh_interval_ms { + debug!( + target: LOG_TARGET, + "Thread {} had {}ms pass. Fetching new template to compare", + thread_number, config.template_refresh_interval_ms ); - last_check_time = Instant::now(); + let new_block_template = + runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; + + if new_block_template.blocktemplate_blob != block_template.blocktemplate_blob { + info!( + target: LOG_TARGET, + "Thead {} found detected template change. Restarting mining cycle", + thread_number + ); + break; + } } + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), nonce as u32, vm.clone())?; + stats_store.inc_hashed_count(); if difficulty.as_u64() > max_difficulty_reached { max_difficulty_reached = difficulty.as_u64(); } if difficulty.as_u64() >= block_template.difficulty { - info!("Valid block found!"); + info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; block_template_bytes[0..42].copy_from_slice(&hash[0..42]); From 8fa95657698e39c2037d87b9436940f08eae0dae Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 4 Sep 2024 17:36:04 +0200 Subject: [PATCH 18/32] Enhance logging and include thread index --- applications/randomx_miner/src/run_miner.rs | 5 +++ .../randomx_miner/src/shared_dataset.rs | 10 ++++-- applications/randomx_miner/src/stats_store.rs | 31 +++++++++++++++++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 8afeb717b0..ef17c7ce7b 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -159,6 +159,11 @@ fn thread_work<'a>( if difficulty.as_u64() > max_difficulty_reached { max_difficulty_reached = difficulty.as_u64(); } + let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); + if elapsed_since_last_check >= Duration::from_secs(2) { + info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, start.elapsed().as_secs(), max_difficulty_reached)); + stats_last_check_time = Instant::now(); + } if difficulty.as_u64() >= block_template.difficulty { info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); diff --git a/applications/randomx_miner/src/shared_dataset.rs b/applications/randomx_miner/src/shared_dataset.rs index e79769f5d9..83f19a923b 100644 --- a/applications/randomx_miner/src/shared_dataset.rs +++ b/applications/randomx_miner/src/shared_dataset.rs @@ -20,8 +20,11 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +pub const LOG_TARGET: &str = "minotari::randomx_miner::shared_dataset"; + use std::sync::RwLock; +use log::debug; use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; use crate::error::DatasetError; @@ -55,11 +58,13 @@ impl SharedDataset { &self, key: String, flags: RandomXFlag, + thread_number: usize, ) -> Result<(RandomXDataset, RandomXCache), DatasetError> { { let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; if let Some(existing_dataset) = read_guard.as_ref() { if existing_dataset.identifier == key { + debug!(target: LOG_TARGET, "Thread {} found existing dataset", thread_number); return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); } } @@ -71,6 +76,7 @@ impl SharedDataset { // Double-check the condition after acquiring the write lock to avoid race conditions. if let Some(existing_dataset) = &*write_guard { if existing_dataset.identifier == key { + debug!(target: LOG_TARGET, "Thread {} found existing dataset found after waiting for write lock", thread_number); return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); } } @@ -78,11 +84,11 @@ impl SharedDataset { let cache = RandomXCache::new(flags, &hex::decode(key.clone())?)?; let new_dataset = RandomXDataset::new(flags, cache.clone(), 0)?; - // Step 4: Update the Option inside the RwLock with the new dataset. *write_guard = Some(Dataset::new(key, new_dataset, cache)); + debug!(target: LOG_TARGET, "Thread {} created new dataset", thread_number); } - // Step 5: Return the updated dataset wrapped in Arc. + // Return the updated or created dataset { let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; if let Some(existing_dataset) = read_guard.as_ref() { diff --git a/applications/randomx_miner/src/stats_store.rs b/applications/randomx_miner/src/stats_store.rs index 4c6ea561d9..8278aac50e 100644 --- a/applications/randomx_miner/src/stats_store.rs +++ b/applications/randomx_miner/src/stats_store.rs @@ -28,13 +28,15 @@ use tari_utilities::epoch_time::EpochTime; pub struct StatsStore { start_time: AtomicU64, hashed_count: AtomicU64, + num_threads: usize, } impl StatsStore { - pub fn new() -> Self { + pub fn new(num_threads: usize) -> Self { Self { start_time: AtomicU64::new(0), hashed_count: AtomicU64::new(0), + num_threads, } } @@ -45,11 +47,34 @@ impl StatsStore { } pub fn hashes_per_second(&self) -> u64 { - let elapsed = EpochTime::now().as_u64() - self.start_time.load(Ordering::SeqCst); - self.hashed_count.load(Ordering::SeqCst) / elapsed + self.hashed_count.load(Ordering::SeqCst) / self.elapsed_time() } pub fn inc_hashed_count(&self) { self.hashed_count.fetch_add(1, Ordering::SeqCst); } + + pub fn start_time(&self) -> u64 { + self.start_time.load(Ordering::SeqCst) + } + + fn elapsed_time(&self) -> u64 { + EpochTime::now().as_u64() - self.start_time.load(Ordering::SeqCst) + } + + pub fn pretty_print( + &self, + thread_number: usize, + nonce: usize, + cycle_start: u64, + max_difficulty_reached: u64, + ) -> String { + format!( + "Thread {} Hash Rate: {:.2} H/s or Total Hash Rate: {:.2} H/s | Thread max difficulty reached: {}", + thread_number, + (nonce / self.num_threads) as u64 / cycle_start, + self.hashes_per_second(), + max_difficulty_reached + ) + } } From d4e57fa15f36aaa8b7be4f5fd6c170675a9d267b Mon Sep 17 00:00:00 2001 From: brianp Date: Wed, 4 Sep 2024 17:36:20 +0200 Subject: [PATCH 19/32] Remove unused includes --- applications/randomx_miner/src/json_rpc/get_block_count.rs | 3 +-- .../randomx_miner/src/json_rpc/get_block_template.rs | 6 +++--- applications/randomx_miner/src/json_rpc/mod.rs | 1 - applications/randomx_miner/src/run_miner.rs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/applications/randomx_miner/src/json_rpc/get_block_count.rs b/applications/randomx_miner/src/json_rpc/get_block_count.rs index 5a96960048..b7ccec8e27 100644 --- a/applications/randomx_miner/src/json_rpc/get_block_count.rs +++ b/applications/randomx_miner/src/json_rpc/get_block_count.rs @@ -42,7 +42,7 @@ pub struct BlockCount { pub status: String, } -pub async fn get_block_count(client: &Client, node_address: &String) -> Result { +pub async fn get_block_count(client: &Client, node_address: &str) -> Result { let response = client .post(format!("{}/json_rpc", &node_address.to_string())) .json(&Request::new("get_block_count", serde_json::Value::Null)) @@ -61,7 +61,6 @@ pub async fn get_block_count(client: &Client, node_address: &String) -> Result( +pub async fn get_block_template( client: &Client, - node_address: &'a str, - monero_wallet_address: &'a str, + node_address: &str, + monero_wallet_address: &str, ) -> Result { let response = client .post(format!("{}/json_rpc", node_address)) diff --git a/applications/randomx_miner/src/json_rpc/mod.rs b/applications/randomx_miner/src/json_rpc/mod.rs index bf5ea473af..d1fbe5abdb 100644 --- a/applications/randomx_miner/src/json_rpc/mod.rs +++ b/applications/randomx_miner/src/json_rpc/mod.rs @@ -22,7 +22,6 @@ use serde::Serialize; -pub mod get_block_count; pub mod get_block_template; pub mod submit_block; diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index ef17c7ce7b..38e362281d 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -43,7 +43,7 @@ use crate::{ cli::Cli, config::RandomXMinerConfig, error::{ConfigError, Error, MiningError, MiningError::TokioRuntime}, - json_rpc::{get_block_count::get_block_count, get_block_template::get_block_template, submit_block::submit_block}, + json_rpc::{get_block_template::get_block_template, submit_block::submit_block}, shared_dataset::SharedDataset, stats_store::StatsStore, }; From 2f474cc6bd105404b0fa771a598bda07ddee23ed Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 5 Sep 2024 10:05:00 +0200 Subject: [PATCH 20/32] formatting --- applications/randomx_miner/src/run_miner.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 38e362281d..1a15135764 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -124,18 +124,18 @@ fn thread_work<'a>( let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; let key = hex::decode(&block_template.seed_hash)?; - let (dataset, cache) = shared_dataset.fetch_or_create_dataset(hex::encode(&key), flags, thread_number)?; - let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; + let mut nonce = thread_number; let mut stats_last_check_time = Instant::now(); let mut max_difficulty_reached = 0; + debug!(target: LOG_TARGET, "Thread {} ⛏️ Mining now", thread_number); stats_store.start(); - let start = Instant::now(); + let template_refresh_time = Instant::now(); loop { - if start.elapsed().as_secs() >= config.template_refresh_interval_ms { + if template_refresh_time.elapsed().as_secs() >= config.template_refresh_interval_ms { debug!( target: LOG_TARGET, "Thread {} had {}ms pass. Fetching new template to compare", @@ -153,15 +153,16 @@ fn thread_work<'a>( break; } } - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), nonce as u32, vm.clone())?; + stats_store.inc_hashed_count(); + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), nonce as u32, vm.clone())?; if difficulty.as_u64() > max_difficulty_reached { max_difficulty_reached = difficulty.as_u64(); } let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); if elapsed_since_last_check >= Duration::from_secs(2) { - info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, start.elapsed().as_secs(), max_difficulty_reached)); + info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, template_refresh_time.elapsed().as_secs(), max_difficulty_reached)); stats_last_check_time = Instant::now(); } From 31f47b62d463b16dea977833e1062a9b4773d2c5 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 5 Sep 2024 10:08:04 +0200 Subject: [PATCH 21/32] machete --- Cargo.lock | 2 -- applications/randomx_miner/Cargo.toml | 2 -- 2 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6418adb616..0608325e03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5002,14 +5002,12 @@ dependencies = [ "hex", "log", "minotari_app_utilities", - "monero", "num_cpus", "randomx-rs", "reqwest 0.12.7", "serde", "serde_json", "tari_common", - "tari_comms", "tari_core", "tari_features", "tari_shutdown 1.3.0-pre.0 (git+https://github.com/tari-project/tari.git?tag=v1.3.0-pre.0)", diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index 2a0c0ab74e..9f8e70f182 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -13,7 +13,6 @@ default = [] [dependencies] minotari_app_utilities = { path = "../minotari_app_utilities", features = ["miner_input"] } tari_common = { path = "../../common" } -tari_comms = { path = "../../comms/core" } tari_core = { path = "../../base_layer/core" } tari_utilities = "0.7.0" @@ -23,7 +22,6 @@ crossterm = { version = "0.25.0" } dialoguer = { version = "0.11.0" } hex = "0.4.3" log = { version = "0.4", features = ["std"] } -monero = { version = "0.21.0" } num_cpus = "1.16" randomx-rs = { version = "1.3.0" } reqwest = { version = "0.12.7", features = ["json"] } From e8b1a2ee6d959b9cc0371914663afd6b8a10dfa3 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 5 Sep 2024 10:13:59 +0200 Subject: [PATCH 22/32] lints --- applications/randomx_miner/src/error.rs | 2 ++ applications/randomx_miner/src/run_miner.rs | 17 +++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs index be088c0f42..4a628057f1 100644 --- a/applications/randomx_miner/src/error.rs +++ b/applications/randomx_miner/src/error.rs @@ -74,6 +74,8 @@ pub enum MiningError { TokioRuntime(String), #[error("Dataset error: {0}")] Dataset(#[from] DatasetError), + #[error("TryFrom int error: {0}")] + TryFromInt(#[from] std::num::TryFromIntError), } #[derive(Debug, thiserror::Error)] diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 1a15135764..2665e220c0 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use std::{ + convert::TryFrom, sync::Arc, thread, time::{Duration, Instant}, @@ -155,7 +156,7 @@ fn thread_work<'a>( } stats_store.inc_hashed_count(); - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), nonce as u32, vm.clone())?; + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), u32::try_from(nonce)?, vm.clone())?; if difficulty.as_u64() > max_difficulty_reached { max_difficulty_reached = difficulty.as_u64(); @@ -193,7 +194,7 @@ fn mining_cycle( blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&nonce.to_le_bytes()); let timestamp_position = 8; - let timestamp_bytes: [u8; 4] = (EpochTime::now().as_u64() as u32).to_le_bytes(); + let timestamp_bytes: [u8; 4] = u32::try_from(EpochTime::now().as_u64())?.to_le_bytes(); blockhashing_bytes[timestamp_position..timestamp_position + 4].copy_from_slice(×tamp_bytes); let hash = vm.calculate_hash(&blockhashing_bytes)?; @@ -210,15 +211,15 @@ fn monero_base_node_address(cli: &Cli, config: &RandomXMinerConfig) -> Result::new() .with_prompt("Please enter the 'monero-base-node-address' ('quit' or 'exit' to quit) ") .interact() .unwrap(); process_quit(&base_node); Some(base_node.trim().to_string()) - } else { - None } }) .ok_or(ConfigError::MissingBaseNode)?; @@ -235,15 +236,15 @@ fn monero_wallet_address(cli: &Cli, config: &RandomXMinerConfig) -> Result::new() .with_prompt("Please enter the 'monero-wallet-address' ('quit' or 'exit' to quit) ") .interact() .unwrap(); process_quit(&address); Some(address.trim().to_string()) - } else { - None } }) .ok_or(ConfigError::MissingMoneroWalletAddress)?; From cdc2e62e3d94d4d9d61fecc1296162fc486dbc34 Mon Sep 17 00:00:00 2001 From: brianp Date: Thu, 5 Sep 2024 10:38:24 +0200 Subject: [PATCH 23/32] tari deps version bump --- Cargo.lock | 38 +++++++++++---------------- applications/randomx_miner/Cargo.toml | 4 +-- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0608325e03..df872ce3c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3430,7 +3430,7 @@ dependencies = [ "tari_contacts", "tari_crypto", "tari_p2p", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_utilities", "thiserror", "tokio", @@ -3479,7 +3479,7 @@ dependencies = [ "tari_max_size", "tari_p2p", "tari_script", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_utilities", "thiserror", "tokio", @@ -3658,7 +3658,7 @@ dependencies = [ "tari_metrics", "tari_p2p", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_storage", "tari_utilities", "thiserror", @@ -3716,7 +3716,7 @@ dependencies = [ "tari_p2p", "tari_script", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_test_utils", "tari_utilities", "tempfile", @@ -3758,7 +3758,7 @@ dependencies = [ "tari_p2p", "tari_script", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_test_utils", "tari_utilities", "tempfile", @@ -5010,7 +5010,7 @@ dependencies = [ "tari_common", "tari_core", "tari_features", - "tari_shutdown 1.3.0-pre.0 (git+https://github.com/tari-project/tari.git?tag=v1.3.0-pre.0)", + "tari_shutdown", "tari_utilities", "thiserror", "tokio", @@ -6252,7 +6252,7 @@ dependencies = [ "tari_max_size", "tari_p2p", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_storage", "thiserror", ] @@ -6355,7 +6355,7 @@ dependencies = [ "tari_comms_rpc_macros", "tari_crypto", "tari_metrics", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6402,7 +6402,7 @@ dependencies = [ "tari_comms", "tari_comms_rpc_macros", "tari_crypto", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6453,7 +6453,7 @@ dependencies = [ "tari_max_size", "tari_p2p", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_test_utils", "tari_utilities", "tempfile", @@ -6526,7 +6526,7 @@ dependencies = [ "tari_p2p", "tari_script", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6615,7 +6615,7 @@ dependencies = [ "tari_key_manager", "tari_p2p", "tari_script", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_utilities", "tempfile", "thiserror", @@ -6739,7 +6739,7 @@ dependencies = [ "tari_comms_dht", "tari_crypto", "tari_service_framework", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_storage", "tari_test_utils", "tari_utilities", @@ -6779,7 +6779,7 @@ dependencies = [ "futures 0.3.29", "futures-test", "log", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tari_test_utils", "thiserror", "tokio", @@ -6795,14 +6795,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tari_shutdown" -version = "1.3.0-pre.0" -source = "git+https://github.com/tari-project/tari.git?tag=v1.3.0-pre.0#e73426904901b24d6c752d8cf456782893e999c1" -dependencies = [ - "futures 0.3.29", -] - [[package]] name = "tari_storage" version = "1.4.0-pre.0" @@ -6824,7 +6816,7 @@ dependencies = [ "futures-test", "rand", "tari_comms", - "tari_shutdown 1.3.0-pre.0", + "tari_shutdown", "tempfile", "tokio", ] diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index 9f8e70f182..3e9ec5b341 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -15,6 +15,7 @@ minotari_app_utilities = { path = "../minotari_app_utilities", features = ["mine tari_common = { path = "../../common" } tari_core = { path = "../../base_layer/core" } tari_utilities = "0.7.0" +tari_shutdown = { path = "../../infrastructure/shutdown" } clap = { version = "3.2", features = ["derive", "env"] } config = "0.14.0" @@ -27,9 +28,8 @@ randomx-rs = { version = "1.3.0" } reqwest = { version = "0.12.7", features = ["json"] } serde = { version = "1.0", default-features = false, features = ["derive"] } serde_json = "1.0" -tari_shutdown = { git = "https://github.com/tari-project/tari.git", tag = "v1.3.0-pre.0" } thiserror = "1.0.63" tokio = { version = "1.36", default-features = false, features = ["rt-multi-thread"] } [build-dependencies] -tari_features = { path = "../../common/tari_features", version = "1.3.0-pre.0" } \ No newline at end of file +tari_features = { path = "../../common/tari_features" } \ No newline at end of file From f3330aa9c343dc54c41d8a1d4276c6488cf74f72 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 09:22:58 +0200 Subject: [PATCH 24/32] Less noisy console --- applications/randomx_miner/log4rs_sample.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/randomx_miner/log4rs_sample.yml b/applications/randomx_miner/log4rs_sample.yml index 01b6630c1c..85ebd30c35 100644 --- a/applications/randomx_miner/log4rs_sample.yml +++ b/applications/randomx_miner/log4rs_sample.yml @@ -18,7 +18,7 @@ appenders: pattern: "{d(%H:%M)} {h({l}):5} {m}{n}" filters: - kind: threshold - level: debug + level: info randomx_miner: kind: rolling_file From a6c8f2238768876735df4153b4425dd0f9fc6ccb Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 09:24:15 +0200 Subject: [PATCH 25/32] Fix refresh limit --- applications/randomx_miner/src/config.rs | 2 +- applications/randomx_miner/src/run_miner.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs index 4027ca1667..6a88f30b1d 100644 --- a/applications/randomx_miner/src/config.rs +++ b/applications/randomx_miner/src/config.rs @@ -70,7 +70,7 @@ impl Default for RandomXMinerConfig { network: Default::default(), config_dir: PathBuf::from("config/randomx_miner"), num_mining_threads: num_cpus::get(), - template_refresh_interval_ms: 500, + template_refresh_interval_ms: 15000, } } } diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 2665e220c0..a68282282e 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -134,9 +134,11 @@ fn thread_work<'a>( debug!(target: LOG_TARGET, "Thread {} ⛏️ Mining now", thread_number); stats_store.start(); - let template_refresh_time = Instant::now(); + let mut template_refresh_time = Instant::now(); + let cycle_start = Instant::now(); loop { - if template_refresh_time.elapsed().as_secs() >= config.template_refresh_interval_ms { + if template_refresh_time.elapsed().as_millis() >= config.template_refresh_interval_ms as u128 { + template_refresh_time = Instant::now(); debug!( target: LOG_TARGET, "Thread {} had {}ms pass. Fetching new template to compare", @@ -148,7 +150,7 @@ fn thread_work<'a>( if new_block_template.blocktemplate_blob != block_template.blocktemplate_blob { info!( target: LOG_TARGET, - "Thead {} found detected template change. Restarting mining cycle", + "Thead {} detected template change. Restarting mining cycle", thread_number ); break; @@ -163,7 +165,7 @@ fn thread_work<'a>( } let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); if elapsed_since_last_check >= Duration::from_secs(2) { - info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, template_refresh_time.elapsed().as_secs(), max_difficulty_reached)); + info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, cycle_start.elapsed().as_secs(), max_difficulty_reached, block_template.difficulty)); stats_last_check_time = Instant::now(); } From 169c77c229f9c1da7ff05a11ec32774c520ac5c0 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 09:25:21 +0200 Subject: [PATCH 26/32] Use thread::scope to avoid cloning --- applications/randomx_miner/src/run_miner.rs | 54 +++++++++---------- applications/randomx_miner/src/stats_store.rs | 9 ++-- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index a68282282e..6adcdb88da 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -72,34 +72,32 @@ pub async fn start_miner(cli: Cli) -> Result<(), Error> { let stats_store = Arc::new(StatsStore::new(num_threads)); info!(target: LOG_TARGET, "Starting {} threads", num_threads); - let mut threads = vec![]; - - for thread_index in 0..num_threads { - let rclient = client.clone(); - let node_address = node_address.clone(); - let monero_wallet_address = monero_wallet_address.clone(); - let randomx_factory = randomx_factory.clone(); - let dataset = shared_dataset.clone(); - let stats = stats_store.clone(); - let config = config.clone(); - threads.push(thread::spawn(move || { - thread_work( - num_threads, - thread_index, - &rclient, - &node_address, - &monero_wallet_address, - &randomx_factory, - dataset, - stats, - config, - ) - })); - } - for t in threads { - t.join().unwrap()?; - } + thread::scope(|s| { + for thread_index in 0..num_threads { + let client = &client; + let node_address = &node_address; + let monero_wallet_address = &monero_wallet_address; + let randomx_factory = &randomx_factory; + let dataset = shared_dataset.clone(); + let stats = stats_store.clone(); + let config = &config; + + s.spawn(move || { + thread_work( + num_threads, + thread_index, + client, + node_address, + monero_wallet_address, + randomx_factory, + dataset, + stats, + config, + ) + }); + } + }); shutdown.trigger(); @@ -115,7 +113,7 @@ fn thread_work<'a>( randomx_factory: &RandomXFactory, shared_dataset: Arc, stats_store: Arc, - config: RandomXMinerConfig, + config: &RandomXMinerConfig, ) -> Result<(), MiningError> { let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; let flags = randomx_factory.get_flags()?; diff --git a/applications/randomx_miner/src/stats_store.rs b/applications/randomx_miner/src/stats_store.rs index 8278aac50e..a74ef3f691 100644 --- a/applications/randomx_miner/src/stats_store.rs +++ b/applications/randomx_miner/src/stats_store.rs @@ -68,13 +68,16 @@ impl StatsStore { nonce: usize, cycle_start: u64, max_difficulty_reached: u64, + difficulty: u64, ) -> String { format!( - "Thread {} Hash Rate: {:.2} H/s or Total Hash Rate: {:.2} H/s | Thread max difficulty reached: {}", + "Thread {} Hash Rate: {:.2} H/s of Total Hash Rate: {:.2} H/s | Thread max difficulty reached: {} | \ + Difficulty goal: {}", thread_number, - (nonce / self.num_threads) as u64 / cycle_start, + (nonce / self.num_threads) as u64 / cycle_start + 1, self.hashes_per_second(), - max_difficulty_reached + max_difficulty_reached, + difficulty ) } } From 7a08e4a42c91b632d7f49dd47bf242045adf24ab Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 09:26:17 +0200 Subject: [PATCH 27/32] Use unique keys when creating vms But use shared keys for caches and datasets. We use the key for local caching of the vms but this key is also passed to the cache naming. We need our cache to be unique but caches to be the shared. --- applications/randomx_miner/src/run_miner.rs | 11 +++++++-- .../core/src/proof_of_work/randomx_factory.rs | 23 ++++--------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 6adcdb88da..add7f76abb 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -123,8 +123,15 @@ fn thread_work<'a>( let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; let key = hex::decode(&block_template.seed_hash)?; - let (dataset, cache) = shared_dataset.fetch_or_create_dataset(hex::encode(&key), flags, thread_number)?; - let vm = randomx_factory.create(&key, Some(cache), Some(dataset))?; + let vm_key = key + .clone() + .into_iter() + .chain(thread_number.to_le_bytes()) + .collect::>(); // RandomXFactory uses the key for caching the VM, and it should be unique, but also the key for the cache and + // dataset can be shared + let (dataset, cache) = + shared_dataset.fetch_or_create_dataset(block_template.seed_hash, flags, thread_number)?; + let vm = randomx_factory.create(&vm_key, Some(cache), Some(dataset))?; let mut nonce = thread_number; let mut stats_last_check_time = Instant::now(); diff --git a/base_layer/core/src/proof_of_work/randomx_factory.rs b/base_layer/core/src/proof_of_work/randomx_factory.rs index 6ced8b201a..4f96871f0f 100644 --- a/base_layer/core/src/proof_of_work/randomx_factory.rs +++ b/base_layer/core/src/proof_of_work/randomx_factory.rs @@ -42,20 +42,15 @@ impl RandomXVMInstance { dataset: Option, ) -> Result { // Note: Memory required per VM in light mode is 256MB + + // Note: RandomXFlag::FULL_MEM and RandomXFlag::LARGE_PAGES are incompatible with + // light mode. These are not set by RandomX automatically even in fast mode. let cache = match cache { Some(c) => c, None => RandomXCache::new(flags, key)?, }; let vm = RandomXVM::new(flags, Some(cache), dataset)?; - // Note: No dataset is initialized here because we want to run in light mode. Only a cache - // is required by the VM for verification, giving it a dataset will only make the VM - // consume more memory than necessary. Dataset is currently an optional value as it may be - // useful at some point in future. - - // Note: RandomXFlag::FULL_MEM and RandomXFlag::LARGE_PAGES are incompatible with - // light mode. These are not set by RandomX automatically even in fast mode. - Ok(Self { #[allow(clippy::arc_with_non_send_sync)] instance: Arc::new(RwLock::new(vm)), @@ -189,16 +184,8 @@ impl RandomXFactoryInner { } if self.vms.len() >= self.max_vms { - let mut oldest_value = Instant::now(); - let mut oldest_key = None; - for (k, v) in &self.vms { - if v.0 < oldest_value { - oldest_key = Some(k.clone()); - oldest_value = v.0; - } - } - if let Some(k) = oldest_key { - self.vms.remove(&k); + if let Some(oldest_key) = self.vms.iter().min_by_key(|(_, (i, _))| *i).map(|(k, _)| k.clone()) { + self.vms.remove(&oldest_key); } } From 7b10c3c96d8c0ecdf8fa8692b5965b139fe7d542 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 09:28:11 +0200 Subject: [PATCH 28/32] Only report block found on success submit --- applications/randomx_miner/src/run_miner.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index add7f76abb..e681cd6e9f 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -175,15 +175,23 @@ fn thread_work<'a>( } if difficulty.as_u64() >= block_template.difficulty { - info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; block_template_bytes[0..42].copy_from_slice(&hash[0..42]); let block_hex = hex::encode(block_template_bytes.clone()); - runtime + match runtime .block_on(submit_block(client, node_address, block_hex)) - .map_err(MiningError::Request)?; + .map_err(MiningError::Request) + { + Ok(_) => { + debug!(target: LOG_TARGET, "Thread {} submitted block with hash: {} successfully", thread_number, hex::encode(&hash)); + info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); + }, + Err(e) => { + debug!(target: LOG_TARGET, "Thread {} failed to submit block: {}", thread_number, e); + }, + } break; } From f4bc93330c2ca778c5922e087b87dfc7ea584f7a Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 12:45:12 +0200 Subject: [PATCH 29/32] Ensure the right loops are broken Make sure the seed hash is checked and updated when needed. Ensure the block template is updated when needed. --- applications/randomx_miner/src/run_miner.rs | 136 ++++++++++-------- .../randomx_miner/src/shared_dataset.rs | 8 +- applications/randomx_miner/src/stats_store.rs | 3 +- 3 files changed, 79 insertions(+), 68 deletions(-) diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index e681cd6e9f..48a9943bd4 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -118,84 +118,96 @@ fn thread_work<'a>( let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; let flags = randomx_factory.get_flags()?; + // dataset control loop loop { - let block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; - let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; - - let key = hex::decode(&block_template.seed_hash)?; - let vm_key = key + let mut block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; + let seed_hash = block_template.seed_hash; + let vm_key = hex::decode(&seed_hash)? .clone() .into_iter() .chain(thread_number.to_le_bytes()) .collect::>(); // RandomXFactory uses the key for caching the VM, and it should be unique, but also the key for the cache and // dataset can be shared - let (dataset, cache) = - shared_dataset.fetch_or_create_dataset(block_template.seed_hash, flags, thread_number)?; + let (dataset, cache) = shared_dataset.fetch_or_create_dataset(seed_hash.clone(), flags, thread_number)?; let vm = randomx_factory.create(&vm_key, Some(cache), Some(dataset))?; - let mut nonce = thread_number; - let mut stats_last_check_time = Instant::now(); - let mut max_difficulty_reached = 0; - - debug!(target: LOG_TARGET, "Thread {} ⛏️ Mining now", thread_number); - stats_store.start(); - let mut template_refresh_time = Instant::now(); - let cycle_start = Instant::now(); - loop { - if template_refresh_time.elapsed().as_millis() >= config.template_refresh_interval_ms as u128 { - template_refresh_time = Instant::now(); - debug!( - target: LOG_TARGET, - "Thread {} had {}ms pass. Fetching new template to compare", - thread_number, config.template_refresh_interval_ms - ); - let new_block_template = - runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; - - if new_block_template.blocktemplate_blob != block_template.blocktemplate_blob { - info!( + // block template loop + 'template: loop { + // Fetch the block template again because dataset initialization takes a minute and the template could + // change in that time. + let block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; + + if seed_hash != block_template.seed_hash { + info!(target: LOG_TARGET, "Thread {} detected seed hash change. Reinitializing dataset", thread_number); + break 'template; + } + + let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; + + let mut nonce = thread_number; + let mut stats_last_check_time = Instant::now(); + let mut max_difficulty_reached = 0; + + debug!(target: LOG_TARGET, "Thread {} ⛏️ Mining now", thread_number); + stats_store.start(); + let mut template_refresh_time = Instant::now(); + let cycle_start = Instant::now(); + 'mining: loop { + if template_refresh_time.elapsed().as_millis() >= config.template_refresh_interval_ms as u128 { + template_refresh_time = Instant::now(); + debug!( target: LOG_TARGET, - "Thead {} detected template change. Restarting mining cycle", - thread_number + "Thread {} had {}ms pass. Fetching new template to compare", + thread_number, config.template_refresh_interval_ms ); - break; + let new_block_template = + runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; + + if new_block_template.blocktemplate_blob != block_template.blocktemplate_blob { + info!( + target: LOG_TARGET, + "Thead {} detected template change. Restarting mining cycle", + thread_number + ); + break 'mining; + } } - } - - stats_store.inc_hashed_count(); - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), u32::try_from(nonce)?, vm.clone())?; - if difficulty.as_u64() > max_difficulty_reached { - max_difficulty_reached = difficulty.as_u64(); - } - let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); - if elapsed_since_last_check >= Duration::from_secs(2) { - info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, cycle_start.elapsed().as_secs(), max_difficulty_reached, block_template.difficulty)); - stats_last_check_time = Instant::now(); - } + stats_store.inc_hashed_count(); + let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), u32::try_from(nonce)?, vm.clone())?; - if difficulty.as_u64() >= block_template.difficulty { - let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; - block_template_bytes[0..42].copy_from_slice(&hash[0..42]); - - let block_hex = hex::encode(block_template_bytes.clone()); - - match runtime - .block_on(submit_block(client, node_address, block_hex)) - .map_err(MiningError::Request) - { - Ok(_) => { - debug!(target: LOG_TARGET, "Thread {} submitted block with hash: {} successfully", thread_number, hex::encode(&hash)); - info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); - }, - Err(e) => { - debug!(target: LOG_TARGET, "Thread {} failed to submit block: {}", thread_number, e); - }, + if difficulty.as_u64() > max_difficulty_reached { + max_difficulty_reached = difficulty.as_u64(); + } + let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); + if elapsed_since_last_check >= Duration::from_secs(2) { + info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, cycle_start.elapsed().as_secs(), max_difficulty_reached, block_template.difficulty)); + stats_last_check_time = Instant::now(); } - break; + if difficulty.as_u64() >= block_template.difficulty { + let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; + block_template_bytes[0..42].copy_from_slice(&hash[0..42]); + + let block_hex = hex::encode(block_template_bytes.clone()); + + match runtime + .block_on(submit_block(client, node_address, block_hex)) + .map_err(MiningError::Request) + { + Ok(_) => { + debug!(target: LOG_TARGET, "Thread {} submitted block with hash: {} with difficulty: {} successfully", thread_number, hex::encode(&hash[0..42]), difficulty); + info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); + }, + Err(e) => { + debug!(target: LOG_TARGET, "Thread {} failed to submit block: {}", thread_number, e); + }, + } + + break 'mining; + } + nonce += num_threads; } - nonce += num_threads; } } } diff --git a/applications/randomx_miner/src/shared_dataset.rs b/applications/randomx_miner/src/shared_dataset.rs index 83f19a923b..6496e529cd 100644 --- a/applications/randomx_miner/src/shared_dataset.rs +++ b/applications/randomx_miner/src/shared_dataset.rs @@ -64,7 +64,7 @@ impl SharedDataset { let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; if let Some(existing_dataset) = read_guard.as_ref() { if existing_dataset.identifier == key { - debug!(target: LOG_TARGET, "Thread {} found existing dataset", thread_number); + debug!(target: LOG_TARGET, "Thread {} found existing dataset with seed {}", thread_number, &key); return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); } } @@ -76,7 +76,7 @@ impl SharedDataset { // Double-check the condition after acquiring the write lock to avoid race conditions. if let Some(existing_dataset) = &*write_guard { if existing_dataset.identifier == key { - debug!(target: LOG_TARGET, "Thread {} found existing dataset found after waiting for write lock", thread_number); + debug!(target: LOG_TARGET, "Thread {} found existing dataset with seed {} found after waiting for write lock", thread_number, &key); return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); } } @@ -84,8 +84,8 @@ impl SharedDataset { let cache = RandomXCache::new(flags, &hex::decode(key.clone())?)?; let new_dataset = RandomXDataset::new(flags, cache.clone(), 0)?; - *write_guard = Some(Dataset::new(key, new_dataset, cache)); - debug!(target: LOG_TARGET, "Thread {} created new dataset", thread_number); + *write_guard = Some(Dataset::new(key.clone(), new_dataset, cache)); + debug!(target: LOG_TARGET, "Thread {} created new dataset with seed {}", thread_number, key); } // Return the updated or created dataset diff --git a/applications/randomx_miner/src/stats_store.rs b/applications/randomx_miner/src/stats_store.rs index a74ef3f691..e045ca7d02 100644 --- a/applications/randomx_miner/src/stats_store.rs +++ b/applications/randomx_miner/src/stats_store.rs @@ -71,8 +71,7 @@ impl StatsStore { difficulty: u64, ) -> String { format!( - "Thread {} Hash Rate: {:.2} H/s of Total Hash Rate: {:.2} H/s | Thread max difficulty reached: {} | \ - Difficulty goal: {}", + "Thread {} Hash Rate: {:.2} H/s of Total Hash Rate: {:.2} H/s | Thread max difficulty reached: {} of {}", thread_number, (nonce / self.num_threads) as u64 / cycle_start + 1, self.hashes_per_second(), From f045a14bda5cd811a4846dfe7eaefc772a5b6231 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 14:26:43 +0200 Subject: [PATCH 30/32] Move blocking code out of the mining cycle - Moves the stats incrementer to cache a number of counts and write later instead of on each cycle - Starts a thread to watch the block template and notify the thread when it changes --- Cargo.lock | 2 +- applications/randomx_miner/Cargo.toml | 2 +- applications/randomx_miner/src/run_miner.rs | 79 +++++++++++++------ applications/randomx_miner/src/stats_store.rs | 4 + 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df872ce3c0..e051e85e38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4993,7 +4993,7 @@ dependencies = [ [[package]] name = "randomx_miner" -version = "1.3.0-pre.0" +version = "1.4.0-pre.0" dependencies = [ "clap 3.2.25", "config", diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml index 3e9ec5b341..6e73ff294e 100644 --- a/applications/randomx_miner/Cargo.toml +++ b/applications/randomx_miner/Cargo.toml @@ -4,7 +4,7 @@ authors = ["The Tari Development Community"] description = "The Tari merge mining proxy for xmrig" repository = "https://github.com/tari-project/tari" license = "BSD-3-Clause" -version = "1.3.0-pre.0" +version = "1.4.0-pre.0" edition = "2018" [features] diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs index 48a9943bd4..eaab357d93 100644 --- a/applications/randomx_miner/src/run_miner.rs +++ b/applications/randomx_miner/src/run_miner.rs @@ -22,7 +22,7 @@ use std::{ convert::TryFrom, - sync::Arc, + sync::{atomic::AtomicBool, Arc}, thread, time::{Duration, Instant}, }; @@ -38,7 +38,6 @@ use tari_core::proof_of_work::{ Difficulty, }; use tari_shutdown::Shutdown; -use tari_utilities::epoch_time::EpochTime; use crate::{ cli::Cli, @@ -118,9 +117,19 @@ fn thread_work<'a>( let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; let flags = randomx_factory.get_flags()?; + let stop_flag = Arc::new(AtomicBool::new(false)); + + runtime.spawn(check_template( + client.clone(), + node_address.to_string(), + monero_wallet_address.to_string(), + config.template_refresh_interval_ms, + stop_flag.clone(), + )); + // dataset control loop loop { - let mut block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; + let block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; let seed_hash = block_template.seed_hash; let vm_key = hex::decode(&seed_hash)? .clone() @@ -142,7 +151,7 @@ fn thread_work<'a>( break 'template; } - let blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; + let mut blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; let mut nonce = thread_number; let mut stats_last_check_time = Instant::now(); @@ -152,37 +161,39 @@ fn thread_work<'a>( stats_store.start(); let mut template_refresh_time = Instant::now(); let cycle_start = Instant::now(); + let mut hash_count = 0u64; 'mining: loop { - if template_refresh_time.elapsed().as_millis() >= config.template_refresh_interval_ms as u128 { + if template_refresh_time.elapsed().as_millis() >= 500 { template_refresh_time = Instant::now(); - debug!( - target: LOG_TARGET, - "Thread {} had {}ms pass. Fetching new template to compare", - thread_number, config.template_refresh_interval_ms - ); - let new_block_template = - runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; - - if new_block_template.blocktemplate_blob != block_template.blocktemplate_blob { + + if stop_flag.load(std::sync::atomic::Ordering::Relaxed) { info!( target: LOG_TARGET, "Thead {} detected template change. Restarting mining cycle", thread_number ); + stop_flag.store(false, std::sync::atomic::Ordering::Relaxed); break 'mining; } } - stats_store.inc_hashed_count(); - let (difficulty, hash) = mining_cycle(blockhashing_bytes.clone(), u32::try_from(nonce)?, vm.clone())?; + let (difficulty, hash) = mining_cycle(&mut blockhashing_bytes, u32::try_from(nonce)?, vm.clone())?; + hash_count += 1; if difficulty.as_u64() > max_difficulty_reached { max_difficulty_reached = difficulty.as_u64(); } + let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); - if elapsed_since_last_check >= Duration::from_secs(2) { + // Add a little entropy on the check time to try and lower the frequency of threads attempting to update + // the AtomicU64 + let check_time = + Duration::from_secs(5) + Duration::from_millis((num_threads * 100 / thread_number) as u64); + if elapsed_since_last_check >= check_time { info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, cycle_start.elapsed().as_secs(), max_difficulty_reached, block_template.difficulty)); stats_last_check_time = Instant::now(); + stats_store.inc_hashed_count_by(hash_count); + hash_count = 0; } if difficulty.as_u64() >= block_template.difficulty { @@ -213,24 +224,46 @@ fn thread_work<'a>( } fn mining_cycle( - mut blockhashing_bytes: Vec, + blockhashing_bytes: &mut Vec, nonce: u32, vm: RandomXVMInstance, -) -> Result<(Difficulty, Vec), MiningError> { +) -> Result<(Difficulty, &Vec), MiningError> { let nonce_position = 38; blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&nonce.to_le_bytes()); - let timestamp_position = 8; - let timestamp_bytes: [u8; 4] = u32::try_from(EpochTime::now().as_u64())?.to_le_bytes(); - blockhashing_bytes[timestamp_position..timestamp_position + 4].copy_from_slice(×tamp_bytes); + // We could but we won't + // let timestamp_position = 8; + // let timestamp_bytes: [u8; 4] = u32::try_from(EpochTime::now().as_u64())?.to_le_bytes(); + // blockhashing_bytes[timestamp_position..timestamp_position + 4].copy_from_slice(×tamp_bytes); - let hash = vm.calculate_hash(&blockhashing_bytes)?; + let hash = vm.calculate_hash(blockhashing_bytes)?; // Check last byte of hash and see if it's over difficulty let difficulty = Difficulty::little_endian_difficulty(&hash)?; Ok((difficulty, blockhashing_bytes)) } +async fn check_template( + client: ReqwestClient, + node_address: String, + monero_wallet_address: String, + template_refresh_interval_ms: u64, + stop_flag: Arc, +) -> Result<(), Error> { + let mut block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; + + loop { + let new_block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; + + if block_template.blocktemplate_blob != new_block_template.blocktemplate_blob { + stop_flag.store(true, std::sync::atomic::Ordering::Relaxed); + block_template = new_block_template; + } + + tokio::time::sleep(Duration::from_millis(template_refresh_interval_ms)).await; + } +} + fn monero_base_node_address(cli: &Cli, config: &RandomXMinerConfig) -> Result { let monero_base_node_address = cli .monero_base_node_address diff --git a/applications/randomx_miner/src/stats_store.rs b/applications/randomx_miner/src/stats_store.rs index e045ca7d02..eceff36898 100644 --- a/applications/randomx_miner/src/stats_store.rs +++ b/applications/randomx_miner/src/stats_store.rs @@ -54,6 +54,10 @@ impl StatsStore { self.hashed_count.fetch_add(1, Ordering::SeqCst); } + pub fn inc_hashed_count_by(&self, count: u64) { + self.hashed_count.fetch_add(count, Ordering::SeqCst); + } + pub fn start_time(&self) -> u64 { self.start_time.load(Ordering::SeqCst) } From 6e743308186b14dd1858f86f57d6057d81015849 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 15:48:15 +0200 Subject: [PATCH 31/32] Remove the randomx miner application --- applications/randomx_miner/Cargo.toml | 35 -- applications/randomx_miner/README.md | 0 applications/randomx_miner/build.rs | 20 -- applications/randomx_miner/log4rs_sample.yml | 64 ---- applications/randomx_miner/src/cli.rs | 60 ---- applications/randomx_miner/src/config.rs | 114 ------- applications/randomx_miner/src/error.rs | 93 ------ .../src/json_rpc/get_block_count.rs | 72 ---- .../src/json_rpc/get_block_template.rs | 90 ----- .../randomx_miner/src/json_rpc/mod.rs | 45 --- .../src/json_rpc/submit_block.rs | 52 --- applications/randomx_miner/src/lib.rs | 47 --- applications/randomx_miner/src/main.rs | 74 ---- applications/randomx_miner/src/run_miner.rs | 315 ------------------ .../randomx_miner/src/shared_dataset.rs | 101 ------ applications/randomx_miner/src/stats_store.rs | 86 ----- 16 files changed, 1268 deletions(-) delete mode 100644 applications/randomx_miner/Cargo.toml delete mode 100644 applications/randomx_miner/README.md delete mode 100644 applications/randomx_miner/build.rs delete mode 100644 applications/randomx_miner/log4rs_sample.yml delete mode 100644 applications/randomx_miner/src/cli.rs delete mode 100644 applications/randomx_miner/src/config.rs delete mode 100644 applications/randomx_miner/src/error.rs delete mode 100644 applications/randomx_miner/src/json_rpc/get_block_count.rs delete mode 100644 applications/randomx_miner/src/json_rpc/get_block_template.rs delete mode 100644 applications/randomx_miner/src/json_rpc/mod.rs delete mode 100644 applications/randomx_miner/src/json_rpc/submit_block.rs delete mode 100644 applications/randomx_miner/src/lib.rs delete mode 100644 applications/randomx_miner/src/main.rs delete mode 100644 applications/randomx_miner/src/run_miner.rs delete mode 100644 applications/randomx_miner/src/shared_dataset.rs delete mode 100644 applications/randomx_miner/src/stats_store.rs diff --git a/applications/randomx_miner/Cargo.toml b/applications/randomx_miner/Cargo.toml deleted file mode 100644 index 6e73ff294e..0000000000 --- a/applications/randomx_miner/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "randomx_miner" -authors = ["The Tari Development Community"] -description = "The Tari merge mining proxy for xmrig" -repository = "https://github.com/tari-project/tari" -license = "BSD-3-Clause" -version = "1.4.0-pre.0" -edition = "2018" - -[features] -default = [] - -[dependencies] -minotari_app_utilities = { path = "../minotari_app_utilities", features = ["miner_input"] } -tari_common = { path = "../../common" } -tari_core = { path = "../../base_layer/core" } -tari_utilities = "0.7.0" -tari_shutdown = { path = "../../infrastructure/shutdown" } - -clap = { version = "3.2", features = ["derive", "env"] } -config = "0.14.0" -crossterm = { version = "0.25.0" } -dialoguer = { version = "0.11.0" } -hex = "0.4.3" -log = { version = "0.4", features = ["std"] } -num_cpus = "1.16" -randomx-rs = { version = "1.3.0" } -reqwest = { version = "0.12.7", features = ["json"] } -serde = { version = "1.0", default-features = false, features = ["derive"] } -serde_json = "1.0" -thiserror = "1.0.63" -tokio = { version = "1.36", default-features = false, features = ["rt-multi-thread"] } - -[build-dependencies] -tari_features = { path = "../../common/tari_features" } \ No newline at end of file diff --git a/applications/randomx_miner/README.md b/applications/randomx_miner/README.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/applications/randomx_miner/build.rs b/applications/randomx_miner/build.rs deleted file mode 100644 index f4bfd85de7..0000000000 --- a/applications/randomx_miner/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2024 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use tari_features::resolver::build_features; - -#[cfg(windows)] -fn main() { - build_features(); - use std::env; - println!("cargo:rerun-if-changed=icon.res"); - let mut path = env::current_dir().unwrap(); - path.push("icon.res"); - println!("cargo:rustc-link-arg={}", path.into_os_string().into_string().unwrap()); -} - -#[cfg(not(windows))] -pub fn main() { - build_features(); - // Build as usual -} diff --git a/applications/randomx_miner/log4rs_sample.yml b/applications/randomx_miner/log4rs_sample.yml deleted file mode 100644 index 85ebd30c35..0000000000 --- a/applications/randomx_miner/log4rs_sample.yml +++ /dev/null @@ -1,64 +0,0 @@ -# A sample log configuration file for running in release mode. By default, this configuration splits up log messages to -# three destinations: -# * Console: For log messages with level INFO and higher -# * log/randomx_miner/network.log: INFO-level logs related to the comms crate. This file will be quite busy since there -# are lots of P2P debug messages, and so this traffic is segregated from the application log messages -# * log/randomx_miner/base_layer.log: Non-comms related INFO-level messages and higher are logged into this file -# * log/randomx_miner/other.log: Third-party crates' messages will be logged here at an ERROR level -# -# See https://docs.rs/log4rs/0.8.3/log4rs/encode/pattern/index.html for deciphering the log pattern. The log format -# used in this sample configuration prints messages as: -# timestamp [target] LEVEL message -refresh_rate: 30 seconds -appenders: - # An appender named "stdout" that writes to file. - stdout: - kind: console - encoder: - pattern: "{d(%H:%M)} {h({l}):5} {m}{n}" - filters: - - kind: threshold - level: info - - randomx_miner: - kind: rolling_file - path: "{{log_dir}}/log/randomx_miner/randomx_miner.log" - policy: - kind: compound - trigger: - kind: size - limit: 200mb - roller: - kind: fixed_window - base: 1 - count: 50 - pattern: "{{log_dir}}/log/randomx_miner/randomx_miner.{}.log" - encoder: - pattern: "{d(%Y-%m-%d %H:%M:%S.%f)} [{t}] {l:5} {m}{n}" - -# root -root: - level: debug - appenders: - - stdout - - randomx_miner - -loggers: - h2: - level: info - appenders: - - stdout - - randomx_miner - additive: false - hyper: - level: info - appenders: - - stdout - - randomx_miner - additive: false - selectors: - level: error - appenders: - - stdout - - randomx_miner - additive: false \ No newline at end of file diff --git a/applications/randomx_miner/src/cli.rs b/applications/randomx_miner/src/cli.rs deleted file mode 100644 index 2acc556229..0000000000 --- a/applications/randomx_miner/src/cli.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use std::fmt::Debug; - -use clap::Parser; -use minotari_app_utilities::common_cli_args::CommonCliArgs; -use tari_common::configuration::{ConfigOverrideProvider, Network}; - -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -#[clap(propagate_version = true)] -pub struct Cli { - #[clap(flatten)] - pub common: CommonCliArgs, - #[clap(long, alias = "monero-base-node-address")] - pub monero_base_node_address: Option, - #[clap(long, alias = "monero-wallet-address")] - pub monero_wallet_address: Option, - #[clap(long, alias = "mine-until-height")] - pub mine_until_height: Option, - #[clap(long, alias = "max-blocks")] - pub miner_max_blocks: Option, - #[clap(long, alias = "min-difficulty")] - pub miner_min_diff: Option, - #[clap(long, alias = "max-difficulty")] - pub miner_max_diff: Option, - #[clap(short, long, alias = "non-interactive", env = "TARI_NON_INTERACTIVE")] - pub non_interactive_mode: bool, - #[clap(short = 't', long, alias = "num-mining-threads")] - pub num_mining_threads: Option, -} - -impl ConfigOverrideProvider for Cli { - fn get_config_property_overrides(&self, network: &mut Network) -> Vec<(String, String)> { - let mut overrides = self.common.get_config_property_overrides(network); - *network = self.common.network.unwrap_or(*network); - overrides.push(("randomx_miner.network".to_string(), network.to_string())); - overrides - } -} diff --git a/applications/randomx_miner/src/config.rs b/applications/randomx_miner/src/config.rs deleted file mode 100644 index 6a88f30b1d..0000000000 --- a/applications/randomx_miner/src/config.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Minotari Miner Node derives all -// configuration management - -use std::path::{Path, PathBuf}; - -use serde::{Deserialize, Serialize}; -use tari_common::{configuration::Network, SubConfigPath}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields)] -pub struct RandomXMinerConfig { - /// The address for the monero node, or merge mining proxy - pub monero_base_node_address: Option, - /// Monero wallet address - pub monero_wallet_address: Option, - /// An address to post hash results too - pub universe_address: Option, - /// What mode to run in, eco or max - pub mode: MiningMode, - /// Selected network - pub network: Network, - /// The relative path to store persistent config - pub config_dir: PathBuf, - /// Number of mining threads - pub num_mining_threads: usize, - /// How long to wait before checking for a new template in milliseconds - pub template_refresh_interval_ms: u64, -} - -#[derive(Serialize, Deserialize, Debug, Default, PartialEq, Clone)] -pub enum MiningMode { - #[default] - Eco, - Max, -} - -impl SubConfigPath for RandomXMinerConfig { - fn main_key_prefix() -> &'static str { - "randomx_miner" - } -} - -impl Default for RandomXMinerConfig { - fn default() -> Self { - Self { - monero_base_node_address: None, - monero_wallet_address: None, - universe_address: None, - mode: Default::default(), - network: Default::default(), - config_dir: PathBuf::from("config/randomx_miner"), - num_mining_threads: num_cpus::get(), - template_refresh_interval_ms: 15000, - } - } -} - -impl RandomXMinerConfig { - pub fn set_base_path>(&mut self, base_path: P) { - if !self.config_dir.is_absolute() { - self.config_dir = base_path.as_ref().join(self.config_dir.as_path()); - } - } -} - -#[cfg(test)] -mod test { - use config::Config; - use tari_common::DefaultConfigLoader; - - use crate::config::{MiningMode, RandomXMinerConfig}; - - #[test] - fn miner_configuration() { - const CONFIG: &str = r#" -[miner] -monero_wallet_address="44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A" -mode = "eco" -"#; - let mut cfg: Config = Config::default(); - #[allow(deprecated)] - cfg.merge(config::File::from_str(CONFIG, config::FileFormat::Toml)) - .unwrap(); - let config = RandomXMinerConfig::load_from(&cfg).expect("Failed to load config"); - assert_eq!(config.mode, MiningMode::Eco); - assert_eq!( - config.monero_wallet_address, - Some( - "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A" - .to_string() - ) - ); - } -} diff --git a/applications/randomx_miner/src/error.rs b/applications/randomx_miner/src/error.rs deleted file mode 100644 index 4a628057f1..0000000000 --- a/applications/randomx_miner/src/error.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error("Config error: {0}")] - Config(#[from] ConfigError), - #[error("Common config error: {0}")] - CommonConfig(#[from] tari_common::configuration::error::ConfigError), - #[error("Reqwest error: {0}")] - Reqwest(#[from] reqwest::Error), - #[error("Request error: {0}")] - Request(#[from] RequestError), - #[error("Mining cycle error: {0}")] - Mining(#[from] MiningError), -} - -#[derive(Debug, thiserror::Error)] -pub enum ConfigError { - #[error("Missing base node or proxy address")] - MissingBaseNode, - #[error("Missing monero wallet address")] - MissingMoneroWalletAddress, - #[error("Common config error: {0}")] - CommonConfig(#[from] tari_common::configuration::error::ConfigError), -} - -#[derive(Debug, thiserror::Error)] -pub enum RequestError { - #[error("Failed to process request `get_block_count`: {0}")] - GetBlockCount(String), - #[error("Failed to process request `get_block_template`: {0}")] - GetBlockTemplate(String), - #[error("Failed to process request `submit_block`: {0}")] - SubmitBlock(String), -} - -#[derive(Debug, thiserror::Error)] -pub enum MiningError { - #[error("DifficultyError`: {0}")] - Difficulty(#[from] tari_core::proof_of_work::DifficultyError), - #[error("RandomXVMFactoryError`: {0}")] - RandomXVMFactory(#[from] tari_core::proof_of_work::randomx_factory::RandomXVMFactoryError), - #[error("HexError`: {0}")] - Hex(#[from] tari_utilities::hex::HexError), - #[error("FromHexError`: {0}")] - FromHex(#[from] hex::FromHexError), - #[error("MergeMineError`: {0}")] - MergeMine(#[from] tari_core::proof_of_work::monero_rx::MergeMineError), - #[error("Request error: {0}")] - Request(#[from] RequestError), - #[error("RandomXError: {0}")] - RandomX(#[from] randomx_rs::RandomXError), - #[error("Tokio runtime error: {0}")] - TokioRuntime(String), - #[error("Dataset error: {0}")] - Dataset(#[from] DatasetError), - #[error("TryFrom int error: {0}")] - TryFromInt(#[from] std::num::TryFromIntError), -} - -#[derive(Debug, thiserror::Error)] -pub enum DatasetError { - #[error("Read lock error: {0}")] - ReadLock(String), - #[error("Write lock error: {0}")] - WriteLock(String), - #[error("RandomXError: {0}")] - RandomX(#[from] randomx_rs::RandomXError), - #[error("Dataset could not be found or created")] - DatasetNotFound, - #[error("FromHexError`: {0}")] - FromHex(#[from] hex::FromHexError), -} diff --git a/applications/randomx_miner/src/json_rpc/get_block_count.rs b/applications/randomx_miner/src/json_rpc/get_block_count.rs deleted file mode 100644 index b7ccec8e27..0000000000 --- a/applications/randomx_miner/src/json_rpc/get_block_count.rs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use log::{debug, error}; -use reqwest::Client; -use serde::Deserialize; - -use crate::{error::RequestError, Request}; - -pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::get_block_count"; - -#[allow(dead_code)] // jsonrpc and id fields -#[derive(Deserialize, Debug)] -pub struct GetBlockCountResponse { - jsonrpc: String, - id: String, - pub result: BlockCount, -} - -#[derive(Deserialize, Debug)] -pub struct BlockCount { - pub count: u64, - pub status: String, -} - -pub async fn get_block_count(client: &Client, node_address: &str) -> Result { - let response = client - .post(format!("{}/json_rpc", &node_address.to_string())) - .json(&Request::new("get_block_count", serde_json::Value::Null)) - .send() - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - RequestError::GetBlockCount(e.to_string()) - })? - .json::() - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - RequestError::GetBlockCount(e.to_string()) - })?; - debug!(target: LOG_TARGET, "`get_block_count` Response: {:?}", response); - - if response.result.status == "OK" { - Ok(response.result.count) - } else { - debug!(target: LOG_TARGET, "Failed to get the block count. Status: {}", response.result.status); - Err(RequestError::GetBlockCount(format!( - "Failed to get the block count. Status: {}", - response.result.status - ))) - } -} diff --git a/applications/randomx_miner/src/json_rpc/get_block_template.rs b/applications/randomx_miner/src/json_rpc/get_block_template.rs deleted file mode 100644 index 394584e854..0000000000 --- a/applications/randomx_miner/src/json_rpc/get_block_template.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use log::{debug, error}; -use reqwest::Client; -use serde::Deserialize; -use serde_json::json; - -use crate::{error::RequestError, Request}; - -pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::get_block_template"; - -#[allow(dead_code)] // jsonrpc and id fields -#[derive(Deserialize, Debug)] -pub struct GetBlockTemplateResponse { - jsonrpc: String, - id: String, - pub result: BlockTemplate, -} - -#[allow(dead_code)] // not all fields are used currently -#[derive(Deserialize, Debug, Clone)] -pub struct BlockTemplate { - pub blocktemplate_blob: String, - pub blockhashing_blob: String, - pub difficulty: u64, - pub height: u64, - pub prev_hash: String, - pub reserved_offset: u64, - pub seed_hash: String, - pub status: String, -} - -pub async fn get_block_template( - client: &Client, - node_address: &str, - monero_wallet_address: &str, -) -> Result { - let response = client - .post(format!("{}/json_rpc", node_address)) - .json(&Request::new( - "get_block_template", - json!({ - "wallet_address": monero_wallet_address, - "reserve_size": 60, - }), - )) - .send() - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - RequestError::GetBlockTemplate(e.to_string()) - })? - .json::() - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - RequestError::GetBlockTemplate(e.to_string()) - })?; - debug!(target: LOG_TARGET, "`get_block_template` Response: {:?}", response); - - if response.result.status == "OK" { - Ok(response.result) - } else { - debug!(target: LOG_TARGET, "Failed to get the block template. Status: {}", response.result.status); - Err(RequestError::GetBlockCount(format!( - "Failed to get the block template. Status: {}", - response.result.status - ))) - } -} diff --git a/applications/randomx_miner/src/json_rpc/mod.rs b/applications/randomx_miner/src/json_rpc/mod.rs deleted file mode 100644 index d1fbe5abdb..0000000000 --- a/applications/randomx_miner/src/json_rpc/mod.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use serde::Serialize; - -pub mod get_block_template; -pub mod submit_block; - -#[derive(Serialize)] -pub struct Request<'a> { - jsonrpc: &'a str, - id: &'a str, - method: &'a str, - params: serde_json::Value, -} - -impl Request<'_> { - pub fn new(method: &str, params: serde_json::Value) -> Request { - Request { - jsonrpc: "2.0", - id: "0", - method, - params, - } - } -} diff --git a/applications/randomx_miner/src/json_rpc/submit_block.rs b/applications/randomx_miner/src/json_rpc/submit_block.rs deleted file mode 100644 index de1e09c9d5..0000000000 --- a/applications/randomx_miner/src/json_rpc/submit_block.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use log::{debug, error}; -use reqwest::Client; -use serde_json::json; - -use crate::{error::RequestError, json_rpc::Request}; - -pub const LOG_TARGET: &str = "minotari::randomx_miner::json_rpc::submit_block"; - -pub async fn submit_block<'a>(client: &Client, node_address: &'a str, block_hash: String) -> Result<(), RequestError> { - let response = client - .post(format!("{}/json_rpc", &node_address.to_string())) - .json(&Request::new("submitblock", json!([block_hash]))) - .send() - .await - .map_err(|e| { - error!(target: LOG_TARGET, "Reqwest error: {:?}", e); - RequestError::SubmitBlock(e.to_string()) - })?; - debug!(target: LOG_TARGET, "`submit_block` Response: {:?}", response); - - if response.status().is_success() { - Ok(()) - } else { - debug!(target: LOG_TARGET, "Failed to get the block template. {:?}", response); - Err(RequestError::SubmitBlock(format!( - "Failed to get the block template. Status: {:?}", - response - ))) - } -} diff --git a/applications/randomx_miner/src/lib.rs b/applications/randomx_miner/src/lib.rs deleted file mode 100644 index 04a8861fef..0000000000 --- a/applications/randomx_miner/src/lib.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -mod cli; -use cli::Cli; -mod config; -mod error; -pub use error::{ConfigError, Error}; -mod json_rpc; -pub use json_rpc::Request; -mod run_miner; -mod shared_dataset; -mod stats_store; - -use run_miner::start_miner; -use tari_common::exit_codes::{ExitCode, ExitError}; - -pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; -pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; - -// non-64-bit not supported -minotari_app_utilities::deny_non_64_bit_archs!(); - -pub async fn run_miner(cli: Cli) -> Result<(), ExitError> { - start_miner(cli) - .await - .map_err(|e| ExitError::new(ExitCode::UnknownError, e.to_string())) -} diff --git a/applications/randomx_miner/src/main.rs b/applications/randomx_miner/src/main.rs deleted file mode 100644 index f990584541..0000000000 --- a/applications/randomx_miner/src/main.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use std::io::stdout; - -use clap::Parser; -use crossterm::{execute, terminal::SetTitle}; -use log::*; -use minotari_app_utilities::consts; -use tari_common::{exit_codes::ExitError, initialize_logging}; - -pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; -pub const LOG_TARGET_FILE: &str = "minotari::logging::randomx_miner::main"; - -mod cli; -use cli::Cli; -mod run_miner; -use run_miner::start_miner; -mod error; -use tari_common::exit_codes::ExitCode; -mod json_rpc; -use json_rpc::Request; -mod shared_dataset; -mod stats_store; - -mod config; - -#[tokio::main] -async fn main() { - let terminal_title = format!("RandomX- Version {}", consts::APP_VERSION); - if let Err(e) = execute!(stdout(), SetTitle(terminal_title.as_str())) { - println!("Error setting terminal title. {}", e) - } - match main_inner().await { - Ok(_) => std::process::exit(0), - Err(err) => { - error!(target: LOG_TARGET, "Fatal error: {:?}", err); - let exit_code = err.exit_code; - error!(target: LOG_TARGET, "Exiting with code: {:?}", exit_code); - std::process::exit(exit_code as i32) - }, - } -} - -async fn main_inner() -> Result<(), ExitError> { - let cli = Cli::parse(); - initialize_logging( - &cli.common.log_config_path("randomx_miner"), - &cli.common.get_base_path(), - include_str!("../log4rs_sample.yml"), - )?; - start_miner(cli) - .await - .map_err(|e| ExitError::new(ExitCode::UnknownError, e.to_string())) -} diff --git a/applications/randomx_miner/src/run_miner.rs b/applications/randomx_miner/src/run_miner.rs deleted file mode 100644 index eaab357d93..0000000000 --- a/applications/randomx_miner/src/run_miner.rs +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use std::{ - convert::TryFrom, - sync::{atomic::AtomicBool, Arc}, - thread, - time::{Duration, Instant}, -}; - -use dialoguer::Input as InputPrompt; -use log::{debug, info}; -use minotari_app_utilities::parse_miner_input::process_quit; -use randomx_rs::RandomXFlag; -use reqwest::Client as ReqwestClient; -use tari_common::{load_configuration, DefaultConfigLoader}; -use tari_core::proof_of_work::{ - randomx_factory::{RandomXFactory, RandomXVMInstance}, - Difficulty, -}; -use tari_shutdown::Shutdown; - -use crate::{ - cli::Cli, - config::RandomXMinerConfig, - error::{ConfigError, Error, MiningError, MiningError::TokioRuntime}, - json_rpc::{get_block_template::get_block_template, submit_block::submit_block}, - shared_dataset::SharedDataset, - stats_store::StatsStore, -}; - -pub const LOG_TARGET: &str = "minotari::randomx_miner::main"; - -pub async fn start_miner(cli: Cli) -> Result<(), Error> { - let config_path = cli.common.config_path(); - let cfg = load_configuration(config_path.as_path(), true, cli.non_interactive_mode, &cli)?; - let mut config = RandomXMinerConfig::load_from(&cfg).expect("Failed to load config"); - config.set_base_path(cli.common.get_base_path()); - - let node_address = monero_base_node_address(&cli, &config)?; - let monero_wallet_address = monero_wallet_address(&cli, &config)?; - let num_threads = cli.num_mining_threads.unwrap_or(config.num_mining_threads); - - let mut shutdown = Shutdown::new(); - let client = ReqwestClient::new(); - - debug!(target: LOG_TARGET, "Starting new mining cycle"); - - let flags = RandomXFlag::get_recommended_flags() | RandomXFlag::FLAG_FULL_MEM; - let randomx_factory = RandomXFactory::new_with_flags(num_threads, flags); - let shared_dataset = Arc::new(SharedDataset::default()); - let stats_store = Arc::new(StatsStore::new(num_threads)); - - info!(target: LOG_TARGET, "Starting {} threads", num_threads); - - thread::scope(|s| { - for thread_index in 0..num_threads { - let client = &client; - let node_address = &node_address; - let monero_wallet_address = &monero_wallet_address; - let randomx_factory = &randomx_factory; - let dataset = shared_dataset.clone(); - let stats = stats_store.clone(); - let config = &config; - - s.spawn(move || { - thread_work( - num_threads, - thread_index, - client, - node_address, - monero_wallet_address, - randomx_factory, - dataset, - stats, - config, - ) - }); - } - }); - - shutdown.trigger(); - - Ok(()) -} - -fn thread_work<'a>( - num_threads: usize, - thread_number: usize, - client: &ReqwestClient, - node_address: &'a str, - monero_wallet_address: &'a str, - randomx_factory: &RandomXFactory, - shared_dataset: Arc, - stats_store: Arc, - config: &RandomXMinerConfig, -) -> Result<(), MiningError> { - let runtime = tokio::runtime::Runtime::new().map_err(|e| TokioRuntime(e.to_string()))?; - let flags = randomx_factory.get_flags()?; - - let stop_flag = Arc::new(AtomicBool::new(false)); - - runtime.spawn(check_template( - client.clone(), - node_address.to_string(), - monero_wallet_address.to_string(), - config.template_refresh_interval_ms, - stop_flag.clone(), - )); - - // dataset control loop - loop { - let block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; - let seed_hash = block_template.seed_hash; - let vm_key = hex::decode(&seed_hash)? - .clone() - .into_iter() - .chain(thread_number.to_le_bytes()) - .collect::>(); // RandomXFactory uses the key for caching the VM, and it should be unique, but also the key for the cache and - // dataset can be shared - let (dataset, cache) = shared_dataset.fetch_or_create_dataset(seed_hash.clone(), flags, thread_number)?; - let vm = randomx_factory.create(&vm_key, Some(cache), Some(dataset))?; - - // block template loop - 'template: loop { - // Fetch the block template again because dataset initialization takes a minute and the template could - // change in that time. - let block_template = runtime.block_on(get_block_template(client, node_address, monero_wallet_address))?; - - if seed_hash != block_template.seed_hash { - info!(target: LOG_TARGET, "Thread {} detected seed hash change. Reinitializing dataset", thread_number); - break 'template; - } - - let mut blockhashing_bytes = hex::decode(block_template.blockhashing_blob.clone())?; - - let mut nonce = thread_number; - let mut stats_last_check_time = Instant::now(); - let mut max_difficulty_reached = 0; - - debug!(target: LOG_TARGET, "Thread {} ⛏️ Mining now", thread_number); - stats_store.start(); - let mut template_refresh_time = Instant::now(); - let cycle_start = Instant::now(); - let mut hash_count = 0u64; - 'mining: loop { - if template_refresh_time.elapsed().as_millis() >= 500 { - template_refresh_time = Instant::now(); - - if stop_flag.load(std::sync::atomic::Ordering::Relaxed) { - info!( - target: LOG_TARGET, - "Thead {} detected template change. Restarting mining cycle", - thread_number - ); - stop_flag.store(false, std::sync::atomic::Ordering::Relaxed); - break 'mining; - } - } - - let (difficulty, hash) = mining_cycle(&mut blockhashing_bytes, u32::try_from(nonce)?, vm.clone())?; - hash_count += 1; - - if difficulty.as_u64() > max_difficulty_reached { - max_difficulty_reached = difficulty.as_u64(); - } - - let elapsed_since_last_check = Instant::now().duration_since(stats_last_check_time); - // Add a little entropy on the check time to try and lower the frequency of threads attempting to update - // the AtomicU64 - let check_time = - Duration::from_secs(5) + Duration::from_millis((num_threads * 100 / thread_number) as u64); - if elapsed_since_last_check >= check_time { - info!(target: LOG_TARGET, "{}", stats_store.pretty_print(thread_number, nonce, cycle_start.elapsed().as_secs(), max_difficulty_reached, block_template.difficulty)); - stats_last_check_time = Instant::now(); - stats_store.inc_hashed_count_by(hash_count); - hash_count = 0; - } - - if difficulty.as_u64() >= block_template.difficulty { - let mut block_template_bytes = hex::decode(&block_template.blocktemplate_blob)?; - block_template_bytes[0..42].copy_from_slice(&hash[0..42]); - - let block_hex = hex::encode(block_template_bytes.clone()); - - match runtime - .block_on(submit_block(client, node_address, block_hex)) - .map_err(MiningError::Request) - { - Ok(_) => { - debug!(target: LOG_TARGET, "Thread {} submitted block with hash: {} with difficulty: {} successfully", thread_number, hex::encode(&hash[0..42]), difficulty); - info!(target: LOG_TARGET, "Thread {} found a block! 🎉", thread_number); - }, - Err(e) => { - debug!(target: LOG_TARGET, "Thread {} failed to submit block: {}", thread_number, e); - }, - } - - break 'mining; - } - nonce += num_threads; - } - } - } -} - -fn mining_cycle( - blockhashing_bytes: &mut Vec, - nonce: u32, - vm: RandomXVMInstance, -) -> Result<(Difficulty, &Vec), MiningError> { - let nonce_position = 38; - blockhashing_bytes[nonce_position..nonce_position + 4].copy_from_slice(&nonce.to_le_bytes()); - - // We could but we won't - // let timestamp_position = 8; - // let timestamp_bytes: [u8; 4] = u32::try_from(EpochTime::now().as_u64())?.to_le_bytes(); - // blockhashing_bytes[timestamp_position..timestamp_position + 4].copy_from_slice(×tamp_bytes); - - let hash = vm.calculate_hash(blockhashing_bytes)?; - // Check last byte of hash and see if it's over difficulty - let difficulty = Difficulty::little_endian_difficulty(&hash)?; - - Ok((difficulty, blockhashing_bytes)) -} - -async fn check_template( - client: ReqwestClient, - node_address: String, - monero_wallet_address: String, - template_refresh_interval_ms: u64, - stop_flag: Arc, -) -> Result<(), Error> { - let mut block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; - - loop { - let new_block_template = get_block_template(&client, &node_address, &monero_wallet_address).await?; - - if block_template.blocktemplate_blob != new_block_template.blocktemplate_blob { - stop_flag.store(true, std::sync::atomic::Ordering::Relaxed); - block_template = new_block_template; - } - - tokio::time::sleep(Duration::from_millis(template_refresh_interval_ms)).await; - } -} - -fn monero_base_node_address(cli: &Cli, config: &RandomXMinerConfig) -> Result { - let monero_base_node_address = cli - .monero_base_node_address - .as_ref() - .cloned() - .or_else(|| config.monero_base_node_address.as_ref().cloned()) - .or_else(|| { - if cli.non_interactive_mode { - None - } else { - let base_node = InputPrompt::::new() - .with_prompt("Please enter the 'monero-base-node-address' ('quit' or 'exit' to quit) ") - .interact() - .unwrap(); - process_quit(&base_node); - Some(base_node.trim().to_string()) - } - }) - .ok_or(ConfigError::MissingBaseNode)?; - - info!(target: LOG_TARGET, "Using Monero node address: {}", &monero_base_node_address); - - Ok(monero_base_node_address) -} - -fn monero_wallet_address(cli: &Cli, config: &RandomXMinerConfig) -> Result { - let monero_wallet_address = cli - .monero_wallet_address - .as_ref() - .cloned() - .or_else(|| config.monero_wallet_address.as_ref().cloned()) - .or_else(|| { - if cli.non_interactive_mode { - None - } else { - let address = InputPrompt::::new() - .with_prompt("Please enter the 'monero-wallet-address' ('quit' or 'exit' to quit) ") - .interact() - .unwrap(); - process_quit(&address); - Some(address.trim().to_string()) - } - }) - .ok_or(ConfigError::MissingMoneroWalletAddress)?; - - info!(target: LOG_TARGET, "Mining to Monero wallet address: {}", &monero_wallet_address); - - Ok(monero_wallet_address) -} diff --git a/applications/randomx_miner/src/shared_dataset.rs b/applications/randomx_miner/src/shared_dataset.rs deleted file mode 100644 index 6496e529cd..0000000000 --- a/applications/randomx_miner/src/shared_dataset.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -pub const LOG_TARGET: &str = "minotari::randomx_miner::shared_dataset"; - -use std::sync::RwLock; - -use log::debug; -use randomx_rs::{RandomXCache, RandomXDataset, RandomXFlag}; - -use crate::error::DatasetError; - -pub struct Dataset { - pub identifier: String, - pub dataset: RandomXDataset, - pub cache: RandomXCache, -} - -impl Dataset { - pub fn new(identifier: String, dataset: RandomXDataset, cache: RandomXCache) -> Self { - Self { - identifier, - dataset, - cache, - } - } -} - -// This allows us to share the randomx dataset across multiple threads. -#[derive(Default)] -pub struct SharedDataset { - pub inner: RwLock>, -} -unsafe impl Send for SharedDataset {} -unsafe impl Sync for SharedDataset {} - -impl SharedDataset { - pub fn fetch_or_create_dataset( - &self, - key: String, - flags: RandomXFlag, - thread_number: usize, - ) -> Result<(RandomXDataset, RandomXCache), DatasetError> { - { - let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; - if let Some(existing_dataset) = read_guard.as_ref() { - if existing_dataset.identifier == key { - debug!(target: LOG_TARGET, "Thread {} found existing dataset with seed {}", thread_number, &key); - return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); - } - } - } // Read lock is released here - - { - let mut write_guard = self.inner.write().map_err(|e| DatasetError::WriteLock(e.to_string()))?; - - // Double-check the condition after acquiring the write lock to avoid race conditions. - if let Some(existing_dataset) = &*write_guard { - if existing_dataset.identifier == key { - debug!(target: LOG_TARGET, "Thread {} found existing dataset with seed {} found after waiting for write lock", thread_number, &key); - return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); - } - } - - let cache = RandomXCache::new(flags, &hex::decode(key.clone())?)?; - let new_dataset = RandomXDataset::new(flags, cache.clone(), 0)?; - - *write_guard = Some(Dataset::new(key.clone(), new_dataset, cache)); - debug!(target: LOG_TARGET, "Thread {} created new dataset with seed {}", thread_number, key); - } - - // Return the updated or created dataset - { - let read_guard = self.inner.read().map_err(|e| DatasetError::ReadLock(e.to_string()))?; - if let Some(existing_dataset) = read_guard.as_ref() { - return Ok((existing_dataset.dataset.clone(), existing_dataset.cache.clone())); - }; - } - - Err(DatasetError::DatasetNotFound) - } -} diff --git a/applications/randomx_miner/src/stats_store.rs b/applications/randomx_miner/src/stats_store.rs deleted file mode 100644 index eceff36898..0000000000 --- a/applications/randomx_miner/src/stats_store.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2024. The Tari Project -// -// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the -// following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following -// disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the -// following disclaimer in the documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote -// products derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -use std::sync::atomic::{AtomicU64, Ordering}; - -use tari_utilities::epoch_time::EpochTime; - -/// Stats store stores statistics about running miner in memory. -pub struct StatsStore { - start_time: AtomicU64, - hashed_count: AtomicU64, - num_threads: usize, -} - -impl StatsStore { - pub fn new(num_threads: usize) -> Self { - Self { - start_time: AtomicU64::new(0), - hashed_count: AtomicU64::new(0), - num_threads, - } - } - - pub fn start(&self) { - if self.start_time.load(Ordering::SeqCst) == 0 { - self.start_time.swap(EpochTime::now().as_u64(), Ordering::SeqCst); - } - } - - pub fn hashes_per_second(&self) -> u64 { - self.hashed_count.load(Ordering::SeqCst) / self.elapsed_time() - } - - pub fn inc_hashed_count(&self) { - self.hashed_count.fetch_add(1, Ordering::SeqCst); - } - - pub fn inc_hashed_count_by(&self, count: u64) { - self.hashed_count.fetch_add(count, Ordering::SeqCst); - } - - pub fn start_time(&self) -> u64 { - self.start_time.load(Ordering::SeqCst) - } - - fn elapsed_time(&self) -> u64 { - EpochTime::now().as_u64() - self.start_time.load(Ordering::SeqCst) - } - - pub fn pretty_print( - &self, - thread_number: usize, - nonce: usize, - cycle_start: u64, - max_difficulty_reached: u64, - difficulty: u64, - ) -> String { - format!( - "Thread {} Hash Rate: {:.2} H/s of Total Hash Rate: {:.2} H/s | Thread max difficulty reached: {} of {}", - thread_number, - (nonce / self.num_threads) as u64 / cycle_start + 1, - self.hashes_per_second(), - max_difficulty_reached, - difficulty - ) - } -} From 4cb9058bea33a9f4a8b031a185acc7ceccb09ec8 Mon Sep 17 00:00:00 2001 From: brianp Date: Fri, 6 Sep 2024 15:51:06 +0200 Subject: [PATCH 32/32] Remove remnamts --- .github/workflows/build_binaries.yml | 4 +- Cargo.lock | 405 +++------------------ Cargo.toml | 1 - common/config/presets/h_randomx_miner.toml | 16 - common/src/configuration/utils.rs | 5 +- 5 files changed, 48 insertions(+), 383 deletions(-) delete mode 100644 common/config/presets/h_randomx_miner.toml diff --git a/.github/workflows/build_binaries.yml b/.github/workflows/build_binaries.yml index 112ed7d9eb..aba532f474 100644 --- a/.github/workflows/build_binaries.yml +++ b/.github/workflows/build_binaries.yml @@ -22,7 +22,7 @@ env: TS_BUNDLE_ID_BASE: "com.tarilabs" TS_SIG_FN: "sha256-unsigned.txt" ## Must be a JSon string - TS_FILES: '["minotari_node","minotari_console_wallet","minotari_miner","minotari_merge_mining_proxy","randomx_miner"]' + TS_FILES: '["minotari_node","minotari_console_wallet","minotari_miner","minotari_merge_mining_proxy"]' TS_FEATURES: "default, safe" TS_LIBRARIES: "minotari_mining_helper_ffi" # For debug builds @@ -42,7 +42,7 @@ concurrency: group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}' cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/v') || github.ref != 'refs/heads/development' || github.ref != 'refs/heads/nextnet' || github.ref != 'refs/heads/stagenet' }} -permissions: {} +permissions: { } jobs: matrix-prep: diff --git a/Cargo.lock b/Cargo.lock index e051e85e38..1c6662159d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -211,12 +211,6 @@ dependencies = [ "syn 2.0.74", ] -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - [[package]] name = "atty" version = "0.2.14" @@ -254,9 +248,9 @@ dependencies = [ "bitflags 1.3.2", "bytes 1.5.0", "futures-util", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", + "http", + "http-body", + "hyper", "itoa", "matchit", "memchr", @@ -265,7 +259,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper 0.1.2", + "sync_wrapper", "tower", "tower-layer", "tower-service", @@ -280,8 +274,8 @@ dependencies = [ "async-trait", "bytes 1.5.0", "futures-util", - "http 0.2.9", - "http-body 0.4.5", + "http", + "http-body", "mime", "rustversion", "tower-layer", @@ -339,12 +333,6 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "base64-compat" version = "1.0.0" @@ -2294,26 +2282,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.9", - "indexmap 2.1.0", - "slab", - "tokio", - "tokio-util 0.7.10", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" -dependencies = [ - "atomic-waker", - "bytes 1.5.0", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", + "http", "indexmap 2.1.0", "slab", "tokio", @@ -2367,7 +2336,7 @@ dependencies = [ "base64 0.21.5", "bytes 1.5.0", "headers-core", - "http 0.2.9", + "http", "httpdate", "mime", "sha1 0.10.6", @@ -2379,7 +2348,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" dependencies = [ - "http 0.2.9", + "http", ] [[package]] @@ -2494,17 +2463,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes 1.5.0", - "fnv", - "itoa", -] - [[package]] name = "http-body" version = "0.4.5" @@ -2512,30 +2470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.5.0", - "http 0.2.9", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes 1.5.0", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes 1.5.0", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", "pin-project-lite", ] @@ -2576,9 +2511,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -2590,50 +2525,13 @@ dependencies = [ "want", ] -[[package]] -name = "hyper" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" -dependencies = [ - "bytes 1.5.0", - "futures-channel", - "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" -dependencies = [ - "futures-util", - "http 1.1.0", - "hyper 1.4.1", - "hyper-util", - "rustls 0.23.12", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.0", - "tower-service", -] - [[package]] name = "hyper-timeout" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.27", + "hyper", "pin-project-lite", "tokio", "tokio-io-timeout", @@ -2646,48 +2544,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes 1.5.0", - "hyper 0.14.27", + "hyper", "native-tls", "tokio", "tokio-native-tls", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes 1.5.0", - "http-body-util", - "hyper 1.4.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" -dependencies = [ - "bytes 1.5.0", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", - "pin-project-lite", - "socket2 0.5.5", - "tokio", - "tower", - "tower-service", - "tracing", -] - [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3458,7 +3320,7 @@ dependencies = [ "qrcode", "rand", "regex", - "reqwest 0.11.22", + "reqwest", "rpassword", "rustyline", "serde", @@ -3534,7 +3396,7 @@ dependencies = [ "crossterm 0.25.0", "futures 0.3.29", "hex", - "hyper 0.14.27", + "hyper", "jsonrpc", "log", "markup5ever", @@ -3543,7 +3405,7 @@ dependencies = [ "minotari_node_grpc_client", "minotari_wallet_grpc_client", "monero", - "reqwest 0.11.22", + "reqwest", "scraper", "serde", "serde_json", @@ -4991,31 +4853,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "randomx_miner" -version = "1.4.0-pre.0" -dependencies = [ - "clap 3.2.25", - "config", - "crossterm 0.25.0", - "dialoguer 0.11.0", - "hex", - "log", - "minotari_app_utilities", - "num_cpus", - "randomx-rs", - "reqwest 0.12.7", - "serde", - "serde_json", - "tari_common", - "tari_core", - "tari_features", - "tari_shutdown", - "tari_utilities", - "thiserror", - "tokio", -] - [[package]] name = "rayon" version = "1.8.0" @@ -5138,11 +4975,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper-tls 0.5.0", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", "ipnet", "js-sys", "log", @@ -5154,7 +4991,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "system-configuration 0.5.1", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -5165,49 +5002,6 @@ dependencies = [ "winreg", ] -[[package]] -name = "reqwest" -version = "0.12.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" -dependencies = [ - "base64 0.22.1", - "bytes 1.5.0", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.6", - "http 1.1.0", - "http-body 1.0.1", - "http-body-util", - "hyper 1.4.1", - "hyper-rustls", - "hyper-tls 0.6.0", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile 2.1.3", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper 1.0.1", - "system-configuration 0.6.1", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-registry", -] - [[package]] name = "rfc6979" version = "0.4.0" @@ -5354,19 +5148,6 @@ dependencies = [ "webpki", ] -[[package]] -name = "rustls" -version = "0.23.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - [[package]] name = "rustls-native-certs" version = "0.6.3" @@ -5397,33 +5178,6 @@ dependencies = [ "base64 0.21.5", ] -[[package]] -name = "rustls-pemfile" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" -dependencies = [ - "base64 0.22.1", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" - -[[package]] -name = "rustls-webpki" -version = "0.102.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" -dependencies = [ - "ring 0.17.5", - "rustls-pki-types", - "untrusted 0.9.0", -] - [[package]] name = "rustversion" version = "1.0.14" @@ -6097,15 +5851,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" -[[package]] -name = "sync_wrapper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" -dependencies = [ - "futures-core", -] - [[package]] name = "synstructure" version = "0.12.6" @@ -6159,18 +5904,7 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys 0.5.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.4.1", - "core-foundation", - "system-configuration-sys 0.6.0", + "system-configuration-sys", ] [[package]] @@ -6183,16 +5917,6 @@ dependencies = [ "libc", ] -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -6602,7 +6326,7 @@ dependencies = [ "minotari_wallet_ffi", "minotari_wallet_grpc_client", "rand", - "reqwest 0.11.22", + "reqwest", "serde_json", "tari_chat_client", "tari_common", @@ -6692,7 +6416,7 @@ dependencies = [ "log", "once_cell", "prometheus", - "reqwest 0.11.22", + "reqwest", "thiserror", "tokio", "warp", @@ -6730,8 +6454,8 @@ dependencies = [ "pgp", "prost", "rand", - "reqwest 0.11.22", - "rustls 0.20.9", + "reqwest", + "rustls", "semver", "serde", "tari_common", @@ -7084,22 +6808,11 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls 0.20.9", + "rustls", "tokio", "webpki", ] -[[package]] -name = "tokio-rustls" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" -dependencies = [ - "rustls 0.23.12", - "rustls-pki-types", - "tokio", -] - [[package]] name = "tokio-stream" version = "0.1.14" @@ -7233,10 +6946,10 @@ dependencies = [ "bytes 1.5.0", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", + "h2", + "http", + "http-body", + "hyper", "hyper-timeout", "percent-encoding", "pin-project 1.1.3", @@ -7245,7 +6958,7 @@ dependencies = [ "rustls-native-certs", "rustls-pemfile 1.0.3", "tokio", - "tokio-rustls 0.23.4", + "tokio-rustls", "tokio-stream", "tokio-util 0.7.10", "tower", @@ -7267,10 +6980,10 @@ dependencies = [ "bytes 1.5.0", "futures-core", "futures-util", - "h2 0.3.26", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", + "h2", + "http", + "http-body", + "hyper", "hyper-timeout", "percent-encoding", "pin-project 1.1.3", @@ -7415,7 +7128,7 @@ dependencies = [ "radix_trie", "rand", "ring 0.16.20", - "rustls 0.20.9", + "rustls", "thiserror", "time", "tokio", @@ -7442,13 +7155,13 @@ dependencies = [ "log", "rand", "ring 0.16.20", - "rustls 0.20.9", + "rustls", "rustls-pemfile 0.3.0", "smallvec", "thiserror", "tinyvec", "tokio", - "tokio-rustls 0.23.4", + "tokio-rustls", "url", "webpki", ] @@ -7730,8 +7443,8 @@ dependencies = [ "futures-channel", "futures-util", "headers", - "http 0.2.9", - "hyper 0.14.27", + "http", + "hyper", "log", "mime", "mime_guess", @@ -7893,36 +7606,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-registry" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" -dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result", - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 2919f82863..8fed89ad35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ members = [ "applications/minotari_miner", "applications/minotari_ledger_wallet/comms", "applications/minotari_ledger_wallet/common", - "applications/randomx_miner", "integration_tests", "hashing" ] diff --git a/common/config/presets/h_randomx_miner.toml b/common/config/presets/h_randomx_miner.toml deleted file mode 100644 index 1a202ce629..0000000000 --- a/common/config/presets/h_randomx_miner.toml +++ /dev/null @@ -1,16 +0,0 @@ -######################################################################################################################## -# # -# RandomX Miner Configuration Options (RandomXMinerConfig) # -# # -######################################################################################################################## - -[randomx_miner] - -# Monero base node or Tari MergeMinerProxy address (default = "http://127.0.0.1:18081") -#monero_base_node_address = "http://127.0.0.1:18081" - -# Monero wallet address (default = "none") -#monero_wallet_address = "none" - -# Number of mining threads (default: number of logical CPU cores) -#num_mining_threads = 8 \ No newline at end of file diff --git a/common/src/configuration/utils.rs b/common/src/configuration/utils.rs index 863c2efb32..9b0b300daf 100644 --- a/common/src/configuration/utils.rs +++ b/common/src/configuration/utils.rs @@ -108,7 +108,7 @@ pub fn load_configuration_with_overrides, TOverride: ConfigOverri /// Returns a new configuration file template in parts from the embedded presets. If non_interactive is false, the user /// is prompted to select if they would like to select a base node configuration that enables mining or not. /// Also includes the common configuration defined in `config/presets/common.toml`. -pub fn prompt_default_config() -> [&'static str; 13] { +pub fn prompt_default_config() -> [&'static str; 12] { let mine = prompt( "Node config does not exist.\nWould you like to mine (Y/n)?\nNOTE: this will enable additional gRPC methods \ that could be used to monitor and submit blocks from this node.", @@ -118,7 +118,7 @@ pub fn prompt_default_config() -> [&'static str; 13] { /// Returns the default configuration file template in parts from the embedded presets. If use_mining_config is true, /// the base node configuration that enables mining is returned, otherwise the non-mining configuration is returned. -pub fn get_default_config(use_mining_config: bool) -> [&'static str; 13] { +pub fn get_default_config(use_mining_config: bool) -> [&'static str; 12] { let base_node_allow_methods = if use_mining_config { include_str!("../../config/presets/c_base_node_b_mining_allow_methods.toml") } else { @@ -135,7 +135,6 @@ pub fn get_default_config(use_mining_config: bool) -> [&'static str; 13] { include_str!("../../config/presets/d_console_wallet.toml"), include_str!("../../config/presets/g_miner.toml"), include_str!("../../config/presets/f_merge_mining_proxy.toml"), - include_str!("../../config/presets/h_randomx_miner.toml"), include_str!("../../config/presets/e_validator_node.toml"), include_str!("../../config/presets/i_collectibles.toml"), include_str!("../../config/presets/j_indexer.toml"),