Skip to content

Commit 0efb89b

Browse files
authored
Fix/diff interval (dmnd-pool#61)
* make diff adjustment interval configurable * fix * update expected hashrate calculation * update api with initial stats * add submit share failure counter
1 parent ebcb414 commit 0efb89b

6 files changed

Lines changed: 68 additions & 33 deletions

File tree

src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ struct Args {
7777
noise_connection_log: String,
7878
#[clap(long = "delay", default_value = "0")]
7979
delay: u64,
80+
#[clap(long = "interval", short = 'i', default_value = "120000")]
81+
adjustment_interval: u64,
8082
}
8183

8284
#[tokio::main]
@@ -166,6 +168,7 @@ async fn initialize_proxy(
166168
Ok(connection) => connection,
167169
Err(_) => {
168170
error!("No upstream available. Retrying...");
171+
error!("Are you using the correct TOKEN??");
169172
let mut secs = 10;
170173
while secs > 0 {
171174
tracing::warn!("Retrying in {} seconds...", secs);

src/translator/downstream/accept_connection.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,20 @@ pub async fn start_accept_connection(
3333
let _s = tx_mining_notify.subscribe();
3434
while let Some((send, recv, addr)) = downstreams.recv().await {
3535
info!("Translator opening connection for ip {}", addr);
36-
// TODO handle also cases where a cpuminer want to connect
37-
let expected_hash_rate = *crate::EXPECTED_SV1_HASHPOWER;
36+
37+
// The initial difficulty is derived from the formula: difficulty = hash_rate / (shares_per_second * 2^32)
38+
let initial_hash_rate = *crate::EXPECTED_SV1_HASHPOWER;
39+
let share_per_second = crate::SHARE_PER_MIN / 60.0;
40+
let initial_difficulty =
41+
dbg!(initial_hash_rate / (share_per_second * 2f32.powf(32.0)));
42+
let initial_difficulty =
43+
crate::translator::downstream::diff_management::nearest_power_of_10(
44+
initial_difficulty,
45+
);
46+
47+
// Formula: expected_hash_rate = (shares_per_second) * initial_difficulty * 2^32, where shares_per_second = SHARE_PER_MIN / 60
48+
let expected_hash_rate =
49+
(crate::SHARE_PER_MIN / 60.0) * initial_difficulty * 2f32.powf(32.0);
3850
if Bridge::ready(&bridge).await.is_err() {
3951
error!("Bridge not ready");
4052
break;
@@ -66,6 +78,7 @@ pub async fn start_accept_connection(
6678
send,
6779
recv,
6880
task_manager.clone(),
81+
initial_difficulty,
6982
stats_sender.clone(),
7083
)
7184
.await

src/translator/downstream/diff_management.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ impl Downstream {
1717
/// Initializes difficult managment.
1818
/// Send downstream a first target.
1919
pub async fn init_difficulty_management(self_: &Arc<Mutex<Self>>) -> ProxyResult<()> {
20-
let diff = self_.safe_lock(|d| d.difficulty_mgmt.current_difficulty)?;
20+
let (diff, stats_sender, connection_id, estimated_hashrate) = self_.safe_lock(|d| {
21+
(
22+
d.difficulty_mgmt.current_difficulty,
23+
d.stats_sender.clone(),
24+
d.connection_id,
25+
d.difficulty_mgmt.estimated_downstream_hash_rate,
26+
)
27+
})?;
2128

2229
let (message, _) = diff_to_sv1_message(diff as f64)?;
2330
Downstream::send_message_downstream(self_.clone(), message.clone()).await;
@@ -38,7 +45,8 @@ impl Downstream {
3845
Downstream::send_message_downstream(self_clone.clone(), message.clone()).await;
3946
}
4047
});
41-
48+
stats_sender.update_diff(connection_id, diff);
49+
stats_sender.update_hashrate(connection_id, estimated_hashrate);
4250
tokio::spawn(crate::translator::utils::check_share_rate_limit());
4351

4452
Ok(())

src/translator/downstream/downstream.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use crate::{
33
proxy_state::{DownstreamType, ProxyState},
44
shared::utils::AbortOnDrop,
55
translator::{
6-
downstream::diff_management::nearest_power_of_10,
76
error::Error,
87
utils::{allow_submit_share, validate_share},
98
},
@@ -124,18 +123,13 @@ impl Downstream {
124123
send_to_down: Sender<String>,
125124
recv_from_down: Receiver<String>,
126125
task_manager: Arc<Mutex<TaskManager>>,
126+
initial_difficulty: f32,
127127
stats_sender: StatsSender,
128128
) {
129129
assert!(last_notify.is_some());
130130

131131
let (tx_outgoing, receiver_outgoing) = channel(crate::TRANSLATOR_BUFFER_SIZE);
132132

133-
// The initial difficulty is derived from the formula: difficulty = hash_rate / (shares_per_second * 2^32),
134-
let initial_hash_rate = *crate::EXPECTED_SV1_HASHPOWER;
135-
let share_per_second = crate::SHARE_PER_MIN / 60.0;
136-
let initial_difficulty = dbg!(initial_hash_rate / (share_per_second * 2f32.powf(32.0)));
137-
let initial_difficulty = nearest_power_of_10(initial_difficulty);
138-
139133
// The PID controller uses negative proportional (P) and integral (I) gains to reduce difficulty
140134
// when the actual share rate falls below the target rate (SHARE_PER_MIN). Negative gains are chosen
141135
// because a lower share rate indicates the difficulty is too high for the miner, requiring a downward

src/translator/downstream/notify.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ async fn start_update(
145145
{
146146
std::time::Duration::from_millis(5000)
147147
} else {
148-
// TODO we really need to use differenet times seems to work well enaugh with 5 sec
149-
std::time::Duration::from_millis(5000)
148+
std::time::Duration::from_millis(crate::ARGS.adjustment_interval)
150149
};
151150

152151
tokio::time::sleep(sleep_duration).await;

src/translator/proxy/bridge.rs

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ use roles_logic_sv2::{
88
parsers::Mining,
99
utils::{GroupId, Mutex},
1010
};
11-
use std::sync::Arc;
11+
use std::sync::{
12+
atomic::{AtomicU32, Ordering},
13+
Arc,
14+
};
1215
use sv1_api::{client_to_server::Submit, server_to_client, utils::HexU32Be};
1316
use tokio::sync::broadcast;
1417

@@ -23,8 +26,13 @@ use crate::{
2326
proxy_state::{ProxyState, TranslatorState, UpstreamType},
2427
shared::utils::AbortOnDrop,
2528
};
29+
use lazy_static::lazy_static;
2630
use roles_logic_sv2::{channel_logic::channel_factory::OnNewShare, Error as RolesLogicError};
27-
use tracing::{debug, error, info};
31+
use tracing::{debug, error, info, warn};
32+
33+
lazy_static! {
34+
static ref SUBMIT_FAIL_COUNTER: AtomicU32 = AtomicU32::new(0);
35+
}
2836

2937
/// Bridge between the SV2 `Upstream` and SV1 `Downstream` responsible for the following messaging
3038
/// translation:
@@ -78,7 +86,6 @@ impl Bridge {
7886
) -> Result<Arc<Mutex<Self>>, Error<'static>> {
7987
info!("Creating new bridge for up_id {}:", up_id);
8088
let ids = Arc::new(Mutex::new(GroupId::new()));
81-
let share_per_min = 1.0;
8289
let upstream_target: [u8; 32] = target.safe_lock(|t| {
8390
t.clone().try_into().expect("Internal error: this operation can not fail because Vec<U8> can always be converted into [u8; 32]")
8491
}).map_err(|e| Error::TargetError(RolesLogicError::PoisonLock(e.to_string())))?;
@@ -91,7 +98,7 @@ impl Bridge {
9198
ids,
9299
extranonces,
93100
None,
94-
share_per_min,
101+
crate::SHARE_PER_MIN,
95102
ExtendedChannelKind::Proxy { upstream_target },
96103
None,
97104
up_id,
@@ -254,29 +261,33 @@ impl Bridge {
254261
let res = self_
255262
.safe_lock(|s| {
256263
s.channel_factory.set_target(&mut upstream_target);
257-
let sv2_submit = match s.translate_submit(
264+
match s.translate_submit(
258265
share.channel_id,
259266
share.share,
260267
share.version_rolling_mask,
261268
) {
262-
Ok(submit_shares_extended) => submit_shares_extended,
269+
Ok(submit_shares_extended) => {
270+
// Ordering::Relaxed is safe here because we only need simple counter updates.
271+
// No need for strict ordering since it just tracks failures.
272+
SUBMIT_FAIL_COUNTER.store(0, Ordering::Relaxed); // Reset on success
273+
s.channel_factory.on_submit_shares_extended(submit_shares_extended)
274+
},
263275
Err(e) => {
264-
error!("Failed to Translates SV1 mining.submit message to SV2 SubmitSharesExtended message");
265-
return Err(e); // Error will be handled by the caller
276+
error!("Failed to Translates SV1 mining.submit message to SV2 SubmitSharesExtended message: {e}");
277+
Err(roles_logic_sv2::Error::NoValidJob) // Error will be handled by the caller
266278
}
267-
};
268-
Ok(s.channel_factory.on_submit_shares_extended(sv2_submit))
279+
}
269280
})
270281
.map_err(|_| Error::BridgeMutexPoisoned)?;
271282

272283
match res {
273-
Ok(Ok(OnNewShare::SendErrorDownstream(e))) => {
284+
Ok(OnNewShare::SendErrorDownstream(e)) => {
274285
let error_code = std::str::from_utf8(&e.error_code.to_vec()[..])
275286
.unwrap_or("unparsable error code")
276287
.to_string();
277288
error!("Submit share error {}", error_code);
278289
}
279-
Ok(Ok(OnNewShare::SendSubmitShareUpstream((share, _)))) => {
290+
Ok(OnNewShare::SendSubmitShareUpstream((share, _))) => {
280291
info!("SHARE MEETS UPSTREAM TARGET channel id: {}", channel_id);
281292
match share {
282293
Share::Extended(share) => {
@@ -290,19 +301,26 @@ impl Bridge {
290301
}
291302
}
292303
// We are in an extended channel this variant is group channle only
293-
Ok(Ok(OnNewShare::RelaySubmitShareUpstream)) => unreachable!(),
294-
Ok(Ok(OnNewShare::ShareMeetDownstreamTarget)) => {
304+
Ok(OnNewShare::RelaySubmitShareUpstream) => unreachable!(),
305+
Ok(OnNewShare::ShareMeetDownstreamTarget) => {
295306
info!("SHARE MEETS DOWNSTREAM TARGET channel id {}", channel_id);
296307
}
297308
// Proxy do not have JD capabilities
298-
Ok(Ok(OnNewShare::ShareMeetBitcoinTarget(..))) => unreachable!(),
299-
Ok(Err(e)) => {
300-
error!("{}", e);
301-
return Err(Error::RolesSv2Logic(e));
309+
Ok(OnNewShare::ShareMeetBitcoinTarget(..)) => unreachable!(),
310+
Err(roles_logic_sv2::Error::NoValidJob) => {
311+
let count = SUBMIT_FAIL_COUNTER.fetch_add(1, Ordering::Relaxed) + 1;
312+
if count >= 10 {
313+
error!("Failed to translate SV1 mining.submit message to SV2 SubmitSharesExtended message after 10 attempts");
314+
return Err(Error::RolesSv2Logic(roles_logic_sv2::Error::NoValidJob));
315+
} else {
316+
warn!(
317+
"Failed to translate SV1 mining.submit message to SV2 SubmitSharesExtended message, attempt {}",
318+
count
319+
);
320+
}
302321
}
303322
Err(e) => {
304-
error!("{}", e);
305-
return Err(e);
323+
return Err(Error::RolesSv2Logic(e));
306324
}
307325
}
308326
Ok(())

0 commit comments

Comments
 (0)