From 8af3e69829995f98ecd73d4a6ac357ac757ef5c4 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 22 Sep 2025 13:19:14 -0400 Subject: [PATCH 01/39] feat: add Persistence trait for ShareAccounting with async channel support - Add persistence.rs module with trait-based abstraction for share accounting events - Include ShareAccountingEvent enum capturing share accepted, hash flush, and difficulty update events - Implement NoPersistence struct for zero-cost no-op when persistence disabled - Add optional 'persistence' feature flag to Cargo.toml - Expose persistence module in lib.rs for public API access --- protocols/v2/channels-sv2/Cargo.toml | 1 + protocols/v2/channels-sv2/src/lib.rs | 1 + protocols/v2/channels-sv2/src/persistence.rs | 128 +++++++++++++++++++ 3 files changed, 130 insertions(+) create mode 100644 protocols/v2/channels-sv2/src/persistence.rs diff --git a/protocols/v2/channels-sv2/Cargo.toml b/protocols/v2/channels-sv2/Cargo.toml index 6d8cace62a..8277321d90 100644 --- a/protocols/v2/channels-sv2/Cargo.toml +++ b/protocols/v2/channels-sv2/Cargo.toml @@ -28,3 +28,4 @@ hashbrown = { version = "0.15.5", optional = true } [features] default = [] no_std = ["hashbrown"] +persistence = [] diff --git a/protocols/v2/channels-sv2/src/lib.rs b/protocols/v2/channels-sv2/src/lib.rs index dc8feef62e..94e6317939 100644 --- a/protocols/v2/channels-sv2/src/lib.rs +++ b/protocols/v2/channels-sv2/src/lib.rs @@ -28,6 +28,7 @@ pub mod bip141; pub mod chain_tip; pub mod client; pub mod merkle_root; +pub mod persistence; pub mod target; pub mod vardiff; pub use vardiff::{classic::VardiffState, Vardiff}; diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs new file mode 100644 index 0000000000..21539a4bfc --- /dev/null +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -0,0 +1,128 @@ +//! Share Accounting Persistence Abstraction. +//! +//! This module provides a trait-based abstraction for persisting share accounting data +//! without blocking critical mining operations. The design uses async channels to decouple +//! the hot path share processing from persistence operations. +//! +//! ## Design Goals +//! +//! - **Zero Hot Path Impact**: No `Result` types or blocking operations in share accounting methods +//! - **Async Channel Based**: Events are sent via channels for background persistence processing +//! - **Flexible Implementation**: Trait allows different persistence backends (database, file, etc.) +//! - **Optional Compilation**: Gated behind `persistence` feature flag to avoid unnecessary dependencies +//! +//! ## Usage +//! +//! The persistence system works by sending events through async channels when share accounting +//! state changes occur. Implementations of the `Persistence` trait handle these events in +//! background tasks without affecting mining performance. + +use bitcoin::hashes::sha256d::Hash; + +/// Events that can be persisted from share accounting operations. +/// +/// These events capture all the critical state changes that occur during share processing, +/// allowing persistence implementations to maintain complete historical records. +#[derive(Debug, Clone)] +pub enum ShareAccountingEvent { + /// A share was accepted and accounting was updated. + ShareAccepted { + /// The channel identifier (server-assigned for server channels, client-assigned for client channels) + channel_id: u32, + /// Work value of the accepted share + share_work: u64, + /// Sequence number of the share + share_sequence_number: u32, + /// Hash of the accepted share (for duplicate detection) + share_hash: Hash, + /// Total shares accepted after this update + total_shares_accepted: u32, + /// Total work sum after this update + total_share_work_sum: u64, + /// Timestamp when the event occurred + timestamp: std::time::SystemTime, + }, + /// Share hashes were flushed (typically on chain tip update). + ShareHashesFlushed { + /// The channel identifier + channel_id: u32, + /// Timestamp when the flush occurred + timestamp: std::time::SystemTime, + }, + /// Best difficulty was updated for the channel. + BestDifficultyUpdated { + /// The channel identifier + channel_id: u32, + /// The new best difficulty + new_best_diff: f64, + /// The previous best difficulty + previous_best_diff: f64, + /// Timestamp when the update occurred + timestamp: std::time::SystemTime, + }, +} + +/// Trait for persisting share accounting events. +/// +/// Implementations of this trait handle the background persistence of share accounting +/// events sent through async channels. This allows the hot path share processing to +/// remain completely non-blocking. +/// +/// # Design Notes +/// +/// - All methods are infallible from the caller's perspective - persistence failures +/// must be handled internally by implementations +/// - Events are timestamped to allow temporal analysis of mining operations +/// - The trait provides a unified interface regardless of whether persistence is enabled +#[cfg(feature = "persistence")] +pub trait Persistence { + /// Sends a share accounting event for persistence. + /// + /// This method MUST be non-blocking and infallible from the caller's perspective. + /// Any persistence failures should be handled internally (e.g., logged, retried, etc.). + fn persist_event(&self, event: ShareAccountingEvent); + + /// Optional method to flush any pending events. + /// + /// This is a hint that the caller would like any buffered events to be processed + /// immediately, but implementations are free to ignore this if not applicable. + fn flush(&self) {} + + /// Optional method called when the persistence handler is being dropped. + /// + /// Implementations can use this for cleanup operations, but should not block. + fn shutdown(&self) {} +} + +/// A no-op persistence implementation for when persistence is disabled. +/// +/// This allows ShareAccounting to always call persistence methods without +/// needing conditional compilation throughout the hot path code. +pub struct NoPersistence; + +impl NoPersistence { + /// Creates a new no-op persistence handler. + pub fn new() -> Self { + Self + } + + /// No-op method for share accounting events. + pub fn persist_event(&self, _event: ShareAccountingEvent) {} + + /// No-op flush method. + pub fn flush(&self) {} + + /// No-op shutdown method. + pub fn shutdown(&self) {} +} + +impl Default for NoPersistence { + fn default() -> Self { + Self::new() + } +} + +#[cfg(feature = "persistence")] +impl Persistence for NoPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) {} +} \ No newline at end of file From d24dc4e064d8b03e150dd1df08a90a7d3cf22192 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 22 Sep 2025 13:35:36 -0400 Subject: [PATCH 02/39] feat: integrate Persistence trait into ShareAccounting for async event tracking --- .../src/client/share_accounting.rs | 41 +++++++++++++++++-- protocols/v2/channels-sv2/src/persistence.rs | 7 ---- .../src/server/share_accounting.rs | 38 +++++++++++++++-- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index ee51074c30..1f9c7ef827 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -6,6 +6,7 @@ use super::HashSet; use bitcoin::hashes::sha256d::Hash; +use crate::persistence::{NoPersistence, ShareAccountingEvent}; /// The outcome of share validation, as seen by a Mining Client. /// @@ -50,29 +51,36 @@ pub enum ShareValidationError { /// - hashes of seen shares (for duplicate detection) /// - highest difficulty seen in accepted shares #[derive(Clone, Debug)] -pub struct ShareAccounting { +pub struct ShareAccounting

{ last_share_sequence_number: u32, shares_accepted: u32, share_work_sum: u64, seen_shares: HashSet, best_diff: f64, + channel_id: u32, + persistence: P, } impl Default for ShareAccounting { fn default() -> Self { - Self::new() + Self::new(0, NoPersistence::new()) } } -impl ShareAccounting { +impl

ShareAccounting

{ /// Creates a new [`ShareAccounting`] instance, initializing all statistics to zero. - pub fn new() -> Self { + /// + /// `channel_id` identifies the channel for persistence events. + /// `persistence` handles background persistence of share accounting events. + pub fn new(channel_id: u32, persistence: P) -> Self { Self { last_share_sequence_number: 0, shares_accepted: 0, share_work_sum: 0, seen_shares: HashSet::new(), best_diff: 0.0, + channel_id, + persistence, } } @@ -91,6 +99,18 @@ impl ShareAccounting { self.shares_accepted += 1; self.share_work_sum += share_work; self.seen_shares.insert(share_hash); + + // Persist the share accepted event + let event = ShareAccountingEvent::ShareAccepted { + channel_id: self.channel_id, + share_work, + share_sequence_number, + share_hash, + total_shares_accepted: self.shares_accepted, + total_share_work_sum: self.share_work_sum, + timestamp: std::time::SystemTime::now(), + }; + self.persistence.persist_event(event); } /// Clears the set of seen share hashes. @@ -99,6 +119,9 @@ impl ShareAccounting { /// to prevent unbounded memory growth. pub fn flush_seen_shares(&mut self) { self.seen_shares.clear(); + + // Ensure any pending persistence events are flushed + self.persistence.flush(); } /// Returns the sequence number of the last share received. @@ -128,8 +151,18 @@ impl ShareAccounting { /// Updates the best difficulty if the new difficulty is higher than the current best. pub fn update_best_diff(&mut self, diff: f64) { + let previous_best_diff = self.best_diff; if diff > self.best_diff { self.best_diff = diff; + + // Persist the best difficulty updated event + let event = ShareAccountingEvent::BestDifficultyUpdated { + channel_id: self.channel_id, + new_best_diff: diff, + previous_best_diff, + timestamp: std::time::SystemTime::now(), + }; + self.persistence.persist_event(event); } } } diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 21539a4bfc..7b5484c4d6 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -42,13 +42,6 @@ pub enum ShareAccountingEvent { /// Timestamp when the event occurred timestamp: std::time::SystemTime, }, - /// Share hashes were flushed (typically on chain tip update). - ShareHashesFlushed { - /// The channel identifier - channel_id: u32, - /// Timestamp when the flush occurred - timestamp: std::time::SystemTime, - }, /// Best difficulty was updated for the channel. BestDifficultyUpdated { /// The channel identifier diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index 85db09fde4..8d2d33be82 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -20,6 +20,7 @@ use bitcoin::hashes::sha256d::Hash; use std::collections::HashSet; +use crate::persistence::{NoPersistence, ShareAccountingEvent}; /// The outcome of share validation, from the perspective of a Mining Server. /// @@ -81,20 +82,24 @@ pub enum ShareValidationError { /// This struct manages per-channel share statistics, batch acknowledgment, duplicate detection, /// and difficulty tracking. Only meant for usage on Mining Servers. #[derive(Clone, Debug)] -pub struct ShareAccounting { +pub struct ShareAccounting

{ last_share_sequence_number: u32, shares_accepted: u32, share_work_sum: u64, share_batch_size: usize, seen_shares: HashSet, best_diff: f64, + channel_id: u32, + persistence: P, } -impl ShareAccounting { +impl

ShareAccounting

{ /// Constructs a new `ShareAccounting` instance for a channel. /// /// `share_batch_size` controls how many accepted shares trigger a batch acknowledgment. - pub fn new(share_batch_size: usize) -> Self { + /// `channel_id` identifies the channel for persistence events. + /// `persistence` handles background persistence of share accounting events. + pub fn new(share_batch_size: usize, channel_id: u32, persistence: P) -> Self { Self { last_share_sequence_number: 0, shares_accepted: 0, @@ -102,6 +107,8 @@ impl ShareAccounting { share_batch_size, seen_shares: HashSet::new(), best_diff: 0.0, + channel_id, + persistence, } } @@ -120,6 +127,18 @@ impl ShareAccounting { self.shares_accepted += 1; self.share_work_sum += share_work; self.seen_shares.insert(share_hash); + + // Persist the share accepted event + let event = ShareAccountingEvent::ShareAccepted { + channel_id: self.channel_id, + share_work, + share_sequence_number, + share_hash, + total_shares_accepted: self.shares_accepted, + total_share_work_sum: self.share_work_sum, + timestamp: std::time::SystemTime::now(), + }; + self.persistence.persist_event(event); } /// Clears the set of seen share hashes. @@ -128,6 +147,9 @@ impl ShareAccounting { /// and allow new shares for the new tip. pub fn flush_seen_shares(&mut self) { self.seen_shares.clear(); + + // Ensure any pending persistence events are flushed + self.persistence.flush(); } /// Returns the sequence number of the last accepted share. @@ -167,8 +189,18 @@ impl ShareAccounting { /// Updates the best difficulty if the new value is higher. pub fn update_best_diff(&mut self, diff: f64) { + let previous_best_diff = self.best_diff; if diff > self.best_diff { self.best_diff = diff; + + // Persist the best difficulty updated event + let event = ShareAccountingEvent::BestDifficultyUpdated { + channel_id: self.channel_id, + new_best_diff: diff, + previous_best_diff, + timestamp: std::time::SystemTime::now(), + }; + self.persistence.persist_event(event); } } } From da08f0889963f30e865c42038feaa2a4c676c02f Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 23 Sep 2025 09:19:14 -0400 Subject: [PATCH 03/39] feat: add feature gating for non-default Persistence constructors - Add `#[cfg(feature = "persistence")]` to `new_with_persistence` constructors in client modules: - client/extended.rs: `ExtendedChannel::new_with_persistence` - client/standard.rs: `StandardChannel::new_with_persistence` - Add `#[cfg(feature = "persistence")]` to persistence constructors in server/standard.rs: - `StandardChannel::new_for_pool_with_persistence` - `StandardChannel::new_for_job_declaration_client_with_persistence` - Ensure consistency with server/extended.rs which already had proper feature gating - All non-default Persistence constructors now require the 'persistence' feature to be enabled - Maintains backward compatibility by keeping default constructors available without feature gates - apply fmt and semver linting --- .../v2/channels-sv2/src/client/extended.rs | 65 ++++-- .../src/client/share_accounting.rs | 7 +- .../v2/channels-sv2/src/client/standard.rs | 61 ++++-- protocols/v2/channels-sv2/src/persistence.rs | 52 +++-- .../v2/channels-sv2/src/server/extended.rs | 192 ++++++++++++++++-- .../src/server/share_accounting.rs | 7 +- .../v2/channels-sv2/src/server/standard.rs | 92 ++++++++- 7 files changed, 411 insertions(+), 65 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index d0b8a076de..918260fc5d 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -13,6 +13,7 @@ use crate::{ share_accounting::{ShareAccounting, ShareValidationError, ShareValidationResult}, }, merkle_root::merkle_root_from_path, + persistence::{NoPersistence, Persistence}, target::{bytes_to_hex, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; @@ -59,7 +60,7 @@ pub type ExtendedJob<'a> = (NewExtendedMiningJob<'a>, Vec); /// - Share accounting for the channel (as tracked by the client). /// - The channel's current chain tip. #[derive(Clone, Debug)] -pub struct ExtendedChannel<'a> { +pub struct ExtendedChannel<'a, P = NoPersistence> { channel_id: u32, user_identity: String, extranonce_prefix: Vec, @@ -74,11 +75,14 @@ pub struct ExtendedChannel<'a> { past_jobs: HashMap>, // stale jobs are indexed with job_id (u32) stale_jobs: HashMap>, - share_accounting: ShareAccounting, + share_accounting: ShareAccounting

, chain_tip: Option, } -impl<'a> ExtendedChannel<'a> { +impl<'a, P> ExtendedChannel<'a, P> +where + P: Persistence, +{ /// Constructs a new [`ExtendedChannel`]. pub fn new( channel_id: u32, @@ -88,6 +92,38 @@ impl<'a> ExtendedChannel<'a> { nominal_hashrate: f32, version_rolling: bool, rollable_extranonce_size: u16, + ) -> Self + where + P: Default, + { + Self { + channel_id, + user_identity, + extranonce_prefix, + rollable_extranonce_size, + target, + nominal_hashrate, + version_rolling, + future_jobs: HashMap::new(), + active_job: None, + past_jobs: HashMap::new(), + stale_jobs: HashMap::new(), + share_accounting: ShareAccounting::new(channel_id, P::default()), + chain_tip: None, + } + } + + /// Constructs a new [`ExtendedChannel`] with custom persistence. + #[cfg(feature = "persistence")] + pub fn new_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + target: Target, + nominal_hashrate: f32, + version_rolling: bool, + rollable_extranonce_size: u16, + persistence: P, ) -> Self { Self { channel_id, @@ -101,7 +137,7 @@ impl<'a> ExtendedChannel<'a> { active_job: None, past_jobs: HashMap::new(), stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(), + share_accounting: ShareAccounting::new(channel_id, persistence), chain_tip: None, } } @@ -202,7 +238,7 @@ impl<'a> ExtendedChannel<'a> { } /// Returns a reference to the [`ShareAccounting`] for this channel. - pub fn get_share_accounting(&self) -> &ShareAccounting { + pub fn get_share_accounting(&self) -> &ShareAccounting

{ &self.share_accounting } @@ -564,9 +600,12 @@ impl<'a> ExtendedChannel<'a> { #[cfg(test)] mod tests { - use crate::client::{ - extended::ExtendedChannel, - share_accounting::{ShareValidationError, ShareValidationResult}, + use crate::{ + client::{ + extended::ExtendedChannel, + share_accounting::{ShareValidationError, ShareValidationResult}, + }, + persistence::NoPersistence, }; use binary_sv2::Sv2Option; use bitcoin::Target; @@ -589,7 +628,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 4u16; - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -671,7 +710,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 4u16; - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -744,7 +783,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 8u16; - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -836,7 +875,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 8u16; - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -931,7 +970,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 8u16; - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::::new( channel_id, user_identity, extranonce_prefix.clone(), diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 1f9c7ef827..7945b69b9f 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -5,8 +5,8 @@ //! are intended for use in Mining Clients. use super::HashSet; +use crate::persistence::{NoPersistence, Persistence, ShareAccountingEvent}; use bitcoin::hashes::sha256d::Hash; -use crate::persistence::{NoPersistence, ShareAccountingEvent}; /// The outcome of share validation, as seen by a Mining Client. /// @@ -67,7 +67,10 @@ impl Default for ShareAccounting { } } -impl

ShareAccounting

{ +impl

ShareAccounting

+where + P: Persistence, +{ /// Creates a new [`ShareAccounting`] instance, initializing all statistics to zero. /// /// `channel_id` identifies the channel for persistence events. diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index df56ec2d9d..9b05915935 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -13,6 +13,7 @@ use crate::{ share_accounting::{ShareAccounting, ShareValidationError, ShareValidationResult}, }, merkle_root::merkle_root_from_path, + persistence::{NoPersistence, Persistence}, target::{bytes_to_hex, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; @@ -43,7 +44,7 @@ use tracing::debug; /// - share accounting state /// - chain tip state #[derive(Debug, Clone)] -pub struct StandardChannel<'a> { +pub struct StandardChannel<'a, P = NoPersistence> { channel_id: u32, user_identity: String, extranonce_prefix: Vec, @@ -53,11 +54,14 @@ pub struct StandardChannel<'a> { active_job: Option>, past_jobs: HashMap>, stale_jobs: HashMap>, - share_accounting: ShareAccounting, + share_accounting: ShareAccounting

, chain_tip: Option, } -impl<'a> StandardChannel<'a> { +impl<'a, P> StandardChannel<'a, P> +where + P: Persistence, +{ /// Creates a new [`StandardChannel`] instance with provided channel parameters. pub fn new( channel_id: u32, @@ -65,6 +69,34 @@ impl<'a> StandardChannel<'a> { extranonce_prefix: Vec, target: Target, nominal_hashrate: f32, + ) -> Self + where + P: Default, + { + Self { + channel_id, + user_identity, + extranonce_prefix, + target, + nominal_hashrate, + future_jobs: HashMap::new(), + active_job: None, + past_jobs: HashMap::new(), + stale_jobs: HashMap::new(), + share_accounting: ShareAccounting::new(channel_id, P::default()), + chain_tip: None, + } + } + + /// Creates a new [`StandardChannel`] instance with custom persistence. + #[cfg(feature = "persistence")] + pub fn new_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + target: Target, + nominal_hashrate: f32, + persistence: P, ) -> Self { Self { channel_id, @@ -76,7 +108,7 @@ impl<'a> StandardChannel<'a> { active_job: None, past_jobs: HashMap::new(), stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(), + share_accounting: ShareAccounting::new(channel_id, persistence), chain_tip: None, } } @@ -161,7 +193,7 @@ impl<'a> StandardChannel<'a> { } /// Returns the share accounting state for this channel. - pub fn get_share_accounting(&self) -> &ShareAccounting { + pub fn get_share_accounting(&self) -> &ShareAccounting

{ &self.share_accounting } @@ -361,9 +393,12 @@ impl<'a> StandardChannel<'a> { #[cfg(test)] mod tests { - use crate::client::{ - share_accounting::{ShareValidationError, ShareValidationResult}, - standard::StandardChannel, + use crate::{ + client::{ + share_accounting::{ShareValidationError, ShareValidationResult}, + standard::StandardChannel, + }, + persistence::NoPersistence, }; use binary_sv2::Sv2Option; use bitcoin::Target; @@ -381,7 +416,7 @@ mod tests { let target = Target::from_le_bytes([0xff; 32]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::new( + let mut channel = StandardChannel::::new( channel_id, user_identity, extranonce_prefix, @@ -441,7 +476,7 @@ mod tests { let target = Target::from_le_bytes([0xff; 32]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::new( + let mut channel = StandardChannel::::new( channel_id, user_identity, extranonce_prefix, @@ -489,7 +524,7 @@ mod tests { let target = Target::from_le_bytes([0xff; 32]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::new( + let mut channel = StandardChannel::::new( channel_id, user_identity, extranonce_prefix, @@ -562,7 +597,7 @@ mod tests { ]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::new( + let mut channel = StandardChannel::::new( channel_id, user_identity, extranonce_prefix, @@ -638,7 +673,7 @@ mod tests { ]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::new( + let mut channel = StandardChannel::::new( channel_id, user_identity, extranonce_prefix, diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 7b5484c4d6..64942ac643 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -8,8 +8,10 @@ //! //! - **Zero Hot Path Impact**: No `Result` types or blocking operations in share accounting methods //! - **Async Channel Based**: Events are sent via channels for background persistence processing -//! - **Flexible Implementation**: Trait allows different persistence backends (database, file, etc.) -//! - **Optional Compilation**: Gated behind `persistence` feature flag to avoid unnecessary dependencies +//! - **Flexible Implementation**: Trait allows different persistence backends (database, file, +//! etc.) +//! - **Optional Compilation**: Gated behind `persistence` feature flag to avoid unnecessary +//! dependencies //! //! ## Usage //! @@ -27,7 +29,8 @@ use bitcoin::hashes::sha256d::Hash; pub enum ShareAccountingEvent { /// A share was accepted and accounting was updated. ShareAccepted { - /// The channel identifier (server-assigned for server channels, client-assigned for client channels) + /// The channel identifier (server-assigned for server channels, client-assigned for client + /// channels) channel_id: u32, /// Work value of the accepted share share_work: u64, @@ -57,18 +60,16 @@ pub enum ShareAccountingEvent { /// Trait for persisting share accounting events. /// -/// Implementations of this trait handle the background persistence of share accounting -/// events sent through async channels. This allows the hot path share processing to -/// remain completely non-blocking. -/// -/// # Design Notes -/// -/// - All methods are infallible from the caller's perspective - persistence failures -/// must be handled internally by implementations -/// - Events are timestamped to allow temporal analysis of mining operations -/// - The trait provides a unified interface regardless of whether persistence is enabled -#[cfg(feature = "persistence")] +/// Implementations of this trait handle the persistence of share accounting events, +/// ensuring that persistence operations are non-blocking and can handle failures internally. pub trait Persistence { + /// The type of channel sender used to send events for persistence. + /// + /// This is typically something like `tokio::sync::mpsc::UnboundedSender` + /// or `async_channel::Sender`. + #[cfg(feature = "persistence")] + type Sender: Clone + Send + 'static; + /// Sends a share accounting event for persistence. /// /// This method MUST be non-blocking and infallible from the caller's perspective. @@ -85,12 +86,19 @@ pub trait Persistence { /// /// Implementations can use this for cleanup operations, but should not block. fn shutdown(&self) {} + + #[cfg(feature = "persistence")] + fn new(sender: Self::Sender) -> Self; + + #[cfg(not(feature = "persistence"))] + fn new() -> Self; } /// A no-op persistence implementation for when persistence is disabled. /// /// This allows ShareAccounting to always call persistence methods without /// needing conditional compilation throughout the hot path code. +#[derive(Debug, Clone)] pub struct NoPersistence; impl NoPersistence { @@ -115,7 +123,19 @@ impl Default for NoPersistence { } } -#[cfg(feature = "persistence")] impl Persistence for NoPersistence { + #[cfg(feature = "persistence")] + type Sender = (); + fn persist_event(&self, _event: ShareAccountingEvent) {} -} \ No newline at end of file + + #[cfg(feature = "persistence")] + fn new(_sender: Self::Sender) -> Self { + Self + } + + #[cfg(not(feature = "persistence"))] + fn new() -> Self { + Self + } +} diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index bd20a0d59f..2d56b49e3c 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -42,6 +42,7 @@ use crate::{ chain_tip::ChainTip, merkle_root::merkle_root_from_path, + persistence::{NoPersistence, Persistence}, server::{ error::ExtendedChannelError, jobs::{extended::ExtendedJob, factory::JobFactory, job_store::JobStore, JobOrigin}, @@ -83,7 +84,7 @@ use tracing::debug; /// - the channel's job factory /// - the channel's chain tip #[derive(Debug)] -pub struct ExtendedChannel<'a, J> +pub struct ExtendedChannel<'a, J, P = NoPersistence> where J: JobStore>, { @@ -96,15 +97,16 @@ where nominal_hashrate: f32, job_store: J, job_factory: JobFactory, - share_accounting: ShareAccounting, + share_accounting: ShareAccounting

, expected_share_per_minute: f32, chain_tip: Option, phantom: PhantomData<&'a ()>, } -impl<'a, J> ExtendedChannel<'a, J> +impl<'a, J, P> ExtendedChannel<'a, J, P> where J: JobStore>, + P: Persistence + Default, { /// Constructor of `ExtendedChannel` for a Sv2 Pool Server. /// Not meant for usage on a Sv2 Job Declaration Client. @@ -186,7 +188,170 @@ where Some(miner_tag_string), ) } +} + +#[cfg(feature = "persistence")] +impl<'a, J, P> ExtendedChannel<'a, J, P> +where + J: JobStore>, + P: Persistence, +{ + /// Constructor of `ExtendedChannel` for a Sv2 Pool Server with custom persistence. + /// Not meant for usage on a Sv2 Job Declaration Client. + /// + /// Initializes the extended channel state with the provided parameters, including channel + /// identifiers, difficulty targets, share accounting, and job management. + /// Returns an error if target/difficulty parameters are invalid or extranonce prefix + /// requirements are not met. + /// + /// For non-JD jobs, `pool_tag_string` is added to the coinbase scriptSig in between `/` + /// and `//` delimiters: `/pool_tag_string//` + #[allow(clippy::too_many_arguments)] + pub fn new_for_pool_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + max_target: Target, + nominal_hashrate: f32, + version_rolling_allowed: bool, + rollable_extranonce_size: u16, + share_batch_size: usize, + expected_share_per_minute: f32, + job_store: J, + pool_tag_string: String, + persistence: P, + ) -> Result { + Self::new_with_persistence( + channel_id, + user_identity, + extranonce_prefix, + max_target, + nominal_hashrate, + version_rolling_allowed, + rollable_extranonce_size, + share_batch_size, + expected_share_per_minute, + job_store, + Some(pool_tag_string), + None, + persistence, + ) + } + + /// Constructor of `ExtendedChannel` for a Sv2 Job Declaration Client with custom persistence. + /// Not meant for usage on a Sv2 Pool Server. + /// + /// Initializes the extended channel state with the provided parameters, including channel + /// identifiers, difficulty targets, share accounting, and job management. + /// Returns an error if target/failure parameters are invalid or extranonce prefix + /// requirements are not met. + /// + /// The `pool_tag_string` and `miner_tag_string` are added to the coinbase scriptSig in between + /// `/` delimiters: `/pool_tag_string/miner_tag_string/` + #[allow(clippy::too_many_arguments)] + pub fn new_for_job_declaration_client_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + max_target: Target, + nominal_hashrate: f32, + version_rolling_allowed: bool, + rollable_extranonce_size: u16, + share_batch_size: usize, + expected_share_per_minute: f32, + job_store: J, + pool_tag_string: Option, + miner_tag_string: String, + persistence: P, + ) -> Result { + Self::new_with_persistence( + channel_id, + user_identity, + extranonce_prefix, + max_target, + nominal_hashrate, + version_rolling_allowed, + rollable_extranonce_size, + share_batch_size, + expected_share_per_minute, + job_store, + pool_tag_string, + Some(miner_tag_string), + persistence, + ) + } + + // private constructor with custom persistence + #[allow(clippy::too_many_arguments)] + fn new_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + max_target: Target, + nominal_hashrate: f32, + version_rolling_allowed: bool, + rollable_extranonce_size: u16, + share_batch_size: usize, + expected_share_per_minute: f32, + job_store: J, + pool_tag: Option, + miner_tag: Option, + persistence: P, + ) -> Result { + let target_u256 = + match hash_rate_to_target(nominal_hashrate.into(), expected_share_per_minute.into()) { + Ok(target_u256) => target_u256, + Err(_) => { + return Err(ExtendedChannelError::InvalidNominalHashrate); + } + }; + + let target: Target = target_u256.clone().into(); + + if target > max_target { + return Err(ExtendedChannelError::RequestedMaxTargetOutOfRange); + } + + if extranonce_prefix.len() > MAX_EXTRANONCE_PREFIX_LEN { + return Err(ExtendedChannelError::ExtranoncePrefixTooLarge); + } + + let script_sig_size = 5 + // BIP34 + 1 + // OP_PUSHBYTES + 3 + // `/` delimiters + pool_tag.as_ref().map_or(0, |s| s.len()) + + miner_tag.as_ref().map_or(0, |s| s.len()) + + 1 + // OP_PUSHBYTES + extranonce_prefix.len() + + rollable_extranonce_size as usize; + if script_sig_size > 100 { + return Err(ExtendedChannelError::ScriptSigSizeTooLarge); + } + + Ok(Self { + channel_id, + user_identity, + extranonce_prefix, + rollable_extranonce_size, + requested_max_target: max_target, + target, + nominal_hashrate, + job_store, + job_factory: JobFactory::new(version_rolling_allowed, pool_tag, miner_tag), + share_accounting: ShareAccounting::new(share_batch_size, channel_id, persistence), + expected_share_per_minute, + chain_tip: None, + phantom: PhantomData, + }) + } +} + +impl<'a, J, P> ExtendedChannel<'a, J, P> +where + J: JobStore>, + P: Persistence + Default, +{ // private constructor #[allow(clippy::too_many_arguments)] fn new( @@ -244,7 +409,7 @@ where nominal_hashrate, job_store, job_factory: JobFactory::new(version_rolling_allowed, pool_tag, miner_tag), - share_accounting: ShareAccounting::new(share_batch_size), + share_accounting: ShareAccounting::new(share_batch_size, channel_id, P::default()), expected_share_per_minute, chain_tip: None, phantom: PhantomData, @@ -418,7 +583,7 @@ where self.job_store.get_past_jobs() } /// Returns a reference to the share accounting state for this channel. - pub fn get_share_accounting(&self) -> &ShareAccounting { + pub fn get_share_accounting(&self) -> &ShareAccounting

{ &self.share_accounting } @@ -737,6 +902,7 @@ where mod tests { use crate::{ chain_tip::ChainTip, + persistence::NoPersistence, server::{ error::ExtendedChannelError, extended::ExtendedChannel, @@ -772,7 +938,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -923,7 +1089,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1043,7 +1209,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1121,7 +1287,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1230,7 +1396,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1342,7 +1508,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1469,7 +1635,7 @@ mod tests { let max_target = Target::from_le_bytes([0xff; 32]); // Create a channel with initial hashrate - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1556,7 +1722,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::new( + let mut channel = ExtendedChannel::, NoPersistence>::new( channel_id, user_identity, extranonce_prefix.clone(), diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index 8d2d33be82..ecf0a69427 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -18,9 +18,9 @@ //! Intended for use within mining server implementations that process SV2 share submissions and //! issue `SubmitShares.Success` messages. Not intended for use by mining clients. +use crate::persistence::{NoPersistence, Persistence, ShareAccountingEvent}; use bitcoin::hashes::sha256d::Hash; use std::collections::HashSet; -use crate::persistence::{NoPersistence, ShareAccountingEvent}; /// The outcome of share validation, from the perspective of a Mining Server. /// @@ -93,7 +93,10 @@ pub struct ShareAccounting

{ persistence: P, } -impl

ShareAccounting

{ +impl

ShareAccounting

+where + P: Persistence, +{ /// Constructs a new `ShareAccounting` instance for a channel. /// /// `share_batch_size` controls how many accepted shares trigger a batch acknowledgment. diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 1ffd3a1a8d..0b3b73e7e8 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -35,6 +35,7 @@ //! - Job lifecycle and share accounting are managed on a per-channel basis. use crate::{ chain_tip::ChainTip, + persistence::{NoPersistence, Persistence}, server::{ error::StandardChannelError, jobs::{ @@ -80,7 +81,7 @@ use tracing::debug; /// - the channel's job factory /// - the channel's chain tip #[derive(Debug)] -pub struct StandardChannel<'a, J> +pub struct StandardChannel<'a, J, P = NoPersistence> where J: JobStore>, { @@ -90,7 +91,7 @@ where requested_max_target: Target, target: Target, nominal_hashrate: f32, - share_accounting: ShareAccounting, + share_accounting: ShareAccounting

, expected_share_per_minute: f32, job_store: J, job_factory: JobFactory, @@ -98,9 +99,10 @@ where phantom: PhantomData<&'a ()>, } -impl<'a, J> StandardChannel<'a, J> +impl<'a, J, P> StandardChannel<'a, J, P> where J: JobStore>, + P: Persistence, { /// Constructor of `StandardChannel` for a Sv2 Pool Server. /// Not meant for usage on a Sv2 Job Declaration Client. @@ -123,7 +125,10 @@ where expected_share_per_minute: f32, job_store: J, pool_tag_string: String, - ) -> Result { + ) -> Result + where + P: Default, + { Self::new( channel_id, user_identity, @@ -135,6 +140,7 @@ where job_store, Some(pool_tag_string), None, + P::default(), ) } @@ -160,6 +166,70 @@ where job_store: J, pool_tag_string: Option, miner_tag_string: String, + ) -> Result + where + P: Default, + { + Self::new( + channel_id, + user_identity, + extranonce_prefix, + requested_max_target, + nominal_hashrate, + share_batch_size, + expected_share_per_minute, + job_store, + pool_tag_string, + Some(miner_tag_string), + P::default(), + ) + } + + /// Constructor of `StandardChannel` for a Sv2 Pool Server with custom persistence. + #[cfg(feature = "persistence")] + #[allow(clippy::too_many_arguments)] + pub fn new_for_pool_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + requested_max_target: Target, + nominal_hashrate: f32, + share_batch_size: usize, + expected_share_per_minute: f32, + job_store: J, + pool_tag_string: String, + persistence: P, + ) -> Result { + Self::new( + channel_id, + user_identity, + extranonce_prefix, + requested_max_target, + nominal_hashrate, + share_batch_size, + expected_share_per_minute, + job_store, + Some(pool_tag_string), + None, + persistence, + ) + } + + /// Constructor of `StandardChannel` for a Sv2 Job Declaration Client with custom persistence. + #[cfg(feature = "persistence")] + #[allow(clippy::too_many_arguments)] + pub fn new_for_job_declaration_client_with_persistence( + channel_id: u32, + user_identity: String, + extranonce_prefix: Vec, + requested_max_target: Target, + nominal_hashrate: f32, + share_batch_size: usize, + expected_share_per_minute: f32, + job_store: J, + pool_tag_string: Option, + miner_tag_string: String, + persistence: P, ) -> Result { Self::new( channel_id, @@ -172,6 +242,7 @@ where job_store, pool_tag_string, Some(miner_tag_string), + persistence, ) } @@ -188,6 +259,7 @@ where job_store: J, pool_tag_string: Option, miner_tag_string: Option, + persistence: P, ) -> Result { let calculated_target = match hash_rate_to_target(nominal_hashrate.into(), expected_share_per_minute.into()) { @@ -226,7 +298,7 @@ where requested_max_target, target, nominal_hashrate, - share_accounting: ShareAccounting::new(share_batch_size), + share_accounting: ShareAccounting::new(share_batch_size, channel_id, persistence), expected_share_per_minute, job_factory: JobFactory::new(true, pool_tag_string, miner_tag_string), chain_tip: None, @@ -388,7 +460,7 @@ where } /// Returns a reference to the share accounting state for this channel. - pub fn get_share_accounting(&self) -> &ShareAccounting { + pub fn get_share_accounting(&self) -> &ShareAccounting

{ &self.share_accounting } @@ -673,6 +745,7 @@ where mod tests { use crate::{ chain_tip::ChainTip, + persistence::NoPersistence, server::{ error::StandardChannelError, jobs::{job_store::DefaultJobStore, standard::StandardJob}, @@ -719,6 +792,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -847,6 +921,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -951,6 +1026,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1057,6 +1133,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1166,6 +1243,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1269,6 +1347,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1356,6 +1435,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); From 7d8a1159109560dda211e2a05c4aee9ac72423a8 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Wed, 24 Sep 2025 12:27:49 -0400 Subject: [PATCH 04/39] feat: add file writing for share persistence --- protocols/v2/channels-sv2/Cargo.toml | 1 - .../v2/channels-sv2/src/client/extended.rs | 33 +----- .../src/client/share_accounting.rs | 9 +- .../v2/channels-sv2/src/client/standard.rs | 29 +---- protocols/v2/channels-sv2/src/persistence.rs | 14 --- .../v2/channels-sv2/src/server/extended.rs | 14 ++- .../src/server/share_accounting.rs | 4 +- .../v2/channels-sv2/src/server/standard.rs | 75 +------------ roles/pool/Cargo.toml | 6 + roles/pool/src/lib/mod.rs | 1 + roles/pool/src/lib/share_persistence/mod.rs | 104 ++++++++++++++++++ 11 files changed, 132 insertions(+), 158 deletions(-) create mode 100644 roles/pool/src/lib/share_persistence/mod.rs diff --git a/protocols/v2/channels-sv2/Cargo.toml b/protocols/v2/channels-sv2/Cargo.toml index 8277321d90..6d8cace62a 100644 --- a/protocols/v2/channels-sv2/Cargo.toml +++ b/protocols/v2/channels-sv2/Cargo.toml @@ -28,4 +28,3 @@ hashbrown = { version = "0.15.5", optional = true } [features] default = [] no_std = ["hashbrown"] -persistence = [] diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 918260fc5d..4b253d4987 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -60,7 +60,7 @@ pub type ExtendedJob<'a> = (NewExtendedMiningJob<'a>, Vec); /// - Share accounting for the channel (as tracked by the client). /// - The channel's current chain tip. #[derive(Clone, Debug)] -pub struct ExtendedChannel<'a, P = NoPersistence> { +pub struct ExtendedChannel<'a, P> { channel_id: u32, user_identity: String, extranonce_prefix: Vec, @@ -92,37 +92,6 @@ where nominal_hashrate: f32, version_rolling: bool, rollable_extranonce_size: u16, - ) -> Self - where - P: Default, - { - Self { - channel_id, - user_identity, - extranonce_prefix, - rollable_extranonce_size, - target, - nominal_hashrate, - version_rolling, - future_jobs: HashMap::new(), - active_job: None, - past_jobs: HashMap::new(), - stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(channel_id, P::default()), - chain_tip: None, - } - } - - /// Constructs a new [`ExtendedChannel`] with custom persistence. - #[cfg(feature = "persistence")] - pub fn new_with_persistence( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - target: Target, - nominal_hashrate: f32, - version_rolling: bool, - rollable_extranonce_size: u16, persistence: P, ) -> Self { Self { diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 7945b69b9f..debcf7a00a 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -5,7 +5,7 @@ //! are intended for use in Mining Clients. use super::HashSet; -use crate::persistence::{NoPersistence, Persistence, ShareAccountingEvent}; +use crate::persistence::{Persistence, ShareAccountingEvent}; use bitcoin::hashes::sha256d::Hash; /// The outcome of share validation, as seen by a Mining Client. @@ -51,7 +51,7 @@ pub enum ShareValidationError { /// - hashes of seen shares (for duplicate detection) /// - highest difficulty seen in accepted shares #[derive(Clone, Debug)] -pub struct ShareAccounting

{ +pub struct ShareAccounting

{ last_share_sequence_number: u32, shares_accepted: u32, share_work_sum: u64, @@ -61,11 +61,6 @@ pub struct ShareAccounting

{ persistence: P, } -impl Default for ShareAccounting { - fn default() -> Self { - Self::new(0, NoPersistence::new()) - } -} impl

ShareAccounting

where diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 9b05915935..b9f657afa7 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -44,7 +44,7 @@ use tracing::debug; /// - share accounting state /// - chain tip state #[derive(Debug, Clone)] -pub struct StandardChannel<'a, P = NoPersistence> { +pub struct StandardChannel<'a, P> { channel_id: u32, user_identity: String, extranonce_prefix: Vec, @@ -69,33 +69,6 @@ where extranonce_prefix: Vec, target: Target, nominal_hashrate: f32, - ) -> Self - where - P: Default, - { - Self { - channel_id, - user_identity, - extranonce_prefix, - target, - nominal_hashrate, - future_jobs: HashMap::new(), - active_job: None, - past_jobs: HashMap::new(), - stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(channel_id, P::default()), - chain_tip: None, - } - } - - /// Creates a new [`StandardChannel`] instance with custom persistence. - #[cfg(feature = "persistence")] - pub fn new_with_persistence( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - target: Target, - nominal_hashrate: f32, persistence: P, ) -> Self { Self { diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 64942ac643..019f4c9d67 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -10,8 +10,6 @@ //! - **Async Channel Based**: Events are sent via channels for background persistence processing //! - **Flexible Implementation**: Trait allows different persistence backends (database, file, //! etc.) -//! - **Optional Compilation**: Gated behind `persistence` feature flag to avoid unnecessary -//! dependencies //! //! ## Usage //! @@ -67,7 +65,6 @@ pub trait Persistence { /// /// This is typically something like `tokio::sync::mpsc::UnboundedSender` /// or `async_channel::Sender`. - #[cfg(feature = "persistence")] type Sender: Clone + Send + 'static; /// Sends a share accounting event for persistence. @@ -87,11 +84,7 @@ pub trait Persistence { /// Implementations can use this for cleanup operations, but should not block. fn shutdown(&self) {} - #[cfg(feature = "persistence")] fn new(sender: Self::Sender) -> Self; - - #[cfg(not(feature = "persistence"))] - fn new() -> Self; } /// A no-op persistence implementation for when persistence is disabled. @@ -124,18 +117,11 @@ impl Default for NoPersistence { } impl Persistence for NoPersistence { - #[cfg(feature = "persistence")] type Sender = (); fn persist_event(&self, _event: ShareAccountingEvent) {} - #[cfg(feature = "persistence")] fn new(_sender: Self::Sender) -> Self { Self } - - #[cfg(not(feature = "persistence"))] - fn new() -> Self { - Self - } } diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 2d56b49e3c..799f7dd140 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -42,7 +42,7 @@ use crate::{ chain_tip::ChainTip, merkle_root::merkle_root_from_path, - persistence::{NoPersistence, Persistence}, + persistence::Persistence, server::{ error::ExtendedChannelError, jobs::{extended::ExtendedJob, factory::JobFactory, job_store::JobStore, JobOrigin}, @@ -51,6 +51,8 @@ use crate::{ target::{bytes_to_hex, hash_rate_to_target, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; +use mining_sv2::MAX_EXTRANONCE_LEN; +use binary_sv2::{self}; use bitcoin::{ blockdata::block::{Header, Version}, hashes::sha256d::Hash, @@ -84,7 +86,7 @@ use tracing::debug; /// - the channel's job factory /// - the channel's chain tip #[derive(Debug)] -pub struct ExtendedChannel<'a, J, P = NoPersistence> +pub struct ExtendedChannel<'a, J, P> where J: JobStore>, { @@ -131,8 +133,9 @@ where expected_share_per_minute: f32, job_store: J, pool_tag_string: String, + persistence: P, ) -> Result { - Self::new( + Self::new_with_persistence( channel_id, user_identity, extranonce_prefix, @@ -145,6 +148,7 @@ where job_store, Some(pool_tag_string), None, + persistence, ) } @@ -172,8 +176,9 @@ where job_store: J, pool_tag_string: Option, miner_tag_string: String, + persistence: P, ) -> Result { - Self::new( + Self::new_with_persistence( channel_id, user_identity, extranonce_prefix, @@ -186,6 +191,7 @@ where job_store, pool_tag_string, Some(miner_tag_string), + persistence, ) } } diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index ecf0a69427..e58997687a 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -18,7 +18,7 @@ //! Intended for use within mining server implementations that process SV2 share submissions and //! issue `SubmitShares.Success` messages. Not intended for use by mining clients. -use crate::persistence::{NoPersistence, Persistence, ShareAccountingEvent}; +use crate::persistence::{Persistence, ShareAccountingEvent}; use bitcoin::hashes::sha256d::Hash; use std::collections::HashSet; @@ -82,7 +82,7 @@ pub enum ShareValidationError { /// This struct manages per-channel share statistics, batch acknowledgment, duplicate detection, /// and difficulty tracking. Only meant for usage on Mining Servers. #[derive(Clone, Debug)] -pub struct ShareAccounting

{ +pub struct ShareAccounting

{ last_share_sequence_number: u32, shares_accepted: u32, share_work_sum: u64, diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 0b3b73e7e8..207fc4a532 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -35,7 +35,7 @@ //! - Job lifecycle and share accounting are managed on a per-channel basis. use crate::{ chain_tip::ChainTip, - persistence::{NoPersistence, Persistence}, + persistence::Persistence, server::{ error::StandardChannelError, jobs::{ @@ -81,7 +81,7 @@ use tracing::debug; /// - the channel's job factory /// - the channel's chain tip #[derive(Debug)] -pub struct StandardChannel<'a, J, P = NoPersistence> +pub struct StandardChannel<'a, J, P> where J: JobStore>, { @@ -125,10 +125,8 @@ where expected_share_per_minute: f32, job_store: J, pool_tag_string: String, - ) -> Result - where - P: Default, - { + persistence: P, + ) -> Result { Self::new( channel_id, user_identity, @@ -140,7 +138,7 @@ where job_store, Some(pool_tag_string), None, - P::default(), + persistence, ) } @@ -166,69 +164,6 @@ where job_store: J, pool_tag_string: Option, miner_tag_string: String, - ) -> Result - where - P: Default, - { - Self::new( - channel_id, - user_identity, - extranonce_prefix, - requested_max_target, - nominal_hashrate, - share_batch_size, - expected_share_per_minute, - job_store, - pool_tag_string, - Some(miner_tag_string), - P::default(), - ) - } - - /// Constructor of `StandardChannel` for a Sv2 Pool Server with custom persistence. - #[cfg(feature = "persistence")] - #[allow(clippy::too_many_arguments)] - pub fn new_for_pool_with_persistence( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - requested_max_target: Target, - nominal_hashrate: f32, - share_batch_size: usize, - expected_share_per_minute: f32, - job_store: J, - pool_tag_string: String, - persistence: P, - ) -> Result { - Self::new( - channel_id, - user_identity, - extranonce_prefix, - requested_max_target, - nominal_hashrate, - share_batch_size, - expected_share_per_minute, - job_store, - Some(pool_tag_string), - None, - persistence, - ) - } - - /// Constructor of `StandardChannel` for a Sv2 Job Declaration Client with custom persistence. - #[cfg(feature = "persistence")] - #[allow(clippy::too_many_arguments)] - pub fn new_for_job_declaration_client_with_persistence( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - requested_max_target: Target, - nominal_hashrate: f32, - share_batch_size: usize, - expected_share_per_minute: f32, - job_store: J, - pool_tag_string: Option, - miner_tag_string: String, persistence: P, ) -> Result { Self::new( diff --git a/roles/pool/Cargo.toml b/roles/pool/Cargo.toml index dffd724e02..493866a7eb 100644 --- a/roles/pool/Cargo.toml +++ b/roles/pool/Cargo.toml @@ -19,6 +19,8 @@ path = "src/lib/mod.rs" [dependencies] stratum-apps = { path = "../stratum-apps", features = ["pool"] } async-channel = "1.5.1" +stratum-common = { path = "../../common", features = ["with_network_helpers"] } +buffer_sv2 = { path = "../../utils/buffer" } rand = "0.8.4" serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } secp256k1 = { version = "0.28.2", default-features = false, features = ["alloc", "rand", "rand-std"] } @@ -26,3 +28,7 @@ tokio = { version = "1.44.1", features = ["full"] } ext-config = { version = "0.14.0", features = ["toml"], package = "config" } tracing = { version = "0.1" } clap = { version = "4.5.39", features = ["derive"] } + +[dev-dependencies] +hex = "0.4.3" +integration_tests_sv2 = { path = "../../test/integration-tests" } diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index df2381d661..e13d6eddf6 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -25,6 +25,7 @@ pub mod status; pub mod task_manager; pub mod template_receiver; pub mod utils; +pub mod share_persistence; #[derive(Debug, Clone)] pub struct PoolSv2 { diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs new file mode 100644 index 0000000000..72f09a1f9b --- /dev/null +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -0,0 +1,104 @@ +use stratum_common::roles_logic_sv2::channels_sv2::persistence::{ + Persistence, ShareAccountingEvent, +}; +use tokio::io::AsyncWriteExt; +use tracing::error; + +use crate::status::Status; + +pub struct ShareFileHandler { + file: tokio::fs::File, + receiver: async_channel::Receiver, + sender: async_channel::Sender, + status_tx: async_channel::Sender, +} + +impl ShareFileHandler { + pub async fn new(path: &str, status_tx: async_channel::Sender) -> Self { + let file = tokio::fs::File::create(path).await.unwrap(); + let (sender, receiver) = async_channel::bounded(1024); + Self { + file, + receiver, + sender, + status_tx + } + } + + pub fn get_receiver(self) -> async_channel::Receiver { + self.receiver + } + + pub fn get_sender(self) -> async_channel::Sender { + self.sender + } + + pub async fn write_event_to_file(&mut self, event: ShareAccountingEvent) { + match event { + ShareAccountingEvent::ShareAccepted { + channel_id, + share_work, + share_sequence_number, + share_hash, + total_shares_accepted, + total_share_work_sum, + timestamp, + } => { + let _ = self.file.write_all( + format!( + "ShareAccepted: channel_id: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:#?}\n", + channel_id, + share_work, + share_sequence_number, + share_hash, + total_shares_accepted, + total_share_work_sum, + timestamp + ) + .as_bytes(), + ).await.map_err(|e| { + error!(target = "share_file_handler", "{}", e); + }); + } + ShareAccountingEvent::BestDifficultyUpdated { + channel_id, + new_best_diff, + previous_best_diff, + timestamp, + } => { + let _ = self.file.write_all( + format!( + "BestDifficultyUpdated: channel_id: {}, new_best_diff: {}, previous_best_diff: {}, timestamp: {:#?}\n", + channel_id, + new_best_diff, + previous_best_diff, + timestamp + ) + .as_bytes(), + ).await + .map_err(|e| { + error!(target = "share_file_handler", "{}", e); + }); + }, + } + } +} + +pub struct ShareFilePersistence { + sender: async_channel::Sender, +} + +impl Persistence for ShareFilePersistence { + type Sender = async_channel::Sender; + + fn persist_event(&self, event: ShareAccountingEvent) { + let _ = self + .sender + .try_send(event) + .map_err(|e| error!(target = "share_file_persistence", "{}", e)); + } + + fn new(sender: Self::Sender) -> Self { + Self { sender } + } +} From 069e24403fadfebddd9e1e57e14bfd7a75b023dd Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Wed, 24 Sep 2025 14:27:44 -0400 Subject: [PATCH 05/39] feat: add Persistence to Pool --- roles/pool/src/lib/config.rs | 8 +++++ roles/pool/src/lib/share_persistence/mod.rs | 34 +++++++++++++-------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/roles/pool/src/lib/config.rs b/roles/pool/src/lib/config.rs index 51e74317b4..7d62e622fc 100644 --- a/roles/pool/src/lib/config.rs +++ b/roles/pool/src/lib/config.rs @@ -34,6 +34,7 @@ pub struct PoolConfig { share_batch_size: usize, log_file: Option, server_id: u16, + share_persistence_file_path: Option, } impl PoolConfig { @@ -50,6 +51,7 @@ impl PoolConfig { shares_per_minute: f32, share_batch_size: usize, server_id: u16, + share_persistence_file_path: Option, ) -> Self { Self { listen_address: pool_connection.listen_address, @@ -64,6 +66,7 @@ impl PoolConfig { share_batch_size, log_file: None, server_id, + share_persistence_file_path } } @@ -149,6 +152,11 @@ impl PoolConfig { script_pubkey: self.coinbase_reward_script.script_pubkey().to_owned(), } } + + /// Returns the share persistence file path. + pub fn share_persistence_file_path(&self) -> Option<&String> { + self.share_persistence_file_path.as_ref() + } } /// Configuration for connecting to a Template Provider. diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index 72f09a1f9b..c26397d11c 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -4,17 +4,17 @@ use stratum_common::roles_logic_sv2::channels_sv2::persistence::{ use tokio::io::AsyncWriteExt; use tracing::error; -use crate::status::Status; +use crate::status::{self}; pub struct ShareFileHandler { file: tokio::fs::File, receiver: async_channel::Receiver, sender: async_channel::Sender, - status_tx: async_channel::Sender, + status_tx: status::Sender, } impl ShareFileHandler { - pub async fn new(path: &str, status_tx: async_channel::Sender) -> Self { + pub async fn new(path: &str, status_tx: status::Sender) -> Self { let file = tokio::fs::File::create(path).await.unwrap(); let (sender, receiver) = async_channel::bounded(1024); Self { @@ -25,12 +25,12 @@ impl ShareFileHandler { } } - pub fn get_receiver(self) -> async_channel::Receiver { - self.receiver + pub fn get_receiver(&self) -> async_channel::Receiver { + self.receiver.clone() } - pub fn get_sender(self) -> async_channel::Sender { - self.sender + pub fn get_sender(&self) -> async_channel::Sender { + self.sender.clone() } pub async fn write_event_to_file(&mut self, event: ShareAccountingEvent) { @@ -84,21 +84,29 @@ impl ShareFileHandler { } } +#[derive(Clone, Debug)] pub struct ShareFilePersistence { - sender: async_channel::Sender, + sender: Option>, } impl Persistence for ShareFilePersistence { type Sender = async_channel::Sender; fn persist_event(&self, event: ShareAccountingEvent) { - let _ = self - .sender - .try_send(event) - .map_err(|e| error!(target = "share_file_persistence", "{}", e)); + if let Some(sender) = &self.sender { + let _ = sender + .try_send(event) + .map_err(|e| error!(target = "share_file_persistence", "{}", e)); + } } fn new(sender: Self::Sender) -> Self { - Self { sender } + Self { sender: Some(sender) } + } +} + +impl Default for ShareFilePersistence { + fn default() -> Self { + Self { sender: None } } } From 20aa89b27312f9278d63d463e6ffb1e92eed0dbb Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 25 Sep 2025 09:15:55 -0400 Subject: [PATCH 06/39] refactor: don't pretty print --- roles/pool/src/lib/share_persistence/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index c26397d11c..5b84444ff0 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -46,7 +46,7 @@ impl ShareFileHandler { } => { let _ = self.file.write_all( format!( - "ShareAccepted: channel_id: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:#?}\n", + "ShareAccepted: channel_id: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}\n", channel_id, share_work, share_sequence_number, @@ -68,7 +68,7 @@ impl ShareFileHandler { } => { let _ = self.file.write_all( format!( - "BestDifficultyUpdated: channel_id: {}, new_best_diff: {}, previous_best_diff: {}, timestamp: {:#?}\n", + "BestDifficultyUpdated: channel_id: {}, new_best_diff: {}, previous_best_diff: {}, timestamp: {:?}\n", channel_id, new_best_diff, previous_best_diff, From f2be5f365b04d917ff077afcbf519e52979dcdc8 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 9 Oct 2025 11:06:35 -0400 Subject: [PATCH 07/39] feat(share-accounting): Add block_found flag to ShareAccountingEvent - Update ShareAccountingEvent struct to include a new `block_found` boolean field - Modify share accounting methods in client and server modules to pass block_found status - Update persistence tracking to capture whether a share resulted in a block discovery - Propagate block_found flag through extended, standard, and share_accounting client/server implementations --- protocols/v2/channels-sv2/src/client/extended.rs | 2 ++ .../v2/channels-sv2/src/client/share_accounting.rs | 2 ++ protocols/v2/channels-sv2/src/client/standard.rs | 2 ++ protocols/v2/channels-sv2/src/persistence.rs | 2 ++ protocols/v2/channels-sv2/src/server/extended.rs | 2 ++ .../v2/channels-sv2/src/server/share_accounting.rs | 2 ++ protocols/v2/channels-sv2/src/server/standard.rs | 14 ++++++++------ roles/pool/src/lib/share_persistence/mod.rs | 6 ++++-- 8 files changed, 24 insertions(+), 8 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 4b253d4987..5ef3689528 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -541,6 +541,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + true ); return Ok(ShareValidationResult::BlockFound); } @@ -555,6 +556,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + false ); // update the best diff diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index debcf7a00a..691cb7e55e 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -92,6 +92,7 @@ where share_work: u64, share_sequence_number: u32, share_hash: Hash, + block_found: bool ) { self.last_share_sequence_number = share_sequence_number; self.shares_accepted += 1; @@ -107,6 +108,7 @@ where total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, timestamp: std::time::SystemTime::now(), + block_found }; self.persistence.persist_event(event); } diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index b9f657afa7..6231f09928 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -338,6 +338,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + true, ); return Ok(ShareValidationResult::BlockFound); } @@ -352,6 +353,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + false, ); // update the best diff diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 019f4c9d67..ad97b8f464 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -42,6 +42,8 @@ pub enum ShareAccountingEvent { total_share_work_sum: u64, /// Timestamp when the event occurred timestamp: std::time::SystemTime, + /// Block found? + block_found: bool, }, /// Best difficulty was updated for the channel. BestDifficultyUpdated { diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 799f7dd140..3c9a62f1e2 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -847,6 +847,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + true, ); let mut coinbase = vec![]; @@ -878,6 +879,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + false, ); // update the best diff diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index e58997687a..b4726d2716 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -125,6 +125,7 @@ where share_work: u64, share_sequence_number: u32, share_hash: Hash, + block_found: bool ) { self.last_share_sequence_number = share_sequence_number; self.shares_accepted += 1; @@ -140,6 +141,7 @@ where total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, timestamp: std::time::SystemTime::now(), + block_found }; self.persistence.persist_event(event); } diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 207fc4a532..fcc6c51636 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -600,12 +600,6 @@ where // check if a block was found if network_target.is_met_by(hash) { - self.share_accounting.update_share_accounting( - self.target.difficulty_float() as u64, - share.sequence_number, - hash.to_raw_hash(), - ); - let op_pushbytes_pool_miner_tag = self .job_factory .op_pushbytes_pool_miner_tag() @@ -634,6 +628,13 @@ where .consensus_encode(&mut serialized_coinbase) .map_err(|_| ShareValidationError::InvalidCoinbase)?; + self.share_accounting.update_share_accounting( + target_to_difficulty(self.target.clone()) as u64, + share.sequence_number, + hash.to_raw_hash(), + true + ); + return Ok(ShareValidationResult::BlockFound( Some(job.get_template().template_id), serialized_coinbase, @@ -650,6 +651,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), + false, ); // update the best diff diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index 5b84444ff0..e3649cc777 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -43,17 +43,19 @@ impl ShareFileHandler { total_shares_accepted, total_share_work_sum, timestamp, + block_found, } => { let _ = self.file.write_all( format!( - "ShareAccepted: channel_id: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}\n", + "ShareAccepted: channel_id: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", channel_id, share_work, share_sequence_number, share_hash, total_shares_accepted, total_share_work_sum, - timestamp + timestamp, + block_found ) .as_bytes(), ).await.map_err(|e| { From 0afb89cc7c6f44847d3b8034f7bf350c70bf358d Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Wed, 24 Sep 2025 12:28:58 -0400 Subject: [PATCH 08/39] feat: add user_identity to ShareAccounting --- protocols/v2/channels-sv2/src/client/extended.rs | 4 ++-- .../v2/channels-sv2/src/client/share_accounting.rs | 11 +++++++++-- protocols/v2/channels-sv2/src/client/standard.rs | 4 ++-- protocols/v2/channels-sv2/src/server/extended.rs | 4 ++-- .../v2/channels-sv2/src/server/share_accounting.rs | 10 +++++++++- protocols/v2/channels-sv2/src/server/standard.rs | 4 ++-- 6 files changed, 26 insertions(+), 11 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 5ef3689528..6d697f2371 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -96,7 +96,7 @@ where ) -> Self { Self { channel_id, - user_identity, + user_identity: user_identity.clone(), extranonce_prefix, rollable_extranonce_size, target, @@ -106,7 +106,7 @@ where active_job: None, past_jobs: HashMap::new(), stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(channel_id, persistence), + share_accounting: ShareAccounting::new(channel_id, persistence, user_identity.clone()), chain_tip: None, } } diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 691cb7e55e..510bf8624b 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -59,9 +59,9 @@ pub struct ShareAccounting

{ best_diff: f64, channel_id: u32, persistence: P, + user_identity: String, } - impl

ShareAccounting

where P: Persistence, @@ -70,7 +70,8 @@ where /// /// `channel_id` identifies the channel for persistence events. /// `persistence` handles background persistence of share accounting events. - pub fn new(channel_id: u32, persistence: P) -> Self { + /// `user_identity` is the identity string associated with the channel. + pub fn new(channel_id: u32, persistence: P, user_identity: String) -> Self { Self { last_share_sequence_number: 0, shares_accepted: 0, @@ -79,6 +80,7 @@ where best_diff: 0.0, channel_id, persistence, + user_identity, } } @@ -165,4 +167,9 @@ where self.persistence.persist_event(event); } } + + /// Returns the user identity string associated with this channel. + pub fn get_user_identity(&self) -> &String { + &self.user_identity + } } diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 6231f09928..5c29fcf611 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -73,7 +73,7 @@ where ) -> Self { Self { channel_id, - user_identity, + user_identity: user_identity.clone(), extranonce_prefix, target, nominal_hashrate, @@ -81,7 +81,7 @@ where active_job: None, past_jobs: HashMap::new(), stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(channel_id, persistence), + share_accounting: ShareAccounting::new(channel_id, persistence, user_identity.clone()), chain_tip: None, } } diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 3c9a62f1e2..91031783bc 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -407,7 +407,7 @@ where Ok(Self { channel_id, - user_identity, + user_identity: user_identity.clone(), extranonce_prefix, rollable_extranonce_size, requested_max_target: max_target, @@ -415,7 +415,7 @@ where nominal_hashrate, job_store, job_factory: JobFactory::new(version_rolling_allowed, pool_tag, miner_tag), - share_accounting: ShareAccounting::new(share_batch_size, channel_id, P::default()), + share_accounting: ShareAccounting::new(share_batch_size, channel_id, P::default(), user_identity.clone()), expected_share_per_minute, chain_tip: None, phantom: PhantomData, diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index b4726d2716..83fe023091 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -91,6 +91,7 @@ pub struct ShareAccounting

{ best_diff: f64, channel_id: u32, persistence: P, + user_identity: String, } impl

ShareAccounting

@@ -102,7 +103,8 @@ where /// `share_batch_size` controls how many accepted shares trigger a batch acknowledgment. /// `channel_id` identifies the channel for persistence events. /// `persistence` handles background persistence of share accounting events. - pub fn new(share_batch_size: usize, channel_id: u32, persistence: P) -> Self { + /// `user_identity` is the identity string associated with the channel. + pub fn new(share_batch_size: usize, channel_id: u32, persistence: P, user_identity: String) -> Self { Self { last_share_sequence_number: 0, shares_accepted: 0, @@ -112,6 +114,7 @@ where best_diff: 0.0, channel_id, persistence, + user_identity, } } @@ -208,4 +211,9 @@ where self.persistence.persist_event(event); } } + + /// Returns the user identity string associated with this channel. + pub fn get_user_identity(&self) -> &String { + &self.user_identity + } } diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index fcc6c51636..45ad413f6f 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -228,12 +228,12 @@ where Ok(Self { channel_id, - user_identity, + user_identity: user_identity.clone(), extranonce_prefix, requested_max_target, target, nominal_hashrate, - share_accounting: ShareAccounting::new(share_batch_size, channel_id, persistence), + share_accounting: ShareAccounting::new(share_batch_size, channel_id, persistence, user_identity.clone()), expected_share_per_minute, job_factory: JobFactory::new(true, pool_tag_string, miner_tag_string), chain_tip: None, From 96f3dcdfca7381ddb97780684dc0eb0f4b00f49e Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 9 Oct 2025 13:24:53 -0400 Subject: [PATCH 09/39] refactor(share-accounting): Remove channel_id and user_identity from ShareAccounting struct - Modify ShareAccounting to remove channel_id and user_identity as struct fields - Update method signatures to pass channel_id and user_identity as parameters - Remove get_user_identity method - Simplify ShareAccounting constructor to remove unnecessary parameters - Update client implementations to pass channel_id and user_identity to share accounting methods --- .../v2/channels-sv2/src/client/extended.rs | 8 +++++-- .../src/client/share_accounting.rs | 22 ++++++------------- .../v2/channels-sv2/src/client/standard.rs | 10 +++++++-- protocols/v2/channels-sv2/src/persistence.rs | 2 ++ .../v2/channels-sv2/src/server/extended.rs | 14 ++++++++---- .../src/server/share_accounting.rs | 22 ++++++------------- .../v2/channels-sv2/src/server/standard.rs | 8 +++++-- roles/pool/src/lib/share_persistence/mod.rs | 4 +++- 8 files changed, 49 insertions(+), 41 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 6d697f2371..34d23107e5 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -106,7 +106,7 @@ where active_job: None, past_jobs: HashMap::new(), stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(channel_id, persistence, user_identity.clone()), + share_accounting: ShareAccounting::new(persistence), chain_tip: None, } } @@ -538,6 +538,8 @@ where // check if a block was found if network_target.is_met_by(hash) { self.share_accounting.update_share_accounting( + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -553,6 +555,8 @@ where } self.share_accounting.update_share_accounting( + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -560,7 +564,7 @@ where ); // update the best diff - self.share_accounting.update_best_diff(hash_as_diff); + self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); return Ok(ShareValidationResult::Valid); } diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 510bf8624b..cf99265700 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -57,9 +57,7 @@ pub struct ShareAccounting

{ share_work_sum: u64, seen_shares: HashSet, best_diff: f64, - channel_id: u32, persistence: P, - user_identity: String, } impl

ShareAccounting

@@ -68,19 +66,15 @@ where { /// Creates a new [`ShareAccounting`] instance, initializing all statistics to zero. /// - /// `channel_id` identifies the channel for persistence events. /// `persistence` handles background persistence of share accounting events. - /// `user_identity` is the identity string associated with the channel. - pub fn new(channel_id: u32, persistence: P, user_identity: String) -> Self { + pub fn new(persistence: P) -> Self { Self { last_share_sequence_number: 0, shares_accepted: 0, share_work_sum: 0, seen_shares: HashSet::new(), best_diff: 0.0, - channel_id, persistence, - user_identity, } } @@ -91,6 +85,8 @@ where /// - Records share hash to detect duplicates. pub fn update_share_accounting( &mut self, + channel_id: u32, + user_identity: &str, share_work: u64, share_sequence_number: u32, share_hash: Hash, @@ -103,7 +99,8 @@ where // Persist the share accepted event let event = ShareAccountingEvent::ShareAccepted { - channel_id: self.channel_id, + channel_id, + user_identity: user_identity.to_string(), share_work, share_sequence_number, share_hash, @@ -152,14 +149,14 @@ where } /// Updates the best difficulty if the new difficulty is higher than the current best. - pub fn update_best_diff(&mut self, diff: f64) { + pub fn update_best_diff(&mut self, channel_id: u32, diff: f64) { let previous_best_diff = self.best_diff; if diff > self.best_diff { self.best_diff = diff; // Persist the best difficulty updated event let event = ShareAccountingEvent::BestDifficultyUpdated { - channel_id: self.channel_id, + channel_id, new_best_diff: diff, previous_best_diff, timestamp: std::time::SystemTime::now(), @@ -167,9 +164,4 @@ where self.persistence.persist_event(event); } } - - /// Returns the user identity string associated with this channel. - pub fn get_user_identity(&self) -> &String { - &self.user_identity - } } diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 5c29fcf611..54f83ca879 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -81,7 +81,7 @@ where active_job: None, past_jobs: HashMap::new(), stale_jobs: HashMap::new(), - share_accounting: ShareAccounting::new(channel_id, persistence, user_identity.clone()), + share_accounting: ShareAccounting::new(persistence), chain_tip: None, } } @@ -335,6 +335,9 @@ where // check if a block was found if network_target.is_met_by(hash) { self.share_accounting.update_share_accounting( + self.target.difficulty_float() as u64, + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -350,6 +353,9 @@ where } self.share_accounting.update_share_accounting( + self.target.difficulty_float() as u64, + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -357,7 +363,7 @@ where ); // update the best diff - self.share_accounting.update_best_diff(hash_as_diff); + self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); return Ok(ShareValidationResult::Valid); } diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index ad97b8f464..cf5b1d6695 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -30,6 +30,8 @@ pub enum ShareAccountingEvent { /// The channel identifier (server-assigned for server channels, client-assigned for client /// channels) channel_id: u32, + /// User identity associated with the channel + user_identity: String, /// Work value of the accepted share share_work: u64, /// Sequence number of the share diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 91031783bc..b12ba593f3 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -337,7 +337,7 @@ where Ok(Self { channel_id, - user_identity, + user_identity: user_identity.clone(), extranonce_prefix, rollable_extranonce_size, requested_max_target: max_target, @@ -345,7 +345,7 @@ where nominal_hashrate, job_store, job_factory: JobFactory::new(version_rolling_allowed, pool_tag, miner_tag), - share_accounting: ShareAccounting::new(share_batch_size, channel_id, persistence), + share_accounting: ShareAccounting::new(share_batch_size, persistence), expected_share_per_minute, chain_tip: None, phantom: PhantomData, @@ -415,7 +415,7 @@ where nominal_hashrate, job_store, job_factory: JobFactory::new(version_rolling_allowed, pool_tag, miner_tag), - share_accounting: ShareAccounting::new(share_batch_size, channel_id, P::default(), user_identity.clone()), + share_accounting: ShareAccounting::new(share_batch_size, P::default()), expected_share_per_minute, chain_tip: None, phantom: PhantomData, @@ -844,6 +844,9 @@ where // check if a block was found if network_target.is_met_by(hash) { self.share_accounting.update_share_accounting( + self.target.difficulty_float() as u64, + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -876,6 +879,9 @@ where } self.share_accounting.update_share_accounting( + self.target.difficulty_float() as u64, + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -883,7 +889,7 @@ where ); // update the best diff - self.share_accounting.update_best_diff(hash_as_diff); + self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); let last_sequence_number = self.share_accounting.get_last_share_sequence_number(); let new_submits_accepted_count = self.share_accounting.get_shares_accepted(); diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index 83fe023091..003b2186bc 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -89,9 +89,7 @@ pub struct ShareAccounting

{ share_batch_size: usize, seen_shares: HashSet, best_diff: f64, - channel_id: u32, persistence: P, - user_identity: String, } impl

ShareAccounting

@@ -101,10 +99,8 @@ where /// Constructs a new `ShareAccounting` instance for a channel. /// /// `share_batch_size` controls how many accepted shares trigger a batch acknowledgment. - /// `channel_id` identifies the channel for persistence events. /// `persistence` handles background persistence of share accounting events. - /// `user_identity` is the identity string associated with the channel. - pub fn new(share_batch_size: usize, channel_id: u32, persistence: P, user_identity: String) -> Self { + pub fn new(share_batch_size: usize, persistence: P) -> Self { Self { last_share_sequence_number: 0, shares_accepted: 0, @@ -112,9 +108,7 @@ where share_batch_size, seen_shares: HashSet::new(), best_diff: 0.0, - channel_id, persistence, - user_identity, } } @@ -125,6 +119,8 @@ where /// - Records the share hash to detect duplicates. pub fn update_share_accounting( &mut self, + channel_id: u32, + user_identity: &str, share_work: u64, share_sequence_number: u32, share_hash: Hash, @@ -137,7 +133,8 @@ where // Persist the share accepted event let event = ShareAccountingEvent::ShareAccepted { - channel_id: self.channel_id, + channel_id, + user_identity: user_identity.to_string(), share_work, share_sequence_number, share_hash, @@ -196,14 +193,14 @@ where } /// Updates the best difficulty if the new value is higher. - pub fn update_best_diff(&mut self, diff: f64) { + pub fn update_best_diff(&mut self, channel_id: u32, diff: f64) { let previous_best_diff = self.best_diff; if diff > self.best_diff { self.best_diff = diff; // Persist the best difficulty updated event let event = ShareAccountingEvent::BestDifficultyUpdated { - channel_id: self.channel_id, + channel_id, new_best_diff: diff, previous_best_diff, timestamp: std::time::SystemTime::now(), @@ -211,9 +208,4 @@ where self.persistence.persist_event(event); } } - - /// Returns the user identity string associated with this channel. - pub fn get_user_identity(&self) -> &String { - &self.user_identity - } } diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 45ad413f6f..131327bf59 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -233,7 +233,7 @@ where requested_max_target, target, nominal_hashrate, - share_accounting: ShareAccounting::new(share_batch_size, channel_id, persistence, user_identity.clone()), + share_accounting: ShareAccounting::new(share_batch_size, persistence), expected_share_per_minute, job_factory: JobFactory::new(true, pool_tag_string, miner_tag_string), chain_tip: None, @@ -629,6 +629,8 @@ where .map_err(|_| ShareValidationError::InvalidCoinbase)?; self.share_accounting.update_share_accounting( + self.channel_id, + &self.user_identity, target_to_difficulty(self.target.clone()) as u64, share.sequence_number, hash.to_raw_hash(), @@ -648,6 +650,8 @@ where } self.share_accounting.update_share_accounting( + self.channel_id, + &self.user_identity, self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), @@ -655,7 +659,7 @@ where ); // update the best diff - self.share_accounting.update_best_diff(hash_as_diff); + self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); let last_sequence_number = self.share_accounting.get_last_share_sequence_number(); let new_submits_accepted_count = self.share_accounting.get_shares_accepted(); diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index e3649cc777..88cad3c730 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -37,6 +37,7 @@ impl ShareFileHandler { match event { ShareAccountingEvent::ShareAccepted { channel_id, + user_identity, share_work, share_sequence_number, share_hash, @@ -47,8 +48,9 @@ impl ShareFileHandler { } => { let _ = self.file.write_all( format!( - "ShareAccepted: channel_id: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", + "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", channel_id, + user_identity, share_work, share_sequence_number, share_hash, From a5b9e42b8bdb636294930f8d33031e6d6782ab57 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 20 Oct 2025 12:01:19 -0400 Subject: [PATCH 10/39] feat(share-persistence): Add robust error handling for share file persistence - Implement SharePersistence variant in status::Sender enum - Add SharePersistenceError state to status::State enum - Enhance ShareFileHandler to send status messages on file write errors - Send status message when a block is found during share persistence - Improve error logging for share file write failures - Prevent pool from stopping on share persistence errors - Wrap status sender with SharePersistence variant when creating file handler Improves error handling and tracking for share file persistence, ensuring that persistence errors are logged and communicated without interrupting pool operations. --- roles/pool/src/lib/mod.rs | 7 +++++ roles/pool/src/lib/share_persistence/mod.rs | 31 +++++++++++++++------ roles/pool/src/lib/status.rs | 6 +++- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index e13d6eddf6..286b2646f0 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -155,6 +155,13 @@ impl PoolSv2 { let _ = notify_shutdown.send(ShutdownMessage::ShutdownAll); break; } + State::SharePersistenceError(err) => { + error!("Share persistence error: {}", err); + // Continue running - persistence errors shouldn't stop the pool + } + State::Healthy(msg) => { + info!("Healthy status: {}", msg); + } } } } diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index 88cad3c730..43d09bcf0d 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -46,7 +46,7 @@ impl ShareFileHandler { timestamp, block_found, } => { - let _ = self.file.write_all( + let result = self.file.write_all( format!( "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", channel_id, @@ -60,9 +60,18 @@ impl ShareFileHandler { block_found ) .as_bytes(), - ).await.map_err(|e| { - error!(target = "share_file_handler", "{}", e); - }); + ).await; + + if let Err(e) = result { + error!(target = "share_file_handler", "Failed to write share event: {}", e); + let _ = self.status_tx.send(status::Status { + state: status::State::SharePersistenceError(format!("Failed to write share event: {}", e)), + }).await; + } else if block_found { + let _ = self.status_tx.send(status::Status { + state: status::State::Healthy(format!("Block found! channel_id: {}, user: {}", channel_id, user_identity)), + }).await; + } } ShareAccountingEvent::BestDifficultyUpdated { channel_id, @@ -70,7 +79,7 @@ impl ShareFileHandler { previous_best_diff, timestamp, } => { - let _ = self.file.write_all( + let result = self.file.write_all( format!( "BestDifficultyUpdated: channel_id: {}, new_best_diff: {}, previous_best_diff: {}, timestamp: {:?}\n", channel_id, @@ -79,10 +88,14 @@ impl ShareFileHandler { timestamp ) .as_bytes(), - ).await - .map_err(|e| { - error!(target = "share_file_handler", "{}", e); - }); + ).await; + + if let Err(e) = result { + error!(target = "share_file_handler", "Failed to write difficulty update: {}", e); + let _ = self.status_tx.send(status::Status { + state: status::State::SharePersistenceError(format!("Failed to write difficulty update: {}", e)), + }).await; + } }, } } diff --git a/roles/pool/src/lib/status.rs b/roles/pool/src/lib/status.rs index 0c1933c6a1..707ff46303 100644 --- a/roles/pool/src/lib/status.rs +++ b/roles/pool/src/lib/status.rs @@ -83,9 +83,13 @@ pub enum State { TemplateReceiverShutdown(PoolError), /// Channel manager has shut down with a reason. ChannelManagerShutdown(PoolError), + /// Share persistence encountered an error (non-fatal). + SharePersistenceError(String), + /// Represents a healthy state with an accompanying status message. + Healthy(String), } -/// Wrapper around a component’s state, sent as status updates across the system. +/// Wrapper around a component's state, sent as status updates across the system. #[derive(Debug)] pub struct Status { /// The current state being reported. From e3b478c99855c5b6f94ad423e971b596280de686 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 20 Oct 2025 13:05:29 -0400 Subject: [PATCH 11/39] refactor: remove '_with_persistence' suffix from constructors Since persistence is now a required parameter (no feature flag), the '_with_persistence' naming is redundant. Simplified by: - Renaming private new_with_persistence() to new() - Removing '+ Default' trait bounds that are no longer needed - Removing duplicate impl block with P::default() usage --- .../v2/channels-sv2/src/server/extended.rs | 76 ++----------------- 1 file changed, 6 insertions(+), 70 deletions(-) diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index b12ba593f3..27b5bd11e6 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -108,7 +108,7 @@ where impl<'a, J, P> ExtendedChannel<'a, J, P> where J: JobStore>, - P: Persistence + Default, + P: Persistence, { /// Constructor of `ExtendedChannel` for a Sv2 Pool Server. /// Not meant for usage on a Sv2 Job Declaration Client. @@ -135,7 +135,7 @@ where pool_tag_string: String, persistence: P, ) -> Result { - Self::new_with_persistence( + Self::new( channel_id, user_identity, extranonce_prefix, @@ -178,7 +178,7 @@ where miner_tag_string: String, persistence: P, ) -> Result { - Self::new_with_persistence( + Self::new( channel_id, user_identity, extranonce_prefix, @@ -287,9 +287,9 @@ where ) } - // private constructor with custom persistence + // private constructor #[allow(clippy::too_many_arguments)] - fn new_with_persistence( + fn new( channel_id: u32, user_identity: String, extranonce_prefix: Vec, @@ -356,72 +356,8 @@ where impl<'a, J, P> ExtendedChannel<'a, J, P> where J: JobStore>, - P: Persistence + Default, + P: Persistence, { - // private constructor - #[allow(clippy::too_many_arguments)] - fn new( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - max_target: Target, - nominal_hashrate: f32, - version_rolling_allowed: bool, - rollable_extranonce_size: u16, - share_batch_size: usize, - expected_share_per_minute: f32, - job_store: J, - pool_tag: Option, - miner_tag: Option, - ) -> Result { - let target = - match hash_rate_to_target(nominal_hashrate.into(), expected_share_per_minute.into()) { - Ok(target) => target, - Err(_) => { - return Err(ExtendedChannelError::InvalidNominalHashrate); - } - }; - - if target > max_target { - println!("target: {:?}", target.to_be_bytes()); - println!("max_target: {:?}", max_target.to_be_bytes()); - return Err(ExtendedChannelError::RequestedMaxTargetOutOfRange); - } - - if extranonce_prefix.len() > MAX_EXTRANONCE_PREFIX_LEN { - return Err(ExtendedChannelError::ExtranoncePrefixTooLarge); - } - - let script_sig_size = 5 + // BIP34 - 1 + // OP_PUSHBYTES - 3 + // `/` delimiters - pool_tag.as_ref().map_or(0, |s| s.len()) + - miner_tag.as_ref().map_or(0, |s| s.len()) + - 1 + // OP_PUSHBYTES - extranonce_prefix.len() + - rollable_extranonce_size as usize; - - if script_sig_size > 100 { - return Err(ExtendedChannelError::ScriptSigSizeTooLarge); - } - - Ok(Self { - channel_id, - user_identity: user_identity.clone(), - extranonce_prefix, - rollable_extranonce_size, - requested_max_target: max_target, - target, - nominal_hashrate, - job_store, - job_factory: JobFactory::new(version_rolling_allowed, pool_tag, miner_tag), - share_accounting: ShareAccounting::new(share_batch_size, P::default()), - expected_share_per_minute, - chain_tip: None, - phantom: PhantomData, - }) - } - /// Returns the unique channel ID for this channel. pub fn get_channel_id(&self) -> u32 { self.channel_id From 9da1e554ddbccebd7ab5e5fd1ded342e20fea841 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 20 Oct 2025 13:09:03 -0400 Subject: [PATCH 12/39] style: run cargo fmt --- protocols/v2/channels-sv2/src/client/extended.rs | 7 ++++--- protocols/v2/channels-sv2/src/client/share_accounting.rs | 4 ++-- protocols/v2/channels-sv2/src/client/standard.rs | 3 ++- protocols/v2/channels-sv2/src/server/extended.rs | 5 +++-- protocols/v2/channels-sv2/src/server/share_accounting.rs | 4 ++-- protocols/v2/channels-sv2/src/server/standard.rs | 5 +++-- 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 34d23107e5..4d5fb885fc 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -543,7 +543,7 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), - true + true, ); return Ok(ShareValidationResult::BlockFound); } @@ -560,11 +560,12 @@ where self.target.difficulty_float() as u64, share.sequence_number, hash.to_raw_hash(), - false + false, ); // update the best diff - self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); + self.share_accounting + .update_best_diff(self.channel_id, hash_as_diff); return Ok(ShareValidationResult::Valid); } diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index cf99265700..20fe93d194 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -90,7 +90,7 @@ where share_work: u64, share_sequence_number: u32, share_hash: Hash, - block_found: bool + block_found: bool, ) { self.last_share_sequence_number = share_sequence_number; self.shares_accepted += 1; @@ -107,7 +107,7 @@ where total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, timestamp: std::time::SystemTime::now(), - block_found + block_found, }; self.persistence.persist_event(event); } diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 54f83ca879..2ab5987aa1 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -363,7 +363,8 @@ where ); // update the best diff - self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); + self.share_accounting + .update_best_diff(self.channel_id, hash_as_diff); return Ok(ShareValidationResult::Valid); } diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 27b5bd11e6..c0cd475f35 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -51,7 +51,6 @@ use crate::{ target::{bytes_to_hex, hash_rate_to_target, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; -use mining_sv2::MAX_EXTRANONCE_LEN; use binary_sv2::{self}; use bitcoin::{ blockdata::block::{Header, Version}, @@ -59,6 +58,7 @@ use bitcoin::{ transaction::TxOut, CompactTarget, Target, }; +use mining_sv2::MAX_EXTRANONCE_LEN; use mining_sv2::{SetCustomMiningJob, SubmitSharesExtended}; use std::{collections::HashMap, convert::TryInto, marker::PhantomData}; use template_distribution_sv2::{NewTemplate, SetNewPrevHash as SetNewPrevHashTdp}; @@ -825,7 +825,8 @@ where ); // update the best diff - self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); + self.share_accounting + .update_best_diff(self.channel_id, hash_as_diff); let last_sequence_number = self.share_accounting.get_last_share_sequence_number(); let new_submits_accepted_count = self.share_accounting.get_shares_accepted(); diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index 003b2186bc..faf3eae2ff 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -124,7 +124,7 @@ where share_work: u64, share_sequence_number: u32, share_hash: Hash, - block_found: bool + block_found: bool, ) { self.last_share_sequence_number = share_sequence_number; self.shares_accepted += 1; @@ -141,7 +141,7 @@ where total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, timestamp: std::time::SystemTime::now(), - block_found + block_found, }; self.persistence.persist_event(event); } diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 131327bf59..e576ae7841 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -634,7 +634,7 @@ where target_to_difficulty(self.target.clone()) as u64, share.sequence_number, hash.to_raw_hash(), - true + true, ); return Ok(ShareValidationResult::BlockFound( @@ -659,7 +659,8 @@ where ); // update the best diff - self.share_accounting.update_best_diff(self.channel_id, hash_as_diff); + self.share_accounting + .update_best_diff(self.channel_id, hash_as_diff); let last_sequence_number = self.share_accounting.get_last_share_sequence_number(); let new_submits_accepted_count = self.share_accounting.get_shares_accepted(); From 8f82a11627fe3054083e44c4a1ce606a8bddb34c Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 20 Oct 2025 13:30:16 -0400 Subject: [PATCH 13/39] feat(channels-sv2): Add NoPersistence to test constructors - Update test constructors in extended, standard, and server channels - Add NoPersistence::new() to all test method calls - Suppress clippy warning for constructor with many arguments in extended channel --- .../v2/channels-sv2/src/client/extended.rs | 6 ++ .../v2/channels-sv2/src/client/standard.rs | 5 + .../v2/channels-sv2/src/server/extended.rs | 100 ++---------------- 3 files changed, 19 insertions(+), 92 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 4d5fb885fc..715d8d5cdd 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -84,6 +84,7 @@ where P: Persistence, { /// Constructs a new [`ExtendedChannel`]. + #[allow(clippy::too_many_arguments)] pub fn new( channel_id: u32, user_identity: String, @@ -612,6 +613,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, + NoPersistence::new(), ); let future_job = NewExtendedMiningJob { @@ -694,6 +696,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, + NoPersistence::new(), ); let ntime: u32 = 1746839905; @@ -767,6 +770,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, + NoPersistence::new(), ); let future_job = NewExtendedMiningJob { @@ -859,6 +863,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, + NoPersistence::new(), ); let future_job = NewExtendedMiningJob { @@ -954,6 +959,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, + NoPersistence::new(), ); let future_job = NewExtendedMiningJob { diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 2ab5987aa1..68a0f7fd92 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -404,6 +404,7 @@ mod tests { extranonce_prefix, target, nominal_hashrate, + NoPersistence::new(), ); let future_job = NewMiningJob { @@ -464,6 +465,7 @@ mod tests { extranonce_prefix, target, nominal_hashrate, + NoPersistence::new(), ); let ntime: u32 = 1746839905; @@ -512,6 +514,7 @@ mod tests { extranonce_prefix, target, nominal_hashrate, + NoPersistence::new(), ); let future_job = NewMiningJob { @@ -585,6 +588,7 @@ mod tests { extranonce_prefix, target, nominal_hashrate, + NoPersistence::new(), ); let future_job = NewMiningJob { @@ -661,6 +665,7 @@ mod tests { extranonce_prefix, target, nominal_hashrate, + NoPersistence::new(), ); let future_job = NewMiningJob { diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index c0cd475f35..56f5ab1469 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -194,98 +194,6 @@ where persistence, ) } -} - -#[cfg(feature = "persistence")] -impl<'a, J, P> ExtendedChannel<'a, J, P> -where - J: JobStore>, - P: Persistence, -{ - /// Constructor of `ExtendedChannel` for a Sv2 Pool Server with custom persistence. - /// Not meant for usage on a Sv2 Job Declaration Client. - /// - /// Initializes the extended channel state with the provided parameters, including channel - /// identifiers, difficulty targets, share accounting, and job management. - /// Returns an error if target/difficulty parameters are invalid or extranonce prefix - /// requirements are not met. - /// - /// For non-JD jobs, `pool_tag_string` is added to the coinbase scriptSig in between `/` - /// and `//` delimiters: `/pool_tag_string//` - #[allow(clippy::too_many_arguments)] - pub fn new_for_pool_with_persistence( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - max_target: Target, - nominal_hashrate: f32, - version_rolling_allowed: bool, - rollable_extranonce_size: u16, - share_batch_size: usize, - expected_share_per_minute: f32, - job_store: J, - pool_tag_string: String, - persistence: P, - ) -> Result { - Self::new_with_persistence( - channel_id, - user_identity, - extranonce_prefix, - max_target, - nominal_hashrate, - version_rolling_allowed, - rollable_extranonce_size, - share_batch_size, - expected_share_per_minute, - job_store, - Some(pool_tag_string), - None, - persistence, - ) - } - - /// Constructor of `ExtendedChannel` for a Sv2 Job Declaration Client with custom persistence. - /// Not meant for usage on a Sv2 Pool Server. - /// - /// Initializes the extended channel state with the provided parameters, including channel - /// identifiers, difficulty targets, share accounting, and job management. - /// Returns an error if target/failure parameters are invalid or extranonce prefix - /// requirements are not met. - /// - /// The `pool_tag_string` and `miner_tag_string` are added to the coinbase scriptSig in between - /// `/` delimiters: `/pool_tag_string/miner_tag_string/` - #[allow(clippy::too_many_arguments)] - pub fn new_for_job_declaration_client_with_persistence( - channel_id: u32, - user_identity: String, - extranonce_prefix: Vec, - max_target: Target, - nominal_hashrate: f32, - version_rolling_allowed: bool, - rollable_extranonce_size: u16, - share_batch_size: usize, - expected_share_per_minute: f32, - job_store: J, - pool_tag_string: Option, - miner_tag_string: String, - persistence: P, - ) -> Result { - Self::new_with_persistence( - channel_id, - user_identity, - extranonce_prefix, - max_target, - nominal_hashrate, - version_rolling_allowed, - rollable_extranonce_size, - share_batch_size, - expected_share_per_minute, - job_store, - pool_tag_string, - Some(miner_tag_string), - persistence, - ) - } // private constructor #[allow(clippy::too_many_arguments)] @@ -902,6 +810,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1053,6 +962,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1173,6 +1083,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1251,6 +1162,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1360,6 +1272,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1472,6 +1385,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1599,6 +1513,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); @@ -1686,6 +1601,7 @@ mod tests { job_store, None, None, + NoPersistence::new(), ) .unwrap(); From e998903644aa890295f7db529b4b7c2fd05ac6c4 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 20 Oct 2025 14:54:30 -0400 Subject: [PATCH 14/39] feat(pool-persistence): Add configurable share persistence mechanism - Introduce PoolPersistence enum to support runtime persistence selection - Implement Persistence trait for PoolPersistence to handle different persistence strategies - Add file-based share persistence with optional configuration - Update ChannelManager to support configurable persistence mechanism - Modify channel creation methods to pass persistence configuration - Add logging for persistence initialization status --- .../channel_manager/mining_message_handler.rs | 3 +- roles/pool/src/lib/channel_manager/mod.rs | 71 ++++++++++++++++++- roles/pool/src/lib/mod.rs | 2 + 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/roles/pool/src/lib/channel_manager/mining_message_handler.rs b/roles/pool/src/lib/channel_manager/mining_message_handler.rs index 5f2dff2fc5..0b2d0d734b 100644 --- a/roles/pool/src/lib/channel_manager/mining_message_handler.rs +++ b/roles/pool/src/lib/channel_manager/mining_message_handler.rs @@ -137,7 +137,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { let channel_id = downstream_data.channel_id_factory.fetch_add(1, Ordering::SeqCst); let job_store = DefaultJobStore::new(); - let mut standard_channel = match StandardChannel::new_for_pool(channel_id as u32, user_identity.to_string(), extranonce_prefix.to_vec(), requested_max_target, nominal_hash_rate, self.share_batch_size, self.shares_per_minute, job_store, self.pool_tag_string.clone()) { + let mut standard_channel = match StandardChannel::new_for_pool(channel_id as u32, user_identity.to_string(), extranonce_prefix.to_vec(), requested_max_target, nominal_hash_rate, self.share_batch_size, self.shares_per_minute, job_store, self.pool_tag_string.clone(), self.persistence.clone()) { Ok(channel) => channel, Err(e) => match e { StandardChannelError::InvalidNominalHashrate => { @@ -303,6 +303,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { self.shares_per_minute, job_store, self.pool_tag_string.clone(), + self.persistence.clone(), ) { Ok(channel) => channel, Err(e) => match e { diff --git a/roles/pool/src/lib/channel_manager/mod.rs b/roles/pool/src/lib/channel_manager/mod.rs index c0096cd30f..f620e02787 100644 --- a/roles/pool/src/lib/channel_manager/mod.rs +++ b/roles/pool/src/lib/channel_manager/mod.rs @@ -13,6 +13,7 @@ use stratum_apps::{ network_helpers::noise_stream::NoiseTcpStream, stratum_core::{ channels_sv2::{ + persistence::{NoPersistence, Persistence, ShareAccountingEvent}, server::{ extended::ExtendedChannel, jobs::{extended::ExtendedJob, job_store::DefaultJobStore, standard::StandardJob}, @@ -36,7 +37,8 @@ use crate::{ config::PoolConfig, downstream::Downstream, error::PoolResult, - status::{handle_error, Status, StatusSender}, + share_persistence::{ShareFileHandler, ShareFilePersistence}, + status::{self, handle_error, Status, StatusSender}, task_manager::TaskManager, utils::{Message, ShutdownMessage}, }; @@ -44,6 +46,43 @@ use crate::{ mod mining_message_handler; mod template_distribution_message_handler; +/// Enum wrapper for different persistence implementations used by the pool. +/// Allows runtime selection between file-based persistence and no-op persistence. +#[derive(Clone, Debug)] +pub enum PoolPersistence { + File(ShareFilePersistence), + None(NoPersistence), +} + +impl Persistence for PoolPersistence { + type Sender = async_channel::Sender; + + fn persist_event(&self, event: ShareAccountingEvent) { + match self { + PoolPersistence::File(p) => p.persist_event(event), + PoolPersistence::None(p) => p.persist_event(event), + } + } + + fn flush(&self) { + match self { + PoolPersistence::File(p) => p.flush(), + PoolPersistence::None(p) => p.flush(), + } + } + + fn shutdown(&self) { + match self { + PoolPersistence::File(p) => p.shutdown(), + PoolPersistence::None(p) => p.shutdown(), + } + } + + fn new(sender: Self::Sender) -> Self { + PoolPersistence::File(ShareFilePersistence::new(sender)) + } +} + const POOL_ALLOCATION_BYTES: usize = 4; const CLIENT_SEARCH_SPACE_BYTES: usize = 8; pub const FULL_EXTRANONCE_SIZE: usize = POOL_ALLOCATION_BYTES + CLIENT_SEARCH_SPACE_BYTES; @@ -90,6 +129,7 @@ pub struct ChannelManager { share_batch_size: usize, shares_per_minute: f32, coinbase_reward_script: CoinbaseRewardScript, + persistence: PoolPersistence, } impl ChannelManager { @@ -102,6 +142,8 @@ impl ChannelManager { downstream_sender: broadcast::Sender<(u32, Mining<'static>)>, downstream_receiver: Receiver<(u32, Mining<'static>)>, coinbase_outputs: Vec, + status_tx: status::Sender, + task_manager: Arc, ) -> PoolResult { let range_0 = 0..0; let range_1 = 0..POOL_ALLOCATION_BYTES; @@ -143,6 +185,32 @@ impl ChannelManager { downstream_receiver, }; + // Initialize persistence based on config + let persistence = if let Some(path) = config.share_persistence_file_path() { + info!("Initializing file-based share persistence: {}", path); + let mut share_file_handler = ShareFileHandler::new(path, status_tx.clone()).await; + let sender = share_file_handler.get_sender(); + let receiver = share_file_handler.get_receiver(); + + // Spawn the share file handler task + task_manager.spawn_task(async move { + loop { + match receiver.recv().await { + Ok(event) => share_file_handler.write_event_to_file(event).await, + Err(_) => { + info!("Share persistence channel closed, stopping file handler"); + break; + } + } + } + }); + + PoolPersistence::File(ShareFilePersistence::new(sender)) + } else { + info!("Share persistence disabled - using NoPersistence"); + PoolPersistence::None(NoPersistence::new()) + }; + let channel_manager = ChannelManager { channel_manager_data, channel_manager_channel, @@ -150,6 +218,7 @@ impl ChannelManager { shares_per_minute: config.shares_per_minute(), pool_tag_string: config.pool_signature().to_string(), coinbase_reward_script: config.coinbase_reward_script().clone(), + persistence, }; Ok(channel_manager) diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index 286b2646f0..b36a3e61a1 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -76,6 +76,8 @@ impl PoolSv2 { channel_manager_to_downstream_sender.clone(), downstream_to_channel_manager_receiver, encoded_outputs.clone(), + status_sender.clone(), + task_manager.clone(), ) .await?; From 9b217064d0df55a1fe6756f08c5cab26e89768a5 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Mon, 20 Oct 2025 15:19:54 -0400 Subject: [PATCH 15/39] refactor(pool): Update dependencies and persistence handling - Replace `stratum-common` with `stratum-core` in dependencies - Update channel and downstream structs to use generic `PoolPersistence` - Modify `ShareFileHandler` to use `StatusSender` enum variant - Remove unused imports and simplify task management methods - Update task spawning method in `ChannelManager` - Refactor status handling and error logging - Remove dev dependencies from `Cargo.toml` --- roles/Cargo.lock | 2 ++ roles/pool/Cargo.toml | 5 +---- roles/pool/src/lib/channel_manager/mod.rs | 10 +++++----- roles/pool/src/lib/downstream/mod.rs | 13 +++++++++---- roles/pool/src/lib/mod.rs | 6 +++--- roles/pool/src/lib/share_persistence/mod.rs | 8 ++++---- 6 files changed, 24 insertions(+), 20 deletions(-) diff --git a/roles/Cargo.lock b/roles/Cargo.lock index acdbd055fd..437662919f 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -2332,12 +2332,14 @@ name = "pool_sv2" version = "0.2.0" dependencies = [ "async-channel 1.9.0", + "buffer_sv2 2.0.0", "clap", "config", "rand", "secp256k1 0.28.2", "serde", "stratum-apps", + "stratum-core", "tokio", "tracing", ] diff --git a/roles/pool/Cargo.toml b/roles/pool/Cargo.toml index 493866a7eb..4d6b81677a 100644 --- a/roles/pool/Cargo.toml +++ b/roles/pool/Cargo.toml @@ -19,7 +19,7 @@ path = "src/lib/mod.rs" [dependencies] stratum-apps = { path = "../stratum-apps", features = ["pool"] } async-channel = "1.5.1" -stratum-common = { path = "../../common", features = ["with_network_helpers"] } +stratum-core = { path = "../../stratum-core" } buffer_sv2 = { path = "../../utils/buffer" } rand = "0.8.4" serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } @@ -29,6 +29,3 @@ ext-config = { version = "0.14.0", features = ["toml"], package = "config" } tracing = { version = "0.1" } clap = { version = "4.5.39", features = ["derive"] } -[dev-dependencies] -hex = "0.4.3" -integration_tests_sv2 = { path = "../../test/integration-tests" } diff --git a/roles/pool/src/lib/channel_manager/mod.rs b/roles/pool/src/lib/channel_manager/mod.rs index f620e02787..91a98c0467 100644 --- a/roles/pool/src/lib/channel_manager/mod.rs +++ b/roles/pool/src/lib/channel_manager/mod.rs @@ -38,7 +38,7 @@ use crate::{ downstream::Downstream, error::PoolResult, share_persistence::{ShareFileHandler, ShareFilePersistence}, - status::{self, handle_error, Status, StatusSender}, + status::{handle_error, Status, StatusSender}, task_manager::TaskManager, utils::{Message, ShutdownMessage}, }; @@ -142,7 +142,7 @@ impl ChannelManager { downstream_sender: broadcast::Sender<(u32, Mining<'static>)>, downstream_receiver: Receiver<(u32, Mining<'static>)>, coinbase_outputs: Vec, - status_tx: status::Sender, + status_tx: StatusSender, task_manager: Arc, ) -> PoolResult { let range_0 = 0..0; @@ -193,7 +193,7 @@ impl ChannelManager { let receiver = share_file_handler.get_receiver(); // Spawn the share file handler task - task_manager.spawn_task(async move { + task_manager.spawn(async move { loop { match receiver.recv().await { Ok(event) => share_file_handler.write_event_to_file(event).await, @@ -441,7 +441,7 @@ impl ChannelManager { fn run_vardiff_on_extended_channel( downstream_id: u32, channel_id: u32, - channel_state: &mut ExtendedChannel<'static, DefaultJobStore>>, + channel_state: &mut ExtendedChannel<'static, DefaultJobStore>, PoolPersistence>, vardiff_state: &mut VardiffState, updates: &mut Vec, ) { @@ -486,7 +486,7 @@ impl ChannelManager { fn run_vardiff_on_standard_channel( downstream_id: u32, channel_id: u32, - channel: &mut StandardChannel<'static, DefaultJobStore>>, + channel: &mut StandardChannel<'static, DefaultJobStore>, PoolPersistence>, vardiff_state: &mut VardiffState, updates: &mut Vec, ) { diff --git a/roles/pool/src/lib/downstream/mod.rs b/roles/pool/src/lib/downstream/mod.rs index 180c79fab0..0a03c886d7 100644 --- a/roles/pool/src/lib/downstream/mod.rs +++ b/roles/pool/src/lib/downstream/mod.rs @@ -27,6 +27,7 @@ use tokio::sync::broadcast; use tracing::{debug, error, warn}; use crate::{ + channel_manager::PoolPersistence, error::{PoolError, PoolResult}, status::{handle_error, Status, StatusSender}, task_manager::TaskManager, @@ -47,10 +48,14 @@ mod common_message_handler; /// - Active [`StandardChannel`]s keyed by channel ID. pub struct DownstreamData { pub group_channels: Option>>>, - pub extended_channels: - HashMap>>>, - pub standard_channels: - HashMap>>>, + pub extended_channels: HashMap< + u32, + ExtendedChannel<'static, DefaultJobStore>, PoolPersistence>, + >, + pub standard_channels: HashMap< + u32, + StandardChannel<'static, DefaultJobStore>, PoolPersistence>, + >, pub channel_id_factory: AtomicUsize, } diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index b36a3e61a1..e8e2b04d8e 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -5,13 +5,13 @@ use stratum_apps::stratum_core::{ bitcoin::consensus::Encodable, parsers_sv2::TemplateDistribution, }; use tokio::sync::broadcast; -use tracing::{debug, info, warn}; +use tracing::{debug, info, warn, error}; use crate::{ channel_manager::ChannelManager, config::PoolConfig, error::PoolResult, - status::{State, Status}, + status::{State, Status, StatusSender}, task_manager::TaskManager, template_receiver::TemplateReceiver, utils::ShutdownMessage, @@ -76,7 +76,7 @@ impl PoolSv2 { channel_manager_to_downstream_sender.clone(), downstream_to_channel_manager_receiver, encoded_outputs.clone(), - status_sender.clone(), + StatusSender::ChannelManager(status_sender.clone()), task_manager.clone(), ) .await?; diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index 43d09bcf0d..b24a85a76e 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -1,20 +1,20 @@ -use stratum_common::roles_logic_sv2::channels_sv2::persistence::{ +use stratum_core::channels_sv2::persistence::{ Persistence, ShareAccountingEvent, }; use tokio::io::AsyncWriteExt; use tracing::error; -use crate::status::{self}; +use crate::status::{self, StatusSender}; pub struct ShareFileHandler { file: tokio::fs::File, receiver: async_channel::Receiver, sender: async_channel::Sender, - status_tx: status::Sender, + status_tx: StatusSender, } impl ShareFileHandler { - pub async fn new(path: &str, status_tx: status::Sender) -> Self { + pub async fn new(path: &str, status_tx: StatusSender) -> Self { let file = tokio::fs::File::create(path).await.unwrap(); let (sender, receiver) = async_channel::bounded(1024); Self { From e49c5d45780d7b868291a9b3c8b4874feffc1e19 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 10:40:26 -0400 Subject: [PATCH 16/39] refactor(channels-sv2): Add NoPersistence to channel types - Update channel manager and downstream modules to use NoPersistence - Modify type signatures for ExtendedChannel and StandardChannel to include NoPersistence - Remove unnecessary dependencies in Cargo.lock - Update constructor calls to include NoPersistence::new() - Standardize channel type definitions across different modules - Prepare for more flexible persistence mechanism in future implementations --- roles/Cargo.lock | 4 +- .../downstream_message_handler.rs | 3 + .../jd-client/src/lib/channel_manager/mod.rs | 10 ++- .../upstream_message_handler.rs | 3 +- roles/jd-client/src/lib/downstream/mod.rs | 25 ++++--- roles/jd-server/src/lib/config.rs | 8 +-- roles/pool/Cargo.toml | 2 - roles/pool/src/lib/channel_manager/mod.rs | 12 +++- roles/pool/src/lib/config.rs | 3 +- roles/pool/src/lib/mod.rs | 4 +- roles/pool/src/lib/share_persistence/mod.rs | 66 ++++++++++++------- .../sv2/channel_manager/channel_manager.rs | 5 +- .../src/lib/sv2/channel_manager/data.rs | 7 +- .../sv2/channel_manager/message_handler.rs | 5 +- 14 files changed, 101 insertions(+), 56 deletions(-) diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 437662919f..62a6d96212 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -2332,14 +2332,12 @@ name = "pool_sv2" version = "0.2.0" dependencies = [ "async-channel 1.9.0", - "buffer_sv2 2.0.0", "clap", "config", "rand", "secp256k1 0.28.2", "serde", "stratum-apps", - "stratum-core", "tokio", "tracing", ] diff --git a/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs b/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs index 6b88979517..962d612900 100644 --- a/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs +++ b/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs @@ -6,6 +6,7 @@ use stratum_apps::stratum_core::{ channels_sv2::{ client, outputs::deserialize_outputs, + persistence::NoPersistence, server::{ error::{ExtendedChannelError, StandardChannelError}, extended::ExtendedChannel, @@ -348,6 +349,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { job_store, channel_manager_data.pool_tag_string.clone(), self.miner_tag_string.clone(), + NoPersistence::new(), ) { Ok(channel) => channel, Err(e) => { @@ -586,6 +588,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { job_store, channel_manager_data.pool_tag_string.clone(), self.miner_tag_string.clone(), + NoPersistence::new(), ) { Ok(c) => c, Err(e) => { diff --git a/roles/jd-client/src/lib/channel_manager/mod.rs b/roles/jd-client/src/lib/channel_manager/mod.rs index d35c01f38c..afb314cb29 100644 --- a/roles/jd-client/src/lib/channel_manager/mod.rs +++ b/roles/jd-client/src/lib/channel_manager/mod.rs @@ -16,6 +16,7 @@ use stratum_apps::{ bitcoin::Target, channels_sv2::{ client::extended::ExtendedChannel, + persistence::NoPersistence, server::{ jobs::{ extended::ExtendedJob, factory::JobFactory, job_store::DefaultJobStore, @@ -135,7 +136,7 @@ pub struct ChannelManagerData { // Maps channel ID → downstream ID. channel_id_to_downstream_id: HashMap, // The active upstream extended channel (client-side instance), if any. - upstream_channel: Option>, + upstream_channel: Option>, // Optional "pool tag" string, identifying the pool. pool_tag_string: Option, // List of pending downstream connection requests, @@ -922,6 +923,7 @@ impl ChannelManager { channel_state: &mut stratum_apps::stratum_core::channels_sv2::server::extended::ExtendedChannel< 'static, DefaultJobStore>, + NoPersistence, >, vardiff_state: &mut VardiffState, updates: &mut Vec, @@ -967,7 +969,11 @@ impl ChannelManager { fn run_vardiff_on_standard_channel( downstream_id: u32, channel_id: u32, - channel: &mut StandardChannel<'static, DefaultJobStore>>, + channel: &mut StandardChannel< + 'static, + DefaultJobStore>, + NoPersistence, + >, vardiff_state: &mut VardiffState, updates: &mut Vec, ) { diff --git a/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs b/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs index d1d95116ef..78b08b62d6 100644 --- a/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs +++ b/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs @@ -4,7 +4,7 @@ use stratum_apps::stratum_core::{ bitcoin::Target, channels_sv2::{ client::extended::ExtendedChannel, outputs::deserialize_outputs, - server::jobs::factory::JobFactory, + persistence::NoPersistence, server::jobs::factory::JobFactory, }, handlers_sv2::{HandleMiningMessagesFromServerAsync, SupportedChannelTypes}, mining_sv2::*, @@ -144,6 +144,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { hashrate, true, msg.extranonce_size, + NoPersistence::new(), ); if let Some(ref mut prevhash) = data.last_new_prev_hash { diff --git a/roles/jd-client/src/lib/downstream/mod.rs b/roles/jd-client/src/lib/downstream/mod.rs index a9a37d8014..b51ed5bc71 100644 --- a/roles/jd-client/src/lib/downstream/mod.rs +++ b/roles/jd-client/src/lib/downstream/mod.rs @@ -5,11 +5,14 @@ use stratum_apps::{ custom_mutex::Mutex, network_helpers::noise_stream::NoiseTcpStream, stratum_core::{ - channels_sv2::server::{ - extended::ExtendedChannel, - group::GroupChannel, - jobs::{extended::ExtendedJob, job_store::DefaultJobStore, standard::StandardJob}, - standard::StandardChannel, + channels_sv2::{ + persistence::NoPersistence, + server::{ + extended::ExtendedChannel, + group::GroupChannel, + jobs::{extended::ExtendedJob, job_store::DefaultJobStore, standard::StandardJob}, + standard::StandardChannel, + }, }, common_messages_sv2::MESSAGE_TYPE_SETUP_CONNECTION, handlers_sv2::HandleCommonMessagesFromClientAsync, @@ -42,10 +45,14 @@ mod message_handler; pub struct DownstreamData { pub require_std_job: bool, pub group_channels: Option>>>, - pub extended_channels: - HashMap>>>, - pub standard_channels: - HashMap>>>, + pub extended_channels: HashMap< + u32, + ExtendedChannel<'static, DefaultJobStore>, NoPersistence>, + >, + pub standard_channels: HashMap< + u32, + StandardChannel<'static, DefaultJobStore>, NoPersistence>, + >, } /// Communication layer for a downstream connection. diff --git a/roles/jd-server/src/lib/config.rs b/roles/jd-server/src/lib/config.rs index ee01a046ec..96bba8c921 100644 --- a/roles/jd-server/src/lib/config.rs +++ b/roles/jd-server/src/lib/config.rs @@ -181,7 +181,7 @@ mod tests { use crate::config::JobDeclaratorServerConfig; - const COINBASE_CONFIG_TEMPLATE: &'static str = r#" + const COINBASE_CONFIG_TEMPLATE: &str = r#" full_template_mode_required = true authority_public_key = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72" authority_secret_key = "mkDLTBBRxdBv998612qipDYoTK3YUrqLe8uWw7gu3iXbSrn2n" @@ -198,9 +198,9 @@ mod tests { unit = "secs" value = 1 "#; - const TEST_PK_HEX: &'static str = + const TEST_PK_HEX: &str = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075"; - const TEST_INVALID_PK_HEX: &'static str = + const TEST_INVALID_PK_HEX: &str = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7ffffff"; fn load_config(path: &str) -> JobDeclaratorServerConfig { @@ -276,7 +276,7 @@ mod tests { #[test] fn test_get_invalid_miniscript_in_coinbase_reward_script() { - let error = load_coinbase_config_str(&format!("\"INVALID\"")) + let error = load_coinbase_config_str("\"INVALID\"") .expect_err("Cannot parse config with bad miniscript"); assert_eq!( error.to_string(), diff --git a/roles/pool/Cargo.toml b/roles/pool/Cargo.toml index 4d6b81677a..7d8a138d13 100644 --- a/roles/pool/Cargo.toml +++ b/roles/pool/Cargo.toml @@ -19,8 +19,6 @@ path = "src/lib/mod.rs" [dependencies] stratum-apps = { path = "../stratum-apps", features = ["pool"] } async-channel = "1.5.1" -stratum-core = { path = "../../stratum-core" } -buffer_sv2 = { path = "../../utils/buffer" } rand = "0.8.4" serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } secp256k1 = { version = "0.28.2", default-features = false, features = ["alloc", "rand", "rand-std"] } diff --git a/roles/pool/src/lib/channel_manager/mod.rs b/roles/pool/src/lib/channel_manager/mod.rs index 91a98c0467..f9f0183592 100644 --- a/roles/pool/src/lib/channel_manager/mod.rs +++ b/roles/pool/src/lib/channel_manager/mod.rs @@ -441,7 +441,11 @@ impl ChannelManager { fn run_vardiff_on_extended_channel( downstream_id: u32, channel_id: u32, - channel_state: &mut ExtendedChannel<'static, DefaultJobStore>, PoolPersistence>, + channel_state: &mut ExtendedChannel< + 'static, + DefaultJobStore>, + PoolPersistence, + >, vardiff_state: &mut VardiffState, updates: &mut Vec, ) { @@ -486,7 +490,11 @@ impl ChannelManager { fn run_vardiff_on_standard_channel( downstream_id: u32, channel_id: u32, - channel: &mut StandardChannel<'static, DefaultJobStore>, PoolPersistence>, + channel: &mut StandardChannel< + 'static, + DefaultJobStore>, + PoolPersistence, + >, vardiff_state: &mut VardiffState, updates: &mut Vec, ) { diff --git a/roles/pool/src/lib/config.rs b/roles/pool/src/lib/config.rs index 7d62e622fc..15edcae708 100644 --- a/roles/pool/src/lib/config.rs +++ b/roles/pool/src/lib/config.rs @@ -43,6 +43,7 @@ impl PoolConfig { /// # Panics /// /// Panics if `coinbase_reward_script` is empty. + #[allow(clippy::too_many_arguments)] pub fn new( pool_connection: ConnectionConfig, template_provider: TemplateProviderConfig, @@ -66,7 +67,7 @@ impl PoolConfig { share_batch_size, log_file: None, server_id, - share_persistence_file_path + share_persistence_file_path, } } diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index e8e2b04d8e..17ee776d8a 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -5,7 +5,7 @@ use stratum_apps::stratum_core::{ bitcoin::consensus::Encodable, parsers_sv2::TemplateDistribution, }; use tokio::sync::broadcast; -use tracing::{debug, info, warn, error}; +use tracing::{debug, error, info, warn}; use crate::{ channel_manager::ChannelManager, @@ -21,11 +21,11 @@ pub mod channel_manager; pub mod config; pub mod downstream; pub mod error; +pub mod share_persistence; pub mod status; pub mod task_manager; pub mod template_receiver; pub mod utils; -pub mod share_persistence; #[derive(Debug, Clone)] pub struct PoolSv2 { diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index b24a85a76e..b3e75e94a5 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -1,6 +1,4 @@ -use stratum_core::channels_sv2::persistence::{ - Persistence, ShareAccountingEvent, -}; +use stratum_apps::stratum_core::channels_sv2::persistence::{Persistence, ShareAccountingEvent}; use tokio::io::AsyncWriteExt; use tracing::error; @@ -21,7 +19,7 @@ impl ShareFileHandler { file, receiver, sender, - status_tx + status_tx, } } @@ -63,14 +61,29 @@ impl ShareFileHandler { ).await; if let Err(e) = result { - error!(target = "share_file_handler", "Failed to write share event: {}", e); - let _ = self.status_tx.send(status::Status { - state: status::State::SharePersistenceError(format!("Failed to write share event: {}", e)), - }).await; + error!( + target = "share_file_handler", + "Failed to write share event: {}", e + ); + let _ = self + .status_tx + .send(status::Status { + state: status::State::SharePersistenceError(format!( + "Failed to write share event: {}", + e + )), + }) + .await; } else if block_found { - let _ = self.status_tx.send(status::Status { - state: status::State::Healthy(format!("Block found! channel_id: {}, user: {}", channel_id, user_identity)), - }).await; + let _ = self + .status_tx + .send(status::Status { + state: status::State::Healthy(format!( + "Block found! channel_id: {}, user: {}", + channel_id, user_identity + )), + }) + .await; } } ShareAccountingEvent::BestDifficultyUpdated { @@ -91,17 +104,26 @@ impl ShareFileHandler { ).await; if let Err(e) = result { - error!(target = "share_file_handler", "Failed to write difficulty update: {}", e); - let _ = self.status_tx.send(status::Status { - state: status::State::SharePersistenceError(format!("Failed to write difficulty update: {}", e)), - }).await; + error!( + target = "share_file_handler", + "Failed to write difficulty update: {}", e + ); + let _ = self + .status_tx + .send(status::Status { + state: status::State::SharePersistenceError(format!( + "Failed to write difficulty update: {}", + e + )), + }) + .await; } - }, + } } } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct ShareFilePersistence { sender: Option>, } @@ -118,12 +140,8 @@ impl Persistence for ShareFilePersistence { } fn new(sender: Self::Sender) -> Self { - Self { sender: Some(sender) } - } -} - -impl Default for ShareFilePersistence { - fn default() -> Self { - Self { sender: None } + Self { + sender: Some(sender), + } } } diff --git a/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs b/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs index e242b32a4e..bbb871ef1e 100644 --- a/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs +++ b/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs @@ -16,7 +16,7 @@ use std::sync::{Arc, RwLock}; use stratum_apps::{ custom_mutex::Mutex, stratum_core::{ - channels_sv2::client::extended::ExtendedChannel, + channels_sv2::{client::extended::ExtendedChannel, persistence::NoPersistence}, framing_sv2::framing::Frame, handlers_sv2::HandleMiningMessagesFromServerAsync, mining_sv2::OpenExtendedMiningChannelSuccess, @@ -319,6 +319,7 @@ impl ChannelManager { hashrate, true, new_extranonce_size as u16, + NoPersistence::new(), ); self.channel_manager_data.super_safe_lock(|c| { c.extended_channels.insert( @@ -786,7 +787,7 @@ mod tests { let update_channel = UpdateChannel { channel_id: 1, nominal_hash_rate: 2000.0, - maximum_target: [0xFFu8; 32].try_into().unwrap(), + maximum_target: [0xFFu8; 32].into(), }; // Test that the message can be handled diff --git a/roles/translator/src/lib/sv2/channel_manager/data.rs b/roles/translator/src/lib/sv2/channel_manager/data.rs index c79bae825b..d20f9f5900 100644 --- a/roles/translator/src/lib/sv2/channel_manager/data.rs +++ b/roles/translator/src/lib/sv2/channel_manager/data.rs @@ -5,7 +5,8 @@ use std::{ use stratum_apps::{ custom_mutex::Mutex, stratum_core::{ - channels_sv2::client::extended::ExtendedChannel, mining_sv2::ExtendedExtranonce, + channels_sv2::{client::extended::ExtendedChannel, persistence::NoPersistence}, + mining_sv2::ExtendedExtranonce, }, }; @@ -38,9 +39,9 @@ pub struct ChannelManagerData { /// downstream_extranonce_len) pub pending_channels: HashMap, /// Map of active extended channels by channel ID - pub extended_channels: HashMap>>>, + pub extended_channels: HashMap>>>, /// The upstream extended channel used in aggregated mode - pub upstream_extended_channel: Option>>>, + pub upstream_extended_channel: Option>>>, /// Extranonce prefix factory for allocating unique prefixes in aggregated mode pub extranonce_prefix_factory: Option>>, /// Current operational mode diff --git a/roles/translator/src/lib/sv2/channel_manager/message_handler.rs b/roles/translator/src/lib/sv2/channel_manager/message_handler.rs index bfa714e7cd..469ae51549 100644 --- a/roles/translator/src/lib/sv2/channel_manager/message_handler.rs +++ b/roles/translator/src/lib/sv2/channel_manager/message_handler.rs @@ -9,7 +9,7 @@ use stratum_apps::{ custom_mutex::Mutex, stratum_core::{ bitcoin::Target, - channels_sv2::client::extended::ExtendedChannel, + channels_sv2::{client::extended::ExtendedChannel, persistence::NoPersistence}, handlers_sv2::{HandleMiningMessagesFromServerAsync, SupportedChannelTypes}, mining_sv2::{ CloseChannel, ExtendedExtranonce, Extranonce, NewExtendedMiningJob, NewMiningJob, @@ -86,6 +86,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { nominal_hashrate, version_rolling, m.extranonce_size, + NoPersistence::new(), ); // If we are in aggregated mode, we need to create a new extranonce prefix and @@ -139,6 +140,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { nominal_hashrate, true, new_extranonce_size, + NoPersistence::new(), ); channel_manager_data.extended_channels.insert( m.channel_id, @@ -194,6 +196,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { nominal_hashrate, true, downstream_extranonce_len as u16, + NoPersistence::new(), ); channel_manager_data.extended_channels.insert( m.channel_id, From 0ddd34cb97fdae4d40c33930434b8076e4c2af4e Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 11:01:52 -0400 Subject: [PATCH 17/39] fix(fmt): use correct rust version to satify GH actions --- roles/jd-server/src/lib/config.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/roles/jd-server/src/lib/config.rs b/roles/jd-server/src/lib/config.rs index 96bba8c921..f59310df42 100644 --- a/roles/jd-server/src/lib/config.rs +++ b/roles/jd-server/src/lib/config.rs @@ -198,8 +198,7 @@ mod tests { unit = "secs" value = 1 "#; - const TEST_PK_HEX: &str = - "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075"; + const TEST_PK_HEX: &str = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075"; const TEST_INVALID_PK_HEX: &str = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7ffffff"; From 20e07a1783c2498b102a36682961a78d3aa1d887 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 11:42:40 -0400 Subject: [PATCH 18/39] chore(dependencies): Update Cargo.lock files and dependencies - Bump versions of several internal crates: * binary_sv2 from 4.0.0 to 5.0.0 * codec_sv2 from 4.0.0 to 4.0.1 * common_messages_sv2 from 6.0.1 to 6.0.2 * framing_sv2 from 5.0.1 to 5.0.2 - Remove unused dependencies and clean up Cargo.lock files - Simplify dependency graph across multiple project Cargo.lock files - Ensure consistent dependency versions across project workspaces --- protocols/fuzz-tests/Cargo.lock | 511 +----------------------------- roles/Cargo.lock | 206 ++++-------- test/integration-tests/Cargo.lock | 201 +++--------- test/integration-tests/lib/mod.rs | 1 + utils/Cargo.lock | 22 +- 5 files changed, 134 insertions(+), 807 deletions(-) diff --git a/protocols/fuzz-tests/Cargo.lock b/protocols/fuzz-tests/Cargo.lock index 7c93c90277..f904956fdc 100644 --- a/protocols/fuzz-tests/Cargo.lock +++ b/protocols/fuzz-tests/Cargo.lock @@ -58,110 +58,27 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "base58ck" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" -dependencies = [ - "bitcoin-internals 0.3.0", - "bitcoin_hashes 0.14.0", -] - -[[package]] -name = "bech32" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" - [[package]] name = "binary_sv2" -version = "4.0.0" +version = "5.0.0" dependencies = [ - "buffer_sv2", "derive_codec_sv2", ] -[[package]] -name = "bitcoin" -version = "0.32.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" -dependencies = [ - "base58ck", - "bech32", - "bitcoin-internals 0.3.0", - "bitcoin-io", - "bitcoin-units", - "bitcoin_hashes 0.14.0", - "hex-conservative 0.2.1", - "hex_lit", - "secp256k1 0.29.1", -] - [[package]] name = "bitcoin-internals" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" -[[package]] -name = "bitcoin-internals" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" - -[[package]] -name = "bitcoin-io" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" - -[[package]] -name = "bitcoin-units" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" -dependencies = [ - "bitcoin-internals 0.3.0", -] - [[package]] name = "bitcoin_hashes" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ - "bitcoin-internals 0.2.0", - "hex-conservative 0.1.2", -] - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" -dependencies = [ - "bitcoin-io", - "hex-conservative 0.2.1", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", + "bitcoin-internals", + "hex-conservative", ] [[package]] @@ -172,18 +89,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "byte-slice-cast" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "cc" version = "1.2.41" @@ -226,20 +131,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "channels_sv2" -version = "2.0.0" -dependencies = [ - "binary_sv2", - "bitcoin", - "common_messages_sv2", - "job_declaration_sv2", - "mining_sv2", - "primitive-types", - "template_distribution_sv2", - "tracing", -] - [[package]] name = "cipher" version = "0.4.4" @@ -253,7 +144,7 @@ dependencies = [ [[package]] name = "codec_sv2" -version = "4.0.0" +version = "4.0.1" dependencies = [ "binary_sv2", "buffer_sv2", @@ -265,31 +156,11 @@ dependencies = [ [[package]] name = "common_messages_sv2" -version = "6.0.1" +version = "6.0.2" dependencies = [ "binary_sv2", ] -[[package]] -name = "const_format" -version = "0.2.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -299,12 +170,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - [[package]] name = "crypto-common" version = "0.1.6" @@ -312,7 +177,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", - "rand_core", "typenum", ] @@ -340,12 +204,6 @@ dependencies = [ name = "derive_codec_sv2" version = "1.1.1" -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - [[package]] name = "errno" version = "0.3.14" @@ -362,33 +220,14 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - [[package]] name = "framing_sv2" -version = "5.0.1" +version = "5.0.2" dependencies = [ "binary_sv2", - "buffer_sv2", "noise_sv2", ] -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "fuzz-tests" version = "1.0.1" @@ -402,7 +241,6 @@ dependencies = [ "libfuzzer-sys", "parsers_sv2", "rand", - "roles_logic_sv2", "threadpool", ] @@ -449,97 +287,18 @@ dependencies = [ "polyval", ] -[[package]] -name = "handlers_sv2" -version = "0.2.0" -dependencies = [ - "binary_sv2", - "common_messages_sv2", - "job_declaration_sv2", - "mining_sv2", - "parsers_sv2", - "template_distribution_sv2", - "trait-variant", -] - -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - [[package]] name = "hermit-abi" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "hex-conservative" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" -[[package]] -name = "hex-conservative" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "hex-conservative" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afe881d0527571892c4034822e59bb10c6c991cce6abe8199b6f5cf10766f55" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "hex_lit" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" - -[[package]] -name = "impl-codec" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d40b9d5e17727407e55028eafc22b2dc68781786e6d7eb8a21103f5058e3a14" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "indexmap" -version = "2.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" -dependencies = [ - "equivalent", - "hashbrown", -] - [[package]] name = "inout" version = "0.1.4" @@ -551,7 +310,7 @@ dependencies = [ [[package]] name = "job_declaration_sv2" -version = "5.0.1" +version = "5.0.2" dependencies = [ "binary_sv2", ] @@ -588,25 +347,13 @@ dependencies = [ "cc", ] -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - [[package]] name = "mining_sv2" -version = "5.0.1" +version = "5.0.2" dependencies = [ "binary_sv2", ] -[[package]] -name = "nohash-hasher" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" - [[package]] name = "noise_sv2" version = "1.4.0" @@ -616,7 +363,7 @@ dependencies = [ "generic-array", "rand", "rand_chacha", - "secp256k1 0.28.2", + "secp256k1", ] [[package]] @@ -641,37 +388,9 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "parity-scale-codec" -version = "3.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" -dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "const_format", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "rustversion", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "parsers_sv2" -version = "0.1.1" +version = "0.1.2" dependencies = [ "binary_sv2", "common_messages_sv2", @@ -719,26 +438,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "primitive-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" -dependencies = [ - "fixed-hash", - "impl-codec", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" -dependencies = [ - "toml_edit", -] - [[package]] name = "proc-macro2" version = "1.0.101" @@ -763,12 +462,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" version = "0.8.5" @@ -799,58 +492,15 @@ dependencies = [ "getrandom 0.2.16", ] -[[package]] -name = "roles_logic_sv2" -version = "5.0.0" -dependencies = [ - "binary_sv2", - "bitcoin", - "chacha20poly1305", - "channels_sv2", - "codec_sv2", - "common_messages_sv2", - "handlers_sv2", - "hex-conservative 0.3.0", - "job_declaration_sv2", - "mining_sv2", - "nohash-hasher", - "parsers_sv2", - "primitive-types", - "template_distribution_sv2", - "tracing", -] - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - [[package]] name = "secp256k1" version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes", "rand", - "secp256k1-sys 0.9.2", -] - -[[package]] -name = "secp256k1" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" -dependencies = [ - "bitcoin_hashes 0.14.0", - "secp256k1-sys 0.10.1", + "secp256k1-sys", ] [[package]] @@ -862,56 +512,12 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" -dependencies = [ - "cc", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "subtle" version = "2.6.1" @@ -920,24 +526,18 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "template_distribution_sv2" -version = "4.0.1" +version = "4.0.2" dependencies = [ "binary_sv2", ] @@ -951,36 +551,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "toml_datetime" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.23.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" -dependencies = [ - "indexmap", - "toml_datetime", - "toml_parser", - "winnow", -] - -[[package]] -name = "toml_parser" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" -dependencies = [ - "winnow", -] - [[package]] name = "tracing" version = "0.1.41" @@ -1012,46 +582,17 @@ dependencies = [ "once_cell", ] -[[package]] -name = "trait-variant" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "uint" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "universal-hash" @@ -1099,30 +640,12 @@ dependencies = [ "windows-link", ] -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "zerocopy" version = "0.8.27" diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 62a6d96212..665c9de504 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -1,21 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +version = 3 [[package]] name = "aead" @@ -377,7 +362,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -392,21 +377,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.1", -] - [[package]] name = "base58ck" version = "0.1.0" @@ -549,11 +519,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -667,9 +637,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" @@ -765,9 +735,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -775,9 +745,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -794,7 +764,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1017,21 +987,21 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ "csv-core", "itoa", "ryu", - "serde", + "serde_core", ] [[package]] name = "csv-core" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" dependencies = [ "memchr", ] @@ -1310,7 +1280,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1374,12 +1344,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "gloo-timers" version = "0.3.0" @@ -1650,14 +1614,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -1692,17 +1656,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags 2.9.4", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1956,24 +1909,15 @@ dependencies = [ "bitcoin", ] -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", "wasi", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2068,15 +2012,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -2136,7 +2071,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2208,20 +2143,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -2229,24 +2163,23 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ - "once_cell", "pest", "sha2 0.10.9", ] @@ -2431,7 +2364,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", ] [[package]] @@ -2515,7 +2448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.9.4", + "bitflags 2.10.0", "serde", "serde_derive", ] @@ -2546,12 +2479,6 @@ dependencies = [ "ordered-multimap", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hex" version = "2.1.0" @@ -2578,7 +2505,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2591,7 +2518,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.11.0", @@ -2691,7 +2618,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2937,9 +2864,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -2952,7 +2879,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.4", + "bitflags 2.10.0", "core-foundation", "system-configuration-sys", ] @@ -2989,26 +2916,6 @@ dependencies = [ "binary_sv2 5.0.0", ] -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "thread_local" version = "1.1.9" @@ -3039,33 +2946,30 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2 0.6.1", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -3177,7 +3081,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -3227,7 +3131,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -3277,9 +3181,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-segmentation" @@ -3381,7 +3285,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "wasm-bindgen-shared", ] @@ -3416,7 +3320,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3780,7 +3684,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] diff --git a/test/integration-tests/Cargo.lock b/test/integration-tests/Cargo.lock index d9135ea85d..a2e1337ed5 100644 --- a/test/integration-tests/Cargo.lock +++ b/test/integration-tests/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -188,7 +179,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -197,21 +188,6 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" -[[package]] -name = "backtrace" -version = "0.3.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-link 0.2.1", -] - [[package]] name = "base58ck" version = "0.1.0" @@ -361,11 +337,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -454,9 +430,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chacha20" @@ -525,9 +501,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" +checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" dependencies = [ "clap_builder", "clap_derive", @@ -535,9 +511,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.49" +version = "4.5.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" +checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" dependencies = [ "anstream", "anstyle", @@ -554,7 +530,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1005,7 +981,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1056,19 +1032,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.7+wasi-0.2.4", + "wasip2", ] [[package]] @@ -1081,12 +1057,6 @@ dependencies = [ "polyval", ] -[[package]] -name = "gimli" -version = "0.32.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" - [[package]] name = "h2" version = "0.4.12" @@ -1323,14 +1293,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] name = "indexmap" -version = "2.11.4" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -1368,17 +1338,6 @@ dependencies = [ "translator_sv2", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1610,12 +1569,10 @@ dependencies = [ [[package]] name = "minreq" -version = "2.13.2" +version = "2.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0c420feb01b9fb5061f8c8f452534361dd783756dcf38ec45191ce55e7a161" +checksum = "05015102dad0f7d61691ca347e9d9d9006685a64aefb3d79eecf62665de2153d" dependencies = [ - "log", - "once_cell", "rustls", "rustls-webpki", "serde", @@ -1625,13 +1582,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -1707,15 +1664,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "object" -version = "0.37.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1769,7 +1717,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -1835,20 +1783,19 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" +checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" dependencies = [ "memchr", - "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" dependencies = [ "pest", "pest_generator", @@ -1856,24 +1803,23 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" +checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] name = "pest_meta" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" +checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" dependencies = [ - "once_cell", "pest", "sha2 0.10.9", ] @@ -2043,7 +1989,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -2169,12 +2115,6 @@ dependencies = [ "ordered-multimap", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - [[package]] name = "rustc-hex" version = "2.1.0" @@ -2311,7 +2251,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2531,9 +2471,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -2605,26 +2545,6 @@ dependencies = [ "binary_sv2 5.0.0", ] -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "thread_local" version = "1.1.9" @@ -2645,34 +2565,31 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", "socket2", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2784,7 +2701,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2834,7 +2751,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] @@ -2883,9 +2800,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-segmentation" @@ -2948,15 +2865,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasi" -version = "0.14.7+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" -dependencies = [ - "wasip2", -] - [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -3031,15 +2939,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -3239,7 +3138,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.107", ] [[package]] diff --git a/test/integration-tests/lib/mod.rs b/test/integration-tests/lib/mod.rs index a93b836a47..89b4fe4d7b 100644 --- a/test/integration-tests/lib/mod.rs +++ b/test/integration-tests/lib/mod.rs @@ -106,6 +106,7 @@ pub async fn start_pool(template_provider_address: Option) -> (PoolS SHARES_PER_MINUTE, share_batch_size, 1, + None, ); let pool = PoolSv2::new(config); let pool_clone = pool.clone(); diff --git a/utils/Cargo.lock b/utils/Cargo.lock index b21d533eb1..822bdd2d2c 100644 --- a/utils/Cargo.lock +++ b/utils/Cargo.lock @@ -94,9 +94,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cipher" @@ -201,21 +201,21 @@ dependencies = [ [[package]] name = "csv" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" dependencies = [ "csv-core", "itoa", "ryu", - "serde", + "serde_core", ] [[package]] name = "csv-core" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" dependencies = [ "memchr", ] @@ -599,9 +599,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -635,9 +635,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "unicode-width" From 3e34b8fbf2754295e7eafc32a2db556e9473bedc Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 11:57:19 -0400 Subject: [PATCH 19/39] fix(ci/cd): revert lock to main --- protocols/fuzz-tests/Cargo.lock | 511 +++++++++++++++++++++++++++++- roles/Cargo.lock | 204 ++++++++---- test/integration-tests/Cargo.lock | 201 +++++++++--- utils/Cargo.lock | 22 +- 4 files changed, 806 insertions(+), 132 deletions(-) diff --git a/protocols/fuzz-tests/Cargo.lock b/protocols/fuzz-tests/Cargo.lock index f904956fdc..7c93c90277 100644 --- a/protocols/fuzz-tests/Cargo.lock +++ b/protocols/fuzz-tests/Cargo.lock @@ -58,27 +58,110 @@ dependencies = [ "derive_arbitrary", ] +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.0", +] + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + [[package]] name = "binary_sv2" -version = "5.0.0" +version = "4.0.0" dependencies = [ + "buffer_sv2", "derive_codec_sv2", ] +[[package]] +name = "bitcoin" +version = "0.32.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" +dependencies = [ + "base58ck", + "bech32", + "bitcoin-internals 0.3.0", + "bitcoin-io", + "bitcoin-units", + "bitcoin_hashes 0.14.0", + "hex-conservative 0.2.1", + "hex_lit", + "secp256k1 0.29.1", +] + [[package]] name = "bitcoin-internals" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" +[[package]] +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" + +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", +] + [[package]] name = "bitcoin_hashes" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" dependencies = [ - "bitcoin-internals", - "hex-conservative", + "bitcoin-internals 0.2.0", + "hex-conservative 0.1.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative 0.2.1", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", ] [[package]] @@ -89,6 +172,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.2.41" @@ -131,6 +226,20 @@ dependencies = [ "zeroize", ] +[[package]] +name = "channels_sv2" +version = "2.0.0" +dependencies = [ + "binary_sv2", + "bitcoin", + "common_messages_sv2", + "job_declaration_sv2", + "mining_sv2", + "primitive-types", + "template_distribution_sv2", + "tracing", +] + [[package]] name = "cipher" version = "0.4.4" @@ -144,7 +253,7 @@ dependencies = [ [[package]] name = "codec_sv2" -version = "4.0.1" +version = "4.0.0" dependencies = [ "binary_sv2", "buffer_sv2", @@ -156,11 +265,31 @@ dependencies = [ [[package]] name = "common_messages_sv2" -version = "6.0.2" +version = "6.0.1" dependencies = [ "binary_sv2", ] +[[package]] +name = "const_format" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -170,6 +299,12 @@ dependencies = [ "libc", ] +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -177,6 +312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", + "rand_core", "typenum", ] @@ -204,6 +340,12 @@ dependencies = [ name = "derive_codec_sv2" version = "1.1.1" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "errno" version = "0.3.14" @@ -220,14 +362,33 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + [[package]] name = "framing_sv2" -version = "5.0.2" +version = "5.0.1" dependencies = [ "binary_sv2", + "buffer_sv2", "noise_sv2", ] +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "fuzz-tests" version = "1.0.1" @@ -241,6 +402,7 @@ dependencies = [ "libfuzzer-sys", "parsers_sv2", "rand", + "roles_logic_sv2", "threadpool", ] @@ -287,18 +449,97 @@ dependencies = [ "polyval", ] +[[package]] +name = "handlers_sv2" +version = "0.2.0" +dependencies = [ + "binary_sv2", + "common_messages_sv2", + "job_declaration_sv2", + "mining_sv2", + "parsers_sv2", + "template_distribution_sv2", + "trait-variant", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "hermit-abi" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hex-conservative" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex-conservative" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4afe881d0527571892c4034822e59bb10c6c991cce6abe8199b6f5cf10766f55" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "impl-codec" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d40b9d5e17727407e55028eafc22b2dc68781786e6d7eb8a21103f5058e3a14" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.4" @@ -310,7 +551,7 @@ dependencies = [ [[package]] name = "job_declaration_sv2" -version = "5.0.2" +version = "5.0.1" dependencies = [ "binary_sv2", ] @@ -347,13 +588,25 @@ dependencies = [ "cc", ] +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + [[package]] name = "mining_sv2" -version = "5.0.2" +version = "5.0.1" dependencies = [ "binary_sv2", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "noise_sv2" version = "1.4.0" @@ -363,7 +616,7 @@ dependencies = [ "generic-array", "rand", "rand_chacha", - "secp256k1", + "secp256k1 0.28.2", ] [[package]] @@ -388,9 +641,37 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "parsers_sv2" -version = "0.1.2" +version = "0.1.1" dependencies = [ "binary_sv2", "common_messages_sv2", @@ -438,6 +719,26 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "primitive-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d15600a7d856470b7d278b3fe0e311fe28c2526348549f8ef2ff7db3299c87f5" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -462,6 +763,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.8.5" @@ -492,15 +799,58 @@ dependencies = [ "getrandom 0.2.16", ] +[[package]] +name = "roles_logic_sv2" +version = "5.0.0" +dependencies = [ + "binary_sv2", + "bitcoin", + "chacha20poly1305", + "channels_sv2", + "codec_sv2", + "common_messages_sv2", + "handlers_sv2", + "hex-conservative 0.3.0", + "job_declaration_sv2", + "mining_sv2", + "nohash-hasher", + "parsers_sv2", + "primitive-types", + "template_distribution_sv2", + "tracing", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + [[package]] name = "secp256k1" version = "0.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" dependencies = [ - "bitcoin_hashes", + "bitcoin_hashes 0.13.0", "rand", - "secp256k1-sys", + "secp256k1-sys 0.9.2", +] + +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.0", + "secp256k1-sys 0.10.1", ] [[package]] @@ -512,12 +862,56 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "subtle" version = "2.6.1" @@ -526,18 +920,24 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "template_distribution_sv2" -version = "4.0.2" +version = "4.0.1" dependencies = [ "binary_sv2", ] @@ -551,6 +951,36 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow", +] + [[package]] name = "tracing" version = "0.1.41" @@ -582,17 +1012,46 @@ dependencies = [ "once_cell", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "uint" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "909988d098b2f738727b161a106cfc7cab00c539c2687a8836f8e565976fb53e" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "universal-hash" @@ -640,12 +1099,30 @@ dependencies = [ "windows-link", ] +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "zerocopy" version = "0.8.27" diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 665c9de504..acdbd055fd 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aead" version = "0.5.2" @@ -362,7 +377,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -377,6 +392,21 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.1", +] + [[package]] name = "base58ck" version = "0.1.0" @@ -519,11 +549,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ - "serde_core", + "serde", ] [[package]] @@ -637,9 +667,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chacha20" @@ -735,9 +765,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" dependencies = [ "clap_builder", "clap_derive", @@ -745,9 +775,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" dependencies = [ "anstream", "anstyle", @@ -764,7 +794,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -987,21 +1017,21 @@ dependencies = [ [[package]] name = "csv" -version = "1.4.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", "ryu", - "serde_core", + "serde", ] [[package]] name = "csv-core" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] @@ -1280,7 +1310,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -1344,6 +1374,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "gloo-timers" version = "0.3.0" @@ -1614,14 +1650,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] name = "indexmap" -version = "2.12.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -1656,6 +1692,17 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1909,15 +1956,24 @@ dependencies = [ "bitcoin", ] +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + [[package]] name = "mio" -version = "1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "wasi", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -2012,6 +2068,15 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -2071,7 +2136,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -2143,19 +2208,20 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ "memchr", + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -2163,23 +2229,24 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] name = "pest_meta" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ + "once_cell", "pest", "sha2 0.10.9", ] @@ -2364,7 +2431,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", ] [[package]] @@ -2448,7 +2515,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.10.0", + "bitflags 2.9.4", "serde", "serde_derive", ] @@ -2479,6 +2546,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -2505,7 +2578,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.4.15", @@ -2518,7 +2591,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys 0.11.0", @@ -2618,7 +2691,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -2864,9 +2937,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.107" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2879,7 +2952,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.9.4", "core-foundation", "system-configuration-sys", ] @@ -2916,6 +2989,26 @@ dependencies = [ "binary_sv2 5.0.0", ] +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -2946,30 +3039,33 @@ dependencies = [ [[package]] name = "tokio" -version = "1.48.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ + "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2 0.6.1", "tokio-macros", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -3081,7 +3177,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -3131,7 +3227,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -3181,9 +3277,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-segmentation" @@ -3285,7 +3381,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", "wasm-bindgen-shared", ] @@ -3320,7 +3416,7 @@ checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3684,7 +3780,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] diff --git a/test/integration-tests/Cargo.lock b/test/integration-tests/Cargo.lock index a2e1337ed5..d9135ea85d 100644 --- a/test/integration-tests/Cargo.lock +++ b/test/integration-tests/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli", +] + [[package]] name = "adler2" version = "2.0.1" @@ -179,7 +188,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -188,6 +197,21 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-link 0.2.1", +] + [[package]] name = "base58ck" version = "0.1.0" @@ -337,11 +361,11 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ - "serde_core", + "serde", ] [[package]] @@ -430,9 +454,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "chacha20" @@ -501,9 +525,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.50" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623" +checksum = "f4512b90fa68d3a9932cea5184017c5d200f5921df706d45e853537dea51508f" dependencies = [ "clap_builder", "clap_derive", @@ -511,9 +535,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.50" +version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0" +checksum = "0025e98baa12e766c67ba13ff4695a887a1eba19569aad00a472546795bd6730" dependencies = [ "anstream", "anstyle", @@ -530,7 +554,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -981,7 +1005,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -1032,19 +1056,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.3.4" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", "r-efi", - "wasip2", + "wasi 0.14.7+wasi-0.2.4", ] [[package]] @@ -1057,6 +1081,12 @@ dependencies = [ "polyval", ] +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + [[package]] name = "h2" version = "0.4.12" @@ -1293,14 +1323,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] name = "indexmap" -version = "2.12.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown 0.16.0", @@ -1338,6 +1368,17 @@ dependencies = [ "translator_sv2", ] +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1569,10 +1610,12 @@ dependencies = [ [[package]] name = "minreq" -version = "2.14.1" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05015102dad0f7d61691ca347e9d9d9006685a64aefb3d79eecf62665de2153d" +checksum = "da0c420feb01b9fb5061f8c8f452534361dd783756dcf38ec45191ce55e7a161" dependencies = [ + "log", + "once_cell", "rustls", "rustls-webpki", "serde", @@ -1582,13 +1625,13 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", - "wasi", - "windows-sys 0.61.2", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", ] [[package]] @@ -1664,6 +1707,15 @@ dependencies = [ "itoa", ] +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -1717,7 +1769,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -1783,19 +1835,20 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e7521a040efde50c3ab6bbadafbe15ab6dc042686926be59ac35d74607df4" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ "memchr", + "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187da9a3030dbafabbbfb20cb323b976dc7b7ce91fcd84f2f74d6e31d378e2de" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -1803,23 +1856,24 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b401d98f5757ebe97a26085998d6c0eecec4995cad6ab7fc30ffdf4b052843" +checksum = "db7d01726be8ab66ab32f9df467ae8b1148906685bbe75c82d1e65d7f5b3f841" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] name = "pest_meta" -version = "2.8.3" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72f27a2cfee9f9039c4d86faa5af122a0ac3851441a34865b8a043b46be0065a" +checksum = "7f9f832470494906d1fca5329f8ab5791cc60beb230c74815dff541cbd2b5ca0" dependencies = [ + "once_cell", "pest", "sha2 0.10.9", ] @@ -1989,7 +2043,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.3.3", ] [[package]] @@ -2115,6 +2169,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + [[package]] name = "rustc-hex" version = "2.1.0" @@ -2251,7 +2311,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -2471,9 +2531,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.107" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -2545,6 +2605,26 @@ dependencies = [ "binary_sv2 5.0.0", ] +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "thread_local" version = "1.1.9" @@ -2565,31 +2645,34 @@ dependencies = [ [[package]] name = "tokio" -version = "1.48.0" +version = "1.47.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" dependencies = [ + "backtrace", "bytes", + "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", "tracing", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -2701,7 +2784,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -2751,7 +2834,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] @@ -2800,9 +2883,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-segmentation" @@ -2865,6 +2948,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + [[package]] name = "wasip2" version = "1.0.1+wasi-0.2.4" @@ -2939,6 +3031,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" @@ -3138,7 +3239,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.107", + "syn 2.0.106", ] [[package]] diff --git a/utils/Cargo.lock b/utils/Cargo.lock index 822bdd2d2c..b21d533eb1 100644 --- a/utils/Cargo.lock +++ b/utils/Cargo.lock @@ -94,9 +94,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "cipher" @@ -201,21 +201,21 @@ dependencies = [ [[package]] name = "csv" -version = "1.4.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", "ryu", - "serde_core", + "serde", ] [[package]] name = "csv-core" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] @@ -599,9 +599,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.107" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -635,9 +635,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.20" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-width" From 554403ecc1308e4d76ddbc8a2824bfdcf0e58347 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 21:01:38 -0400 Subject: [PATCH 20/39] fix: no unecessary cloning and extra code block --- protocols/v2/channels-sv2/src/client/extended.rs | 2 +- protocols/v2/channels-sv2/src/client/standard.rs | 2 +- protocols/v2/channels-sv2/src/server/extended.rs | 10 ++-------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 715d8d5cdd..aa8abca3f3 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -97,7 +97,7 @@ where ) -> Self { Self { channel_id, - user_identity: user_identity.clone(), + user_identity: user_identity, extranonce_prefix, rollable_extranonce_size, target, diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 68a0f7fd92..111e7eaed0 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -73,7 +73,7 @@ where ) -> Self { Self { channel_id, - user_identity: user_identity.clone(), + user_identity: user_identity, extranonce_prefix, target, nominal_hashrate, diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 56f5ab1469..ea04ca8ec4 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -245,7 +245,7 @@ where Ok(Self { channel_id, - user_identity: user_identity.clone(), + user_identity: user_identity, extranonce_prefix, rollable_extranonce_size, requested_max_target: max_target, @@ -259,13 +259,7 @@ where phantom: PhantomData, }) } -} - -impl<'a, J, P> ExtendedChannel<'a, J, P> -where - J: JobStore>, - P: Persistence, -{ + /// Returns the unique channel ID for this channel. pub fn get_channel_id(&self) -> u32 { self.channel_id From ff65f3e6fb6a497c473b0cc6e3da93ce5bce5a0e Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 21:05:44 -0400 Subject: [PATCH 21/39] refactor(channels-sv2): Revise persistence trait and implementation - Replace `Persistence` trait with `PersistenceHandler` - Introduce `Persistence` enum to handle enabled/disabled states - Remove `NoPersistence` struct in favor of enum variant - Simplify persistence handling with more flexible design - Implement default trait for new `Persistence` enum --- protocols/v2/channels-sv2/src/persistence.rs | 81 +++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index cf5b1d6695..36ae75e9b9 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -60,17 +60,11 @@ pub enum ShareAccountingEvent { }, } -/// Trait for persisting share accounting events. +/// Trait for handling persistence of share accounting events. /// -/// Implementations of this trait handle the persistence of share accounting events, +/// Implementations of this trait handle the actual persistence operations, /// ensuring that persistence operations are non-blocking and can handle failures internally. -pub trait Persistence { - /// The type of channel sender used to send events for persistence. - /// - /// This is typically something like `tokio::sync::mpsc::UnboundedSender` - /// or `async_channel::Sender`. - type Sender: Clone + Send + 'static; - +pub trait PersistenceHandler { /// Sends a share accounting event for persistence. /// /// This method MUST be non-blocking and infallible from the caller's perspective. @@ -87,45 +81,60 @@ pub trait Persistence { /// /// Implementations can use this for cleanup operations, but should not block. fn shutdown(&self) {} - - fn new(sender: Self::Sender) -> Self; } -/// A no-op persistence implementation for when persistence is disabled. -/// -/// This allows ShareAccounting to always call persistence methods without -/// needing conditional compilation throughout the hot path code. +/// Main persistence abstraction that handles enabled/disabled states. #[derive(Debug, Clone)] -pub struct NoPersistence; +pub enum Persistence { + /// Persistence is enabled with the given handler + Enabled(T), + /// Persistence is disabled (no-op) + Disabled, +} -impl NoPersistence { - /// Creates a new no-op persistence handler. - pub fn new() -> Self { - Self +impl Persistence { + /// Creates persistence state from an Option. + /// Some(persistence) becomes Enabled, None becomes Disabled. + pub fn new(persistence: Option) -> Self { + match persistence { + Some(p) => Self::Enabled(p), + None => Self::Disabled, + } } - - /// No-op method for share accounting events. - pub fn persist_event(&self, _event: ShareAccountingEvent) {} - - /// No-op flush method. - pub fn flush(&self) {} - - /// No-op shutdown method. - pub fn shutdown(&self) {} } -impl Default for NoPersistence { +impl Default for Persistence { + /// Default persistence state is Disabled (no persistence). fn default() -> Self { - Self::new() + Self::Disabled } } -impl Persistence for NoPersistence { - type Sender = (); +impl PersistenceHandler for Persistence { + fn persist_event(&self, event: ShareAccountingEvent) { + match self { + Self::Enabled(persistence) => persistence.persist_event(event), + Self::Disabled => { + // No-op - persistence is disabled + } + } + } - fn persist_event(&self, _event: ShareAccountingEvent) {} + fn flush(&self) { + match self { + Self::Enabled(persistence) => persistence.flush(), + Self::Disabled => { + // No-op - persistence is disabled + } + } + } - fn new(_sender: Self::Sender) -> Self { - Self + fn shutdown(&self) { + match self { + Self::Enabled(persistence) => persistence.shutdown(), + Self::Disabled => { + // No-op - persistence is disabled + } + } } } From 6a2827a7516cfe4350d1e58727958e4d2a0557e2 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 21:43:00 -0400 Subject: [PATCH 22/39] refactor(channels-sv2): Update persistence trait and implementation - Rename `Persistence` trait to `PersistenceHandler` in multiple protocol and role files - Update type references from `Persistence` to `PersistenceHandler` across client and server modules - Modify channel constructors to use `Persistence::default()` instead of `NoPersistence::new()` - Ensure consistent trait naming and implementation across channel management components - Improve type consistency and clarity in persistence-related code --- .../v2/channels-sv2/src/client/extended.rs | 4 +- .../src/client/share_accounting.rs | 4 +- .../v2/channels-sv2/src/client/standard.rs | 4 +- .../v2/channels-sv2/src/server/extended.rs | 48 +++++++++++-------- .../src/server/share_accounting.rs | 4 +- .../v2/channels-sv2/src/server/standard.rs | 4 +- .../downstream_message_handler.rs | 6 +-- .../jd-client/src/lib/channel_manager/mod.rs | 21 ++++++-- .../upstream_message_handler.rs | 6 +-- roles/jd-client/src/lib/downstream/mod.rs | 18 ++++--- roles/pool/src/lib/channel_manager/mod.rs | 46 +++--------------- roles/pool/src/lib/share_persistence/mod.rs | 31 ++++++------ .../sv2/channel_manager/channel_manager.rs | 4 +- .../src/lib/sv2/channel_manager/data.rs | 23 +++++++-- .../sv2/channel_manager/message_handler.rs | 8 ++-- 15 files changed, 117 insertions(+), 114 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index aa8abca3f3..d529f39745 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -13,7 +13,7 @@ use crate::{ share_accounting::{ShareAccounting, ShareValidationError, ShareValidationResult}, }, merkle_root::merkle_root_from_path, - persistence::{NoPersistence, Persistence}, + persistence::{NoPersistence, PersistenceHandler}, target::{bytes_to_hex, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; @@ -81,7 +81,7 @@ pub struct ExtendedChannel<'a, P> { impl<'a, P> ExtendedChannel<'a, P> where - P: Persistence, + P: PersistenceHandler, { /// Constructs a new [`ExtendedChannel`]. #[allow(clippy::too_many_arguments)] diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 20fe93d194..42c2e990bd 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -5,7 +5,7 @@ //! are intended for use in Mining Clients. use super::HashSet; -use crate::persistence::{Persistence, ShareAccountingEvent}; +use crate::persistence::{PersistenceHandler, ShareAccountingEvent}; use bitcoin::hashes::sha256d::Hash; /// The outcome of share validation, as seen by a Mining Client. @@ -62,7 +62,7 @@ pub struct ShareAccounting

{ impl

ShareAccounting

where - P: Persistence, + P: PersistenceHandler, { /// Creates a new [`ShareAccounting`] instance, initializing all statistics to zero. /// diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 111e7eaed0..66c7fd5dc5 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -13,7 +13,7 @@ use crate::{ share_accounting::{ShareAccounting, ShareValidationError, ShareValidationResult}, }, merkle_root::merkle_root_from_path, - persistence::{NoPersistence, Persistence}, + persistence::{NoPersistence, PersistenceHandler}, target::{bytes_to_hex, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; @@ -60,7 +60,7 @@ pub struct StandardChannel<'a, P> { impl<'a, P> StandardChannel<'a, P> where - P: Persistence, + P: PersistenceHandler, { /// Creates a new [`StandardChannel`] instance with provided channel parameters. pub fn new( diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index ea04ca8ec4..f107d415b8 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -42,7 +42,7 @@ use crate::{ chain_tip::ChainTip, merkle_root::merkle_root_from_path, - persistence::Persistence, + persistence::PersistenceHandler, server::{ error::ExtendedChannelError, jobs::{extended::ExtendedJob, factory::JobFactory, job_store::JobStore, JobOrigin}, @@ -108,7 +108,7 @@ where impl<'a, J, P> ExtendedChannel<'a, J, P> where J: JobStore>, - P: Persistence, + P: PersistenceHandler, { /// Constructor of `ExtendedChannel` for a Sv2 Pool Server. /// Not meant for usage on a Sv2 Job Declaration Client. @@ -755,7 +755,7 @@ where mod tests { use crate::{ chain_tip::ChainTip, - persistence::NoPersistence, + persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, server::{ error::ExtendedChannelError, extended::ExtendedChannel, @@ -763,6 +763,16 @@ mod tests { share_accounting::{ShareValidationError, ShareValidationResult}, }, }; + + /// Unit-like type for persistence in tests + #[derive(Debug, Clone)] + struct TestPersistence; + + impl PersistenceHandler for TestPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op for tests + } + } use binary_sv2::Sv2Option; use bitcoin::{transaction::TxOut, Amount, ScriptBuf, Target}; use mining_sv2::{NewExtendedMiningJob, SubmitSharesExtended}; @@ -791,7 +801,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -804,7 +814,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -943,7 +953,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -956,7 +966,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -1064,7 +1074,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1077,7 +1087,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -1143,7 +1153,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1156,7 +1166,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -1253,7 +1263,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1266,7 +1276,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -1366,7 +1376,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1379,7 +1389,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -1494,7 +1504,7 @@ mod tests { let max_target = Target::from_le_bytes([0xff; 32]); // Create a channel with initial hashrate - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix, @@ -1507,7 +1517,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); @@ -1582,7 +1592,7 @@ mod tests { let share_batch_size = 100; let job_store = DefaultJobStore::new(); - let mut channel = ExtendedChannel::, NoPersistence>::new( + let mut channel = ExtendedChannel::, Persistence>::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -1595,7 +1605,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::default(), ) .unwrap(); diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index faf3eae2ff..dab58d5634 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -18,7 +18,7 @@ //! Intended for use within mining server implementations that process SV2 share submissions and //! issue `SubmitShares.Success` messages. Not intended for use by mining clients. -use crate::persistence::{Persistence, ShareAccountingEvent}; +use crate::persistence::{PersistenceHandler, ShareAccountingEvent}; use bitcoin::hashes::sha256d::Hash; use std::collections::HashSet; @@ -94,7 +94,7 @@ pub struct ShareAccounting

{ impl

ShareAccounting

where - P: Persistence, + P: PersistenceHandler, { /// Constructs a new `ShareAccounting` instance for a channel. /// diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index e576ae7841..1a314b19e3 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -35,7 +35,7 @@ //! - Job lifecycle and share accounting are managed on a per-channel basis. use crate::{ chain_tip::ChainTip, - persistence::Persistence, + persistence::PersistenceHandler, server::{ error::StandardChannelError, jobs::{ @@ -102,7 +102,7 @@ where impl<'a, J, P> StandardChannel<'a, J, P> where J: JobStore>, - P: Persistence, + P: PersistenceHandler, { /// Constructor of `StandardChannel` for a Sv2 Pool Server. /// Not meant for usage on a Sv2 Job Declaration Client. diff --git a/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs b/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs index 962d612900..75c473b1a8 100644 --- a/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs +++ b/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs @@ -6,7 +6,7 @@ use stratum_apps::stratum_core::{ channels_sv2::{ client, outputs::deserialize_outputs, - persistence::NoPersistence, + persistence::Persistence, server::{ error::{ExtendedChannelError, StandardChannelError}, extended::ExtendedChannel, @@ -349,7 +349,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { job_store, channel_manager_data.pool_tag_string.clone(), self.miner_tag_string.clone(), - NoPersistence::new(), + Persistence::default(), ) { Ok(channel) => channel, Err(e) => { @@ -588,7 +588,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { job_store, channel_manager_data.pool_tag_string.clone(), self.miner_tag_string.clone(), - NoPersistence::new(), + Persistence::default(), ) { Ok(c) => c, Err(e) => { diff --git a/roles/jd-client/src/lib/channel_manager/mod.rs b/roles/jd-client/src/lib/channel_manager/mod.rs index afb314cb29..e56c761f16 100644 --- a/roles/jd-client/src/lib/channel_manager/mod.rs +++ b/roles/jd-client/src/lib/channel_manager/mod.rs @@ -16,7 +16,7 @@ use stratum_apps::{ bitcoin::Target, channels_sv2::{ client::extended::ExtendedChannel, - persistence::NoPersistence, + persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, server::{ jobs::{ extended::ExtendedJob, factory::JobFactory, job_store::DefaultJobStore, @@ -66,6 +66,19 @@ mod upstream_message_handler; pub const JDC_SEARCH_SPACE_BYTES: usize = 4; +/// Unit-like type for persistence when disabled +#[derive(Debug, Clone)] +pub(crate) struct NoOpPersistence; + +impl PersistenceHandler for NoOpPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op - this should never be called when using Persistence::Disabled + } +} + +/// Type alias for disabled persistence used in JD client +pub(crate) type DisabledPersistence = Persistence; + /// A `DeclaredJob` encapsulates all the relevant data associated with a single /// job declaration, including its template, optional messages, coinbase output, /// and transaction list. @@ -136,7 +149,7 @@ pub struct ChannelManagerData { // Maps channel ID → downstream ID. channel_id_to_downstream_id: HashMap, // The active upstream extended channel (client-side instance), if any. - upstream_channel: Option>, + upstream_channel: Option>, // Optional "pool tag" string, identifying the pool. pool_tag_string: Option, // List of pending downstream connection requests, @@ -923,7 +936,7 @@ impl ChannelManager { channel_state: &mut stratum_apps::stratum_core::channels_sv2::server::extended::ExtendedChannel< 'static, DefaultJobStore>, - NoPersistence, + Persistence, >, vardiff_state: &mut VardiffState, updates: &mut Vec, @@ -972,7 +985,7 @@ impl ChannelManager { channel: &mut StandardChannel< 'static, DefaultJobStore>, - NoPersistence, + Persistence, >, vardiff_state: &mut VardiffState, updates: &mut Vec, diff --git a/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs b/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs index 78b08b62d6..6741fefaaa 100644 --- a/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs +++ b/roles/jd-client/src/lib/channel_manager/upstream_message_handler.rs @@ -4,7 +4,7 @@ use stratum_apps::stratum_core::{ bitcoin::Target, channels_sv2::{ client::extended::ExtendedChannel, outputs::deserialize_outputs, - persistence::NoPersistence, server::jobs::factory::JobFactory, + server::jobs::factory::JobFactory, }, handlers_sv2::{HandleMiningMessagesFromServerAsync, SupportedChannelTypes}, mining_sv2::*, @@ -15,7 +15,7 @@ use tracing::{debug, error, info, warn}; use crate::{ channel_manager::{ - downstream_message_handler::RouteMessageTo, ChannelManager, DeclaredJob, + downstream_message_handler::RouteMessageTo, ChannelManager, DeclaredJob, Persistence, JDC_SEARCH_SPACE_BYTES, }, error::{ChannelSv2Error, JDCError}, @@ -144,7 +144,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { hashrate, true, msg.extranonce_size, - NoPersistence::new(), + Persistence::default(), ); if let Some(ref mut prevhash) = data.last_new_prev_hash { diff --git a/roles/jd-client/src/lib/downstream/mod.rs b/roles/jd-client/src/lib/downstream/mod.rs index b51ed5bc71..09d5ceac02 100644 --- a/roles/jd-client/src/lib/downstream/mod.rs +++ b/roles/jd-client/src/lib/downstream/mod.rs @@ -5,14 +5,11 @@ use stratum_apps::{ custom_mutex::Mutex, network_helpers::noise_stream::NoiseTcpStream, stratum_core::{ - channels_sv2::{ - persistence::NoPersistence, - server::{ - extended::ExtendedChannel, - group::GroupChannel, - jobs::{extended::ExtendedJob, job_store::DefaultJobStore, standard::StandardJob}, - standard::StandardChannel, - }, + channels_sv2::server::{ + extended::ExtendedChannel, + group::GroupChannel, + jobs::{extended::ExtendedJob, job_store::DefaultJobStore, standard::StandardJob}, + standard::StandardChannel, }, common_messages_sv2::MESSAGE_TYPE_SETUP_CONNECTION, handlers_sv2::HandleCommonMessagesFromClientAsync, @@ -24,6 +21,7 @@ use tokio::sync::broadcast; use tracing::{debug, error, warn}; use crate::{ + channel_manager::DisabledPersistence, error::JDCError, status::{handle_error, Status, StatusSender}, task_manager::TaskManager, @@ -47,11 +45,11 @@ pub struct DownstreamData { pub group_channels: Option>>>, pub extended_channels: HashMap< u32, - ExtendedChannel<'static, DefaultJobStore>, NoPersistence>, + ExtendedChannel<'static, DefaultJobStore>, DisabledPersistence>, >, pub standard_channels: HashMap< u32, - StandardChannel<'static, DefaultJobStore>, NoPersistence>, + StandardChannel<'static, DefaultJobStore>, DisabledPersistence>, >, } diff --git a/roles/pool/src/lib/channel_manager/mod.rs b/roles/pool/src/lib/channel_manager/mod.rs index f9f0183592..cb7028d2a3 100644 --- a/roles/pool/src/lib/channel_manager/mod.rs +++ b/roles/pool/src/lib/channel_manager/mod.rs @@ -13,7 +13,7 @@ use stratum_apps::{ network_helpers::noise_stream::NoiseTcpStream, stratum_core::{ channels_sv2::{ - persistence::{NoPersistence, Persistence, ShareAccountingEvent}, + persistence::Persistence, server::{ extended::ExtendedChannel, jobs::{extended::ExtendedJob, job_store::DefaultJobStore, standard::StandardJob}, @@ -46,42 +46,8 @@ use crate::{ mod mining_message_handler; mod template_distribution_message_handler; -/// Enum wrapper for different persistence implementations used by the pool. -/// Allows runtime selection between file-based persistence and no-op persistence. -#[derive(Clone, Debug)] -pub enum PoolPersistence { - File(ShareFilePersistence), - None(NoPersistence), -} - -impl Persistence for PoolPersistence { - type Sender = async_channel::Sender; - - fn persist_event(&self, event: ShareAccountingEvent) { - match self { - PoolPersistence::File(p) => p.persist_event(event), - PoolPersistence::None(p) => p.persist_event(event), - } - } - - fn flush(&self) { - match self { - PoolPersistence::File(p) => p.flush(), - PoolPersistence::None(p) => p.flush(), - } - } - - fn shutdown(&self) { - match self { - PoolPersistence::File(p) => p.shutdown(), - PoolPersistence::None(p) => p.shutdown(), - } - } - - fn new(sender: Self::Sender) -> Self { - PoolPersistence::File(ShareFilePersistence::new(sender)) - } -} +/// Type alias for the pool's persistence implementation. +pub type PoolPersistence = Persistence; const POOL_ALLOCATION_BYTES: usize = 4; const CLIENT_SEARCH_SPACE_BYTES: usize = 8; @@ -205,10 +171,10 @@ impl ChannelManager { } }); - PoolPersistence::File(ShareFilePersistence::new(sender)) + Persistence::new(Some(ShareFilePersistence::new(sender))) } else { - info!("Share persistence disabled - using NoPersistence"); - PoolPersistence::None(NoPersistence::new()) + info!("Share persistence disabled"); + Persistence::new(None) }; let channel_manager = ChannelManager { diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index b3e75e94a5..548f0fe047 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -1,4 +1,6 @@ -use stratum_apps::stratum_core::channels_sv2::persistence::{Persistence, ShareAccountingEvent}; +use stratum_apps::stratum_core::channels_sv2::persistence::{ + PersistenceHandler, ShareAccountingEvent, +}; use tokio::io::AsyncWriteExt; use tracing::error; @@ -123,25 +125,22 @@ impl ShareFileHandler { } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct ShareFilePersistence { - sender: Option>, + sender: async_channel::Sender, } -impl Persistence for ShareFilePersistence { - type Sender = async_channel::Sender; - - fn persist_event(&self, event: ShareAccountingEvent) { - if let Some(sender) = &self.sender { - let _ = sender - .try_send(event) - .map_err(|e| error!(target = "share_file_persistence", "{}", e)); - } +impl ShareFilePersistence { + pub fn new(sender: async_channel::Sender) -> Self { + Self { sender } } +} - fn new(sender: Self::Sender) -> Self { - Self { - sender: Some(sender), - } +impl PersistenceHandler for ShareFilePersistence { + fn persist_event(&self, event: ShareAccountingEvent) { + let _ = self + .sender + .try_send(event) + .map_err(|e| error!(target = "share_file_persistence", "{}", e)); } } diff --git a/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs b/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs index bbb871ef1e..af4e9d1edb 100644 --- a/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs +++ b/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs @@ -16,7 +16,7 @@ use std::sync::{Arc, RwLock}; use stratum_apps::{ custom_mutex::Mutex, stratum_core::{ - channels_sv2::{client::extended::ExtendedChannel, persistence::NoPersistence}, + channels_sv2::{client::extended::ExtendedChannel, persistence::Persistence}, framing_sv2::framing::Frame, handlers_sv2::HandleMiningMessagesFromServerAsync, mining_sv2::OpenExtendedMiningChannelSuccess, @@ -319,7 +319,7 @@ impl ChannelManager { hashrate, true, new_extranonce_size as u16, - NoPersistence::new(), + Persistence::default(), ); self.channel_manager_data.super_safe_lock(|c| { c.extended_channels.insert( diff --git a/roles/translator/src/lib/sv2/channel_manager/data.rs b/roles/translator/src/lib/sv2/channel_manager/data.rs index d20f9f5900..b544968cb6 100644 --- a/roles/translator/src/lib/sv2/channel_manager/data.rs +++ b/roles/translator/src/lib/sv2/channel_manager/data.rs @@ -5,11 +5,27 @@ use std::{ use stratum_apps::{ custom_mutex::Mutex, stratum_core::{ - channels_sv2::{client::extended::ExtendedChannel, persistence::NoPersistence}, + channels_sv2::{ + client::extended::ExtendedChannel, + persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, + }, mining_sv2::ExtendedExtranonce, }, }; +/// Unit-like type for persistence when disabled in translator +#[derive(Debug, Clone)] +pub struct NoOpPersistence; + +impl PersistenceHandler for NoOpPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op - this should never be called when using Persistence::Disabled + } +} + +/// Type alias for disabled persistence used in translator +pub type DisabledPersistence = Persistence; + /// Defines the operational mode for channel management. /// /// The channel manager can operate in two different modes that affect how @@ -39,9 +55,10 @@ pub struct ChannelManagerData { /// downstream_extranonce_len) pub pending_channels: HashMap, /// Map of active extended channels by channel ID - pub extended_channels: HashMap>>>, + pub extended_channels: HashMap>>>, /// The upstream extended channel used in aggregated mode - pub upstream_extended_channel: Option>>>, + pub upstream_extended_channel: + Option>>>, /// Extranonce prefix factory for allocating unique prefixes in aggregated mode pub extranonce_prefix_factory: Option>>, /// Current operational mode diff --git a/roles/translator/src/lib/sv2/channel_manager/message_handler.rs b/roles/translator/src/lib/sv2/channel_manager/message_handler.rs index 469ae51549..47377c71af 100644 --- a/roles/translator/src/lib/sv2/channel_manager/message_handler.rs +++ b/roles/translator/src/lib/sv2/channel_manager/message_handler.rs @@ -9,7 +9,7 @@ use stratum_apps::{ custom_mutex::Mutex, stratum_core::{ bitcoin::Target, - channels_sv2::{client::extended::ExtendedChannel, persistence::NoPersistence}, + channels_sv2::{client::extended::ExtendedChannel, persistence::Persistence}, handlers_sv2::{HandleMiningMessagesFromServerAsync, SupportedChannelTypes}, mining_sv2::{ CloseChannel, ExtendedExtranonce, Extranonce, NewExtendedMiningJob, NewMiningJob, @@ -86,7 +86,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { nominal_hashrate, version_rolling, m.extranonce_size, - NoPersistence::new(), + Persistence::default(), ); // If we are in aggregated mode, we need to create a new extranonce prefix and @@ -140,7 +140,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { nominal_hashrate, true, new_extranonce_size, - NoPersistence::new(), + Persistence::default(), ); channel_manager_data.extended_channels.insert( m.channel_id, @@ -196,7 +196,7 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager { nominal_hashrate, true, downstream_extranonce_len as u16, - NoPersistence::new(), + Persistence::default(), ); channel_manager_data.extended_channels.insert( m.channel_id, From 1f175e6beb17ed67ede1d74c7dae07399c3af1ff Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 21:53:57 -0400 Subject: [PATCH 23/39] docs(pool-config): Add share persistence configuration example - Add optional share_persistence_file_path configuration in pool config examples - Include comments explaining the purpose and usage of share persistence logging --- .../pool/config-examples/pool-config-hosted-tp-example.toml | 6 ++++++ .../pool/config-examples/pool-config-local-tp-example.toml | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/roles/pool/config-examples/pool-config-hosted-tp-example.toml b/roles/pool/config-examples/pool-config-hosted-tp-example.toml index cb9747e9fb..1a2ac991aa 100644 --- a/roles/pool/config-examples/pool-config-hosted-tp-example.toml +++ b/roles/pool/config-examples/pool-config-hosted-tp-example.toml @@ -22,6 +22,12 @@ pool_signature = "Stratum V2 SRI Pool" # The CLI option --log-file (or -f) will override this setting if provided. # log_file = "./pool.log" +# Share persistence file path (optional) +# When enabled, all share accounting events (accepted shares, difficulty updates, etc.) +# will be logged to this file for auditing and analysis purposes. +# Comment out or remove this line to disable share persistence. +# share_persistence_file_path = "./shares.txt" + # Template Provider config # Local TP (this is pointing to localhost so you must run a TP locally for this configuration to work) #tp_address = "127.0.0.1:8442" diff --git a/roles/pool/config-examples/pool-config-local-tp-example.toml b/roles/pool/config-examples/pool-config-local-tp-example.toml index 000e3e0fd2..ae4548cb32 100644 --- a/roles/pool/config-examples/pool-config-local-tp-example.toml +++ b/roles/pool/config-examples/pool-config-local-tp-example.toml @@ -22,6 +22,11 @@ pool_signature = "Stratum V2 SRI Pool" # The CLI option --log-file (or -f) will override this setting if provided. # log_file = "./pool.log" +# Share persistence file path (optional) +# When enabled, all share accounting events (accepted shares, difficulty updates, etc.) +# will be logged to this file for auditing and analysis purposes. +# Comment out or remove this line to disable share persistence. +# share_persistence_file_path = "./shares.txt" # Template Provider config # Local TP (this is pointing to localhost so you must run a TP locally for this configuration to work) From 3b97a8566ea48b2de93d4cdd62b03e1cd945c996 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 22:18:37 -0400 Subject: [PATCH 24/39] refactor(channels-sv2): Remove redundant user_identity assignment --- protocols/v2/channels-sv2/src/client/extended.rs | 2 +- protocols/v2/channels-sv2/src/client/standard.rs | 2 +- protocols/v2/channels-sv2/src/server/extended.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index d529f39745..67d1ac5967 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -97,7 +97,7 @@ where ) -> Self { Self { channel_id, - user_identity: user_identity, + user_identity, extranonce_prefix, rollable_extranonce_size, target, diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 66c7fd5dc5..54db83ab25 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -73,7 +73,7 @@ where ) -> Self { Self { channel_id, - user_identity: user_identity, + user_identity, extranonce_prefix, target, nominal_hashrate, diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index f107d415b8..509c932c1f 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -245,7 +245,7 @@ where Ok(Self { channel_id, - user_identity: user_identity, + user_identity, extranonce_prefix, rollable_extranonce_size, requested_max_target: max_target, From d90846e3324088ad507f31c73a1bf4b164d24640 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 22:33:44 -0400 Subject: [PATCH 25/39] refactor(channels-sv2): Update persistence handling in test modules - Replace `NoPersistence` with generic `Persistence` in test cases - Add `TestPersistence` struct implementing `PersistenceHandler` trait --- .../v2/channels-sv2/src/client/extended.rs | 32 ++++++++++++------- .../v2/channels-sv2/src/client/standard.rs | 32 ++++++++++++------- .../v2/channels-sv2/src/server/standard.rs | 30 ++++++++++------- 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 67d1ac5967..29cbb279be 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -582,7 +582,7 @@ mod tests { extended::ExtendedChannel, share_accounting::{ShareValidationError, ShareValidationResult}, }, - persistence::NoPersistence, + persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, }; use binary_sv2::Sv2Option; use bitcoin::Target; @@ -591,6 +591,16 @@ mod tests { }; use std::convert::TryInto; + /// Unit-like type for persistence in tests + #[derive(Debug, Clone)] + struct TestPersistence; + + impl PersistenceHandler for TestPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op for tests + } + } + #[test] fn test_future_job_activation_flow() { let channel_id = 1; @@ -605,7 +615,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 4u16; - let mut channel = ExtendedChannel::::new( + let mut channel = ExtendedChannel::>::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -613,7 +623,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewExtendedMiningJob { @@ -688,7 +698,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 4u16; - let mut channel = ExtendedChannel::::new( + let mut channel = ExtendedChannel::>::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -696,7 +706,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, - NoPersistence::new(), + Persistence::default(), ); let ntime: u32 = 1746839905; @@ -762,7 +772,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 8u16; - let mut channel = ExtendedChannel::::new( + let mut channel = ExtendedChannel::>::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -770,7 +780,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewExtendedMiningJob { @@ -855,7 +865,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 8u16; - let mut channel = ExtendedChannel::::new( + let mut channel = ExtendedChannel::>::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -863,7 +873,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewExtendedMiningJob { @@ -951,7 +961,7 @@ mod tests { let version_rolling = true; let rollable_extranonce_size = 8u16; - let mut channel = ExtendedChannel::::new( + let mut channel = ExtendedChannel::>::new( channel_id, user_identity, extranonce_prefix.clone(), @@ -959,7 +969,7 @@ mod tests { nominal_hashrate, version_rolling, rollable_extranonce_size, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewExtendedMiningJob { diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 54db83ab25..861ec9d348 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -380,8 +380,18 @@ mod tests { share_accounting::{ShareValidationError, ShareValidationResult}, standard::StandardChannel, }, - persistence::NoPersistence, + persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, }; + + /// Unit-like type for persistence in tests + #[derive(Debug, Clone)] + struct TestPersistence; + + impl PersistenceHandler for TestPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op for tests + } + } use binary_sv2::Sv2Option; use bitcoin::Target; use mining_sv2::{NewMiningJob, SetNewPrevHash as SetNewPrevHashMp, SubmitSharesStandard}; @@ -398,13 +408,13 @@ mod tests { let target = Target::from_le_bytes([0xff; 32]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::::new( + let mut channel = StandardChannel::>::new( channel_id, user_identity, extranonce_prefix, target, nominal_hashrate, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewMiningJob { @@ -459,13 +469,13 @@ mod tests { let target = Target::from_le_bytes([0xff; 32]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::::new( + let mut channel = StandardChannel::>::new( channel_id, user_identity, extranonce_prefix, target, nominal_hashrate, - NoPersistence::new(), + Persistence::default(), ); let ntime: u32 = 1746839905; @@ -508,13 +518,13 @@ mod tests { let target = Target::from_le_bytes([0xff; 32]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::::new( + let mut channel = StandardChannel::>::new( channel_id, user_identity, extranonce_prefix, target, nominal_hashrate, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewMiningJob { @@ -582,13 +592,13 @@ mod tests { ]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::::new( + let mut channel = StandardChannel::>::new( channel_id, user_identity, extranonce_prefix, target, nominal_hashrate, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewMiningJob { @@ -659,13 +669,13 @@ mod tests { ]); let nominal_hashrate = 1.0; - let mut channel = StandardChannel::::new( + let mut channel = StandardChannel::>::new( channel_id, user_identity, extranonce_prefix, target, nominal_hashrate, - NoPersistence::new(), + Persistence::default(), ); let future_job = NewMiningJob { diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 1a314b19e3..7006b0da85 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -686,15 +686,23 @@ where #[cfg(test)] mod tests { use crate::{ - chain_tip::ChainTip, - persistence::NoPersistence, - server::{ + chain_tip::ChainTip, persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, server::{ error::StandardChannelError, jobs::{job_store::DefaultJobStore, standard::StandardJob}, share_accounting::{ShareValidationError, ShareValidationResult}, standard::StandardChannel, - }, + } }; + + /// Unit-like type for persistence in tests + #[derive(Debug, Clone)] + struct TestPersistence; + + impl PersistenceHandler for TestPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op for tests + } + } use binary_sv2::Sv2Option; use bitcoin::{transaction::TxOut, Amount, ScriptBuf, Target}; use mining_sv2::{NewMiningJob, SubmitSharesStandard}; @@ -734,7 +742,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); @@ -863,7 +871,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); @@ -968,7 +976,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); @@ -1075,7 +1083,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); @@ -1185,7 +1193,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); @@ -1289,7 +1297,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); @@ -1377,7 +1385,7 @@ mod tests { job_store, None, None, - NoPersistence::new(), + Persistence::Enabled(TestPersistence), ) .unwrap(); From 1af1f83333be91830a1b3eb0555edc22e361dfb6 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 22:37:15 -0400 Subject: [PATCH 26/39] fmt: fix formatting --- protocols/v2/channels-sv2/src/server/extended.rs | 2 +- protocols/v2/channels-sv2/src/server/standard.rs | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 509c932c1f..1b94f316c4 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -259,7 +259,7 @@ where phantom: PhantomData, }) } - + /// Returns the unique channel ID for this channel. pub fn get_channel_id(&self) -> u32 { self.channel_id diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 7006b0da85..1d7439df57 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -228,7 +228,7 @@ where Ok(Self { channel_id, - user_identity: user_identity.clone(), + user_identity, extranonce_prefix, requested_max_target, target, @@ -686,12 +686,14 @@ where #[cfg(test)] mod tests { use crate::{ - chain_tip::ChainTip, persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, server::{ + chain_tip::ChainTip, + persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, + server::{ error::StandardChannelError, jobs::{job_store::DefaultJobStore, standard::StandardJob}, share_accounting::{ShareValidationError, ShareValidationResult}, standard::StandardChannel, - } + }, }; /// Unit-like type for persistence in tests From 6e93d7d36695a9b3df251c31f3b608bc422ac32b Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Tue, 21 Oct 2025 22:50:06 -0400 Subject: [PATCH 27/39] revert: bad fmt --- roles/jd-server/src/lib/config.rs | 9 +++++---- .../src/lib/sv2/channel_manager/channel_manager.rs | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/roles/jd-server/src/lib/config.rs b/roles/jd-server/src/lib/config.rs index f59310df42..ee01a046ec 100644 --- a/roles/jd-server/src/lib/config.rs +++ b/roles/jd-server/src/lib/config.rs @@ -181,7 +181,7 @@ mod tests { use crate::config::JobDeclaratorServerConfig; - const COINBASE_CONFIG_TEMPLATE: &str = r#" + const COINBASE_CONFIG_TEMPLATE: &'static str = r#" full_template_mode_required = true authority_public_key = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72" authority_secret_key = "mkDLTBBRxdBv998612qipDYoTK3YUrqLe8uWw7gu3iXbSrn2n" @@ -198,8 +198,9 @@ mod tests { unit = "secs" value = 1 "#; - const TEST_PK_HEX: &str = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075"; - const TEST_INVALID_PK_HEX: &str = + const TEST_PK_HEX: &'static str = + "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7554075"; + const TEST_INVALID_PK_HEX: &'static str = "036adc3bdf21e6f9a0f0fb0066bf517e5b7909ed1563d6958a10993849a7ffffff"; fn load_config(path: &str) -> JobDeclaratorServerConfig { @@ -275,7 +276,7 @@ mod tests { #[test] fn test_get_invalid_miniscript_in_coinbase_reward_script() { - let error = load_coinbase_config_str("\"INVALID\"") + let error = load_coinbase_config_str(&format!("\"INVALID\"")) .expect_err("Cannot parse config with bad miniscript"); assert_eq!( error.to_string(), diff --git a/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs b/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs index af4e9d1edb..1982a7ee76 100644 --- a/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs +++ b/roles/translator/src/lib/sv2/channel_manager/channel_manager.rs @@ -787,7 +787,7 @@ mod tests { let update_channel = UpdateChannel { channel_id: 1, nominal_hash_rate: 2000.0, - maximum_target: [0xFFu8; 32].into(), + maximum_target: [0xFFu8; 32].try_into().unwrap(), }; // Test that the message can be handled From d3ab6fea2afc489ad234e9551a85ac3775ac0b1b Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 09:20:19 -0400 Subject: [PATCH 28/39] refactor(share-persistence): Genericize SharePersistence - Remove `status_tx` parameter from `ShareFileHandler::new()` method - Remove status sender from `ShareFileHandler` struct - Simplify share persistence error handling This refactoring removes the direct status communication from the share persistence module, improving separation of concerns and reducing complexity. --- roles/pool/src/lib/channel_manager/mod.rs | 3 +- roles/pool/src/lib/mod.rs | 3 +- roles/pool/src/lib/share_persistence/mod.rs | 40 ++++----------------- 3 files changed, 9 insertions(+), 37 deletions(-) diff --git a/roles/pool/src/lib/channel_manager/mod.rs b/roles/pool/src/lib/channel_manager/mod.rs index cb7028d2a3..08b2031418 100644 --- a/roles/pool/src/lib/channel_manager/mod.rs +++ b/roles/pool/src/lib/channel_manager/mod.rs @@ -108,7 +108,6 @@ impl ChannelManager { downstream_sender: broadcast::Sender<(u32, Mining<'static>)>, downstream_receiver: Receiver<(u32, Mining<'static>)>, coinbase_outputs: Vec, - status_tx: StatusSender, task_manager: Arc, ) -> PoolResult { let range_0 = 0..0; @@ -154,7 +153,7 @@ impl ChannelManager { // Initialize persistence based on config let persistence = if let Some(path) = config.share_persistence_file_path() { info!("Initializing file-based share persistence: {}", path); - let mut share_file_handler = ShareFileHandler::new(path, status_tx.clone()).await; + let mut share_file_handler = ShareFileHandler::new(path).await; let sender = share_file_handler.get_sender(); let receiver = share_file_handler.get_receiver(); diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index 17ee776d8a..c32b545f6d 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -11,7 +11,7 @@ use crate::{ channel_manager::ChannelManager, config::PoolConfig, error::PoolResult, - status::{State, Status, StatusSender}, + status::{State, Status}, task_manager::TaskManager, template_receiver::TemplateReceiver, utils::ShutdownMessage, @@ -76,7 +76,6 @@ impl PoolSv2 { channel_manager_to_downstream_sender.clone(), downstream_to_channel_manager_receiver, encoded_outputs.clone(), - StatusSender::ChannelManager(status_sender.clone()), task_manager.clone(), ) .await?; diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs index 548f0fe047..bfea796143 100644 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ b/roles/pool/src/lib/share_persistence/mod.rs @@ -2,26 +2,22 @@ use stratum_apps::stratum_core::channels_sv2::persistence::{ PersistenceHandler, ShareAccountingEvent, }; use tokio::io::AsyncWriteExt; -use tracing::error; - -use crate::status::{self, StatusSender}; +use tracing::{error, info}; pub struct ShareFileHandler { file: tokio::fs::File, receiver: async_channel::Receiver, sender: async_channel::Sender, - status_tx: StatusSender, } impl ShareFileHandler { - pub async fn new(path: &str, status_tx: StatusSender) -> Self { + pub async fn new(path: &str) -> Self { let file = tokio::fs::File::create(path).await.unwrap(); let (sender, receiver) = async_channel::bounded(1024); Self { file, receiver, sender, - status_tx, } } @@ -67,25 +63,12 @@ impl ShareFileHandler { target = "share_file_handler", "Failed to write share event: {}", e ); - let _ = self - .status_tx - .send(status::Status { - state: status::State::SharePersistenceError(format!( - "Failed to write share event: {}", - e - )), - }) - .await; } else if block_found { - let _ = self - .status_tx - .send(status::Status { - state: status::State::Healthy(format!( - "Block found! channel_id: {}, user: {}", - channel_id, user_identity - )), - }) - .await; + info!( + target = "share_file_handler", + "Block found! channel_id: {}, user: {}", + channel_id, user_identity + ); } } ShareAccountingEvent::BestDifficultyUpdated { @@ -110,15 +93,6 @@ impl ShareFileHandler { target = "share_file_handler", "Failed to write difficulty update: {}", e ); - let _ = self - .status_tx - .send(status::Status { - state: status::State::SharePersistenceError(format!( - "Failed to write difficulty update: {}", - e - )), - }) - .await; } } } From 4a9e0f269410beaaed5a1f2648c0cb427b9b3222 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 12:09:55 -0400 Subject: [PATCH 29/39] refactor(share-persistence): Move share persistence to stratum-apps - Relocate share persistence implementation from pool role to stratum-apps - Remove local share_persistence module from pool role - Update import paths in channel_manager modules - Add new share_persistence module to stratum-apps with existing implementation - Improve modularity and reusability of share persistence code - Prepare for potential cross-role share persistence usage --- .../jd-client/src/lib/channel_manager/mod.rs | 13 +- roles/pool/src/lib/channel_manager/mod.rs | 2 +- roles/pool/src/lib/mod.rs | 1 - roles/pool/src/lib/share_persistence/mod.rs | 120 ---------- roles/stratum-apps/src/lib.rs | 8 + .../stratum-apps/src/share_persistence/mod.rs | 218 ++++++++++++++++++ .../src/lib/sv2/channel_manager/data.rs | 16 +- 7 files changed, 231 insertions(+), 147 deletions(-) delete mode 100644 roles/pool/src/lib/share_persistence/mod.rs create mode 100644 roles/stratum-apps/src/share_persistence/mod.rs diff --git a/roles/jd-client/src/lib/channel_manager/mod.rs b/roles/jd-client/src/lib/channel_manager/mod.rs index e56c761f16..838617c092 100644 --- a/roles/jd-client/src/lib/channel_manager/mod.rs +++ b/roles/jd-client/src/lib/channel_manager/mod.rs @@ -12,11 +12,12 @@ use stratum_apps::{ custom_mutex::Mutex, key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}, network_helpers::noise_stream::NoiseTcpStream, + share_persistence::NoOpPersistence, stratum_core::{ bitcoin::Target, channels_sv2::{ client::extended::ExtendedChannel, - persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, + persistence::Persistence, server::{ jobs::{ extended::ExtendedJob, factory::JobFactory, job_store::DefaultJobStore, @@ -66,16 +67,6 @@ mod upstream_message_handler; pub const JDC_SEARCH_SPACE_BYTES: usize = 4; -/// Unit-like type for persistence when disabled -#[derive(Debug, Clone)] -pub(crate) struct NoOpPersistence; - -impl PersistenceHandler for NoOpPersistence { - fn persist_event(&self, _event: ShareAccountingEvent) { - // No-op - this should never be called when using Persistence::Disabled - } -} - /// Type alias for disabled persistence used in JD client pub(crate) type DisabledPersistence = Persistence; diff --git a/roles/pool/src/lib/channel_manager/mod.rs b/roles/pool/src/lib/channel_manager/mod.rs index 08b2031418..af4e99d481 100644 --- a/roles/pool/src/lib/channel_manager/mod.rs +++ b/roles/pool/src/lib/channel_manager/mod.rs @@ -11,6 +11,7 @@ use stratum_apps::{ custom_mutex::Mutex, key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}, network_helpers::noise_stream::NoiseTcpStream, + share_persistence::{ShareFileHandler, ShareFilePersistence}, stratum_core::{ channels_sv2::{ persistence::Persistence, @@ -37,7 +38,6 @@ use crate::{ config::PoolConfig, downstream::Downstream, error::PoolResult, - share_persistence::{ShareFileHandler, ShareFilePersistence}, status::{handle_error, Status, StatusSender}, task_manager::TaskManager, utils::{Message, ShutdownMessage}, diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index c32b545f6d..4f7b34ef1f 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -21,7 +21,6 @@ pub mod channel_manager; pub mod config; pub mod downstream; pub mod error; -pub mod share_persistence; pub mod status; pub mod task_manager; pub mod template_receiver; diff --git a/roles/pool/src/lib/share_persistence/mod.rs b/roles/pool/src/lib/share_persistence/mod.rs deleted file mode 100644 index bfea796143..0000000000 --- a/roles/pool/src/lib/share_persistence/mod.rs +++ /dev/null @@ -1,120 +0,0 @@ -use stratum_apps::stratum_core::channels_sv2::persistence::{ - PersistenceHandler, ShareAccountingEvent, -}; -use tokio::io::AsyncWriteExt; -use tracing::{error, info}; - -pub struct ShareFileHandler { - file: tokio::fs::File, - receiver: async_channel::Receiver, - sender: async_channel::Sender, -} - -impl ShareFileHandler { - pub async fn new(path: &str) -> Self { - let file = tokio::fs::File::create(path).await.unwrap(); - let (sender, receiver) = async_channel::bounded(1024); - Self { - file, - receiver, - sender, - } - } - - pub fn get_receiver(&self) -> async_channel::Receiver { - self.receiver.clone() - } - - pub fn get_sender(&self) -> async_channel::Sender { - self.sender.clone() - } - - pub async fn write_event_to_file(&mut self, event: ShareAccountingEvent) { - match event { - ShareAccountingEvent::ShareAccepted { - channel_id, - user_identity, - share_work, - share_sequence_number, - share_hash, - total_shares_accepted, - total_share_work_sum, - timestamp, - block_found, - } => { - let result = self.file.write_all( - format!( - "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", - channel_id, - user_identity, - share_work, - share_sequence_number, - share_hash, - total_shares_accepted, - total_share_work_sum, - timestamp, - block_found - ) - .as_bytes(), - ).await; - - if let Err(e) = result { - error!( - target = "share_file_handler", - "Failed to write share event: {}", e - ); - } else if block_found { - info!( - target = "share_file_handler", - "Block found! channel_id: {}, user: {}", - channel_id, user_identity - ); - } - } - ShareAccountingEvent::BestDifficultyUpdated { - channel_id, - new_best_diff, - previous_best_diff, - timestamp, - } => { - let result = self.file.write_all( - format!( - "BestDifficultyUpdated: channel_id: {}, new_best_diff: {}, previous_best_diff: {}, timestamp: {:?}\n", - channel_id, - new_best_diff, - previous_best_diff, - timestamp - ) - .as_bytes(), - ).await; - - if let Err(e) = result { - error!( - target = "share_file_handler", - "Failed to write difficulty update: {}", e - ); - } - } - } - } -} - -#[derive(Clone, Debug)] -pub struct ShareFilePersistence { - sender: async_channel::Sender, -} - -impl ShareFilePersistence { - pub fn new(sender: async_channel::Sender) -> Self { - Self { sender } - } -} - -impl PersistenceHandler for ShareFilePersistence { - fn persist_event(&self, event: ShareAccountingEvent) { - let _ = self - .sender - .try_send(event) - .map_err(|e| error!(target = "share_file_persistence", "{}", e)); - } -} diff --git a/roles/stratum-apps/src/lib.rs b/roles/stratum-apps/src/lib.rs index 37a88b8cdd..5a241c3a83 100644 --- a/roles/stratum-apps/src/lib.rs +++ b/roles/stratum-apps/src/lib.rs @@ -58,3 +58,11 @@ pub mod rpc; /// Provides Secp256k1 key management, serialization/deserialization, and signature services. /// Supports both standard and no_std environments. pub mod key_utils; + +/// Share persistence utilities +/// +/// Persistence implementations for share accounting events. +/// This module provides reusable handlers that can be used by any role (Pool, JD Client, etc.) +/// to persist share accounting data without impacting mining performance. +#[cfg(feature = "core")] +pub mod share_persistence; diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs new file mode 100644 index 0000000000..d7b947b6a0 --- /dev/null +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -0,0 +1,218 @@ +//! Share Persistence File Handler +//! +//! This module provides a generic file-based persistence implementation for share accounting events. +//! It is designed to be reusable across different Stratum V2 roles (Pool, JD Client, Translator, etc.). +//! +//! ## Design +//! +//! - **Non-blocking**: Uses async channels to decouple persistence from critical mining operations +//! - **Generic**: No role-specific dependencies, uses standard `tracing` for logging +//! - **File-based**: Writes share accounting events to a text file for audit/analysis +//! +//! ## Usage +//! +//! ```rust,ignore +//! use stratum_apps::share_persistence::{ShareFileHandler, ShareFilePersistence}; +//! use stratum_apps::stratum_core::channels_sv2::persistence::Persistence; +//! +//! // Create the handler +//! let mut handler = ShareFileHandler::new("/path/to/shares.txt").await; +//! let sender = handler.get_sender(); +//! let receiver = handler.get_receiver(); +//! +//! // Spawn background task to write events +//! tokio::spawn(async move { +//! loop { +//! match receiver.recv().await { +//! Ok(event) => handler.write_event_to_file(event).await, +//! Err(_) => break, +//! } +//! } +//! }); +//! +//! // Create persistence handler for share accounting +//! let persistence = Persistence::new(Some(ShareFilePersistence::new(sender))); +//! ``` + +use stratum_core::channels_sv2::persistence::{PersistenceHandler, ShareAccountingEvent}; +use tokio::io::AsyncWriteExt; +use tracing::{debug, error, info}; + +/// File-based handler for writing share accounting events to disk. +/// +/// This handler maintains an async channel for receiving events and writes them +/// to a file in a human-readable format. It uses non-blocking I/O to ensure +/// persistence operations don't impact mining performance. +pub struct ShareFileHandler { + file: tokio::fs::File, + receiver: async_channel::Receiver, + sender: async_channel::Sender, +} + +impl ShareFileHandler { + /// Creates a new share file handler that writes to the specified path. + /// + /// # Arguments + /// + /// * `path` - File path where share events will be written + /// + /// # Panics + /// + /// Panics if the file cannot be created. + pub async fn new(path: &str) -> Self { + let file = tokio::fs::File::create(path).await.unwrap(); + let (sender, receiver) = async_channel::bounded(1024); + info!("Share accounting file created at {}", path); + Self { + file, + receiver, + sender, + } + + } + + /// Returns a receiver for consuming share accounting events. + /// + /// The receiver should be used in a background task that calls + /// `write_event_to_file` for each received event. + pub fn get_receiver(&self) -> async_channel::Receiver { + self.receiver.clone() + } + + /// Returns a sender for producing share accounting events. + /// + /// This sender should be wrapped in a `ShareFilePersistence` and passed + /// to the channel's persistence configuration. + pub fn get_sender(&self) -> async_channel::Sender { + self.sender.clone() + } + + /// Writes a share accounting event to the file. + /// + /// Events are formatted as human-readable text lines. Errors are logged + /// using `tracing::error!` but do not propagate to avoid impacting mining. + /// + /// Special events like block discoveries are logged at `info` level. + pub async fn write_event_to_file(&mut self, event: ShareAccountingEvent) { + match event { + ShareAccountingEvent::ShareAccepted { + channel_id, + user_identity, + share_work, + share_sequence_number, + share_hash, + total_shares_accepted, + total_share_work_sum, + timestamp, + block_found, + } => { + let result = self.file.write_all( + format!( + "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", + channel_id, + user_identity, + share_work, + share_sequence_number, + share_hash, + total_shares_accepted, + total_share_work_sum, + timestamp, + block_found + ) + .as_bytes(), + ).await; + + if let Err(e) = result { + error!( + target = "share_file_handler", + "Failed to write share event: {}", e + ); + } + debug!("Wrote record") + } + ShareAccountingEvent::BestDifficultyUpdated { + channel_id, + new_best_diff, + previous_best_diff, + timestamp, + } => { + let result = self.file.write_all( + format!( + "BestDifficultyUpdated: channel_id: {}, new_best_diff: {}, previous_best_diff: {}, timestamp: {:?}\n", + channel_id, + new_best_diff, + previous_best_diff, + timestamp + ) + .as_bytes(), + ).await; + + if let Err(e) = result { + error!( + target = "share_file_handler", + "Failed to write difficulty update: {}", e + ); + } + } + } + } +} + +/// Channel-based persistence handler for share accounting. +/// +/// This implements the `PersistenceHandler` trait and sends events through +/// an async channel to be processed by a `ShareFileHandler` in a background task. +#[derive(Clone, Debug)] +pub struct ShareFilePersistence { + sender: async_channel::Sender, +} + +impl ShareFilePersistence { + /// Creates a new persistence handler with the given event sender. + /// + /// # Arguments + /// + /// * `sender` - Channel sender connected to a `ShareFileHandler` + pub fn new(sender: async_channel::Sender) -> Self { + info!("File persistence enabled for share accounting."); + Self { sender } + } +} + +impl PersistenceHandler for ShareFilePersistence { + /// Sends a share accounting event for persistence. + /// + /// This is non-blocking and will not return errors. Failed sends are logged + /// but do not propagate to avoid impacting the hot path. + fn persist_event(&self, event: ShareAccountingEvent) { + let _ = self + .sender + .try_send(event) + .map_err(|e| error!(target = "share_file_persistence", "{}", e)); + } +} + +/// No-op persistence handler for roles that don't need persistence. +/// +/// This is a unit-like type that implements `PersistenceHandler` but does nothing. +/// It's useful for roles that need to instantiate channels but don't want to persist +/// share accounting events (e.g., JD Client, Translator). +/// +/// ## Usage +/// +/// ```rust,ignore +/// use stratum_apps::share_persistence::NoOpPersistence; +/// use stratum_apps::stratum_core::channels_sv2::persistence::Persistence; +/// +/// // Create disabled persistence +/// type DisabledPersistence = Persistence; +/// let persistence = Persistence::Disabled; // or Persistence::new(None) +/// ``` +#[derive(Debug, Clone, Copy)] +pub struct NoOpPersistence; + +impl PersistenceHandler for NoOpPersistence { + fn persist_event(&self, _event: ShareAccountingEvent) { + // No-op - this should never be called when using Persistence::Disabled + } +} diff --git a/roles/translator/src/lib/sv2/channel_manager/data.rs b/roles/translator/src/lib/sv2/channel_manager/data.rs index b544968cb6..e2b05f041c 100644 --- a/roles/translator/src/lib/sv2/channel_manager/data.rs +++ b/roles/translator/src/lib/sv2/channel_manager/data.rs @@ -4,25 +4,13 @@ use std::{ }; use stratum_apps::{ custom_mutex::Mutex, + share_persistence::NoOpPersistence, stratum_core::{ - channels_sv2::{ - client::extended::ExtendedChannel, - persistence::{Persistence, PersistenceHandler, ShareAccountingEvent}, - }, + channels_sv2::{client::extended::ExtendedChannel, persistence::Persistence}, mining_sv2::ExtendedExtranonce, }, }; -/// Unit-like type for persistence when disabled in translator -#[derive(Debug, Clone)] -pub struct NoOpPersistence; - -impl PersistenceHandler for NoOpPersistence { - fn persist_event(&self, _event: ShareAccountingEvent) { - // No-op - this should never be called when using Persistence::Disabled - } -} - /// Type alias for disabled persistence used in translator pub type DisabledPersistence = Persistence; From 510c7d719a33fc414c091d7a5b8e7d07889cd885 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 13:14:03 -0400 Subject: [PATCH 30/39] refactor(channels-sv2): Update share accounting and persistence handling - Change share work sum type from u64 to f64 for more precise difficulty tracking - Remove unnecessary type casting of difficulty to u64 in share accounting methods - Update share accounting methods to use floating-point difficulty values - Remove unused NoPersistence import in multiple files - Simplify share accounting event persistence tracking - Improve comments describing share work and difficulty calculations This refactoring improves the precision of share difficulty tracking and simplifies the share accounting implementation across multiple Stratum V2 protocol components. --- protocols/v2/channels-sv2/src/client/extended.rs | 6 +++--- .../v2/channels-sv2/src/client/share_accounting.rs | 10 +++++----- protocols/v2/channels-sv2/src/client/standard.rs | 8 +++----- protocols/v2/channels-sv2/src/persistence.rs | 8 ++++---- protocols/v2/channels-sv2/src/server/extended.rs | 8 ++------ .../v2/channels-sv2/src/server/share_accounting.rs | 12 ++++++------ protocols/v2/channels-sv2/src/server/standard.rs | 4 ++-- .../channel_manager/downstream_message_handler.rs | 8 ++++---- .../lib/channel_manager/mining_message_handler.rs | 8 ++++---- roles/pool/src/lib/mod.rs | 9 +-------- roles/pool/src/lib/status.rs | 4 ---- roles/stratum-apps/src/share_persistence/mod.rs | 3 +-- 12 files changed, 35 insertions(+), 53 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/extended.rs b/protocols/v2/channels-sv2/src/client/extended.rs index 29cbb279be..0f78572cbd 100644 --- a/protocols/v2/channels-sv2/src/client/extended.rs +++ b/protocols/v2/channels-sv2/src/client/extended.rs @@ -13,7 +13,7 @@ use crate::{ share_accounting::{ShareAccounting, ShareValidationError, ShareValidationResult}, }, merkle_root::merkle_root_from_path, - persistence::{NoPersistence, PersistenceHandler}, + persistence::PersistenceHandler, target::{bytes_to_hex, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; @@ -541,7 +541,7 @@ where self.share_accounting.update_share_accounting( self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), true, @@ -558,7 +558,7 @@ where self.share_accounting.update_share_accounting( self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), false, diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 42c2e990bd..956d43c431 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -47,14 +47,14 @@ pub enum ShareValidationError { /// Keeps statistics and state for shares submitted through the channel: /// - last received share's sequence number /// - total accepted shares -/// - cumulative work from accepted shares +/// - cumulative work from accepted shares (sum of share difficulties as floating point) /// - hashes of seen shares (for duplicate detection) /// - highest difficulty seen in accepted shares #[derive(Clone, Debug)] pub struct ShareAccounting

{ last_share_sequence_number: u32, shares_accepted: u32, - share_work_sum: u64, + share_work_sum: f64, seen_shares: HashSet, best_diff: f64, persistence: P, @@ -71,7 +71,7 @@ where Self { last_share_sequence_number: 0, shares_accepted: 0, - share_work_sum: 0, + share_work_sum: 0.0, seen_shares: HashSet::new(), best_diff: 0.0, persistence, @@ -87,7 +87,7 @@ where &mut self, channel_id: u32, user_identity: &str, - share_work: u64, + share_work: f64, share_sequence_number: u32, share_hash: Hash, block_found: bool, @@ -134,7 +134,7 @@ where } /// Returns the cumulative work of all accepted shares. - pub fn get_share_work_sum(&self) -> u64 { + pub fn get_share_work_sum(&self) -> f64 { self.share_work_sum } diff --git a/protocols/v2/channels-sv2/src/client/standard.rs b/protocols/v2/channels-sv2/src/client/standard.rs index 861ec9d348..7864cd14c4 100644 --- a/protocols/v2/channels-sv2/src/client/standard.rs +++ b/protocols/v2/channels-sv2/src/client/standard.rs @@ -13,7 +13,7 @@ use crate::{ share_accounting::{ShareAccounting, ShareValidationError, ShareValidationResult}, }, merkle_root::merkle_root_from_path, - persistence::{NoPersistence, PersistenceHandler}, + persistence::PersistenceHandler, target::{bytes_to_hex, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; @@ -335,10 +335,9 @@ where // check if a block was found if network_target.is_met_by(hash) { self.share_accounting.update_share_accounting( - self.target.difficulty_float() as u64, self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), true, @@ -353,10 +352,9 @@ where } self.share_accounting.update_share_accounting( - self.target.difficulty_float() as u64, self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), false, diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 36ae75e9b9..1cce23b546 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -32,16 +32,16 @@ pub enum ShareAccountingEvent { channel_id: u32, /// User identity associated with the channel user_identity: String, - /// Work value of the accepted share - share_work: u64, + /// Work value of the accepted share (difficulty as floating point) + share_work: f64, /// Sequence number of the share share_sequence_number: u32, /// Hash of the accepted share (for duplicate detection) share_hash: Hash, /// Total shares accepted after this update total_shares_accepted: u32, - /// Total work sum after this update - total_share_work_sum: u64, + /// Total work sum after this update (sum of all share difficulties) + total_share_work_sum: f64, /// Timestamp when the event occurred timestamp: std::time::SystemTime, /// Block found? diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 1b94f316c4..f17049a266 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -51,14 +51,12 @@ use crate::{ target::{bytes_to_hex, hash_rate_to_target, u256_to_block_hash}, MAX_EXTRANONCE_PREFIX_LEN, }; -use binary_sv2::{self}; use bitcoin::{ blockdata::block::{Header, Version}, hashes::sha256d::Hash, transaction::TxOut, CompactTarget, Target, }; -use mining_sv2::MAX_EXTRANONCE_LEN; use mining_sv2::{SetCustomMiningJob, SubmitSharesExtended}; use std::{collections::HashMap, convert::TryInto, marker::PhantomData}; use template_distribution_sv2::{NewTemplate, SetNewPrevHash as SetNewPrevHashTdp}; @@ -682,10 +680,9 @@ where // check if a block was found if network_target.is_met_by(hash) { self.share_accounting.update_share_accounting( - self.target.difficulty_float() as u64, self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), true, @@ -717,10 +714,9 @@ where } self.share_accounting.update_share_accounting( - self.target.difficulty_float() as u64, self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), false, diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index dab58d5634..bf5c3f8f5d 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -44,8 +44,8 @@ pub enum ShareValidationResult { /// Contains: /// - `last_sequence_number`: The sequence number of the last accepted share in the batch. /// - `new_submits_accepted_count`: The number of new shares accepted in this batch. - /// - `new_shares_sum`: The total work contributed by shares in this batch. - ValidWithAcknowledgement(u32, u32, u64), + /// - `new_shares_sum`: The total work contributed by shares in this batch (as floating point). + ValidWithAcknowledgement(u32, u32, f64), /// The share solves a block. /// Contains: /// - `template_id`: The template ID associated with the job, or `None` for custom jobs. @@ -85,7 +85,7 @@ pub enum ShareValidationError { pub struct ShareAccounting

{ last_share_sequence_number: u32, shares_accepted: u32, - share_work_sum: u64, + share_work_sum: f64, share_batch_size: usize, seen_shares: HashSet, best_diff: f64, @@ -104,7 +104,7 @@ where Self { last_share_sequence_number: 0, shares_accepted: 0, - share_work_sum: 0, + share_work_sum: 0.0, share_batch_size, seen_shares: HashSet::new(), best_diff: 0.0, @@ -121,7 +121,7 @@ where &mut self, channel_id: u32, user_identity: &str, - share_work: u64, + share_work: f64, share_sequence_number: u32, share_hash: Hash, block_found: bool, @@ -168,7 +168,7 @@ where } /// Returns the sum of work contributed by all accepted shares. - pub fn get_share_work_sum(&self) -> u64 { + pub fn get_share_work_sum(&self) -> f64 { self.share_work_sum } diff --git a/protocols/v2/channels-sv2/src/server/standard.rs b/protocols/v2/channels-sv2/src/server/standard.rs index 1d7439df57..8f12ae36da 100644 --- a/protocols/v2/channels-sv2/src/server/standard.rs +++ b/protocols/v2/channels-sv2/src/server/standard.rs @@ -631,7 +631,7 @@ where self.share_accounting.update_share_accounting( self.channel_id, &self.user_identity, - target_to_difficulty(self.target.clone()) as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), true, @@ -652,7 +652,7 @@ where self.share_accounting.update_share_accounting( self.channel_id, &self.user_identity, - self.target.difficulty_float() as u64, + self.target.difficulty_float(), share.sequence_number, hash.to_raw_hash(), false, diff --git a/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs b/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs index 75c473b1a8..8e831279b2 100644 --- a/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs +++ b/roles/jd-client/src/lib/channel_manager/downstream_message_handler.rs @@ -986,7 +986,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number, new_submits_accepted_count, - new_shares_sum, + new_shares_sum: new_shares_sum as u64, }; is_downstream_share_valid = true; info!("SubmitSharesStandard on downstream channel: {} ✅", success); @@ -1015,7 +1015,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number: share_accounting.get_last_share_sequence_number(), new_submits_accepted_count: share_accounting.get_shares_accepted(), - new_shares_sum: share_accounting.get_share_work_sum(), + new_shares_sum: share_accounting.get_share_work_sum() as u64, }; messages.push(( downstream.downstream_id, @@ -1187,7 +1187,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number, new_submits_accepted_count, - new_shares_sum, + new_shares_sum: new_shares_sum as u64, }; info!("SubmitSharesExtended on downstream channel: {} ✅", success); is_downstream_share_valid = true; @@ -1214,7 +1214,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number: share_accounting.get_last_share_sequence_number(), new_submits_accepted_count: share_accounting.get_shares_accepted(), - new_shares_sum: share_accounting.get_share_work_sum(), + new_shares_sum: share_accounting.get_share_work_sum() as u64, }; is_downstream_share_valid = true; messages.push(( diff --git a/roles/pool/src/lib/channel_manager/mining_message_handler.rs b/roles/pool/src/lib/channel_manager/mining_message_handler.rs index 0b2d0d734b..77b3bea644 100644 --- a/roles/pool/src/lib/channel_manager/mining_message_handler.rs +++ b/roles/pool/src/lib/channel_manager/mining_message_handler.rs @@ -545,7 +545,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number, new_submits_accepted_count, - new_shares_sum, + new_shares_sum: new_shares_sum as u64, }; info!("SubmitSharesStandard: {} ✅", success); messages.push((downstream_id, Mining::SubmitSharesSuccess(success)).into()); @@ -570,7 +570,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number: share_accounting.get_last_share_sequence_number(), new_submits_accepted_count: share_accounting.get_shares_accepted(), - new_shares_sum: share_accounting.get_share_work_sum(), + new_shares_sum: share_accounting.get_share_work_sum() as u64, }; messages.push((downstream_id, Mining::SubmitSharesSuccess(success)).into()); } @@ -703,7 +703,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number, new_submits_accepted_count, - new_shares_sum, + new_shares_sum: new_shares_sum as u64, }; info!("SubmitSharesExtended: {} ✅", success); messages.push((downstream_id, Mining::SubmitSharesSuccess(success)).into()); @@ -728,7 +728,7 @@ impl HandleMiningMessagesFromClientAsync for ChannelManager { channel_id, last_sequence_number: share_accounting.get_last_share_sequence_number(), new_submits_accepted_count: share_accounting.get_shares_accepted(), - new_shares_sum: share_accounting.get_share_work_sum(), + new_shares_sum: share_accounting.get_share_work_sum() as u64, }; messages.push((downstream_id, Mining::SubmitSharesSuccess(success)).into()); } diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index 4f7b34ef1f..b8e1467ece 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -5,7 +5,7 @@ use stratum_apps::stratum_core::{ bitcoin::consensus::Encodable, parsers_sv2::TemplateDistribution, }; use tokio::sync::broadcast; -use tracing::{debug, error, info, warn}; +use tracing::{debug, info, warn}; use crate::{ channel_manager::ChannelManager, @@ -155,13 +155,6 @@ impl PoolSv2 { let _ = notify_shutdown.send(ShutdownMessage::ShutdownAll); break; } - State::SharePersistenceError(err) => { - error!("Share persistence error: {}", err); - // Continue running - persistence errors shouldn't stop the pool - } - State::Healthy(msg) => { - info!("Healthy status: {}", msg); - } } } } diff --git a/roles/pool/src/lib/status.rs b/roles/pool/src/lib/status.rs index 707ff46303..d3ecb8ad78 100644 --- a/roles/pool/src/lib/status.rs +++ b/roles/pool/src/lib/status.rs @@ -83,10 +83,6 @@ pub enum State { TemplateReceiverShutdown(PoolError), /// Channel manager has shut down with a reason. ChannelManagerShutdown(PoolError), - /// Share persistence encountered an error (non-fatal). - SharePersistenceError(String), - /// Represents a healthy state with an accompanying status message. - Healthy(String), } /// Wrapper around a component's state, sent as status updates across the system. diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index d7b947b6a0..de540e5834 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -68,7 +68,6 @@ impl ShareFileHandler { receiver, sender, } - } /// Returns a receiver for consuming share accounting events. @@ -127,7 +126,7 @@ impl ShareFileHandler { target = "share_file_handler", "Failed to write share event: {}", e ); - } + } debug!("Wrote record") } ShareAccountingEvent::BestDifficultyUpdated { From 27706fac55ab4a9ff436756c172a775cb3a19dbe Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 13:26:33 -0400 Subject: [PATCH 31/39] fix: CI clippy and formatting issues --- protocols/v2/channels-sv2/src/server/extended.rs | 2 +- roles/stratum-apps/src/share_persistence/mod.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index f17049a266..75258c4d59 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -218,7 +218,7 @@ where } }; - let target: Target = target_u256.clone().into(); + let target: Target = target_u256; if target > max_target { return Err(ExtendedChannelError::RequestedMaxTargetOutOfRange); diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index de540e5834..cb4d391b2d 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -1,7 +1,8 @@ //! Share Persistence File Handler //! -//! This module provides a generic file-based persistence implementation for share accounting events. -//! It is designed to be reusable across different Stratum V2 roles (Pool, JD Client, Translator, etc.). +//! This module provides a generic file-based persistence implementation for share accounting +//! events. It is designed to be reusable across different Stratum V2 roles (Pool, JD Client, +//! Translator, etc.). //! //! ## Design //! From 268430c84f1eecd8d763a0de986a25b998c1ccd6 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 13:57:29 -0400 Subject: [PATCH 32/39] refactor(channels-sv2): Simplify target calculation in extended channel --- protocols/v2/channels-sv2/src/server/extended.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/protocols/v2/channels-sv2/src/server/extended.rs b/protocols/v2/channels-sv2/src/server/extended.rs index 75258c4d59..5c5f0a283a 100644 --- a/protocols/v2/channels-sv2/src/server/extended.rs +++ b/protocols/v2/channels-sv2/src/server/extended.rs @@ -210,16 +210,14 @@ where miner_tag: Option, persistence: P, ) -> Result { - let target_u256 = + let target: Target = match hash_rate_to_target(nominal_hashrate.into(), expected_share_per_minute.into()) { - Ok(target_u256) => target_u256, + Ok(target) => target, Err(_) => { return Err(ExtendedChannelError::InvalidNominalHashrate); } }; - let target: Target = target_u256; - if target > max_target { return Err(ExtendedChannelError::RequestedMaxTargetOutOfRange); } From fb7e4aa82960cbb2020ac577658f76967acbf216 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 14:08:04 -0400 Subject: [PATCH 33/39] refactor(share-persistence): Remove share sequence number from persistence events --- protocols/v2/channels-sv2/src/client/share_accounting.rs | 1 - protocols/v2/channels-sv2/src/persistence.rs | 2 -- protocols/v2/channels-sv2/src/server/share_accounting.rs | 1 - roles/stratum-apps/src/share_persistence/mod.rs | 4 +--- 4 files changed, 1 insertion(+), 7 deletions(-) diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index 956d43c431..f2ab122a90 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -102,7 +102,6 @@ where channel_id, user_identity: user_identity.to_string(), share_work, - share_sequence_number, share_hash, total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 1cce23b546..3312210fd5 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -34,8 +34,6 @@ pub enum ShareAccountingEvent { user_identity: String, /// Work value of the accepted share (difficulty as floating point) share_work: f64, - /// Sequence number of the share - share_sequence_number: u32, /// Hash of the accepted share (for duplicate detection) share_hash: Hash, /// Total shares accepted after this update diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index bf5c3f8f5d..2cc92fb451 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -136,7 +136,6 @@ where channel_id, user_identity: user_identity.to_string(), share_work, - share_sequence_number, share_hash, total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index cb4d391b2d..94795b69bc 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -99,7 +99,6 @@ impl ShareFileHandler { channel_id, user_identity, share_work, - share_sequence_number, share_hash, total_shares_accepted, total_share_work_sum, @@ -108,11 +107,10 @@ impl ShareFileHandler { } => { let result = self.file.write_all( format!( - "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", + "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", channel_id, user_identity, share_work, - share_sequence_number, share_hash, total_shares_accepted, total_share_work_sum, From 61915a6a4ffa607699b79bc53c7eac340a8c83e7 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 14:33:25 -0400 Subject: [PATCH 34/39] refactor: use type alias --- roles/jd-client/src/lib/channel_manager/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/roles/jd-client/src/lib/channel_manager/mod.rs b/roles/jd-client/src/lib/channel_manager/mod.rs index 838617c092..3f7165c329 100644 --- a/roles/jd-client/src/lib/channel_manager/mod.rs +++ b/roles/jd-client/src/lib/channel_manager/mod.rs @@ -927,7 +927,7 @@ impl ChannelManager { channel_state: &mut stratum_apps::stratum_core::channels_sv2::server::extended::ExtendedChannel< 'static, DefaultJobStore>, - Persistence, + DisabledPersistence, >, vardiff_state: &mut VardiffState, updates: &mut Vec, @@ -976,7 +976,7 @@ impl ChannelManager { channel: &mut StandardChannel< 'static, DefaultJobStore>, - Persistence, + DisabledPersistence, >, vardiff_state: &mut VardiffState, updates: &mut Vec, From 9cf7fc568df6664df151d81a369e6e659e0706fa Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 14:43:44 -0400 Subject: [PATCH 35/39] fix: remove erroneous docstring --- roles/stratum-apps/src/share_persistence/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index 94795b69bc..9fd74feadc 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -91,8 +91,6 @@ impl ShareFileHandler { /// /// Events are formatted as human-readable text lines. Errors are logged /// using `tracing::error!` but do not propagate to avoid impacting mining. - /// - /// Special events like block discoveries are logged at `info` level. pub async fn write_event_to_file(&mut self, event: ShareAccountingEvent) { match event { ShareAccountingEvent::ShareAccepted { From 8987110de0ab0e890a3fea00ee6d3c8a587b8d28 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 14:45:32 -0400 Subject: [PATCH 36/39] fix: debug logging --- roles/stratum-apps/src/share_persistence/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index 9fd74feadc..d382ca2464 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -123,8 +123,9 @@ impl ShareFileHandler { target = "share_file_handler", "Failed to write share event: {}", e ); + } else { + debug!("Wrote share record to file."); } - debug!("Wrote record") } ShareAccountingEvent::BestDifficultyUpdated { channel_id, @@ -142,12 +143,14 @@ impl ShareFileHandler { ) .as_bytes(), ).await; - + if let Err(e) = result { error!( target = "share_file_handler", "Failed to write difficulty update: {}", e ); + } else { + debug!("Wrote difficulty update record to file."); } } } From ecfe6568977490fa4f1546c776d1f09e31332097 Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Thu, 23 Oct 2025 14:46:56 -0400 Subject: [PATCH 37/39] fix: docstring --- roles/stratum-apps/src/share_persistence/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index d382ca2464..f8fd553af7 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -195,7 +195,7 @@ impl PersistenceHandler for ShareFilePersistence { /// /// This is a unit-like type that implements `PersistenceHandler` but does nothing. /// It's useful for roles that need to instantiate channels but don't want to persist -/// share accounting events (e.g., JD Client, Translator). +/// share accounting events. /// /// ## Usage /// From 71d9b55a9f2883e990165be3edeba2f261dd4d7c Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Fri, 24 Oct 2025 08:25:21 -0400 Subject: [PATCH 38/39] fix: whitespace --- roles/stratum-apps/src/share_persistence/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index f8fd553af7..af1caa5bd7 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -143,7 +143,7 @@ impl ShareFileHandler { ) .as_bytes(), ).await; - + if let Err(e) = result { error!( target = "share_file_handler", From 9e1f624eb87a305f849754e1a20d69144f3fd28a Mon Sep 17 00:00:00 2001 From: Gary Krause Date: Fri, 24 Oct 2025 08:46:37 -0400 Subject: [PATCH 39/39] Revert "refactor(share-persistence): Remove share sequence number from persistence events" This reverts commit fb7e4aa82960cbb2020ac577658f76967acbf216. --- protocols/v2/channels-sv2/src/client/share_accounting.rs | 1 + protocols/v2/channels-sv2/src/persistence.rs | 2 ++ protocols/v2/channels-sv2/src/server/share_accounting.rs | 1 + roles/stratum-apps/src/share_persistence/mod.rs | 4 +++- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/protocols/v2/channels-sv2/src/client/share_accounting.rs b/protocols/v2/channels-sv2/src/client/share_accounting.rs index f2ab122a90..956d43c431 100644 --- a/protocols/v2/channels-sv2/src/client/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/client/share_accounting.rs @@ -102,6 +102,7 @@ where channel_id, user_identity: user_identity.to_string(), share_work, + share_sequence_number, share_hash, total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, diff --git a/protocols/v2/channels-sv2/src/persistence.rs b/protocols/v2/channels-sv2/src/persistence.rs index 3312210fd5..1cce23b546 100644 --- a/protocols/v2/channels-sv2/src/persistence.rs +++ b/protocols/v2/channels-sv2/src/persistence.rs @@ -34,6 +34,8 @@ pub enum ShareAccountingEvent { user_identity: String, /// Work value of the accepted share (difficulty as floating point) share_work: f64, + /// Sequence number of the share + share_sequence_number: u32, /// Hash of the accepted share (for duplicate detection) share_hash: Hash, /// Total shares accepted after this update diff --git a/protocols/v2/channels-sv2/src/server/share_accounting.rs b/protocols/v2/channels-sv2/src/server/share_accounting.rs index 2cc92fb451..bf5c3f8f5d 100644 --- a/protocols/v2/channels-sv2/src/server/share_accounting.rs +++ b/protocols/v2/channels-sv2/src/server/share_accounting.rs @@ -136,6 +136,7 @@ where channel_id, user_identity: user_identity.to_string(), share_work, + share_sequence_number, share_hash, total_shares_accepted: self.shares_accepted, total_share_work_sum: self.share_work_sum, diff --git a/roles/stratum-apps/src/share_persistence/mod.rs b/roles/stratum-apps/src/share_persistence/mod.rs index af1caa5bd7..168ad48a3f 100644 --- a/roles/stratum-apps/src/share_persistence/mod.rs +++ b/roles/stratum-apps/src/share_persistence/mod.rs @@ -97,6 +97,7 @@ impl ShareFileHandler { channel_id, user_identity, share_work, + share_sequence_number, share_hash, total_shares_accepted, total_share_work_sum, @@ -105,10 +106,11 @@ impl ShareFileHandler { } => { let result = self.file.write_all( format!( - "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", + "ShareAccepted: channel_id: {}, user_identity: {}, share_work: {}, share_sequence_number: {}, share_hash: {}, total_shares_accepted: {}, total_share_work_sum: {}, timestamp: {:?}, block_found: {}\n", channel_id, user_identity, share_work, + share_sequence_number, share_hash, total_shares_accepted, total_share_work_sum,