From 3dcd85dd550aa82f1dde8de319ede48ff4a11c09 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Mon, 22 Jan 2024 16:46:54 +0100 Subject: [PATCH 01/28] automatic diff management enhancement + fix #712 --- .../src/downstream_sv1/diff_management.rs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/roles/translator/src/downstream_sv1/diff_management.rs b/roles/translator/src/downstream_sv1/diff_management.rs index fa5b587ed..db121deda 100644 --- a/roles/translator/src/downstream_sv1/diff_management.rs +++ b/roles/translator/src/downstream_sv1/diff_management.rs @@ -3,7 +3,6 @@ use super::{Downstream, DownstreamMessages, SetDownstreamTarget}; use crate::{error::Error, ProxyResult}; use roles_logic_sv2::utils::Mutex; use std::{ops::Div, sync::Arc}; -use tracing::error; use v1::json_rpc; use stratum_common::bitcoin::util::uint::Uint256; @@ -212,7 +211,7 @@ impl Downstream { } let delta_time = timestamp_secs - d.difficulty_mgmt.timestamp_of_last_update; - if delta_time == 0 { + if delta_time <= 15 { return Ok(None); } tracing::debug!("\nDELTA TIME: {:?}", delta_time); @@ -225,7 +224,7 @@ impl Downstream { ) { Ok(hashrate) => hashrate as f32, Err(e) => { - error!("{:?} -> Probably min_individual_miner_hashrate parameter was not set properly in config file. New hashrate will be automatically adjusted to match the real one.", e); + tracing::debug!("{:?} -> Probably min_individual_miner_hashrate parameter was not set properly in config file. New hashrate will be automatically adjusted to match the real one.", e); d.difficulty_mgmt.min_individual_miner_hashrate * realized_share_per_min as f32 / d.difficulty_mgmt.shares_per_minute } }; @@ -244,11 +243,20 @@ impl Downstream { || (hashrate_delta_percentage >= 30.0) && (delta_time >= 240) || (hashrate_delta_percentage >= 15.0) && (delta_time >= 300) { - if realized_share_per_min < 0.01 { + if realized_share_per_min == 0.0 { new_miner_hashrate = match delta_time { - dt if dt < 30 => d.difficulty_mgmt.min_individual_miner_hashrate / 2.0, - dt if dt < 60 => d.difficulty_mgmt.min_individual_miner_hashrate / 3.0, - _ => d.difficulty_mgmt.min_individual_miner_hashrate / 5.0, + dt if dt <= 30 => d.difficulty_mgmt.min_individual_miner_hashrate / 1.5, + dt if dt < 60 => d.difficulty_mgmt.min_individual_miner_hashrate / 2.0, + _ => d.difficulty_mgmt.min_individual_miner_hashrate / 3.0, + }; + hashrate_delta = + new_miner_hashrate - d.difficulty_mgmt.min_individual_miner_hashrate; + } + if (realized_share_per_min > 0.0) && (hashrate_delta_percentage > 1000.0) { + new_miner_hashrate = match delta_time { + dt if dt <= 30 => d.difficulty_mgmt.min_individual_miner_hashrate * 10.0, + dt if dt < 60 => d.difficulty_mgmt.min_individual_miner_hashrate * 5.0, + _ => d.difficulty_mgmt.min_individual_miner_hashrate * 3.0, }; hashrate_delta = new_miner_hashrate - d.difficulty_mgmt.min_individual_miner_hashrate; @@ -256,9 +264,12 @@ impl Downstream { d.difficulty_mgmt.min_individual_miner_hashrate = new_miner_hashrate; d.difficulty_mgmt.timestamp_of_last_update = timestamp_secs; d.difficulty_mgmt.submits_since_last_update = 0; - // update channel hashrate (read by upstream) d.upstream_difficulty_config.super_safe_lock(|c| { + if c.channel_nominal_hashrate + hashrate_delta > 0.0 { c.channel_nominal_hashrate += hashrate_delta; + } else { + c.channel_nominal_hashrate = 0.0; + } }); Ok(Some(new_miner_hashrate)) } else { From 2fabdfecdc37aeaa6576b0176433a93b38a66c5c Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Mon, 22 Jan 2024 16:47:37 +0100 Subject: [PATCH 02/28] invalid-job-id error added --- .../src/channel_logic/channel_factory.rs | 24 +++++++++++++++++++ .../subprotocols/mining/src/submit_shares.rs | 3 +++ roles/translator/src/proxy/bridge.rs | 1 - 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs index 62df0643e..26e22989e 100644 --- a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs +++ b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs @@ -1494,6 +1494,19 @@ impl ProxyExtendedChannelFactory { .clone() .ok_or(Error::ShareDoNotMatchAnyJob)? .0; + + if referenced_job.job_id != m.job_id { + let error = SubmitSharesError { + channel_id: m.channel_id, + sequence_number: m.sequence_number, + error_code: SubmitSharesError::invalid_job_id_error_code() + .to_string() + .try_into() + .unwrap(), + }; + return Ok(OnNewShare::SendErrorDownstream(error)); + } + if let Some(job_creator) = self.job_creator.as_mut() { let template_id = job_creator .get_template_id_from_job(referenced_job.job_id) @@ -1571,6 +1584,17 @@ impl ProxyExtendedChannelFactory { .clone() .ok_or(Error::ShareDoNotMatchAnyJob)? .0; + if referenced_job.job_id != m.job_id { + let error = SubmitSharesError { + channel_id: m.channel_id, + sequence_number: m.sequence_number, + error_code: SubmitSharesError::invalid_job_id_error_code() + .to_string() + .try_into() + .unwrap(), + }; + return Ok(OnNewShare::SendErrorDownstream(error)); + } match self.inner.channel_to_group_id.get(&m.channel_id) { Some(g_id) => { if let Some(job_creator) = self.job_creator.as_mut() { diff --git a/protocols/v2/subprotocols/mining/src/submit_shares.rs b/protocols/v2/subprotocols/mining/src/submit_shares.rs index 3614e1896..078da6013 100644 --- a/protocols/v2/subprotocols/mining/src/submit_shares.rs +++ b/protocols/v2/subprotocols/mining/src/submit_shares.rs @@ -108,6 +108,9 @@ impl<'a> SubmitSharesError<'a> { pub fn difficulty_too_low_error_code() -> &'static str { "difficulty-too-low" } + pub fn invalid_job_id_error_code() -> &'static str { + "invalid-job-id" + } } #[cfg(feature = "with_serde")] use binary_sv2::GetSize; diff --git a/roles/translator/src/proxy/bridge.rs b/roles/translator/src/proxy/bridge.rs index 0f3e8def3..589b8f96c 100644 --- a/roles/translator/src/proxy/bridge.rs +++ b/roles/translator/src/proxy/bridge.rs @@ -239,7 +239,6 @@ impl Bridge { "Submit share error {:?}", std::str::from_utf8(&e.error_code.to_vec()[..]) ); - error!("Make sure to set `min_individual_miner_hashrate` in the config file"); } Ok(Ok(OnNewShare::SendSubmitShareUpstream((share, _)))) => { info!("SHARE MEETS UPSTREAM TARGET"); From 08c49fb902064df43c8adde3ce12dd77367b7877 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Mon, 22 Jan 2024 17:53:24 +0100 Subject: [PATCH 03/28] fix --- .../src/channel_logic/channel_factory.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs index 26e22989e..dfb133e8b 100644 --- a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs +++ b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs @@ -1584,17 +1584,6 @@ impl ProxyExtendedChannelFactory { .clone() .ok_or(Error::ShareDoNotMatchAnyJob)? .0; - if referenced_job.job_id != m.job_id { - let error = SubmitSharesError { - channel_id: m.channel_id, - sequence_number: m.sequence_number, - error_code: SubmitSharesError::invalid_job_id_error_code() - .to_string() - .try_into() - .unwrap(), - }; - return Ok(OnNewShare::SendErrorDownstream(error)); - } match self.inner.channel_to_group_id.get(&m.channel_id) { Some(g_id) => { if let Some(job_creator) = self.job_creator.as_mut() { From 764ae997b9b2b3de00e8fde1972028d8a738a8ac Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 11:36:38 +0100 Subject: [PATCH 04/28] 'invalid-job-id' added into SubmitShares.Error doc --- protocols/v2/subprotocols/mining/src/submit_shares.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/v2/subprotocols/mining/src/submit_shares.rs b/protocols/v2/subprotocols/mining/src/submit_shares.rs index 078da6013..0325760db 100644 --- a/protocols/v2/subprotocols/mining/src/submit_shares.rs +++ b/protocols/v2/subprotocols/mining/src/submit_shares.rs @@ -90,6 +90,7 @@ pub struct SubmitSharesSuccess { /// * ‘invalid-channel-id’ /// * ‘stale-share’ /// * ‘difficulty-too-low’ +/// * 'invalid-job-id' #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SubmitSharesError<'decoder> { pub channel_id: u32, From 41000001d5f7bb7fff8b05b9ff74248ca4553839 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:19:39 +0100 Subject: [PATCH 05/28] Fix issue #730 --- roles/jd-server/src/lib/mempool/mod.rs | 15 ++++++++++- roles/jd-server/src/main.rs | 35 ++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 39b0096a3..e4fe050ac 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -8,6 +8,8 @@ use serde::{Deserialize, Serialize}; use std::{convert::TryInto, sync::Arc}; use stratum_common::{bitcoin, bitcoin::hash_types::Txid}; +use self::rpc_client::BitcoincoreRpcError; + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Hash([u8; 32]); @@ -57,7 +59,11 @@ impl JDsMempool { .ok_or(JdsMempoolError::NoClient)?; let new_mempool: Result, JdsMempoolError> = tokio::task::spawn(async move { - let mempool: Vec = client.get_raw_mempool_verbose().unwrap(); + let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); + let mempool = mempool.map_err(|e| { + println!("Error fetching mempool: {:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", e); + JdsMempoolError::BitcoinCoreRpcError(e) + })?; for id in &mempool { let tx: Result = client.get_raw_transaction(id, None); if let Ok(tx) = tx { @@ -106,4 +112,11 @@ impl JDsMempool { pub enum JdsMempoolError { EmptyMempool, NoClient, + BitcoinCoreRpcError(BitcoincoreRpcError), } + +impl From for JdsMempoolError { + fn from(error: BitcoincoreRpcError) -> Self { + JdsMempoolError::BitcoinCoreRpcError(error) + } +} \ No newline at end of file diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 6082e6ecf..81d984793 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -75,6 +75,8 @@ pub struct Configuration { pub core_rpc_port: u16, pub core_rpc_user: String, pub core_rpc_pass: String, + #[serde(deserialize_with = "duration_from_toml")] + pub mempool_update_timeout: Duration, } mod args { @@ -140,6 +142,35 @@ mod args { } } +fn duration_from_toml<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + #[derive(Deserialize)] + struct Helper { + unit: String, + value: u64, + } + + let helper = Helper::deserialize(deserializer)?; + match helper.unit.as_str() { + "seconds" => Ok(Duration::from_secs(helper.value)), + "secs" => Ok(Duration::from_secs(helper.value)), + "s" => Ok(Duration::from_secs(helper.value)), + "milliseconds" => Ok(Duration::from_millis(helper.value)), + "millis" => Ok(Duration::from_millis(helper.value)), + "ms" => Ok(Duration::from_millis(helper.value)), + "microseconds" => Ok(Duration::from_micros(helper.value)), + "micros" => Ok(Duration::from_micros(helper.value)), + "us" => Ok(Duration::from_micros(helper.value)), + "nanoseconds" => Ok(Duration::from_nanos(helper.value)), + "nanos" => Ok(Duration::from_nanos(helper.value)), + "ns" => Ok(Duration::from_nanos(helper.value)), + // ... add other units as needed + _ => Err(serde::de::Error::custom("Unsupported duration unit")), + } +} + #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); @@ -174,13 +205,13 @@ async fn main() { username, password, ))); + let mempool_update_timeout = config.mempool_update_timeout.clone(); let mempool_cloned_ = mempool.clone(); if url.contains("http") { task::spawn(async move { loop { let _ = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; - // TODO this should be configurable by the user - tokio::time::sleep(Duration::from_millis(10000)).await; + tokio::time::sleep(mempool_update_timeout).await; } }); }; From 9251f0e6d201c96716c2f245e65fc9c083c15d52 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:19:58 +0100 Subject: [PATCH 06/28] Mempool update timout management --- .../jd-server/config-examples/jds-config-hosted-example.toml | 4 ++++ roles/jd-server/config-examples/jds-config-local-example.toml | 4 ++++ roles/jd-server/jds-config.toml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/roles/jd-server/config-examples/jds-config-hosted-example.toml b/roles/jd-server/config-examples/jds-config-hosted-example.toml index c16090fc6..a9655f783 100644 --- a/roles/jd-server/config-examples/jds-config-hosted-example.toml +++ b/roles/jd-server/config-examples/jds-config-hosted-example.toml @@ -22,3 +22,7 @@ core_rpc_url = "http://127.0.0.1" core_rpc_port = 18332 core_rpc_user = "username" core_rpc_pass = "password" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 diff --git a/roles/jd-server/config-examples/jds-config-local-example.toml b/roles/jd-server/config-examples/jds-config-local-example.toml index 871724eac..b1c4af3d5 100644 --- a/roles/jd-server/config-examples/jds-config-local-example.toml +++ b/roles/jd-server/config-examples/jds-config-local-example.toml @@ -22,3 +22,7 @@ core_rpc_url = "http://127.0.0.1" core_rpc_port = 18332 core_rpc_user = "username" core_rpc_pass = "password" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 diff --git a/roles/jd-server/jds-config.toml b/roles/jd-server/jds-config.toml index 803493fa5..05b2356a0 100644 --- a/roles/jd-server/jds-config.toml +++ b/roles/jd-server/jds-config.toml @@ -18,3 +18,7 @@ core_rpc_url = "http://127.0.0.1" core_rpc_port = 18332 core_rpc_user = "username" core_rpc_pass = "password" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 From 6029ad7b1c2f8bc85ebb65fd3fff046ecd9ed138 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:21:17 +0100 Subject: [PATCH 07/28] fmt fix --- roles/jd-server/src/lib/mempool/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index e4fe050ac..098e4b4c0 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -119,4 +119,4 @@ impl From for JdsMempoolError { fn from(error: BitcoincoreRpcError) -> Self { JdsMempoolError::BitcoinCoreRpcError(error) } -} \ No newline at end of file +} From 88c7c41c70b563e7d2171696680d38c133e0bbe0 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:23:37 +0100 Subject: [PATCH 08/28] clippy fix --- roles/jd-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 81d984793..47fea3cde 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -205,7 +205,7 @@ async fn main() { username, password, ))); - let mempool_update_timeout = config.mempool_update_timeout.clone(); + let mempool_update_timeout = config.mempool_update_timeout; let mempool_cloned_ = mempool.clone(); if url.contains("http") { task::spawn(async move { From 12b3e050a5b49fa38980b5c6f1c6be8bed133c87 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:37:10 +0100 Subject: [PATCH 09/28] MG fixes --- test/config/interop-jd-change-upstream/jds-config.toml | 4 ++++ test/config/interop-jd-translator/jds-config.toml | 4 ++++ .../jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml | 4 ++++ .../jds-do-not-panic-if-jdc-close-connection/jds-config.toml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/test/config/interop-jd-change-upstream/jds-config.toml b/test/config/interop-jd-change-upstream/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/interop-jd-change-upstream/jds-config.toml +++ b/test/config/interop-jd-change-upstream/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file diff --git a/test/config/interop-jd-translator/jds-config.toml b/test/config/interop-jd-translator/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/interop-jd-translator/jds-config.toml +++ b/test/config/interop-jd-translator/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file diff --git a/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml b/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml +++ b/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file diff --git a/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml b/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml +++ b/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file From e67a00e185e31a7144cb9e1c4024daab71b933d7 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 14:17:51 +0100 Subject: [PATCH 10/28] panic if TP is not responding --- roles/jd-server/src/lib/mempool/mod.rs | 1 - roles/jd-server/src/main.rs | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 098e4b4c0..0aba115fc 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -61,7 +61,6 @@ impl JDsMempool { tokio::task::spawn(async move { let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); let mempool = mempool.map_err(|e| { - println!("Error fetching mempool: {:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", e); JdsMempoolError::BitcoinCoreRpcError(e) })?; for id in &mempool { diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 47fea3cde..e0a8e8bae 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -210,7 +210,10 @@ async fn main() { if url.contains("http") { task::spawn(async move { loop { - let _ = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; + let updated_mempool = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; + if let Err(err) = updated_mempool { + panic!("{:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", err) + } tokio::time::sleep(mempool_update_timeout).await; } }); From bdd1064def6dab076fedea16609a48f19668d037 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 15:33:28 +0100 Subject: [PATCH 11/28] fmt fixes --- roles/jd-server/src/lib/mempool/mod.rs | 7 +++---- roles/jd-server/src/main.rs | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 0aba115fc..2e174242c 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -59,10 +59,9 @@ impl JDsMempool { .ok_or(JdsMempoolError::NoClient)?; let new_mempool: Result, JdsMempoolError> = tokio::task::spawn(async move { - let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); - let mempool = mempool.map_err(|e| { - JdsMempoolError::BitcoinCoreRpcError(e) - })?; + let mempool: Result, BitcoincoreRpcError> = + client.get_raw_mempool_verbose(); + let mempool = mempool.map_err(|e| JdsMempoolError::BitcoinCoreRpcError(e))?; for id in &mempool { let tx: Result = client.get_raw_transaction(id, None); if let Ok(tx) = tx { diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index e0a8e8bae..fcd25b070 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -210,7 +210,8 @@ async fn main() { if url.contains("http") { task::spawn(async move { loop { - let updated_mempool = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; + let updated_mempool = + mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; if let Err(err) = updated_mempool { panic!("{:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", err) } From 2519367c02de790f3eebb6b828b35936a3749d13 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 15:37:55 +0100 Subject: [PATCH 12/28] clippy fix --- roles/jd-server/src/lib/mempool/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 2e174242c..d022d651f 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -61,7 +61,7 @@ impl JDsMempool { tokio::task::spawn(async move { let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); - let mempool = mempool.map_err(|e| JdsMempoolError::BitcoinCoreRpcError(e))?; + let mempool = mempool.map_err(JdsMempoolError::BitcoinCoreRpcError)?; for id in &mempool { let tx: Result = client.get_raw_transaction(id, None); if let Ok(tx) = tx { From 583d23a22fe168f7d248ea750ca6aae8d63a9b1b Mon Sep 17 00:00:00 2001 From: Gabriele Vernetti Date: Wed, 24 Jan 2024 16:29:10 +0100 Subject: [PATCH 13/28] last changes --- roles/jd-server/src/error.rs | 10 ++++++++++ roles/jd-server/src/main.rs | 15 ++++++++++----- roles/jd-server/src/status.rs | 10 ++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/roles/jd-server/src/error.rs b/roles/jd-server/src/error.rs index 08c34186b..e13d3099d 100644 --- a/roles/jd-server/src/error.rs +++ b/roles/jd-server/src/error.rs @@ -6,6 +6,8 @@ use std::{ use roles_logic_sv2::parsers::Mining; +use crate::lib::mempool::JdsMempoolError; + #[derive(std::fmt::Debug)] pub enum JdsError { Io(std::io::Error), @@ -19,6 +21,7 @@ pub enum JdsError { PoisonLock(String), Custom(String), Sv2ProtocolError((u32, Mining<'static>)), + MempoolError(JdsMempoolError), } impl std::fmt::Display for JdsError { @@ -38,6 +41,7 @@ impl std::fmt::Display for JdsError { Sv2ProtocolError(ref e) => { write!(f, "Received Sv2 Protocol Error from upstream: `{:?}`", e) } + MempoolError(ref e) => write!(f, "Mempool error: `{:?}`", e), } } } @@ -106,3 +110,9 @@ impl From<(u32, Mining<'static>)> for JdsError { JdsError::Sv2ProtocolError(e) } } + +impl From for JdsError { + fn from(error: JdsMempoolError) -> Self { + JdsError::MempoolError(error) + } +} diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index fcd25b070..b4a38fc4e 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -8,9 +8,9 @@ use roles_logic_sv2::{ use serde::Deserialize; use std::convert::{TryFrom, TryInto}; -use tracing::{error, info, warn}; - +use error_handling::handle_result; use stratum_common::bitcoin::{Script, TxOut}; +use tracing::{error, info, warn}; use crate::lib::mempool; use roles_logic_sv2::utils::Mutex; @@ -207,24 +207,29 @@ async fn main() { ))); let mempool_update_timeout = config.mempool_update_timeout; let mempool_cloned_ = mempool.clone(); + let (status_tx, status_rx) = unbounded(); + let sender = status::Sender::Downstream(status_tx.clone()); if url.contains("http") { + let sender_clone = sender.clone(); task::spawn(async move { loop { let updated_mempool = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; if let Err(err) = updated_mempool { - panic!("{:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", err) + error!("{:?}", err); + error!("Unable to connect to Template Provider (possible reasons: not fully synced, down)"); + handle_result!(sender_clone, Err(err)); } tokio::time::sleep(mempool_update_timeout).await; } }); }; - let (status_tx, status_rx) = unbounded(); + //let (status_tx, status_rx) = unbounded(); info!("Jds INITIALIZING with config: {:?}", &args.config_path); let cloned = config.clone(); - let sender = status::Sender::Downstream(status_tx.clone()); + let mempool_cloned = mempool.clone(); task::spawn(async move { JobDeclarator::start(cloned, sender, mempool_cloned).await }); diff --git a/roles/jd-server/src/status.rs b/roles/jd-server/src/status.rs index d97d09c15..dbe125bf2 100644 --- a/roles/jd-server/src/status.rs +++ b/roles/jd-server/src/status.rs @@ -60,6 +60,13 @@ async fn send_status( .await .unwrap_or(()); } + JdsError::MempoolError(_) => { + tx.send(Status { + state: State::TemplateProviderShutdown(e), + }) + .await + .unwrap_or(()); + } _ => { let string_err = e.to_string(); tx.send(Status { @@ -111,5 +118,8 @@ pub async fn handle_error(sender: &Sender, e: JdsError) -> error_handling::Error JdsError::Sv2ProtocolError(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } + JdsError::MempoolError(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } } } From 8db76f878cf473ae9d77613c8e8ec9e682e39c8b Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Mon, 22 Jan 2024 16:46:54 +0100 Subject: [PATCH 14/28] automatic diff management enhancement + fix #712 --- .../src/lib/downstream_sv1/diff_management.rs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/roles/translator/src/lib/downstream_sv1/diff_management.rs b/roles/translator/src/lib/downstream_sv1/diff_management.rs index 1e26eac7b..e534af443 100644 --- a/roles/translator/src/lib/downstream_sv1/diff_management.rs +++ b/roles/translator/src/lib/downstream_sv1/diff_management.rs @@ -3,7 +3,6 @@ use super::{Downstream, DownstreamMessages, SetDownstreamTarget}; use super::super::error::{Error, ProxyResult}; use roles_logic_sv2::utils::Mutex; use std::{ops::Div, sync::Arc}; -use tracing::error; use v1::json_rpc; use stratum_common::bitcoin::util::uint::Uint256; @@ -212,7 +211,7 @@ impl Downstream { } let delta_time = timestamp_secs - d.difficulty_mgmt.timestamp_of_last_update; - if delta_time == 0 { + if delta_time <= 15 { return Ok(None); } tracing::debug!("\nDELTA TIME: {:?}", delta_time); @@ -225,7 +224,7 @@ impl Downstream { ) { Ok(hashrate) => hashrate as f32, Err(e) => { - error!("{:?} -> Probably min_individual_miner_hashrate parameter was not set properly in config file. New hashrate will be automatically adjusted to match the real one.", e); + tracing::debug!("{:?} -> Probably min_individual_miner_hashrate parameter was not set properly in config file. New hashrate will be automatically adjusted to match the real one.", e); d.difficulty_mgmt.min_individual_miner_hashrate * realized_share_per_min as f32 / d.difficulty_mgmt.shares_per_minute } }; @@ -244,11 +243,20 @@ impl Downstream { || (hashrate_delta_percentage >= 30.0) && (delta_time >= 240) || (hashrate_delta_percentage >= 15.0) && (delta_time >= 300) { - if realized_share_per_min < 0.01 { + if realized_share_per_min == 0.0 { new_miner_hashrate = match delta_time { - dt if dt < 30 => d.difficulty_mgmt.min_individual_miner_hashrate / 2.0, - dt if dt < 60 => d.difficulty_mgmt.min_individual_miner_hashrate / 3.0, - _ => d.difficulty_mgmt.min_individual_miner_hashrate / 5.0, + dt if dt <= 30 => d.difficulty_mgmt.min_individual_miner_hashrate / 1.5, + dt if dt < 60 => d.difficulty_mgmt.min_individual_miner_hashrate / 2.0, + _ => d.difficulty_mgmt.min_individual_miner_hashrate / 3.0, + }; + hashrate_delta = + new_miner_hashrate - d.difficulty_mgmt.min_individual_miner_hashrate; + } + if (realized_share_per_min > 0.0) && (hashrate_delta_percentage > 1000.0) { + new_miner_hashrate = match delta_time { + dt if dt <= 30 => d.difficulty_mgmt.min_individual_miner_hashrate * 10.0, + dt if dt < 60 => d.difficulty_mgmt.min_individual_miner_hashrate * 5.0, + _ => d.difficulty_mgmt.min_individual_miner_hashrate * 3.0, }; hashrate_delta = new_miner_hashrate - d.difficulty_mgmt.min_individual_miner_hashrate; @@ -256,9 +264,12 @@ impl Downstream { d.difficulty_mgmt.min_individual_miner_hashrate = new_miner_hashrate; d.difficulty_mgmt.timestamp_of_last_update = timestamp_secs; d.difficulty_mgmt.submits_since_last_update = 0; - // update channel hashrate (read by upstream) d.upstream_difficulty_config.super_safe_lock(|c| { + if c.channel_nominal_hashrate + hashrate_delta > 0.0 { c.channel_nominal_hashrate += hashrate_delta; + } else { + c.channel_nominal_hashrate = 0.0; + } }); Ok(Some(new_miner_hashrate)) } else { From 798b842addfed47c1192ad3db97b612039e669a3 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Mon, 22 Jan 2024 16:47:37 +0100 Subject: [PATCH 15/28] invalid-job-id error added --- .../src/channel_logic/channel_factory.rs | 24 +++++++++++++++++++ .../subprotocols/mining/src/submit_shares.rs | 3 +++ roles/translator/src/lib/proxy/bridge.rs | 1 - 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs index 62df0643e..26e22989e 100644 --- a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs +++ b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs @@ -1494,6 +1494,19 @@ impl ProxyExtendedChannelFactory { .clone() .ok_or(Error::ShareDoNotMatchAnyJob)? .0; + + if referenced_job.job_id != m.job_id { + let error = SubmitSharesError { + channel_id: m.channel_id, + sequence_number: m.sequence_number, + error_code: SubmitSharesError::invalid_job_id_error_code() + .to_string() + .try_into() + .unwrap(), + }; + return Ok(OnNewShare::SendErrorDownstream(error)); + } + if let Some(job_creator) = self.job_creator.as_mut() { let template_id = job_creator .get_template_id_from_job(referenced_job.job_id) @@ -1571,6 +1584,17 @@ impl ProxyExtendedChannelFactory { .clone() .ok_or(Error::ShareDoNotMatchAnyJob)? .0; + if referenced_job.job_id != m.job_id { + let error = SubmitSharesError { + channel_id: m.channel_id, + sequence_number: m.sequence_number, + error_code: SubmitSharesError::invalid_job_id_error_code() + .to_string() + .try_into() + .unwrap(), + }; + return Ok(OnNewShare::SendErrorDownstream(error)); + } match self.inner.channel_to_group_id.get(&m.channel_id) { Some(g_id) => { if let Some(job_creator) = self.job_creator.as_mut() { diff --git a/protocols/v2/subprotocols/mining/src/submit_shares.rs b/protocols/v2/subprotocols/mining/src/submit_shares.rs index 504a292de..dbf6d2aba 100644 --- a/protocols/v2/subprotocols/mining/src/submit_shares.rs +++ b/protocols/v2/subprotocols/mining/src/submit_shares.rs @@ -109,6 +109,9 @@ impl<'a> SubmitSharesError<'a> { pub fn difficulty_too_low_error_code() -> &'static str { "difficulty-too-low" } + pub fn invalid_job_id_error_code() -> &'static str { + "invalid-job-id" + } } #[cfg(feature = "with_serde")] use binary_sv2::GetSize; diff --git a/roles/translator/src/lib/proxy/bridge.rs b/roles/translator/src/lib/proxy/bridge.rs index 3501a2736..8cd00ab04 100644 --- a/roles/translator/src/lib/proxy/bridge.rs +++ b/roles/translator/src/lib/proxy/bridge.rs @@ -242,7 +242,6 @@ impl Bridge { "Submit share error {:?}", std::str::from_utf8(&e.error_code.to_vec()[..]) ); - error!("Make sure to set `min_individual_miner_hashrate` in the config file"); } Ok(Ok(OnNewShare::SendSubmitShareUpstream((share, _)))) => { info!("SHARE MEETS UPSTREAM TARGET"); From d94fa27d3305746925f709795fe845545af7c0c0 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Mon, 22 Jan 2024 17:53:24 +0100 Subject: [PATCH 16/28] fix --- .../src/channel_logic/channel_factory.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs index 26e22989e..dfb133e8b 100644 --- a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs +++ b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs @@ -1584,17 +1584,6 @@ impl ProxyExtendedChannelFactory { .clone() .ok_or(Error::ShareDoNotMatchAnyJob)? .0; - if referenced_job.job_id != m.job_id { - let error = SubmitSharesError { - channel_id: m.channel_id, - sequence_number: m.sequence_number, - error_code: SubmitSharesError::invalid_job_id_error_code() - .to_string() - .try_into() - .unwrap(), - }; - return Ok(OnNewShare::SendErrorDownstream(error)); - } match self.inner.channel_to_group_id.get(&m.channel_id) { Some(g_id) => { if let Some(job_creator) = self.job_creator.as_mut() { From 90158fac3b709c40668f0d2fd706efeac0a75489 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 11:36:38 +0100 Subject: [PATCH 17/28] 'invalid-job-id' added into SubmitShares.Error doc --- protocols/v2/subprotocols/mining/src/submit_shares.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/protocols/v2/subprotocols/mining/src/submit_shares.rs b/protocols/v2/subprotocols/mining/src/submit_shares.rs index dbf6d2aba..1a6f489d6 100644 --- a/protocols/v2/subprotocols/mining/src/submit_shares.rs +++ b/protocols/v2/subprotocols/mining/src/submit_shares.rs @@ -91,6 +91,7 @@ pub struct SubmitSharesSuccess { /// * ‘invalid-channel-id’ /// * ‘stale-share’ /// * ‘difficulty-too-low’ +/// * 'invalid-job-id' #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SubmitSharesError<'decoder> { pub channel_id: u32, From 6362640f51bf55f44f2227f31090d315c8b71029 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:19:39 +0100 Subject: [PATCH 18/28] Fix issue #730 --- roles/jd-server/src/lib/mempool/mod.rs | 15 ++++++- roles/jd-server/src/main.rs | 58 +++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 39b0096a3..e4fe050ac 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -8,6 +8,8 @@ use serde::{Deserialize, Serialize}; use std::{convert::TryInto, sync::Arc}; use stratum_common::{bitcoin, bitcoin::hash_types::Txid}; +use self::rpc_client::BitcoincoreRpcError; + #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Hash([u8; 32]); @@ -57,7 +59,11 @@ impl JDsMempool { .ok_or(JdsMempoolError::NoClient)?; let new_mempool: Result, JdsMempoolError> = tokio::task::spawn(async move { - let mempool: Vec = client.get_raw_mempool_verbose().unwrap(); + let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); + let mempool = mempool.map_err(|e| { + println!("Error fetching mempool: {:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", e); + JdsMempoolError::BitcoinCoreRpcError(e) + })?; for id in &mempool { let tx: Result = client.get_raw_transaction(id, None); if let Ok(tx) = tx { @@ -106,4 +112,11 @@ impl JDsMempool { pub enum JdsMempoolError { EmptyMempool, NoClient, + BitcoinCoreRpcError(BitcoincoreRpcError), } + +impl From for JdsMempoolError { + fn from(error: BitcoincoreRpcError) -> Self { + JdsMempoolError::BitcoinCoreRpcError(error) + } +} \ No newline at end of file diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 1f96a7cdf..086e846e5 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -4,10 +4,29 @@ use async_channel::unbounded; use roles_logic_sv2::utils::Mutex; use std::{sync::Arc, time::Duration}; use tokio::{select, task}; -use tracing::{error, info, warn}; -mod lib; -use lib::job_declarator::JobDeclarator; +use crate::{lib::job_declarator::JobDeclarator, status::Status}; + +#[derive(Debug, Deserialize, Clone)] +pub struct CoinbaseOutput { + output_script_type: String, + output_script_value: String, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct Configuration { + pub listen_jd_address: String, + pub authority_public_key: Secp256k1PublicKey, + pub authority_secret_key: Secp256k1SecretKey, + pub cert_validity_sec: u64, + pub coinbase_outputs: Vec, + pub core_rpc_url: String, + pub core_rpc_port: u16, + pub core_rpc_user: String, + pub core_rpc_pass: String, + #[serde(deserialize_with = "duration_from_toml")] + pub mempool_update_timeout: Duration, +} mod args { use std::path::PathBuf; @@ -72,6 +91,35 @@ mod args { } } +fn duration_from_toml<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + #[derive(Deserialize)] + struct Helper { + unit: String, + value: u64, + } + + let helper = Helper::deserialize(deserializer)?; + match helper.unit.as_str() { + "seconds" => Ok(Duration::from_secs(helper.value)), + "secs" => Ok(Duration::from_secs(helper.value)), + "s" => Ok(Duration::from_secs(helper.value)), + "milliseconds" => Ok(Duration::from_millis(helper.value)), + "millis" => Ok(Duration::from_millis(helper.value)), + "ms" => Ok(Duration::from_millis(helper.value)), + "microseconds" => Ok(Duration::from_micros(helper.value)), + "micros" => Ok(Duration::from_micros(helper.value)), + "us" => Ok(Duration::from_micros(helper.value)), + "nanoseconds" => Ok(Duration::from_nanos(helper.value)), + "nanos" => Ok(Duration::from_nanos(helper.value)), + "ns" => Ok(Duration::from_nanos(helper.value)), + // ... add other units as needed + _ => Err(serde::de::Error::custom("Unsupported duration unit")), + } +} + #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); @@ -106,13 +154,13 @@ async fn main() { username, password, ))); + let mempool_update_timeout = config.mempool_update_timeout.clone(); let mempool_cloned_ = mempool.clone(); if url.contains("http") { task::spawn(async move { loop { let _ = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; - // TODO this should be configurable by the user - tokio::time::sleep(Duration::from_millis(10000)).await; + tokio::time::sleep(mempool_update_timeout).await; } }); }; From c365c882c1ef8323bba07963ad44ad39fc95a6dc Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:19:58 +0100 Subject: [PATCH 19/28] Mempool update timout management --- .../jds-config-hosted-example.toml | 4 ++++ .../jds-config-local-example.toml | 4 ++++ roles/jd-server/jds-config.toml | 24 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 roles/jd-server/jds-config.toml diff --git a/roles/jd-server/config-examples/jds-config-hosted-example.toml b/roles/jd-server/config-examples/jds-config-hosted-example.toml index c16090fc6..a9655f783 100644 --- a/roles/jd-server/config-examples/jds-config-hosted-example.toml +++ b/roles/jd-server/config-examples/jds-config-hosted-example.toml @@ -22,3 +22,7 @@ core_rpc_url = "http://127.0.0.1" core_rpc_port = 18332 core_rpc_user = "username" core_rpc_pass = "password" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 diff --git a/roles/jd-server/config-examples/jds-config-local-example.toml b/roles/jd-server/config-examples/jds-config-local-example.toml index 871724eac..b1c4af3d5 100644 --- a/roles/jd-server/config-examples/jds-config-local-example.toml +++ b/roles/jd-server/config-examples/jds-config-local-example.toml @@ -22,3 +22,7 @@ core_rpc_url = "http://127.0.0.1" core_rpc_port = 18332 core_rpc_user = "username" core_rpc_pass = "password" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 diff --git a/roles/jd-server/jds-config.toml b/roles/jd-server/jds-config.toml new file mode 100644 index 000000000..05b2356a0 --- /dev/null +++ b/roles/jd-server/jds-config.toml @@ -0,0 +1,24 @@ +# SRI Pool config +authority_public_key = "3VANfft6ei6jQq1At7d8nmiZzVhBFS4CiQujdgim1ign" +authority_secret_key = "7qbpUjScc865jyX2kiB4NVJANoC7GA7TAJupdzXWkc62" +cert_validity_sec = 3600 + +# List of coinbase outputs used to build the coinbase tx +# ! Right now only one output is supported, so comment all the ones you don't need ! +# For P2PK, P2PKH, P2WPKH, P2TR a BIP32 extended public key is needed +coinbase_outputs = [ + { output_script_type = "P2WPKH", output_script_value = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075" }, +] + +# SRI Pool JD config +listen_jd_address = "0.0.0.0:34264" +# RPC config for mempool (it can be also the same TP if correctly configured) +core_rpc_url = "http://127.0.0.1" +#core_rpc_port = 18443 +core_rpc_port = 18332 +core_rpc_user = "username" +core_rpc_pass = "password" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 From 2c70690ee6a74d1ebcf7e2c217be783cf5c26e42 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:21:17 +0100 Subject: [PATCH 20/28] fmt fix --- roles/jd-server/src/lib/mempool/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index e4fe050ac..098e4b4c0 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -119,4 +119,4 @@ impl From for JdsMempoolError { fn from(error: BitcoincoreRpcError) -> Self { JdsMempoolError::BitcoinCoreRpcError(error) } -} \ No newline at end of file +} From 180db6d0d718572707abe3abdfc225bcc389ebea Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:23:37 +0100 Subject: [PATCH 21/28] clippy fix --- roles/jd-server/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 086e846e5..cfb37bd34 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -154,7 +154,7 @@ async fn main() { username, password, ))); - let mempool_update_timeout = config.mempool_update_timeout.clone(); + let mempool_update_timeout = config.mempool_update_timeout; let mempool_cloned_ = mempool.clone(); if url.contains("http") { task::spawn(async move { From a14c3641f7d89066cfabfb189174d0deff1074f4 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 13:37:10 +0100 Subject: [PATCH 22/28] MG fixes --- test/config/interop-jd-change-upstream/jds-config.toml | 4 ++++ test/config/interop-jd-translator/jds-config.toml | 4 ++++ .../jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml | 4 ++++ .../jds-do-not-panic-if-jdc-close-connection/jds-config.toml | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/test/config/interop-jd-change-upstream/jds-config.toml b/test/config/interop-jd-change-upstream/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/interop-jd-change-upstream/jds-config.toml +++ b/test/config/interop-jd-change-upstream/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file diff --git a/test/config/interop-jd-translator/jds-config.toml b/test/config/interop-jd-translator/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/interop-jd-translator/jds-config.toml +++ b/test/config/interop-jd-translator/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file diff --git a/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml b/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml +++ b/test/config/jds-do-not-fail-on-wrong-txdatasucc/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file diff --git a/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml b/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml index 15cbf9808..92ece9b3c 100644 --- a/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml +++ b/test/config/jds-do-not-panic-if-jdc-close-connection/jds-config.toml @@ -14,3 +14,7 @@ core_rpc_url = "" core_rpc_port = 18332 core_rpc_user = "" core_rpc_pass = "" +# Timeout used for JDS mempool update +[mempool_update_timeout] +unit = "secs" +value = 1 \ No newline at end of file From 788481bb92e3b26fa06ebb8a3a954b927cc674f9 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 14:17:51 +0100 Subject: [PATCH 23/28] panic if TP is not responding --- roles/jd-server/src/lib/mempool/mod.rs | 1 - roles/jd-server/src/main.rs | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 098e4b4c0..0aba115fc 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -61,7 +61,6 @@ impl JDsMempool { tokio::task::spawn(async move { let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); let mempool = mempool.map_err(|e| { - println!("Error fetching mempool: {:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", e); JdsMempoolError::BitcoinCoreRpcError(e) })?; for id in &mempool { diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index cfb37bd34..ea0ca46a5 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -159,7 +159,10 @@ async fn main() { if url.contains("http") { task::spawn(async move { loop { - let _ = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; + let updated_mempool = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; + if let Err(err) = updated_mempool { + panic!("{:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", err) + } tokio::time::sleep(mempool_update_timeout).await; } }); From 78f52080a523d30d116d547a59ed0ab1b68be071 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 15:33:28 +0100 Subject: [PATCH 24/28] fmt fixes --- roles/jd-server/src/lib/mempool/mod.rs | 7 +++---- roles/jd-server/src/main.rs | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 0aba115fc..2e174242c 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -59,10 +59,9 @@ impl JDsMempool { .ok_or(JdsMempoolError::NoClient)?; let new_mempool: Result, JdsMempoolError> = tokio::task::spawn(async move { - let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); - let mempool = mempool.map_err(|e| { - JdsMempoolError::BitcoinCoreRpcError(e) - })?; + let mempool: Result, BitcoincoreRpcError> = + client.get_raw_mempool_verbose(); + let mempool = mempool.map_err(|e| JdsMempoolError::BitcoinCoreRpcError(e))?; for id in &mempool { let tx: Result = client.get_raw_transaction(id, None); if let Ok(tx) = tx { diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index ea0ca46a5..c41acb729 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -159,7 +159,8 @@ async fn main() { if url.contains("http") { task::spawn(async move { loop { - let updated_mempool = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; + let updated_mempool = + mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; if let Err(err) = updated_mempool { panic!("{:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", err) } From e13d166ab27ef52ec3c78c806503e6f067c04d3d Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Tue, 23 Jan 2024 15:37:55 +0100 Subject: [PATCH 25/28] clippy fix --- roles/jd-server/src/lib/mempool/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/jd-server/src/lib/mempool/mod.rs b/roles/jd-server/src/lib/mempool/mod.rs index 2e174242c..d022d651f 100644 --- a/roles/jd-server/src/lib/mempool/mod.rs +++ b/roles/jd-server/src/lib/mempool/mod.rs @@ -61,7 +61,7 @@ impl JDsMempool { tokio::task::spawn(async move { let mempool: Result, BitcoincoreRpcError> = client.get_raw_mempool_verbose(); - let mempool = mempool.map_err(|e| JdsMempoolError::BitcoinCoreRpcError(e))?; + let mempool = mempool.map_err(JdsMempoolError::BitcoinCoreRpcError)?; for id in &mempool { let tx: Result = client.get_raw_transaction(id, None); if let Ok(tx) = tx { From 4b5f3dfade1cff473eb43c357af9d338fe399e5d Mon Sep 17 00:00:00 2001 From: Gabriele Vernetti Date: Wed, 24 Jan 2024 16:29:10 +0100 Subject: [PATCH 26/28] last changes --- roles/jd-server/src/lib/error.rs | 10 ++++++++++ roles/jd-server/src/lib/status.rs | 10 ++++++++++ roles/jd-server/src/main.rs | 24 +++++++++++++++++++++--- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/roles/jd-server/src/lib/error.rs b/roles/jd-server/src/lib/error.rs index 08c34186b..e13d3099d 100644 --- a/roles/jd-server/src/lib/error.rs +++ b/roles/jd-server/src/lib/error.rs @@ -6,6 +6,8 @@ use std::{ use roles_logic_sv2::parsers::Mining; +use crate::lib::mempool::JdsMempoolError; + #[derive(std::fmt::Debug)] pub enum JdsError { Io(std::io::Error), @@ -19,6 +21,7 @@ pub enum JdsError { PoisonLock(String), Custom(String), Sv2ProtocolError((u32, Mining<'static>)), + MempoolError(JdsMempoolError), } impl std::fmt::Display for JdsError { @@ -38,6 +41,7 @@ impl std::fmt::Display for JdsError { Sv2ProtocolError(ref e) => { write!(f, "Received Sv2 Protocol Error from upstream: `{:?}`", e) } + MempoolError(ref e) => write!(f, "Mempool error: `{:?}`", e), } } } @@ -106,3 +110,9 @@ impl From<(u32, Mining<'static>)> for JdsError { JdsError::Sv2ProtocolError(e) } } + +impl From for JdsError { + fn from(error: JdsMempoolError) -> Self { + JdsError::MempoolError(error) + } +} diff --git a/roles/jd-server/src/lib/status.rs b/roles/jd-server/src/lib/status.rs index 2ed9b1cba..b05294e47 100644 --- a/roles/jd-server/src/lib/status.rs +++ b/roles/jd-server/src/lib/status.rs @@ -60,6 +60,13 @@ async fn send_status( .await .unwrap_or(()); } + JdsError::MempoolError(_) => { + tx.send(Status { + state: State::TemplateProviderShutdown(e), + }) + .await + .unwrap_or(()); + } _ => { let string_err = e.to_string(); tx.send(Status { @@ -111,5 +118,8 @@ pub async fn handle_error(sender: &Sender, e: JdsError) -> error_handling::Error JdsError::Sv2ProtocolError(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } + JdsError::MempoolError(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } } } diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index c41acb729..a2b6162c7 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -1,6 +1,19 @@ #![allow(special_module_name)] use crate::lib::{mempool, status, Configuration}; use async_channel::unbounded; +use codec_sv2::{StandardEitherFrame, StandardSv2Frame}; +use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; +use roles_logic_sv2::{ + errors::Error, parsers::PoolMessages as JdsMessages, utils::CoinbaseOutput as CoinbaseOutput_, +}; +use serde::Deserialize; +use std::convert::{TryFrom, TryInto}; + +use error_handling::handle_result; +use stratum_common::bitcoin::{Script, TxOut}; +use tracing::{error, info, warn}; + +use crate::lib::mempool; use roles_logic_sv2::utils::Mutex; use std::{sync::Arc, time::Duration}; use tokio::{select, task}; @@ -156,24 +169,29 @@ async fn main() { ))); let mempool_update_timeout = config.mempool_update_timeout; let mempool_cloned_ = mempool.clone(); + let (status_tx, status_rx) = unbounded(); + let sender = status::Sender::Downstream(status_tx.clone()); if url.contains("http") { + let sender_clone = sender.clone(); task::spawn(async move { loop { let updated_mempool = mempool::JDsMempool::update_mempool(mempool_cloned_.clone()).await; if let Err(err) = updated_mempool { - panic!("{:?}\nUnable to connect to Template Provider (possible reasons: not fully synced, down)", err) + error!("{:?}", err); + error!("Unable to connect to Template Provider (possible reasons: not fully synced, down)"); + handle_result!(sender_clone, Err(err)); } tokio::time::sleep(mempool_update_timeout).await; } }); }; - let (status_tx, status_rx) = unbounded(); + //let (status_tx, status_rx) = unbounded(); info!("Jds INITIALIZING with config: {:?}", &args.config_path); let cloned = config.clone(); - let sender = status::Sender::Downstream(status_tx.clone()); + let mempool_cloned = mempool.clone(); task::spawn(async move { JobDeclarator::start(cloned, sender, mempool_cloned).await }); From b1f815ba2418ceb6e78d8d36efe21f8cecdfc916 Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Thu, 25 Jan 2024 12:12:29 +0100 Subject: [PATCH 27/28] last fixes --- roles/jd-server/jds-config.toml | 24 ----------------- roles/jd-server/src/lib/error.rs | 2 +- roles/jd-server/src/lib/mod.rs | 36 ++++++++++++++++++++++++- roles/jd-server/src/main.rs | 46 ++++++++++---------------------- 4 files changed, 50 insertions(+), 58 deletions(-) delete mode 100644 roles/jd-server/jds-config.toml diff --git a/roles/jd-server/jds-config.toml b/roles/jd-server/jds-config.toml deleted file mode 100644 index 05b2356a0..000000000 --- a/roles/jd-server/jds-config.toml +++ /dev/null @@ -1,24 +0,0 @@ -# SRI Pool config -authority_public_key = "3VANfft6ei6jQq1At7d8nmiZzVhBFS4CiQujdgim1ign" -authority_secret_key = "7qbpUjScc865jyX2kiB4NVJANoC7GA7TAJupdzXWkc62" -cert_validity_sec = 3600 - -# List of coinbase outputs used to build the coinbase tx -# ! Right now only one output is supported, so comment all the ones you don't need ! -# For P2PK, P2PKH, P2WPKH, P2TR a BIP32 extended public key is needed -coinbase_outputs = [ - { output_script_type = "P2WPKH", output_script_value = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075" }, -] - -# SRI Pool JD config -listen_jd_address = "0.0.0.0:34264" -# RPC config for mempool (it can be also the same TP if correctly configured) -core_rpc_url = "http://127.0.0.1" -#core_rpc_port = 18443 -core_rpc_port = 18332 -core_rpc_user = "username" -core_rpc_pass = "password" -# Timeout used for JDS mempool update -[mempool_update_timeout] -unit = "secs" -value = 1 diff --git a/roles/jd-server/src/lib/error.rs b/roles/jd-server/src/lib/error.rs index e13d3099d..ce97fbae1 100644 --- a/roles/jd-server/src/lib/error.rs +++ b/roles/jd-server/src/lib/error.rs @@ -6,7 +6,7 @@ use std::{ use roles_logic_sv2::parsers::Mining; -use crate::lib::mempool::JdsMempoolError; +use crate::mempool::JdsMempoolError; #[derive(std::fmt::Debug)] pub enum JdsError { diff --git a/roles/jd-server/src/lib/mod.rs b/roles/jd-server/src/lib/mod.rs index 33142b454..951157fad 100644 --- a/roles/jd-server/src/lib/mod.rs +++ b/roles/jd-server/src/lib/mod.rs @@ -9,7 +9,10 @@ use roles_logic_sv2::{ errors::Error, parsers::PoolMessages as JdsMessages, utils::CoinbaseOutput as CoinbaseOutput_, }; use serde::Deserialize; -use std::convert::{TryFrom, TryInto}; +use std::{ + convert::{TryFrom, TryInto}, + time::Duration, +}; use stratum_common::bitcoin::{Script, TxOut}; pub type Message = JdsMessages<'static>; @@ -63,4 +66,35 @@ pub struct Configuration { pub core_rpc_port: u16, pub core_rpc_user: String, pub core_rpc_pass: String, + #[serde(deserialize_with = "duration_from_toml")] + pub mempool_update_timeout: Duration, +} + +fn duration_from_toml<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + #[derive(Deserialize)] + struct Helper { + unit: String, + value: u64, + } + + let helper = Helper::deserialize(deserializer)?; + match helper.unit.as_str() { + "seconds" => Ok(Duration::from_secs(helper.value)), + "secs" => Ok(Duration::from_secs(helper.value)), + "s" => Ok(Duration::from_secs(helper.value)), + "milliseconds" => Ok(Duration::from_millis(helper.value)), + "millis" => Ok(Duration::from_millis(helper.value)), + "ms" => Ok(Duration::from_millis(helper.value)), + "microseconds" => Ok(Duration::from_micros(helper.value)), + "micros" => Ok(Duration::from_micros(helper.value)), + "us" => Ok(Duration::from_micros(helper.value)), + "nanoseconds" => Ok(Duration::from_nanos(helper.value)), + "nanos" => Ok(Duration::from_nanos(helper.value)), + "ns" => Ok(Duration::from_nanos(helper.value)), + // ... add other units as needed + _ => Err(serde::de::Error::custom("Unsupported duration unit")), + } } diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index a2b6162c7..eda84464a 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -1,4 +1,4 @@ -#![allow(special_module_name)] +/* #![allow(special_module_name)] use crate::lib::{mempool, status, Configuration}; use async_channel::unbounded; use codec_sv2::{StandardEitherFrame, StandardSv2Frame}; @@ -13,7 +13,7 @@ use error_handling::handle_result; use stratum_common::bitcoin::{Script, TxOut}; use tracing::{error, info, warn}; -use crate::lib::mempool; +//use crate::lib::mempool; use roles_logic_sv2::utils::Mutex; use std::{sync::Arc, time::Duration}; use tokio::{select, task}; @@ -39,7 +39,18 @@ pub struct Configuration { pub core_rpc_pass: String, #[serde(deserialize_with = "duration_from_toml")] pub mempool_update_timeout: Duration, -} +} */ +#![allow(special_module_name)] +use crate::lib::{mempool, status, Configuration}; +use async_channel::unbounded; +use error_handling::handle_result; +use roles_logic_sv2::utils::Mutex; +use std::sync::Arc; +use tokio::{select, task}; +use tracing::{error, info, warn}; +mod lib; + +use lib::job_declarator::JobDeclarator; mod args { use std::path::PathBuf; @@ -104,35 +115,6 @@ mod args { } } -fn duration_from_toml<'de, D>(deserializer: D) -> Result -where - D: serde::Deserializer<'de>, -{ - #[derive(Deserialize)] - struct Helper { - unit: String, - value: u64, - } - - let helper = Helper::deserialize(deserializer)?; - match helper.unit.as_str() { - "seconds" => Ok(Duration::from_secs(helper.value)), - "secs" => Ok(Duration::from_secs(helper.value)), - "s" => Ok(Duration::from_secs(helper.value)), - "milliseconds" => Ok(Duration::from_millis(helper.value)), - "millis" => Ok(Duration::from_millis(helper.value)), - "ms" => Ok(Duration::from_millis(helper.value)), - "microseconds" => Ok(Duration::from_micros(helper.value)), - "micros" => Ok(Duration::from_micros(helper.value)), - "us" => Ok(Duration::from_micros(helper.value)), - "nanoseconds" => Ok(Duration::from_nanos(helper.value)), - "nanos" => Ok(Duration::from_nanos(helper.value)), - "ns" => Ok(Duration::from_nanos(helper.value)), - // ... add other units as needed - _ => Err(serde::de::Error::custom("Unsupported duration unit")), - } -} - #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); From 22f43fe9e85e84b446eccb3cea51b39b2891b71a Mon Sep 17 00:00:00 2001 From: GitGab19 Date: Fri, 26 Jan 2024 15:39:53 +0100 Subject: [PATCH 28/28] last changes --- .../v2/roles-logic-sv2/src/channel_logic/channel_factory.rs | 2 ++ roles/translator/src/lib/downstream_sv1/diff_management.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs index dfb133e8b..8bf351a04 100644 --- a/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs +++ b/protocols/v2/roles-logic-sv2/src/channel_logic/channel_factory.rs @@ -1499,6 +1499,8 @@ impl ProxyExtendedChannelFactory { let error = SubmitSharesError { channel_id: m.channel_id, sequence_number: m.sequence_number, + // Infallible unwrap we already know the len of the error code (is a + // static string) error_code: SubmitSharesError::invalid_job_id_error_code() .to_string() .try_into() diff --git a/roles/translator/src/lib/downstream_sv1/diff_management.rs b/roles/translator/src/lib/downstream_sv1/diff_management.rs index e534af443..775ec282c 100644 --- a/roles/translator/src/lib/downstream_sv1/diff_management.rs +++ b/roles/translator/src/lib/downstream_sv1/diff_management.rs @@ -243,6 +243,8 @@ impl Downstream { || (hashrate_delta_percentage >= 30.0) && (delta_time >= 240) || (hashrate_delta_percentage >= 15.0) && (delta_time >= 300) { + // realized_share_per_min is 0.0 when d.difficulty_mgmt.submits_since_last_update is 0 + // so it's safe to compare realized_share_per_min with == 0.0 if realized_share_per_min == 0.0 { new_miner_hashrate = match delta_time { dt if dt <= 30 => d.difficulty_mgmt.min_individual_miner_hashrate / 1.5,