From 06e844a8c78e3c5fdeebd02cf4acd0f609cd2635 Mon Sep 17 00:00:00 2001 From: Priceless-P Date: Fri, 20 Jun 2025 16:03:37 +0100 Subject: [PATCH 1/2] update `nearest_power_of_10` --- src/translator/downstream/diff_management.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/translator/downstream/diff_management.rs b/src/translator/downstream/diff_management.rs index 552f84bc..00275794 100644 --- a/src/translator/downstream/diff_management.rs +++ b/src/translator/downstream/diff_management.rs @@ -303,14 +303,18 @@ pub fn nearest_power_of_10(x: f32) -> f32 { if x <= 0.0 { return 0.001; } - let exponent = x.log10().round() as i32; - 10f32.powi(exponent) + let log = x.log10(); + let base = 10f32.powi(log.floor() as i32); // Current power of 10 + let scaled = (x / base).ceil(); // Round up to next multiple + scaled * base } #[cfg(test)] mod test { use super::super::super::upstream::diff_management::UpstreamDifficultyConfig; - use crate::translator::downstream::{downstream::DownstreamDifficultyConfig, Downstream}; + use crate::translator::downstream::{ + diff_management::nearest_power_of_10, downstream::DownstreamDifficultyConfig, Downstream, + }; use binary_sv2::U256; use pid::Pid; use rand::{thread_rng, Rng}; @@ -323,6 +327,13 @@ mod test { }; use tokio::sync::mpsc::channel; + #[test] + fn test_nearest_power_of_10() { + assert_eq!(nearest_power_of_10(450.0), 500.0); + assert_eq!(nearest_power_of_10(0.034), 0.04); + assert_eq!(nearest_power_of_10(0.0), 0.001); + } + #[test] #[ignore] // TODO fn test_diff_management() { From 6f30edba89a92199224535c4fe4f126db52a0100 Mon Sep 17 00:00:00 2001 From: Priceless-P Date: Mon, 23 Jun 2025 13:44:26 +0100 Subject: [PATCH 2/2] add docs and fix CI checks --- .github/workflows/checks.yml | 3 +- src/ingress/sv1_ingress.rs | 21 +++++----- src/translator/downstream/diff_management.rs | 41 ++++++++++++++++++-- src/translator/downstream/downstream.rs | 9 +++-- src/translator/downstream/notify.rs | 4 +- 5 files changed, 57 insertions(+), 21 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 66cc2a5b..0419e8f4 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -18,8 +18,9 @@ jobs: uses: actions/checkout@v3 - name: Set up Rust toolchain - uses: dtolnay/rust-toolchain@stable + uses: dtolnay/rust-toolchain@master with: + toolchain: "1.87.0" components: rustfmt, clippy - name: Run cargo fmt diff --git a/src/ingress/sv1_ingress.rs b/src/ingress/sv1_ingress.rs index d8465b01..568470aa 100644 --- a/src/ingress/sv1_ingress.rs +++ b/src/ingress/sv1_ingress.rs @@ -1,4 +1,7 @@ -use std::{net::{IpAddr, SocketAddr}, sync::Arc}; +use std::{ + net::{IpAddr, SocketAddr}, + sync::Arc, +}; use crate::{ config::Configuration, @@ -96,14 +99,12 @@ impl Downstream { if Configuration::sv1_ingress_log() { info!("Sending msg to upstream: {}", message); } - if ! is_subscribed { - if message.contains("mining.subscribe") { - is_subscribed = true; - if message.contains("LUXminer") { - firmware.safe_lock(|f| *f = Firmware::Luxor).unwrap(); - } else { - firmware.safe_lock(|f| *f = Firmware::Other).unwrap(); - } + if !is_subscribed && message.contains("mining.subscribe") { + is_subscribed = true; + if message.contains("LUXminer") { + firmware.safe_lock(|f| *f = Firmware::Luxor).unwrap(); + } else { + firmware.safe_lock(|f| *f = Firmware::Other).unwrap(); } } if send.send(message).await.is_err() { @@ -158,7 +159,7 @@ impl Downstream { } } -#[derive(Debug,Clone,Copy)] +#[derive(Debug, Clone, Copy)] enum Firmware { Luxor, Other, diff --git a/src/translator/downstream/diff_management.rs b/src/translator/downstream/diff_management.rs index 00275794..ad40ad62 100644 --- a/src/translator/downstream/diff_management.rs +++ b/src/translator/downstream/diff_management.rs @@ -299,13 +299,31 @@ fn diff_to_sv1_message(diff: f64) -> ProxyResult<'static, (json_rpc::Message, [u Ok((message, target)) } +/// Takes a number (`f32`) and rounds it up to the next multiple of its current power of 10. +/// For example, 15.0 becomes 20.0, and 1500.0 becomes 2000.0. +/// +/// Returns 0.001 for non-positive inputs (`x <= 0.0`). +/// For positive inputs, it: +/// 1. Identifies the nearest power of 10 (e.g., 10, 100, 1000). +/// 2. Divides the input by this power of 10. +/// 3. Rounds up to the next integer. +/// 4. Multiplies by the power of 10 to get the result. +/// +/// +/// # Arguments +/// +/// * `x` - A 32-bit floating-point number (`f32`). +/// +/// # Returns +/// +/// * `f32` - The nearest power of 10 greater than or equal to `x`, or `0.001` if `x <= 0.0`. pub fn nearest_power_of_10(x: f32) -> f32 { if x <= 0.0 { return 0.001; } let log = x.log10(); - let base = 10f32.powi(log.floor() as i32); // Current power of 10 - let scaled = (x / base).ceil(); // Round up to next multiple + let base = 10f32.powi(log.floor() as i32); + let scaled = (x / base).ceil(); scaled * base } @@ -325,6 +343,10 @@ mod test { sync::Arc, time::{Duration, Instant}, }; + use sv1_api::{ + server_to_client::Notify, + utils::{HexU32Be, MerkleNode, PrevHash}, + }; use tokio::sync::mpsc::channel; #[test] @@ -332,6 +354,7 @@ mod test { assert_eq!(nearest_power_of_10(450.0), 500.0); assert_eq!(nearest_power_of_10(0.034), 0.04); assert_eq!(nearest_power_of_10(0.0), 0.001); + assert_eq!(nearest_power_of_10(147.0), 200.0); } #[test] @@ -451,6 +474,18 @@ mod test { }; let (tx_sv1_submit, _rx_sv1_submit) = tokio::sync::mpsc::channel(10); let (tx_outgoing, _rx_outgoing) = channel(10); + let random_str = rand::thread_rng().gen::<[u8; 32]>().to_vec(); + let first_job = Notify { + job_id: "ciao".to_string(), + prev_hash: PrevHash::try_from("0".repeat(64).as_str()).unwrap(), + coin_base1: "ffff".try_into().unwrap(), + coin_base2: "ffff".try_into().unwrap(), + merkle_branch: vec![MerkleNode::try_from(random_str).unwrap()], + version: HexU32Be(5667), + bits: HexU32Be(5678), + time: HexU32Be(5609), + clean_jobs: true, + }; let mut downstream = Downstream::new( 1, vec![], @@ -459,11 +494,11 @@ mod test { None, tx_sv1_submit, tx_outgoing, - false, 0, downstream_conf.clone(), Arc::new(Mutex::new(upstream_config)), crate::api::stats::StatsSender::new(), + first_job, ); downstream.difficulty_mgmt.estimated_downstream_hash_rate = start_hashrate as f32; diff --git a/src/translator/downstream/downstream.rs b/src/translator/downstream/downstream.rs index a192e4f5..6246e1bc 100644 --- a/src/translator/downstream/downstream.rs +++ b/src/translator/downstream/downstream.rs @@ -354,6 +354,7 @@ impl Downstream { difficulty_mgmt: DownstreamDifficultyConfig, upstream_difficulty_config: Arc>, stats_sender: StatsSender, + first_job: Notify<'static>, ) -> Self { Downstream { connection_id, @@ -367,7 +368,7 @@ impl Downstream { difficulty_mgmt, upstream_difficulty_config, last_call_to_update_hr: 0, - first_job: Notify, + first_job, stats_sender, recent_jobs: RecentJobs::new(), } @@ -494,11 +495,11 @@ impl IsServer<'static> for Downstream { "Share for Job {} and difficulty {} is accepted", request.job_id, met_difficulty ); - return true; + true } else { error!("Share rejected: Invalid share"); self.stats_sender.update_rejected_shares(self.connection_id); - return false; + false } } else { error!( @@ -506,7 +507,7 @@ impl IsServer<'static> for Downstream { request.job_id ); self.stats_sender.update_rejected_shares(self.connection_id); - return false; + false } } Ok(false) => { diff --git a/src/translator/downstream/notify.rs b/src/translator/downstream/notify.rs index 88e66952..e43c1766 100644 --- a/src/translator/downstream/notify.rs +++ b/src/translator/downstream/notify.rs @@ -89,9 +89,7 @@ pub async fn start_notify( } tokio::time::sleep(std::time::Duration::from_secs(1)).await; } - if let Err(e) = - start_update(task_manager, downstream.clone(), connection_id).await - { + if let Err(e) = start_update(task_manager, downstream.clone(), connection_id).await { warn!("Translator impossible to start update task: {e}"); } else if authorized_in_time { // Get the mask after initialization since is set by configure message