Skip to content

Commit 802c84c

Browse files
authored
Merge pull request #2011 from plebhash/2025-11-28-job-store-trait-send-sync
`JobStore` trait methods return owned types instead of refs
2 parents 80c7e7f + 98bf0bb commit 802c84c

7 files changed

Lines changed: 139 additions & 115 deletions

File tree

stratum-core/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ framing_sv2 = { path = "../sv2/framing-sv2", version = "^6.0.0" }
2121
noise_sv2 = { path = "../sv2/noise-sv2", version = "^1.0.0" }
2222
parsers_sv2 = { path = "../sv2/parsers-sv2", version = "^0.2.0" }
2323
handlers_sv2 = { path = "../sv2/handlers-sv2", version = "^0.2.0" }
24-
channels_sv2 = { path = "../sv2/channels-sv2", version = "^2.0.0" }
24+
channels_sv2 = { path = "../sv2/channels-sv2", version = "^3.0.0" }
2525
common_messages_sv2 = { path = "../sv2/subprotocols/common-messages", version = "^6.0.0" }
2626
mining_sv2 = { path = "../sv2/subprotocols/mining", version = "^6.0.0" }
2727
template_distribution_sv2 = { path = "../sv2/subprotocols/template-distribution", version = "^4.0.0" }

stratum-core/stratum-translation/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ path = "src/lib.rs"
1313
bitcoin = { version = "0.32.5" }
1414
binary_sv2 = { path = "../../sv2/binary-sv2", version = "^5.0.0" }
1515
mining_sv2 = { path = "../../sv2/subprotocols/mining", version = "^6.0.0" }
16-
channels_sv2 = { path = "../../sv2/channels-sv2", version = "^2.0.0" }
16+
channels_sv2 = { path = "../../sv2/channels-sv2", version = "^3.0.0" }
1717
v1 = { path = "../../sv1", package = "sv1_api", version = "^2.0.0" }
1818
tracing = "0.1"

sv2/channels-sv2/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "channels_sv2"
3-
version = "2.0.0"
3+
version = "3.0.0"
44
authors = ["The Stratum V2 Developers"]
55
edition = "2021"
66
readme = "README.md"

sv2/channels-sv2/src/server/extended.rs

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ use bitcoin::{
5757
CompactTarget, Target,
5858
};
5959
use mining_sv2::{SetCustomMiningJob, SubmitSharesExtended};
60-
use std::{collections::HashMap, convert::TryInto, marker::PhantomData};
60+
use std::{convert::TryInto, marker::PhantomData};
6161
use template_distribution_sv2::{NewTemplate, SetNewPrevHash as SetNewPrevHashTdp};
6262
use tracing::debug;
6363

@@ -327,9 +327,10 @@ where
327327
self.target = target;
328328
}
329329

330-
/// Returns the mapping of future template IDs to job IDs.
331-
pub fn get_future_template_to_job_id(&self) -> &HashMap<u64, u32> {
332-
self.job_store.get_future_template_to_job_id()
330+
/// Returns the job ID for a future job from a template ID, if any.
331+
pub fn get_future_job_id_from_template_id(&self, template_id: u64) -> Option<u32> {
332+
self.job_store
333+
.get_future_job_id_from_template_id(template_id)
333334
}
334335

335336
/// Returns the nominal hashrate for this channel.
@@ -405,17 +406,23 @@ where
405406

406407
Ok(())
407408
}
408-
/// Returns the currently active job, if any.
409-
pub fn get_active_job(&self) -> Option<&ExtendedJob<'a>> {
409+
410+
/// Returns an owned copy of the currently active job, if any.
411+
pub fn get_active_job(&self) -> Option<ExtendedJob<'a>> {
412+
// cloning happens inside the job store
410413
self.job_store.get_active_job()
411414
}
412-
/// Returns all future jobs for this channel.
413-
pub fn get_future_jobs(&self) -> &HashMap<u32, ExtendedJob<'a>> {
414-
self.job_store.get_future_jobs()
415+
416+
/// Returns an owned copy of a future job from its job ID, if any.
417+
pub fn get_future_job(&self, job_id: u32) -> Option<ExtendedJob<'a>> {
418+
// cloning happens inside the job store
419+
self.job_store.get_future_job(job_id)
415420
}
416-
/// Returns all past jobs for this channel.
417-
pub fn get_past_jobs(&self) -> &HashMap<u32, ExtendedJob<'a>> {
418-
self.job_store.get_past_jobs()
421+
422+
/// Returns an owned copy of a past job from its job ID, if any.
423+
pub fn get_past_job(&self, job_id: u32) -> Option<ExtendedJob<'a>> {
424+
// cloning happens inside the job store
425+
self.job_store.get_past_job(job_id)
419426
}
420427
/// Returns a reference to the share accounting state for this channel.
421428
pub fn get_share_accounting(&self) -> &ShareAccounting {
@@ -489,13 +496,13 @@ where
489496
set_new_prev_hash: SetNewPrevHashTdp<'a>,
490497
) -> Result<(), ExtendedChannelError> {
491498
// extended channels dedicated to custom work don't need to keep track of future jobs
492-
match self.job_store.get_future_jobs().is_empty() {
493-
true => {
499+
match self.job_store.has_future_jobs() {
500+
false => {
494501
// explicitly mark past jobs as stale, because we're not going to
495502
// do it implicitly via activate_future_job in case this extended channel is doing custom work
496503
self.job_store.mark_past_jobs_as_stale();
497504
}
498-
false => {
505+
true => {
499506
// try to activate the future job, and also mark past jobs as stale
500507
if !self.job_store.activate_future_job(
501508
set_new_prev_hash.template_id,
@@ -570,10 +577,10 @@ where
570577
.is_some_and(|job| job.get_job_id() == job_id);
571578

572579
// check if job_id is past job
573-
let is_past_job = self.job_store.get_past_jobs().contains_key(&job_id);
580+
let is_past_job = self.job_store.get_past_job(job_id).is_some();
574581

575582
// check if job_id is stale job
576-
let is_stale_job = self.job_store.get_stale_jobs().contains_key(&job_id);
583+
let is_stale_job = self.job_store.get_stale_job(job_id).is_some();
577584

578585
if is_stale_job {
579586
return Err(ShareValidationError::Stale);
@@ -582,21 +589,19 @@ where
582589
// if job_id is not active, past or stale, return error
583590
if !is_active_job && !is_past_job && !is_stale_job {
584591
return Err(ShareValidationError::InvalidJobId);
585-
}
592+
};
586593

587594
let job = if is_active_job {
588595
self.job_store
589596
.get_active_job()
590597
.expect("active job must exist")
591598
} else if is_past_job {
592599
self.job_store
593-
.get_past_jobs()
594-
.get(&job_id)
600+
.get_past_job(job_id)
595601
.expect("past job must exist")
596602
} else {
597603
self.job_store
598-
.get_stale_jobs()
599-
.get(&job_id)
604+
.get_stale_job(job_id)
600605
.expect("stale job must exist")
601606
};
602607

@@ -733,7 +738,7 @@ mod tests {
733738
server::{
734739
error::ExtendedChannelError,
735740
extended::ExtendedChannel,
736-
jobs::job_store::DefaultJobStore,
741+
jobs::job_store::{DefaultJobStore, JobStore},
737742
share_accounting::{ShareValidationError, ShareValidationResult},
738743
},
739744
};
@@ -816,22 +821,17 @@ mod tests {
816821
script_pubkey: script,
817822
}];
818823

819-
assert!(channel.get_future_jobs().is_empty());
824+
assert!(!channel.job_store.has_future_jobs());
820825
channel
821826
.on_new_template(template.clone(), coinbase_reward_outputs)
822827
.unwrap();
823828
assert!(channel.get_active_job().is_none());
824829

825830
let future_job_id = channel
826-
.get_future_template_to_job_id()
827-
.get(&template.template_id)
831+
.get_future_job_id_from_template_id(template.template_id)
828832
.unwrap();
829833

830-
let future_job = channel
831-
.get_future_jobs()
832-
.get(future_job_id)
833-
.unwrap()
834-
.clone();
834+
let future_job = channel.get_future_job(future_job_id).unwrap();
835835

836836
// we know that the provided template + coinbase_reward_outputs should generate this future
837837
// job
@@ -881,7 +881,7 @@ mod tests {
881881
channel.on_set_new_prev_hash(set_new_prev_hash).unwrap();
882882

883883
// we just activated the only future job
884-
assert!(channel.get_future_jobs().is_empty());
884+
assert!(!channel.job_store.has_future_jobs());
885885

886886
let mut previously_future_job = future_job.clone();
887887
previously_future_job.activate(ntime);
@@ -982,7 +982,7 @@ mod tests {
982982
.on_new_template(template.clone(), coinbase_reward_outputs)
983983
.unwrap();
984984

985-
assert!(channel.get_future_jobs().is_empty());
985+
assert!(!channel.job_store.has_future_jobs());
986986

987987
let active_job = channel.get_active_job().unwrap().clone();
988988

@@ -1090,7 +1090,7 @@ mod tests {
10901090
let res = channel.on_new_template(template.clone(), invalid_coinbase_reward_outputs);
10911091

10921092
assert!(res.is_err());
1093-
assert!(channel.get_future_jobs().is_empty());
1093+
assert!(!channel.job_store.has_future_jobs());
10941094
}
10951095

10961096
#[test]

sv2/channels-sv2/src/server/group.rs

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,7 @@ use crate::{
3939
},
4040
};
4141
use bitcoin::transaction::TxOut;
42-
use std::{
43-
collections::{HashMap, HashSet},
44-
marker::PhantomData,
45-
};
42+
use std::{collections::HashSet, marker::PhantomData};
4643
use template_distribution_sv2::{NewTemplate, SetNewPrevHash as SetNewPrevHashTdp};
4744

4845
/// Abstraction of a Group Channel.
@@ -195,19 +192,22 @@ where
195192
self.chain_tip = Some(chain_tip);
196193
}
197194

198-
/// Returns the currently active job, if any.
199-
pub fn get_active_job(&self) -> Option<&ExtendedJob<'a>> {
195+
/// Returns an owned copy of the currently active job, if any.
196+
pub fn get_active_job(&self) -> Option<ExtendedJob<'a>> {
197+
// cloning happens inside the job store
200198
self.job_store.get_active_job()
201199
}
202200

203-
/// Returns the mapping of future template IDs to job IDs.
204-
pub fn get_future_template_to_job_id(&self) -> &HashMap<u64, u32> {
205-
self.job_store.get_future_template_to_job_id()
201+
/// Returns the job ID for a future job from a template ID, if any.
202+
pub fn get_future_job_id_from_template_id(&self, template_id: u64) -> Option<u32> {
203+
self.job_store
204+
.get_future_job_id_from_template_id(template_id)
206205
}
207206

208-
/// Returns all future jobs for this group channel.
209-
pub fn get_future_jobs(&self) -> &HashMap<u32, ExtendedJob<'a>> {
210-
self.job_store.get_future_jobs()
207+
/// Returns an owned copy of a future job from its job ID, if any.
208+
pub fn get_future_job(&self, job_id: u32) -> Option<ExtendedJob<'a>> {
209+
// cloning happens inside the job store
210+
self.job_store.get_future_job(job_id)
211211
}
212212

213213
/// Updates the group channel state with a new template.
@@ -275,11 +275,11 @@ where
275275
&mut self,
276276
set_new_prev_hash: SetNewPrevHashTdp<'a>,
277277
) -> Result<(), GroupChannelError> {
278-
match self.job_store.get_future_jobs().is_empty() {
279-
true => {
278+
match self.job_store.has_future_jobs() {
279+
false => {
280280
return Err(GroupChannelError::TemplateIdNotFound);
281281
}
282-
false => {
282+
true => {
283283
self.job_store.activate_future_job(
284284
set_new_prev_hash.template_id,
285285
set_new_prev_hash.header_timestamp,
@@ -298,7 +298,10 @@ where
298298
mod tests {
299299
use crate::{
300300
chain_tip::ChainTip,
301-
server::{group::GroupChannel, jobs::job_store::DefaultJobStore},
301+
server::{
302+
group::GroupChannel,
303+
jobs::job_store::{DefaultJobStore, JobStore},
304+
},
302305
};
303306
use binary_sv2::Sv2Option;
304307
use bitcoin::{transaction::TxOut, Amount, ScriptBuf};
@@ -360,22 +363,17 @@ mod tests {
360363
script_pubkey: script,
361364
}];
362365

363-
assert!(group_channel.get_future_jobs().is_empty());
366+
assert!(!group_channel.job_store.has_future_jobs());
364367
group_channel
365368
.on_new_template(template.clone(), coinbase_reward_outputs)
366369
.unwrap();
367370
assert!(group_channel.get_active_job().is_none());
368371

369372
let future_job_id = group_channel
370-
.get_future_template_to_job_id()
371-
.get(&template.template_id)
373+
.get_future_job_id_from_template_id(template.template_id)
372374
.unwrap();
373375

374-
let future_job = group_channel
375-
.get_future_jobs()
376-
.get(future_job_id)
377-
.unwrap()
378-
.clone();
376+
let future_job = group_channel.get_future_job(future_job_id).unwrap();
379377

380378
// we know that the provided template + coinbase_reward_outputs should generate this future
381379
// job
@@ -597,6 +595,6 @@ mod tests {
597595
.on_new_template(template.clone(), invalid_coinbase_reward_outputs)
598596
.is_err());
599597

600-
assert!(group_channel.get_future_jobs().is_empty());
598+
assert!(!group_channel.job_store.has_future_jobs());
601599
}
602600
}

0 commit comments

Comments
 (0)