From da2b37262a315877ca1636f45722eb432f56d4e9 Mon Sep 17 00:00:00 2001 From: RJ Rybarczyk Date: Sat, 21 Dec 2024 18:48:59 -0500 Subject: [PATCH] Common properties doc additions --- .../roles-logic-sv2/src/common_properties.rs | 210 ++++++++++++++---- 1 file changed, 168 insertions(+), 42 deletions(-) diff --git a/protocols/v2/roles-logic-sv2/src/common_properties.rs b/protocols/v2/roles-logic-sv2/src/common_properties.rs index d36c901da5..8010e66b52 100644 --- a/protocols/v2/roles-logic-sv2/src/common_properties.rs +++ b/protocols/v2/roles-logic-sv2/src/common_properties.rs @@ -1,4 +1,9 @@ -//! This module defines traits for properties that every SRI-based application should implement +//! # Common Properties for Stratum V2 (Sv2) Roles +//! +//! Defines common properties, traits, and utilities for implementing upstream and downstream +//! roles. It provides abstractions for features like connection pairing, mining job distribution, +//! and channel management. These definitions form the foundation for consistent communication and +//! behavior across Sv2 roles/applications. use crate::selectors::{ DownstreamMiningSelector, DownstreamSelector, NullDownstreamMiningSelector, @@ -8,32 +13,82 @@ use mining_sv2::{Extranonce, Target}; use nohash_hasher::BuildNoHashHasher; use std::{collections::HashMap, fmt::Debug as D}; -/// Defines a mining downstream node at the most basic level +/// Defines a mining downstream role at the most basic level. #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)] pub struct CommonDownstreamData { + /// Header-only mining flag. + /// + /// Enables the processing of block headers only, leaving transaction management and template + /// construction to the upstream role. It reduces the amount of data processed and transmitted + /// by the downstream role, making it useful when bandwidth is limited and transmitting full + /// block templates is costly. + /// + /// - `true`: The downstream role only processes block headers, relying on the upstream for + /// transaction management. + /// - `false`: The downstream role handles full blocks. pub header_only: bool, + + /// Work selection flag. + /// + /// Enables the selection of which transactions or templates the role will work on. It allows + /// for more autonomy for downstream roles to define specific version bits to roll, adjust the + /// difficulty target, apply `timestamp` range constraints, etc. + /// + /// - `true`: The downstream role can modify or customize the mining job, such as choosing + /// specific transactions to include in a block template. + /// - `false`: The downstream role strictly follows the work provided by the upstream, such as + /// pre-constructed templates from a pool. pub work_selection: bool, + + /// Version rolling flag. + /// + /// Enables rolling the block header version bits which allows for more unique hash generation + /// on the same block template by expanding the nonce-space. Used when other fields (e.g. + /// `nonce` or `extranonce`) are fully exhausted. + /// + /// - `true`: The downstream supports version rolling and can modify specific bits in the + /// version field. This is useful for increasing hash rate efficiency by exploring a larger + /// solution space. + /// - `false`: The downstream does not support version rolling and relies on the upstream to + /// provide jobs with adjusted version fields. pub version_rolling: bool, } -/// SetupConnection sugared +/// Encapsulates settings for pairing upstream and downstream roles. +/// +/// Simplifies the [`SetupConnection`] configuration process by bundling the protocol, version +/// range, and flag settings. #[derive(Debug, Copy, Clone)] pub struct PairSettings { + /// Role the settings apply to. pub protocol: Protocol, + + /// Minimum protocol version the role supports. pub min_v: u16, + + /// Minimum protocol version the role supports. pub max_v: u16, + + /// Flags indicating optional protocol features the role supports (e.g. header-only mining, + /// Noise protocol support, job configuration parameters, etc.). Each protocol field as its own + /// flags. pub flags: u32, } -/// General properties that every Sv2 compatible upstream node must implement. +/// Properties defining behaviors common to all Sv2 upstream roles. pub trait IsUpstream + ?Sized> { - /// Used to bitcoin protocol version for the channel. + /// Returns the protocol version used by the upstream node. fn get_version(&self) -> u16; - /// Used to get flags for the defined sv2 message protocol + + /// Returns the flags indicating the upstream node's protocol capabilities. fn get_flags(&self) -> u32; - /// Used to check if the upstream supports the protocol that the downstream wants to use + + /// Lists the protocols supported by the upstream node. + /// + /// Used to check if the upstream supports the protocol that the downstream wants to use. fn get_supported_protocols(&self) -> Vec; - /// Checking if the upstream supports the protocol that the downstream wants to use. + + /// Verifies if the upstream can pair with the given downstream settings. fn is_pairable(&self, pair_settings: &PairSettings) -> bool { let protocol = pair_settings.protocol; let min_v = pair_settings.min_v; @@ -44,71 +99,117 @@ pub trait IsUpstream + ?Sized> let check_flags = SetupConnection::check_flags(protocol, self.get_flags(), flags); check_version && check_flags } - /// Should return the channel id + + /// Returns the channel ID managed by the upstream node. fn get_id(&self) -> u32; - /// Should return a request id mapper for viewing and handling request ids. + + /// Provides a request ID mapper for viewing and managing upstream-downstream communication. fn get_mapper(&mut self) -> Option<&mut RequestIdMapper>; - /// Should return the selector of the Downstream node. See [`crate::selectors`]. + + /// Returns the selector ([`crate::selectors`] for managing downstream nodes. fn get_remote_selector(&mut self) -> &mut Sel; } -/// Channel to be opened with the upstream nodes. +/// The types of channels that can be opened with upstream roles. #[derive(Debug, Clone, Copy)] pub enum UpstreamChannel { - /// nominal hash rate + /// A standard channel with a nominal hash rate. + /// + /// Typically used for mining devices with a direct connection to an upstream role (e.g. a pool + /// or proxy). The hashrate is specified as a `f32` value, representing the expected + /// computational capacity of the miner. Standard(f32), + + /// A grouped channel for aggregated mining. + /// + /// Aggregates mining work for multiple devices or clients under a single channel, enabling the + /// upstream to manage work distribution and result aggregation for an entire group of miners. + /// + /// Typically used by a mining proxy managing multiple downstream miners. Group, + + /// An extended channel for additional features. + /// + /// Provides additional features or capabilities beyond standard and group channels, + /// accommodating features like custom job templates or experimental protocol extensions. Extended, } +/// Properties of a standard mining channel. +/// +/// Standard channels are intended to be used by end mining devices with a nominal hashrate, where +/// each device operates on an independent connection to its upstream. #[derive(Debug, Clone)] -/// Standard channels are intended to be used by end mining devices. pub struct StandardChannel { - /// Newly assigned identifier of the channel, stable for the whole lifetime of the connection. - /// e.g. it is used for broadcasting new jobs by `NewExtendedMiningJob` + /// Identifies a specific channel, unique to each mining connection. + /// + /// Dynamically assigned when a mining connection is established (as part of the negotiation + /// process) to avoid conflicts with other connections (e.g. other mining devices) managed by + /// the same upstream role. The identifier remains stable for the whole lifetime of the + /// connection. + /// + /// Used for broadcasting new jobs by [`mining_sv2::NewExtendedMiningJob`]. pub channel_id: u32, - /// Identifier of the group where the standard channel belongs + + /// Identifies a specific group in which the standard channel belongs. pub group_id: u32, - /// Initial target for the mining channel + + /// Initial difficulty target assigned to the mining. pub target: Target, - /// Extranonce bytes which need to be added to the coinbase to form a fully valid submission: - /// (full coinbase = coinbase_tx_prefix + extranonce_prefix + extranonce + coinbase_tx_suffix). + + /// Additional nonce value used to differentiate shares within the same channel. + /// + /// Helps to avoid nonce collisions when multiple mining devices are working on the same job. + /// + /// The extranonce bytes are added to the coinbase to form a fully valid submission: + /// `full coinbase = coinbase_tx_prefix + extranonce_prefix + extranonce + coinbase_tx_suffix` pub extranonce: Extranonce, } -/// General properties that every Sv2 compatible mining upstream node must implement. +/// Properties of a Sv2-compatible mining upstream role. +/// +/// This trait extends [`IsUpstream`] with additional functionality specific to mining, such as +/// hashrate management and channel updates. pub trait IsMiningUpstream + ?Sized>: IsUpstream { - /// should return total hash rate local to the node + /// Returns the total hashrate managed by the upstream role. fn total_hash_rate(&self) -> u64; - /// add hashrate to the node + + /// Adds hash rate to the upstream role. fn add_hash_rate(&mut self, to_add: u64); - /// get open channels on the node + + /// Returns the list of open channels on the upstream role. fn get_opened_channels(&mut self) -> &mut Vec; - /// update channels + + /// Updates the list of channels managed by the upstream role. fn update_channels(&mut self, c: UpstreamChannel); - /// check if node is limited to hom + + /// Checks if the upstream role supports header-only mining. fn is_header_only(&self) -> bool { has_requires_std_job(self.get_flags()) } } -/// General properties that every Sv2 compatible downstream node must implement. +/// Properties defining behaviors common to all Sv2 downstream roles. pub trait IsDownstream { - /// get downstream mining data + /// Returns the common properties of the downstream role (e.g. support for header-only mining, + /// work selection, and version rolling). fn get_downstream_mining_data(&self) -> CommonDownstreamData; } -/// General properties that every Sv2 compatible mining downstream node must implement. +/// Properties of a SV2-compatible mining downstream role. +/// +/// This trait extends [`IsDownstream`] with additional functionality specific to mining, such as +/// header-only mining checks. pub trait IsMiningDownstream: IsDownstream { - /// check if node is doing hom + /// Checks if the downstream role supports header-only mining. fn is_header_only(&self) -> bool { self.get_downstream_mining_data().header_only } } -// Implemented for the NullDownstreamMiningSelector +// Implemented for the `NullDownstreamMiningSelector`. impl IsUpstream for () { fn get_version(&self) -> u16 { unreachable!("Null upstream do not have a version"); @@ -134,7 +235,7 @@ impl IsUpstream for } } -// Implemented for the NullDownstreamMiningSelector +// Implemented for the `NullDownstreamMiningSelector`. impl IsDownstream for () { fn get_downstream_mining_data(&self) -> CommonDownstreamData { unreachable!("Null downstream do not have mining data"); @@ -160,18 +261,40 @@ impl IsMiningUpstream downstream ids + // A mapping between upstream-assigned request IDs and the original downstream IDs. + // + // In the hashmap, the key is the upstream request ID and the value is the corresponding + // downstream request ID. `BuildNoHashHasher` is an optimization to bypass the hashing step for + // integer keys. request_ids_map: HashMap>, + + // A counter for assigning unique request IDs to upstream nodes, incrementing after every + // assignment. next_id: u32, } impl RequestIdMapper { - /// Builds a new `RequestIdMapper` initialized with an empty hashmap and initializes `next_id` - /// to `0`. + /// Creates a new [`RequestIdMapper`] instance. pub fn new() -> Self { Self { request_ids_map: HashMap::with_hasher(BuildNoHashHasher::default()), @@ -179,16 +302,19 @@ impl RequestIdMapper { } } - /// Updates the `RequestIdMapper` with a new upstream/downstream mapping. + /// Assigns a new upstream request ID for a request sent by a downstream node. + /// + /// Ensures every request forwarded to the upstream node has a unique ID while retaining + /// traceability to the original downstream request. pub fn on_open_channel(&mut self, id: u32) -> u32 { - let new_id = self.next_id; - self.next_id += 1; + let new_id = self.next_id; // Assign new upstream ID + self.next_id += 1; // Increment next_id for future requests - self.request_ids_map.insert(new_id, id); + self.request_ids_map.insert(new_id, id); // Map new upstream ID to downstream ID new_id } - /// Removes a upstream/downstream mapping from the `RequestIdMapper`. + /// Removes the mapping for a request ID once the response has been processed. pub fn remove(&mut self, upstream_id: u32) -> Option { self.request_ids_map.remove(&upstream_id) }