Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

common_messages_sv2 docs #1242

Merged
merged 4 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)

GitGab19 marked this conversation as resolved.
Show resolved Hide resolved
`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.
GitGab19 marked this conversation as resolved.
Show resolved Hide resolved
- `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)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]

This isn't related to documentation, but either Copy or Clone can be removed, as both aren't necessary. Additionally, Eq is not required. This could be added to the refactoring tracker.

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.
GitGab19 marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't directly related to documentation, but we can create a separate prop_test module to consolidate all the generation code, instead of applying the feature gate to individual lines. This could be included as part of a refactoring issue.

//!
//! 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.
GitGab19 marked this conversation as resolved.
Show resolved Hide resolved
//! - `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.
GitGab19 marked this conversation as resolved.
Show resolved Hide resolved
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
Loading