Skip to content

Commit

Permalink
Merge pull request #1242 from jbesraa/2024-10-29-common-msgs-docs
Browse files Browse the repository at this point in the history
`common_messages_sv2` docs
  • Loading branch information
plebhash authored Dec 9, 2024
2 parents 2543595 + aadf42d commit 407c642
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 81 deletions.
14 changes: 7 additions & 7 deletions protocols/v2/subprotocols/common-messages/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ keywords = ["stratum", "mining", "bitcoin", "protocol"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
serde = { version = "1.0.89", default-features = false, optional= true }
binary_sv2 = {version = "^1.0.0", path = "../../../../protocols/v2/binary-sv2/binary-sv2" }
const_sv2 = {version = "^2.0.0", path = "../../../../protocols/v2/const-sv2"}
quickcheck = { version = "1.0.3", optional=true }
quickcheck_macros = { version = "1", optional=true }
serde_repr = {version= "0.1.10", optional=true}
serde = { version = "1.0.89", default-features = false, optional = true }
binary_sv2 = { version = "^1.0.0", path = "../../binary-sv2/binary-sv2" }
const_sv2 = { version = "^2.0.0", path = "../../const-sv2" }
quickcheck = { version = "1.0.3", optional = true }
quickcheck_macros = { version = "1", optional = true }
serde_repr = { version= "0.1.10", optional = true }

[features]
no_std = []
with_serde = ["binary_sv2/with_serde", "serde", "serde_repr"]
prop_test = ["quickcheck"]

[package.metadata.docs.rs]
all-features = true
all-features = true
30 changes: 30 additions & 0 deletions protocols/v2/subprotocols/common-messages/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# common_messages_sv2

[![crates.io](https://img.shields.io/crates/v/common_messages_sv2.svg)](https://crates.io/crates/common_messages_sv2)
[![docs.rs](https://docs.rs/common_messages_sv2/badge.svg)](https://docs.rs/common_messages_sv2)
[![rustc+](https://img.shields.io/badge/rustc-1.75.0%2B-lightgrey.svg)](https://blog.rust-lang.org/2023/12/28/Rust-1.75.0.html)
[![license](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](https://github.com/stratum-mining/stratum/blob/main/LICENSE.md)
[![codecov](https://codecov.io/gh/stratum-mining/stratum/branch/main/graph/badge.svg)](https://app.codecov.io/gh/stratum-mining/stratum/tree/main/protocols%2Fv2%2Fcommon_messages_sv2)

`common_messages_sv2` is a Rust crate that implements a set of messages shared across all Stratum V2 subprotocols.

For further information, please refer to [Stratum V2 documentation - Common Messages](https://stratumprotocol.org/specification/03-Protocol-Overview/#36-common-protocol-messages).

## Build Options

This crate can be built with the following features:

- `std`: Enables support for standard library features.
- `serde`: Enables support for serialization and deserialization using Serde.
- `quickcheck`: Enables support for property-based testing using QuickCheck.

*Note that `serde` feature flag is only used for the Message Generator, and deprecated for any
other kind of usage. It will likely be fully deprecated in the future.*

## Usage

To include this crate in your project, run:

```bash
$ cargo add common_messages_sv2
```
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
20 changes: 17 additions & 3 deletions protocols/v2/subprotocols/common-messages/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
//! # Stratum V2 Common Messages Crate.
//!
//! This crate defines a set of shared messages used across all Stratum V2 subprotocols.
//!
//! ## Build Options
//! This crate can be built with the following features:
//! - `std`: Enables support for standard library features.
//! - `serde`: Enables support for serialization and deserialization using Serde.
//! - `quickcheck`: Enables support for property-based testing using QuickCheck.
//!
//! *Note that `serde` feature flag is only used for the Message Generator, and deprecated for any
//! other kind of usage. It will likely be fully deprecated in the future.*
//!
//! 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 +35,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
146 changes: 100 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,61 @@ 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.
/// Used by downstream to initiate a Stratum V2 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 --//
/// Device vendor name.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub vendor: Str0255<'decoder>,
/// Device hardware version.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub hardware_version: Str0255<'decoder>,
/// Device firmware version.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub firmware: Str0255<'decoder>,
/// 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 +143,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 +155,73 @@ 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)
}
}

/// Helper function to check if `REQUIRES_STANDARD_JOBS` bit flag present.
pub fn has_requires_std_job(flags: u32) -> bool {
let flags = flags.reverse_bits();
let flag = flags >> 31;
flag != 0
}

/// Helper function to check if `REQUIRES_VERSION_ROLLING` bit flag present.
pub fn has_version_rolling(flags: u32) -> bool {
let flags = flags.reverse_bits();
let flags = flags << 1;
let flag = flags >> 31;
flag != 0
}

/// Helper function to check if `REQUIRES_WORK_SELECTION` bit flag present.
pub fn has_work_selection(flags: u32) -> bool {
let flags = flags.reverse_bits();
let flags = flags << 2;
let flag = flags >> 31;
flag != 0
}

/// C representation of [`SetupConnection`]
#[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,
/// Device vendor name.
pub vendor: CVec,
/// Device hardware version.
pub hardware_version: CVec,
/// Device firmware version.
pub firmware: CVec,
/// 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 +279,59 @@ 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.
///
/// In case `error_code` is `unsupported-feature-flags`, this field is used to indicate which
/// flag is causing an error, otherwise it will be set to 0.
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 [`SetupConnectionError`]
pub struct CSetupConnectionError {
flags: u32,
error_code: CVec,
Expand All @@ -289,6 +341,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 +375,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`],
/// This enum has a list of the different Stratum V2 subprotocols.
#[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
Loading

0 comments on commit 407c642

Please sign in to comment.