Skip to content

Commit

Permalink
Rewrite docs in common_messages_sv2 ..
Browse files Browse the repository at this point in the history
As part of the effort to improve Stratum V2 protocols docs, this commit
aims to improves and make the documentation more comprehensive and
accessible for contributors and end users alike.
  • Loading branch information
jbesraa committed Nov 19, 2024
1 parent c971fab commit 0621c39
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,18 @@ use binary_sv2::{Deserialize, Serialize};
#[cfg(not(feature = "with_serde"))]
use core::convert::TryInto;

/// ## ChannelEndpointChanged (Server -> Client)
/// When a channel’s upstream or downstream endpoint changes and that channel had previously
/// sent messages with [channel_msg] bitset of unknown extension_type, the intermediate proxy
/// MUST send a [`ChannelEndpointChanged`] message. Upon receipt thereof, any extension state
/// (including version negotiation and the presence of support for a given extension) MUST be
/// reset and version/presence negotiation must begin again.
/// Message used by an upstream role for announcing a mining channel endpoint change.
///
/// This message should be sent when a mining channel’s upstream or downstream endpoint changes and
/// that channel had previously exchanged message(s) with `channel_msg` bitset of unknown
/// `extension_type`.
///
/// When a downstream receives such a message, any extension state (including version and extension
/// support) must be reset and renegotiated.
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub struct ChannelEndpointChanged {
/// The channel which has changed endpoint.
/// Unique identifier of the channel that has changed its endpoint.
pub channel_id: u32,
}
#[cfg(feature = "with_serde")]
Expand Down
14 changes: 11 additions & 3 deletions protocols/v2/subprotocols/common-messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
//! # Stratum V2 Common Messages Crate.
//!
//! The following crate defines a set of shared messages used across multiple Stratum V2 roles.
//!
//! This crate offers feature flags to enable or disable the use of `std`, `serde` or `quickcheck`
//! dependencies.
//!
//! For further information about the messages, please refer to [Stratum V2
//! documentation - Common Messages](https://stratumprotocol.org/specification/03-Protocol-Overview/#36-common-protocol-messages).
#![cfg_attr(feature = "no_std", no_std)]

//! Common messages for [stratum v2][Sv2]
//! The following protocol messages are common across all of the sv2 (sub)protocols.
extern crate alloc;
mod channel_endpoint_changed;
mod setup_connection;
Expand All @@ -23,10 +29,12 @@ pub use setup_connection::{CSetupConnection, CSetupConnectionError};

#[cfg(not(feature = "with_serde"))]
#[no_mangle]
/// A C-compatible function that exports the [`ChannelEndpointChanged`] struct.
pub extern "C" fn _c_export_channel_endpoint_changed(_a: ChannelEndpointChanged) {}

#[cfg(not(feature = "with_serde"))]
#[no_mangle]
/// A C-compatible function that exports the `SetupConnection` struct.
pub extern "C" fn _c_export_setup_conn_succ(_a: SetupConnectionSuccess) {}

#[cfg(feature = "prop_test")]
Expand Down
159 changes: 113 additions & 46 deletions protocols/v2/subprotocols/common-messages/src/setup_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,62 @@ use core::convert::TryInto;
#[cfg(feature = "with_serde")]
use serde_repr::*;

/// ## SetupConnection (Client -> Server)
/// Initiates the connection. This MUST be the first message sent by the client on the newly
/// opened connection. Server MUST respond with either a [`SetupConnectionSuccess`] or
/// [`SetupConnectionError`] message. Clients that are not configured to provide telemetry data to
/// the upstream node SHOULD set device_id to 0-length strings. However, they MUST always set
/// vendor to a string describing the manufacturer/developer and firmware version and SHOULD
/// always set hardware_version to a string describing, at least, the particular hardware/software
/// package in use.
/// Message used by a downstream role to initiate a Stratum V2 channel connection with an upstream
/// role.
///
/// This is usually the first message sent by a downstream role on a newly opened connection,
/// after completing the handshake process.
///
/// Downstreams that do not wish to provide telemetry data to the upstream role **should** set
/// [`SetupConnection::device_id`] to an empty string. However, they **must** set
/// [`SetupConnection::vendor`] to a string describing the manufacturer/developer and firmware
/// version and **should** set [`SetupConnection::hardware_version`] to a string describing, at
/// least, the particular hardware/software package in use.
///
/// A valid response to this message from the upstream role can either be [`SetupConnectionSuccess`]
/// or [`SetupConnectionError`] message.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct SetupConnection<'decoder> {
/// [`Protocol`]
/// Protocol to be used for the connection.
pub protocol: Protocol,
/// The minimum protocol version the client supports (currently must be 2).
/// The minimum protocol version supported.
///
/// Currently must be set to 2.
pub min_version: u16,
/// The maximum protocol version the client supports (currently must be 2).
/// The maximum protocol version supported.
///
/// Currently must be set to 2.
pub max_version: u16,
/// Flags indicating optional protocol features the client supports. Each
/// protocol from [`SetupConnection.protocol`] field has its own values/flags.
/// Flags indicating optional protocol features supported by the downstream.
///
/// Each [`SetupConnection::protocol`] value has it's own flags.
pub flags: u32,
/// ASCII text indicating the hostname or IP address.
/// ASCII representation of the connection hostname or IP address.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub endpoint_host: Str0255<'decoder>,
/// Connecting port value
/// Connection port value.
pub endpoint_port: u16,
//-- DEVICE INFORMATION --//
/// ASCII representation of the device vendor name.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub vendor: Str0255<'decoder>,
/// ASCII representation of the device hardware version.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub hardware_version: Str0255<'decoder>,
/// ASCII representation of the device firmware version.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub firmware: Str0255<'decoder>,
/// ASCII representation of the device identifier.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub device_id: Str0255<'decoder>,
}

impl<'decoder> SetupConnection<'decoder> {
/// Set the flag to indicate that the downstream requires a standard job
pub fn set_requires_standard_job(&mut self) {
self.flags |= 0b_0000_0000_0000_0000_0000_0000_0000_0001;
}

/// Set the flag to indicate that the downstream requires an asynchronous job negotiation
pub fn set_async_job_nogotiation(&mut self) {
self.flags |= 0b_0000_0000_0000_0000_0000_0000_0000_0001;
}
Expand Down Expand Up @@ -128,7 +144,10 @@ impl<'decoder> SetupConnection<'decoder> {
}
}

/// Check if passed versions support self versions if yes return the biggest version available
/// Check whether received versions are supported.
///
/// If the versions are not supported, return `None` otherwise return the biggest version
/// available
pub fn get_version(&self, min_version: u16, max_version: u16) -> Option<u16> {
if self.min_version > max_version || min_version > self.max_version {
None
Expand All @@ -137,49 +156,86 @@ impl<'decoder> SetupConnection<'decoder> {
}
}

/// Checks whether passed flags indicate that the downstream requires standard job.
pub fn requires_standard_job(&self) -> bool {
has_requires_std_job(self.flags)
}
}

/// Checks if the flags include the Requires Standard Job flag.
pub fn has_requires_std_job(flags: u32) -> bool {
let flags = flags.reverse_bits();
let flag = flags >> 31;
flag != 0
}

/// Checks if the flags include the Version Rolling flag.
pub fn has_version_rolling(flags: u32) -> bool {
let flags = flags.reverse_bits();
let flags = flags << 1;
let flag = flags >> 31;
flag != 0
}

/// Checks if the flags include the Work Selection flag.
pub fn has_work_selection(flags: u32) -> bool {
let flags = flags.reverse_bits();
let flags = flags << 2;
let flag = flags >> 31;
flag != 0
}

/// Message used by a downstream role to initiate a Stratum V2 channel connection with an upstream
/// role.
///
/// This is usually the first message sent by a downstream role on a newly opened connection,
/// after completing the handshake process.
///
/// Downstreams that do not wish to provide telemetry data to the upstream role **should** set
/// [`SetupConnection::device_id`] to an empty string. However, they **must** set
/// [`SetupConnection::vendor`] to a string describing the manufacturer/developer and firmware
/// version and **should** set [`SetupConnection::hardware_version`] to a string describing, at
/// least, the particular hardware/software package in use.
///
/// A valid response to this message from the upstream role can either be [`SetupConnectionSuccess`]
/// or [`SetupConnectionError`] message.
#[repr(C)]
#[cfg(not(feature = "with_serde"))]
#[derive(Debug, Clone)]
pub struct CSetupConnection {
/// Protocol to be used for the connection.
pub protocol: Protocol,
/// The minimum protocol version supported.
///
/// Currently must be set to 2.
pub min_version: u16,
/// The maximum protocol version supported.
///
/// Currently must be set to 2.
pub max_version: u16,
/// Flags indicating optional protocol features supported by the downstream.
///
/// Each [`SetupConnection::protocol`] value has it's own flags.
pub flags: u32,
/// ASCII representation of the connection hostname or IP address.
pub endpoint_host: CVec,
/// Connection port value.
pub endpoint_port: u16,
/// ASCII representation of the device vendor name.
pub vendor: CVec,
/// ASCII representation of the device hardware version.
pub hardware_version: CVec,
/// ASCII representation of the device firmware version.
pub firmware: CVec,
/// ASCII representation of the device identifier.
pub device_id: CVec,
}

#[cfg(not(feature = "with_serde"))]
impl<'a> CSetupConnection {
#[cfg(not(feature = "with_serde"))]
#[allow(clippy::wrong_self_convention)]
/// Convert C representation to Rust representation
pub fn to_rust_rep_mut(&'a mut self) -> Result<SetupConnection<'a>, Error> {
let endpoint_host: Str0255 = self.endpoint_host.as_mut_slice().try_into()?;
let vendor: Str0255 = self.vendor.as_mut_slice().try_into()?;
Expand Down Expand Up @@ -237,49 +293,58 @@ impl<'a> From<SetupConnection<'a>> for CSetupConnection {
}
}

/// ## SetupConnection.Success (Server -> Client)
/// Response to [`SetupConnection`] message if the server accepts the connection. The client is
/// required to verify the set of feature flags that the server supports and act accordingly.
/// Message used by an upstream role to accept a connection setup request from a downstream role.
///
/// This message is sent in response to a [`SetupConnection`] message.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy)]
#[repr(C)]
pub struct SetupConnectionSuccess {
/// Selected version proposed by the connecting node that the upstream
/// node supports. This version will be used on the connection for the rest
/// of its life.
/// Selected version based on the [`SetupConnection::min_version`] and
/// [`SetupConnection::max_version`] sent by the downstream role.
///
/// This version will be used on the connection for the rest of its life.
pub used_version: u16,
/// Flags indicating optional protocol features the server supports. Each
/// protocol from [`Protocol`] field has its own values/flags.
/// Flags indicating optional protocol features supported by the upstream.
///
/// The downstream is required to verify this set of flags and act accordingly.
///
/// Each [`SetupConnection::protocol`] field has its own values/flags.
pub flags: u32,
}

/// ## SetupConnection.Error (Server -> Client)
/// When protocol version negotiation fails (or there is another reason why the upstream node
/// cannot setup the connection) the server sends this message with a particular error code prior
/// to closing the connection.
/// In order to allow a client to determine the set of available features for a given server (e.g.
/// for proxies which dynamically switch between different pools and need to be aware of supported
/// options), clients SHOULD send a SetupConnection message with all flags set and examine the
/// (potentially) resulting [`SetupConnectionError`] message’s flags field. The Server MUST provide
/// the full set of flags which it does not support in each [`SetupConnectionError`] message and
/// MUST consistently support the same set of flags across all servers on the same hostname and
/// port number. If flags is 0, the error is a result of some condition aside from unsupported
/// flags.
/// Message used by an upstream role to reject a connection setup request from a downstream role.
///
/// This message is sent in response to a [`SetupConnection`] message.
///
/// The connection setup process could fail because of protocol version negotiation. In order
/// to allow a downstream to determine the set of available features for a given upstream (e.g. for
/// proxies which dynamically switch between different pools and need to be aware of supported
/// options), downstream should send a [`SetupConnection`] message with all flags set and examine
/// the (potentially) resulting [`SetupConnectionError`] message’s flags field.
///
/// The upstream must provide the full set of flags which it does not support in each
/// [`SetupConnectionError`] message and must consistently support the same set of flags across all
/// servers on the same hostname and port number.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct SetupConnectionError<'decoder> {
/// Flags indicating features causing an error.
/// Unsupported feature flags.
///
/// If set to 0, then this error is not due to unsupported flags.
pub flags: u32,
/// Human-readable error code(s). See Error Codes section, [link].
/// ### Possible error codes:
/// * ‘unsupported-feature-flags’
/// * ‘unsupported-protocol’
/// * ‘protocol-version-mismatch’
/// Reason for setup connection error.
///
/// Possible error codes:
/// - unsupported-feature-flags
/// - unsupported-protocol
/// - protocol-version-mismatch
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub error_code: Str0255<'decoder>,
}

#[repr(C)]
#[cfg(not(feature = "with_serde"))]
#[derive(Debug, Clone)]
/// C representation of [`SetupConnectionSuccess`]
pub struct CSetupConnectionError {
flags: u32,
error_code: CVec,
Expand All @@ -289,6 +354,7 @@ pub struct CSetupConnectionError {
impl<'a> CSetupConnectionError {
#[cfg(not(feature = "with_serde"))]
#[allow(clippy::wrong_self_convention)]
/// Convert C representation to Rust representation
pub fn to_rust_rep_mut(&'a mut self) -> Result<SetupConnectionError<'a>, Error> {
let error_code: Str0255 = self.error_code.as_mut_slice().try_into()?;

Expand Down Expand Up @@ -322,16 +388,17 @@ impl<'a> From<SetupConnectionError<'a>> for CSetupConnectionError {
}
}

/// MiningProtocol = [`SV2_MINING_PROTOCOL_DISCRIMINANT`],
/// JobDeclarationProtocol = [`SV2_JOB_DECLARATION_PROTOCOL_DISCRIMINANT`],
/// TemplateDistributionProtocol = [`SV2_TEMPLATE_DISTR_PROTOCOL_DISCRIMINANT`],
/// Represents the different Stratum V2 protocols.
#[cfg_attr(feature = "with_serde", derive(Serialize_repr, Deserialize_repr))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
#[allow(clippy::enum_variant_names)]
pub enum Protocol {
/// Mining protocol.
MiningProtocol = SV2_MINING_PROTOCOL_DISCRIMINANT,
/// Job declaration protocol.
JobDeclarationProtocol = SV2_JOB_DECLARATION_PROTOCOL_DISCRIMINANT,
/// Template distribution protocol.
TemplateDistributionProtocol = SV2_TEMPLATE_DISTR_PROTOCOL_DISCRIMINANT,
}

Expand Down

0 comments on commit 0621c39

Please sign in to comment.