diff --git a/protocols/v2/subprotocols/mining/README.md b/protocols/v2/subprotocols/mining/README.md index 813cdfe61b..67aad33815 100644 --- a/protocols/v2/subprotocols/mining/README.md +++ b/protocols/v2/subprotocols/mining/README.md @@ -7,8 +7,10 @@ [![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%2Fmining_sv2) `mining_sv2` is a Rust crate that implements a set of messages defined in the Mining protocol of Stratum V2. -The Mining protocol enables the distribution of work to mining devices and the submission of -proof-of-work results. +The Mining protocol enables: +- distribution of work to mining devices +- submission of proof of work from mining devices +- notification of custom work to pool (in conjunction with Job Declaration Subprotocol) For further information about the messages, please refer to [Stratum V2 documentation - Mining](https://stratumprotocol.org/specification/05-Mining-Protocol/). diff --git a/protocols/v2/subprotocols/mining/src/close_channel.rs b/protocols/v2/subprotocols/mining/src/close_channel.rs index 8aa8a7451a..2fe7deeb9d 100644 --- a/protocols/v2/subprotocols/mining/src/close_channel.rs +++ b/protocols/v2/subprotocols/mining/src/close_channel.rs @@ -6,20 +6,15 @@ use binary_sv2::{Deserialize, Serialize, Str0255}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # CloseChannel (Client -> Server, Server -> Client) +/// Message used by a downstream to close a mining channel. /// -/// Client sends this message when it ends its operation. The server MUST stop sending messages -/// for the channel. A proxy MUST send this message on behalf of all opened channels from a -/// downstream connection in case of downstream connection closure. +/// If you are sending this message through a proxy on behalf of multiple downstreams, you must send +/// it for each open channel separately. /// -/// If a proxy is operating in channel aggregating mode (translating downstream channels into -/// aggregated extended upstream channels), it MUST send an UpdateChannel message when it -/// receives CloseChannel or connection closure from a downstream connection. In general, proxy -/// servers MUST keep the upstream node notified about the real state of the downstream -/// channels. +/// Upon receiving this message, upstream **must** stop sending messages for the channel. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct CloseChannel<'decoder> { - /// Channel identification. + /// Channel id of the channel to be closed. pub channel_id: u32, /// Reason for closing the channel. #[cfg_attr(feature = "with_serde", serde(borrow))] diff --git a/protocols/v2/subprotocols/mining/src/lib.rs b/protocols/v2/subprotocols/mining/src/lib.rs index 83be80d0be..8f10f33b59 100644 --- a/protocols/v2/subprotocols/mining/src/lib.rs +++ b/protocols/v2/subprotocols/mining/src/lib.rs @@ -1,111 +1,33 @@ -#![cfg_attr(feature = "no_std", no_std)] - -//! # Mining Protocol -//! ## Channels -//! The protocol is designed such that downstream devices (or proxies) open communication -//! channels with upstream stratum nodes within established connections. The upstream stratum -//! endpoints could be actual mining servers or proxies that pass the messages further upstream. -//! Each channel identifies a dedicated mining session associated with an authorized user. -//! Upstream stratum nodes accept work submissions and specify a mining target on a -//! per-channel basis. -//! -//! There can theoretically be up to 2^32 open channels within one physical connection to an -//! upstream stratum node. All channels are independent of each other, but share some messages -//! broadcasted from the server for higher efficiency (e.g. information about a new prevhash). -//! Each channel is identified by its channel_id (U32), which is consistent throughout the whole -//! life of the connection. -//! -//! A proxy can either transparently allow its clients to open separate channels with the server -//! (preferred behaviour) or aggregate open connections from downstream devices into its own -//! open channel with the server and translate the messages accordingly (present mainly for -//! allowing v1 proxies). Both options have some practical use cases. In either case, proxies -//! SHOULD aggregate clients’ channels into a smaller number of TCP connections. This saves -//! network traffic for broadcast messages sent by a server because fewer messages need to be -//! sent in total, which leads to lower latencies as a result. And it further increases efficiency -//! by allowing larger packets to be sent. -//! -//! The protocol defines three types of channels: **standard channels** , **extended channels** -//! (mining sessions) and **group channels** (organizational), which are useful for different -//! purposes. The main difference between standard and extended channels is that standard channels -//! cannot manipulate the coinbase transaction / Merkle path, as they operate solely on provided -//! Merkle roots. We call this **header-only mining**. Extended channels, on the other hand, are -//! given extensive control over the search space so that they can implement various advanceduse -//! cases such as translation between v1 and v2 protocols, difficulty aggregation, custom -//! search space splitting, etc. -//! -//! This separation vastly simplifies the protocol implementation for clients that don’t support -//! extended channels, as they only need to implement the subset of protocol messages related to -//! standard channels (see Mining Protocol Messages for details). -//! -//! ### Standard Channels +//! # Stratum V2 Mining Protocol Messages Crate //! -//! Standard channels are intended to be used by end mining devices. -//! The size of the search space for one standard channel (header-only mining) for one particular -//! value in the nTime field is 2^(NONCE_BITS + VERSION_ROLLING_BITS) = ~280Th, where -//! NONCE_BITS = 32 and VERSION_ROLLING_BITS = 16. This is a guaranteed space before -//! nTime rolling (or changing the Merkle root). -//! The protocol dedicates all directly modifiable bits (version, nonce, and nTime) from the block -//! header to one mining channel. This is the smallest assignable unit of search space by the -//! protocol. The client which opened the particular channel owns the whole assigned space and -//! can split it further if necessary (e.g. for multiple hashing boards and for individual chips -//! etc.). +//! `mining_sv2` is a Rust crate that implements a set of messages defined in the Mining protocol +//! of Stratum V2. //! -//! ### Extended channels +//! The Mining protocol enables the distribution of work to mining devices and the submission of +//! proof-of-work results. //! -//! Extended channels are intended to be used by proxies. Upstream servers which accept -//! connections and provide work MUST support extended channels. Clients, on the other hand, do -//! not have to support extended channels, as they MAY be implemented more simply with only -//! standard channels at the end-device level. Thus, upstream servers providing work MUST also -//! support standard channels. -//! The size of search space for an extended channel is -//! 2^(NONCE_BITS+VERSION_ROLLING_BITS+extranonce_size*8) per nTime value. +//! For further information about the messages, please refer to [Stratum V2 documentation - Mining](https://stratumprotocol.org/specification/05-Mining-Protocol/). //! -//! ### Group Channels +//! ## Build Options //! -//! Standard channels opened within one particular connection can be grouped together to be -//! addressable by a common communication group channel. -//! Whenever a standard channel is created it is always put into some channel group identified by -//! its group_channel_id. Group channel ID namespace is the same as channel ID namespace on a -//! particular connection but the values chosen for group channel IDs must be distinct. +//! This crate can be built with the following features: +//! - `no_std`: Disables the standard library. +//! - `with_serde`: Enables support for serialization and deserialization using Serde. //! -//! ### Future Jobs -//! An empty future block job or speculated non-empty job can be sent in advance to speedup -//! new mining job distribution. The point is that the mining server MAY have precomputed such a -//! job and is able to pre-distribute it for all active channels. The only missing information to -//! start to mine on the new block is the new prevhash. This information can be provided -//! independently.Such an approach improves the efficiency of the protocol where the upstream node -//! doesn’t waste precious time immediately after a new block is found in the network. +//! **Note that `with_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.** //! -//! ### Hashing Space Distribution -//! Each mining device has to work on a unique part of the whole search space. The full search -//! space is defined in part by valid values in the following block header fields: -//! * Nonce header field (32 bits), -//! * Version header field (16 bits, as specified by BIP 320), -//! * Timestamp header field. +//! ## Usage //! -//! The other portion of the block header that’s used to define the full search space is the Merkle -//! root hash of all transactions in the block, projected to the last variable field in the block -//! header: +//! To include this crate in your project, run: +//! ```bash +//! $ cargo add mining_sv2 +//! ``` //! -//! * Merkle root, deterministically computed from: -//! * Coinbase transaction: typically 4-8 bytes, possibly much more. -//! * Transaction set: practically unbounded space. All roles in Stratum v2 MUST NOT use -//! transaction selection/ordering for additional hash space extension. This stems both from the -//! concept that miners/pools should be able to choose their transaction set freely without any -//! interference with the protocol, and also to enable future protocol modifications to Bitcoin. -//! In other words, any rules imposed on transaction selection/ordering by miners not described -//! in the rest of this document may result in invalid work/blocks. -//! -//! Mining servers MUST assign a unique subset of the search space to each connection/channel -//! (and therefore each mining device) frequently and rapidly enough so that the mining devices -//! are not running out of search space. Unique jobs can be generated regularly by: -//! * Putting unique data into the coinbase for each connection/channel, and/or -//! * Using unique work from a work provider, e.g. a previous work update (note that this is likely -//! more difficult to implement, especially in light of the requirement that transaction -//! selection/ordering not be used explicitly for additional hash space distribution). -//! -//! This protocol explicitly expects that upstream server software is able to manage the size of -//! the hashing space correctly for its clients and can provide new jobs quickly enough. +//! For further information about the mining protocol, please refer to [Stratum V2 documentation - +//! Mining Protocol](https://stratumprotocol.org/specification/05-Mining-Protocol/). +#![cfg_attr(feature = "no_std", no_std)] use binary_sv2::{B032, U256}; use core::{ cmp::{Ord, PartialOrd}, @@ -215,9 +137,11 @@ impl Ord for Target { // WARNING: do not derive Copy on this type. Some operations performed to a copy of an extranonce // do not affect the original, and this may lead to different extranonce inconsistency -/// Extranonce bytes which need to be added to the coinbase to form a fully valid submission: -/// (full coinbase = coinbase_tx_prefix + extranonce + coinbase_tx_suffix). +/// Extranonce bytes which need to be added to the coinbase to form a fully valid submission. +/// /// Representation is in big endian, so tail is for the digits relative to smaller powers +/// +/// `full coinbase = coinbase_tx_prefix + extranonce + coinbase_tx_suffix`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Extranonce { extranonce: alloc::vec::Vec, @@ -334,9 +258,9 @@ impl From<&mut ExtendedExtranonce> for Extranonce { } #[derive(Debug, Clone)] -/// Downstram and upstream are not global terms but are relative -/// to an actor of the protocol P. In simple terms, upstream is the part of the protocol that a -/// user P sees when he looks above and downstream when he looks beneath. +/// Downstram and upstream are relative to an actor of the protocol P. In simple terms, upstream is +/// the part of the protocol that a user P sees when he looks above and downstream when he looks +/// beneath. /// /// An ExtendedExtranonce is defined by 3 ranges: /// @@ -375,7 +299,6 @@ impl From<&mut ExtendedExtranonce> for Extranonce { /// range_2 -> 32..32 no more downstream /// /// -/// /// About how the pool work having both extended and standard downstreams: /// /// the pool reserve the first 16 bytes for herself and let downstreams change the lase 16, so @@ -397,7 +320,6 @@ impl From<&mut ExtendedExtranonce> for Extranonce { /// 0000 0000 0000 0000 0000 0000 0000 0001 ecc ecc /// /// -/// /// ExtendedExtranonce type is meant to be used in cases where the extranonce length is not /// 32bytes. So, the inner part is an array of 32bytes, but only the firsts corresponding to the /// range_2.end are used by the pool diff --git a/protocols/v2/subprotocols/mining/src/new_mining_job.rs b/protocols/v2/subprotocols/mining/src/new_mining_job.rs index 042f17e680..ab83e59bf7 100644 --- a/protocols/v2/subprotocols/mining/src/new_mining_job.rs +++ b/protocols/v2/subprotocols/mining/src/new_mining_job.rs @@ -6,35 +6,48 @@ use binary_sv2::{Deserialize, Seq0255, Serialize, Sv2Option, B032, B064K, U256}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # NewMiningJob (Server -> Client) +/// Message used by an upstream to provide an updated mining job to downstream. /// -/// The server provides an updated mining job to the client through a standard channel. This MUST be -/// the first message after the channel has been successfully opened. This first message will have -/// min_ntime unset (future job). If the `min_ntime` field is set, the client MUST start to mine on -/// the new job immediately after receiving this message, and use the value for the initial nTime. - +/// This is used for Standard Channels only. +/// +/// Note that Standard Jobs distrbuted through this message are restricted to a fixed Merkle Root, +/// and the only rollable bits are `version`, `nonce`, and `nTime` fields of the block header. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct NewMiningJob<'decoder> { - /// Channel identifier, this must be a standard channel. + /// Channel identifier for the channel that this job is valid for. + /// + /// This must be a Standard Channel. pub channel_id: u32, - /// Server’s identification of the mining job. This identifier must be provided - /// to the server when shares are submitted later in the mining process. + /// Upstream’s identification of the mining job. + /// + /// This identifier must be provided to the upstream when shares are submitted. pub job_id: u32, - /// Smallest nTime value available for hashing for the new mining job. An empty value indicates - /// this is a future job to be activated once a SetNewPrevHash message is received with a - /// matching job_id. This SetNewPrevHash message provides the new prev_hash and min_ntime. - /// If the min_ntime value is set, this mining job is active and miner must start mining on it - /// immediately. In this case, the new mining job uses the prev_hash from the last received - /// SetNewPrevHash message. + /// Smallest `nTime` value available for hashing for the new mining job. + /// + /// An empty value indicates this is a future job and will be ready to mine on once a + /// [`SetNewPrevHash`] message is received with a matching `job_id`. + /// [`SetNewPrevHash`] message will also provide `prev_hash` and `min_ntime`. + /// + /// Otherwise, if [`NewMiningJob::min_ntime`] value is set, the downstream must start mining on + /// it immediately. In this case, the new mining job uses the `prev_hash` from the last + /// received [`SetNewPrevHash`] message. + /// + /// [`SetNewPrevHash`]: crate::SetNewPrevHash #[cfg_attr(feature = "with_serde", serde(borrow))] pub min_ntime: Sv2Option<'decoder, u32>, - /// Valid version field that reflects the current network consensus. The - /// general purpose bits (as specified in BIP320) can be freely manipulated - /// by the downstream node. The downstream node MUST NOT rely on the - /// upstream node to set the BIP320 bits to any particular value. + /// Version field that reflects the current network consensus. + /// + /// As specified in [BIP320](https://github.com/bitcoin/bips/blob/master/bip-0320.mediawiki), + /// the general purpose bits can be freely manipulated by the downstream node. + /// + /// The downstream node must not rely on the upstream node to set the + /// [BIP320](https://github.com/bitcoin/bips/blob/master/bip-0320.mediawiki) bits to any + /// particular value. pub version: u32, /// Merkle root field as used in the bitcoin block header. + /// + /// Note that this field is fixed and cannot be modified by the downstream node. #[cfg_attr(feature = "with_serde", serde(borrow))] pub merkle_root: B032<'decoder>, } @@ -51,59 +64,74 @@ impl<'d> NewMiningJob<'d> { } } -/// NewExtendedMiningJob (Server -> Client) +/// Message used by an upstream to provide an updated mining job to the downstream through +/// Extended or Group Channel only. +/// +/// An Extended Job allows rolling Merkle Roots, giving extensive control over the search space +/// so that they can implement various advanced use cases such as: translation between Sv1 and Sv2 +/// protocols, difficulty aggregation and search space splitting. +/// +/// In the Extended Channel scenario, the full coinbase transaction is reconstructed as: +/// - `NewExtendedMiningJob::coinbase_tx_prefix` +/// - `OpenExtendedMiningChannel.Success::extranonce_size` +/// - `SubmitSharesExtended::extranonce` +/// - `NewExtendedMiningJob::coinbase_tx_suffix` +/// +/// In the Group Channel scenario, the full coinbase transaction is reconstructed as: +/// - `NewExtendedMiningJob::coinbase_tx_prefix` +/// - `OpenStandardMiningChannel.Success::extranonce_size` (unique per Standard Channel) +/// - `SubmitSharesExtended::extranonce` +/// - `NewExtendedMiningJob::coinbase_tx_suffix` /// -/// (Extended and group channels only) -/// For an *extended channel*: The whole search space of the job is owned by the specified -/// channel. If the future_job field is set to *False,* the client MUST start to mine on the new job -/// as soon as possible after receiving this message. -/// For a *group channel*: This is a broadcast variant of NewMiningJob message with the -/// merkle_root field replaced by merkle_path and coinbase TX prefix and suffix, for further traffic -/// optimization. The Merkle root is then defined deterministically for each channel by the -/// common merkle_path and unique extranonce_prefix serialized into the coinbase. The full -/// coinbase is then constructed as follows: *coinbase_tx_prefix* + *extranonce_prefix* + -/// *coinbase_tx_suffix*. The proxy MAY transform this multicast variant for downstream standard -/// channels into NewMiningJob messages by computing the derived Merkle root for them. A proxy MUST -/// translate the message for all downstream channels belonging to the group which don’t signal -/// that they accept extended mining jobs in the SetupConnection message (intended and -/// expected behaviour for end mining devices). +/// [`extranonce_size`]: crate::OpenExtendedMiningChannelSuccess::extranonce_size #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct NewExtendedMiningJob<'decoder> { - /// For a group channel, the message is broadcasted to all standard - /// channels belonging to the group. Otherwise, it is addressed to - /// the specified extended channel. + /// Identifier of the Extended Mining Channel that this job is valid for. + /// + /// For a Group Channel, the message is broadcasted to all standard channels belonging to the + /// group. pub channel_id: u32, - /// Server’s identification of the mining job. + /// Upstream’s identification of the mining job. + /// + /// This identifier must be provided to the upstream when shares are submitted later in the + /// mining process. pub job_id: u32, - /// Smallest nTime value available for hashing for the new mining job. An empty value indicates - /// this is a future job to be activated once a SetNewPrevHash message is received with a - /// matching job_id. This SetNewPrevHash message provides the new prev_hash and min_ntime. - /// If the min_ntime value is set, this mining job is active and miner must start mining on it - /// immediately. In this case, the new mining job uses the prev_hash from the last received - /// SetNewPrevHash message. + /// Smallest `nTime` value available for hashing for the new mining job. + /// + /// An empty value indicates this is a future job and will be ready to mine on once a + /// [`SetNewPrevHash`] message is received with a matching `job_id`. + /// [`SetNewPrevHash`] message will also provide `prev_hash` and `min_ntime`. + /// + /// Otherwise, if [`NewMiningJob::min_ntime`] value is set, the downstream must start mining on + /// it immediately. In this case, the new mining job uses the `prev_hash` from the last + /// received [`SetNewPrevHash`] message. + /// + /// [`SetNewPrevHash`]: crate::SetNewPrevHash #[cfg_attr(feature = "with_serde", serde(borrow))] pub min_ntime: Sv2Option<'decoder, u32>, - /// Valid version field that reflects the current network consensus. + /// Version field that reflects the current network consensus. + /// + /// As specified in [BIP320](https://github.com/bitcoin/bips/blob/master/bip-0320.mediawiki), + /// the general purpose bits can be freely manipulated by the downstream node. + /// + /// The downstream node must not rely on the upstream node to set the + /// [BIP320](https://github.com/bitcoin/bips/blob/master/bip-0320.mediawiki) bits to any + /// particular value. pub version: u32, - /// If set to True, the general purpose bits of version (as specified in - /// BIP320) can be freely manipulated by the downstream node. - /// The downstream node MUST NOT rely on the upstream node to - /// set the BIP320 bits to any particular value. - /// If set to False, the downstream node MUST use version as it is + /// If set to `true`, the general purpose bits of [`NewExtendedMiningJob::version`] (as + /// specified in BIP320) can be freely manipulated by the downstream node. + /// + /// If set to `false`, the downstream node must use [`NewExtendedMiningJob::version`] as it is /// defined by this message. pub version_rolling_allowed: bool, - #[cfg_attr(feature = "with_serde", serde(borrow))] /// Merkle path hashes ordered from deepest. + #[cfg_attr(feature = "with_serde", serde(borrow))] pub merkle_path: Seq0255<'decoder, U256<'decoder>>, /// Prefix part of the coinbase transaction. - /// The full coinbase is constructed by inserting one of the following: - /// * For a *standard channel*: extranonce_prefix - /// * For an *extended channel*: extranonce_prefix + extranonce (=N bytes), where N is the - /// negotiated extranonce space for the channel (OpenMiningChannel.Success.extranonce_size) #[cfg_attr(feature = "with_serde", serde(borrow))] pub coinbase_tx_prefix: B064K<'decoder>, - #[cfg_attr(feature = "with_serde", serde(borrow))] /// Suffix part of the coinbase transaction. + #[cfg_attr(feature = "with_serde", serde(borrow))] pub coinbase_tx_suffix: B064K<'decoder>, } diff --git a/protocols/v2/subprotocols/mining/src/open_channel.rs b/protocols/v2/subprotocols/mining/src/open_channel.rs index d64b1d0a7e..ca21bd07cc 100644 --- a/protocols/v2/subprotocols/mining/src/open_channel.rs +++ b/protocols/v2/subprotocols/mining/src/open_channel.rs @@ -9,41 +9,47 @@ use core::convert::TryInto; #[cfg(feature = "with_serde")] use core::convert::TryInto; -/// # OpenStandardMiningChannel (Client -> Server) -/// This message requests to open a standard channel to the upstream node. -/// After receiving a SetupConnection.Success message, the client SHOULD respond by opening -/// channels on the connection. If no channels are opened within a reasonable period the server -/// SHOULD close the connection for inactivity. -/// Every client SHOULD start its communication with an upstream node by opening a channel, -/// which is necessary for almost all later communication. The upstream node either passes -/// opening the channel further or has enough local information to handle channel opening on its -/// own (this is mainly intended for v1 proxies). -/// Clients must also communicate information about their hashing power in order to receive -/// well-calibrated job assignments. +/// Message used by a downstream to request opening a Standard Channel. +/// +/// Upon receiving `SetupConnectionSuccess` message, the downstream should open channel(s) on the +/// connection within a reasonable period, otherwise the upstream should close the connection for +/// inactivity. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct OpenStandardMiningChannel<'decoder> { - /// Client-specified identifier for matching responses from upstream server. - /// The value MUST be connection-wide unique and is not interpreted by - /// the server. + /// Specified by downstream role. + /// + /// Used for matching responses from upstream. + /// + /// The value must be connection-wide unique and is not interpreted by the upstream. #[cfg(not(feature = "with_serde"))] pub request_id: U32AsRef<'decoder>, + /// Specified by downstream role. + /// + /// Used for matching responses from upstream. + /// + /// The value must be connection-wide unique and is not interpreted by the upstream. #[cfg(feature = "with_serde")] pub request_id: u32, - /// Unconstrained sequence of bytes. Whatever is needed by upstream - /// node to identify/authenticate the client, e.g. “braiinstest.worker1”. - /// Additional restrictions can be imposed by the upstream node (e.g. a - /// pool). It is highly recommended that UTF-8 encoding is used. + /// Unconstrained sequence of bytes. + /// + /// Whatever is needed by upstream role to identify/authenticate the downstream, e.g. + /// “test.worker1”. + /// + /// Additional restrictions can be imposed by the upstream role (e.g. a pool). It is highly + /// recommended to use UTF-8 encoding. #[cfg_attr(feature = "with_serde", serde(borrow))] pub user_identity: Str0255<'decoder>, - /// [h/s] Expected hash rate of the device (or cumulative hashrate on the - /// channel if multiple devices are connected downstream) in h/s. - /// Depending on server’s target setting policy, this value can be used for - /// setting a reasonable target for the channel. Proxy MUST send 0.0f when - /// there are no mining devices connected yet. + /// Expected hash rate of the device (or cumulative hashrate on the channel if multiple devices + /// are connected downstream) in h/s. + /// + /// Depending on upstream’s target setting policy, this value can be used for setting a + /// reasonable target for the channel. + /// + /// Proxy must send 0.0f when there are no mining devices connected yet. pub nominal_hash_rate: f32, - /// Maximum target which can be accepted by the connected device or - /// devices. Server MUST accept the target or respond by sending - /// OpenMiningChannel.Error message. + /// Maximum target which can be accepted by the connected device(s). + /// + /// Upstream must accept the target or respond by sending [`OpenMiningChannelError`] message. #[cfg_attr(feature = "with_serde", serde(borrow))] pub max_target: U256<'decoder>, } @@ -77,31 +83,34 @@ impl<'decoder> OpenStandardMiningChannel<'decoder> { } } -/// # OpenStandardMiningChannel.Success (Server -> Client) -/// Sent as a response for opening a standard channel, if successful. +/// Message used by upstream to accept [`OpenStandardMiningChannel`] request from downstream. #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct OpenStandardMiningChannelSuccess<'decoder> { - /// Client-specified request ID from OpenStandardMiningChannel message, - /// so that the client can pair responses with open channel requests. + /// Used for matching requests/responses. + /// + /// Specified by downstream role and should be extracted from the corresponding + /// [`OpenStandardMiningChannel`] message. #[cfg(not(feature = "with_serde"))] pub request_id: U32AsRef<'decoder>, + /// Used for matching requests/responses. + /// + /// Specified by downstream role and should be extracted from the corresponding + /// [`OpenStandardMiningChannel`] message. #[cfg(feature = "with_serde")] pub request_id: u32, - /// 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. + /// Newly assigned identifier of the channel, stable for the whole lifetime of the connection. + /// + /// This will also be used for broadcasting new jobs by [`crate::NewMiningJob`]. pub channel_id: u32, /// Initial target for the mining channel. #[cfg_attr(feature = "with_serde", serde(borrow))] pub target: U256<'decoder>, - /// Bytes used as implicit first part of extranonce for the scenario when - /// extended job is served by the upstream node for a set of standard - /// channels that belong to the same group. + /// Bytes used as implicit first part of extranonce for the scenario when the job is served by + /// the downstream role for a set of standard channels that belong to the same group. #[cfg_attr(feature = "with_serde", serde(borrow))] pub extranonce_prefix: B032<'decoder>, - /// Group channel into which the new channel belongs. See - /// SetGroupChannel for details. + /// Group channel into which the new channel belongs. See SetGroupChannel for details. pub group_channel_id: u32, } @@ -134,51 +143,65 @@ impl<'decoder> OpenStandardMiningChannelSuccess<'decoder> { } } -/// # OpenExtendedMiningChannel (Client -> Server) -/// Similar to *OpenStandardMiningChannel* but requests to open an extended channel instead of +/// Message used by a downstream to request opening an Extended Channel with an upstream role. +/// +/// Similar to [`OpenStandardMiningChannel`] but requests to open an Extended Channel instead of /// standard channel. +/// +/// The main difference is the extranonce size is not fixed for a Extended Channel and can be set +/// by the upstream role based on the [`OpenExtendedMiningChannel::min_extranonce_size`] requested +/// by the downstream. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct OpenExtendedMiningChannel<'decoder> { - /// Client-specified identifier for matching responses from upstream server. - /// The value MUST be connection-wide unique and is not interpreted by - /// the server. + /// Specified by downstream role. + /// + /// Used for matching responses from upstream. + /// + /// The value must be connection-wide unique and is not interpreted by the upstream. pub request_id: u32, - /// Unconstrained sequence of bytes. Whatever is needed by upstream - /// node to identify/authenticate the client, e.g. “braiinstest.worker1”. - /// Additional restrictions can be imposed by the upstream node (e.g. a - /// pool). It is highly recommended that UTF-8 encoding is used. + /// Unconstrained sequence of bytes. + /// + /// Whatever is needed by upstream role to identify/authenticate the downstream, e.g. + /// “name.worker1”. + /// + /// Additional restrictions can be imposed by the upstream role (e.g. a pool). It is highly + /// recommended to use UTF-8 encoding. #[cfg_attr(feature = "with_serde", serde(borrow))] pub user_identity: Str0255<'decoder>, - /// [h/s] Expected hash rate of the device (or cumulative hashrate on the - /// channel if multiple devices are connected downstream) in h/s. - /// Depending on server’s target setting policy, this value can be used for - /// setting a reasonable target for the channel. Proxy MUST send 0.0f when - /// there are no mining devices connected yet. + /// Expected hash rate of the device (or cumulative hashrate on the channel if multiple devices + /// are connected downstream) in h/s. + /// + /// Depending on upstream’s target setting policy, this value can be used for setting a + /// reasonable target for the channel. + /// + /// Proxy must send 0.0f when there are no mining devices connected yet. pub nominal_hash_rate: f32, - /// Maximum target which can be accepted by the connected device or - /// devices. Server MUST accept the target or respond by sending - /// OpenMiningChannel.Error message. + /// Maximum target which can be accepted by the connected device or devices. + /// + /// Upstream must accept the target or respond by sending [`OpenMiningChannelError`] message. #[cfg_attr(feature = "with_serde", serde(borrow))] pub max_target: U256<'decoder>, - /// Minimum size of extranonce needed by the device/node. + /// Minimum size of extranonce needed by the downstream device/role. pub min_extranonce_size: u16, } + impl<'decoder> OpenExtendedMiningChannel<'decoder> { pub fn get_request_id_as_u32(&self) -> u32 { self.request_id } } -/// # OpenExtendedMiningChannel.Success (Server -> Client) -/// Sent as a response for opening an extended channel. +/// Message used by upstream to accept [`OpenExtendedMiningChannel` request from downstream. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct OpenExtendedMiningChannelSuccess<'decoder> { - /// Client-specified request ID from OpenStandardMiningChannel message, - /// so that the client can pair responses with open channel requests. + /// Used for matching requests/responses. + /// + /// Specified by downstream role and should be extracted from the corresponding + /// [`OpenExtendedMiningChannel`] message. pub request_id: u32, - /// 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. + /// Newly assigned identifier of the channel, stable for the whole lifetime of the connection. + /// + /// This will also be used for broadcasting new jobs by [`crate::NewExtendedMiningJob`]. pub channel_id: u32, /// Initial target for the mining channel. #[cfg_attr(feature = "with_serde", serde(borrow))] @@ -190,15 +213,21 @@ pub struct OpenExtendedMiningChannelSuccess<'decoder> { pub extranonce_prefix: B032<'decoder>, } -/// # OpenMiningChannel.Error (Server -> Client) +/// Message used by upstream to reject [`OpenExtendedMiningChannel`] or +/// [`OpenStandardMiningchannel`] request from downstream. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct OpenMiningChannelError<'decoder> { - /// Client-specified request ID from OpenMiningChannel message. + /// Used for matching requests/responses. + /// + /// Specified by downstream role and should be extracted from the corresponding + /// [`OpenExtendedMiningChannel`] or [`OpenStandardMiningchannel`] message. pub request_id: u32, /// Human-readable error code(s). + /// /// Possible error codes: - /// * ‘unknown-user’ - /// * ‘max-target-out-of-range’ + /// + /// - ‘unknown-user’ + /// - ‘max-target-out-of-range’ #[cfg_attr(feature = "with_serde", serde(borrow))] pub error_code: Str0255<'decoder>, } diff --git a/protocols/v2/subprotocols/mining/src/reconnect.rs b/protocols/v2/subprotocols/mining/src/reconnect.rs index 27cbe033dc..e23dfdf2cd 100644 --- a/protocols/v2/subprotocols/mining/src/reconnect.rs +++ b/protocols/v2/subprotocols/mining/src/reconnect.rs @@ -6,27 +6,22 @@ use binary_sv2::{Deserialize, Serialize, Str0255}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # Reconnect (Server -> Client) +/// Message used by upstream to redirect downstream connection(s) to a new host. /// -/// This message allows clients to be redirected to a new upstream node. +/// Upon receiving the message, the downstream re-initiates the Noise Handshake process and uses +/// the pool’s authority public key to verify the certificate presented by the new server. /// -/// This message is connection-related so that it should not be propagated downstream by -/// intermediate proxies. Upon receiving the message, the client re-initiates the Noise handshake -/// and uses the pool’s authority public key to verify that the certificate presented by the new -/// server has a valid signature. -/// -/// For security reasons, it is not possible to reconnect to a server with a certificate signed by a -/// different pool authority key. The message intentionally does *not* contain a **pool public key** -/// and thus cannot be used to reconnect to a different pool. This ensures that an attacker will not -/// be able to redirect hashrate to an arbitrary server should the pool server get compromised and -/// instructed to send reconnects to a new location. +/// For security reasons, it is not possible to reconnect to an upstream with a certificate signed +/// by a different pool authority key. The message intentionally does not contain a pool public key +/// and thus cannot be used to reconnect to a different pool. This ensures that an attacker will +/// not be able to redirect hashrate to an arbitrary server in case the pool server get compromised +/// and instructed to send reconnects to a new location. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Reconnect<'decoder> { - /// When empty, downstream node attempts to reconnect to its present - /// host. + /// When empty, downstream node should attempt to reconnect to current pool host. #[cfg_attr(feature = "with_serde", serde(borrow))] pub new_host: Str0255<'decoder>, - /// When 0, downstream node attempts to reconnect to its present port. + /// When 0, downstream node should attempt to reconnect to current pool host. pub new_port: u16, } #[cfg(feature = "with_serde")] diff --git a/protocols/v2/subprotocols/mining/src/set_custom_mining_job.rs b/protocols/v2/subprotocols/mining/src/set_custom_mining_job.rs index c4138e4494..1879bff1ca 100644 --- a/protocols/v2/subprotocols/mining/src/set_custom_mining_job.rs +++ b/protocols/v2/subprotocols/mining/src/set_custom_mining_job.rs @@ -6,87 +6,91 @@ use binary_sv2::{Deserialize, Seq0255, Serialize, Str0255, B0255, B064K, U256}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # SetCustomMiningJob (Client -> Server) +/// Message used by downstream role to set a custom job to an upstream (Pool). /// -/// Can be sent only on extended channel. SetupConnection.flags MUST contain -/// *REQUIRES_WORK_SELECTION* flag (work selection feature successfully negotiated). -/// The downstream node has a custom job negotiated by a trusted external Job Declarator. The -/// mining_job_token provides the information for the pool to authorize the custom job that has -/// been or will be negotiated between the Job Declarator and Pool. +/// The [`SetCustomMiningJob::token`] should provide the information for the upstream to authorize +/// the custom job that has been or will be negotiated between the Job Declarator Client and Job +/// Declarator Server. +/// +/// Can be sent only on extended channel. +/// +/// Previously exchanged `SetupConnection::flags` must contain `REQUIRES_WORK_SELECTION` flag i.e., +/// work selection feature was successfully negotiated. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct SetCustomMiningJob<'decoder> { - /// Extended channel identifier. + /// Extended mining channel identifier. pub channel_id: u32, - /// Client-specified identifier for pairing responses. + /// Specified by downstream role. + /// + /// Used for matching responses from upstream. + /// + /// The value must be connection-wide unique and is not interpreted by the upstream. pub request_id: u32, + /// Provide the information for the upstream to authorize the custom job that has been or will + /// be negotiated between the Job Declarator Client and Job Declarator Server. pub token: B0255<'decoder>, - /// Valid version field that reflects the current network - /// consensus. The general purpose bits (as specified in - /// BIP320) can be freely manipulated by the downstream - /// node. + /// Version field that reflects the current network consensus. + /// + /// The general purpose bits (as specified in BIP320) can be freely manipulated by the + /// downstream role. The downstream role must not rely on the upstream role to set the BIP320 + /// bits to any particular value. pub version: u32, - /// Previous block’s hash, found in the block header field. + /// Previous block’s hash. #[cfg_attr(feature = "with_serde", serde(borrow))] pub prev_hash: U256<'decoder>, - /// Smallest nTime value available for hashing. + /// Smallest `nTime` value available for hashing. pub min_ntime: u32, /// Block header field. pub nbits: u32, - /// The coinbase transaction nVersion field. + /// The coinbase transaction `nVersion` field. pub coinbase_tx_version: u32, - /// Up to 8 bytes (not including the length byte) which are - /// to be placed at the beginning of the coinbase field in - /// the coinbase transaction. + /// Up to 8 bytes (not including the length byte) which are to be placed at the beginning of + /// the coinbase field in the coinbase transaction. pub coinbase_prefix: B0255<'decoder>, /// The coinbase transaction input’s nSequence field. pub coinbase_tx_input_n_sequence: u32, - /// The value, in satoshis, available for spending in - /// coinbase outputs added by the client. Includes both - /// transaction fees and block subsidy. + /// The value, in satoshis, available for spending in coinbase outputs added by the client. + /// Includes both transaction fees and block subsidy. pub coinbase_tx_value_remaining: u64, /// All the outputs that will be included in the coinbase txs #[cfg_attr(feature = "with_serde", serde(borrow))] pub coinbase_tx_outputs: B064K<'decoder>, - /// The locktime field in the coinbase transaction. + /// The `locktime` field in the coinbase transaction. pub coinbase_tx_locktime: u32, /// Merkle path hashes ordered from deepest. #[cfg_attr(feature = "with_serde", serde(borrow))] pub merkle_path: Seq0255<'decoder, U256<'decoder>>, - /// Size of extranonce in bytes that will be provided by the - /// downstream node. + /// Size of extranonce in bytes that will be provided by the downstream role. pub extranonce_size: u16, } -/// # SetCustomMiningJob.Success (Server -> Client) +/// Message used by upstream to accept [`SetCustomMiningJob`] request. /// -/// Response from the server when it accepts the custom mining job. Client can start to mine on -/// the job immediately (by using the job_id provided within this response). +/// Upon receiving this message, downstream can start submitting shares for this job immediately (by +/// using the [`SetCustomMiningJobSuccess::job_id`] provided within this response). #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetCustomMiningJobSuccess { - /// Extended channel identifier. + /// Extended mining channel identifier. pub channel_id: u32, - /// Client-specified identifier for pairing responses. Value from the request - /// MUST be provided by upstream in the response message. + /// Request identifier set by the downstream role. pub request_id: u32, - /// Server’s identification of the mining job. + /// Upstream’s identification of the mining job. pub job_id: u32, } -/// # SetCustomMiningJob.Error (Server -> Client) -/// -/// Possible errors: -/// * ‘invalid-channel-id’ -/// * ‘invalid-mining-job-token’ -/// * ‘invalid-job-param-value-{}’ - {} is replaced by a particular field name from -/// SetCustomMiningJob message +/// Message used by upstream to reject [`SetCustomMiningJob`] request. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetCustomMiningJobError<'decoder> { - /// Extended channel identifier. + /// Extended mining channel identifier. pub channel_id: u32, - /// Client-specified identifier for pairing responses. Value from the request - /// MUST be provided by upstream in the response message. + /// Request identifier set by the downstream role. pub request_id: u32, - /// Reason why the custom job has been rejected. + /// Rejection reason. + /// + /// Possible errors: + /// - invalid-channel-id + /// - invalid-mining-job-token + /// - invalid-job-param-value-{field_name} #[cfg_attr(feature = "with_serde", serde(borrow))] pub error_code: Str0255<'decoder>, } diff --git a/protocols/v2/subprotocols/mining/src/set_extranonce_prefix.rs b/protocols/v2/subprotocols/mining/src/set_extranonce_prefix.rs index 140fdf1d3f..f6b6df190b 100644 --- a/protocols/v2/subprotocols/mining/src/set_extranonce_prefix.rs +++ b/protocols/v2/subprotocols/mining/src/set_extranonce_prefix.rs @@ -6,17 +6,18 @@ use binary_sv2::{Deserialize, Serialize, B032}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # SetExtranoncePrefix (Server -> Client) +/// Message used by upstream to change downstream node’s extranonce prefix. /// -/// Changes downstream node’s extranonce prefix. It is applicable for all jobs sent after this -/// message on a given channel (both jobs provided by the upstream or jobs introduced by -/// SetCustomMiningJob message). This message is applicable only for explicitly opened -/// extended channels or standard channels (not group channels). +/// [`SetExtranoncePrefix::extranonce_prefix`], a constant, is part of the full extranonce and is +/// set by the upstream. +/// +/// Note that this message is applicable only for opened Standard or Extended Channels, not Group +/// Channels. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetExtranoncePrefix<'decoder> { - /// Extended or standard channel identifier. + /// Extended or Standard Channel identifier. pub channel_id: u32, - /// Bytes used as implicit first part of extranonce. + /// New extranonce prefix. #[cfg_attr(feature = "with_serde", serde(borrow))] pub extranonce_prefix: B032<'decoder>, } diff --git a/protocols/v2/subprotocols/mining/src/set_group_channel.rs b/protocols/v2/subprotocols/mining/src/set_group_channel.rs index 73fca2c888..e07bb94e04 100644 --- a/protocols/v2/subprotocols/mining/src/set_group_channel.rs +++ b/protocols/v2/subprotocols/mining/src/set_group_channel.rs @@ -6,27 +6,26 @@ use binary_sv2::{Deserialize, Seq064K, Serialize}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # SetGroupChannel (Server -> Client) +/// Message used by upstream to associate a set of Standard Channel(s) to a Group Channel. /// -/// Every standard channel is a member of a group of standard channels, addressed by the -/// upstream server’s provided identifier. The group channel is used mainly for efficient job -/// distribution to multiple standard channels at once. -/// If we want to allow different jobs to be served to different standard channels (e.g. because of -/// different BIP 8 version bits) and still be able to distribute the work by sending -/// NewExtendendedMiningJob instead of a repeated NewMiningJob, we need a more -/// fine-grained grouping for standard channels. -/// This message associates a set of standard channels with a group channel. A channel (identified -/// by particular ID) becomes a group channel when it is used by this message as -/// group_channel_id. The server MUST ensure that a group channel has a unique channel ID -/// within one connection. Channel reinterpretation is not allowed. -/// This message can be sent only to connections that don’t have REQUIRES_STANDARD_JOBS -/// flag in SetupConnection. +/// A channel becomes a group channel when it is used by this message as +/// [`SetGroupChannel::group_channel_id`]. +/// +/// Every standard channel is a member of a group of standard channels, addressed by the upstream +/// server’s provided identifier. The group channel is used mainly for efficient job distribution +/// to multiple standard channels at once. +/// +/// The upstream must ensure that a group channel has a unique channel ID within one connection. +/// +/// Channel reinterpretation is not allowed. +/// +/// This message can be sent only to connections that didnt set `REQUIRES_STANDARD_JOBS` flag in +/// `SetupConnection` message. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetGroupChannel<'decoder> { /// Identifier of the group where the standard channel belongs. pub group_channel_id: u32, - /// A sequence of opened standard channel IDs, for which the group - /// channel is being redefined. + /// A sequence of opened standard channel IDs, for which the group channel is being redefined. #[cfg_attr(feature = "with_serde", serde(borrow))] pub channel_ids: Seq064K<'decoder, u32>, } diff --git a/protocols/v2/subprotocols/mining/src/set_new_prev_hash.rs b/protocols/v2/subprotocols/mining/src/set_new_prev_hash.rs index 7b76b1ef24..ea3b66a25a 100644 --- a/protocols/v2/subprotocols/mining/src/set_new_prev_hash.rs +++ b/protocols/v2/subprotocols/mining/src/set_new_prev_hash.rs @@ -6,27 +6,28 @@ use binary_sv2::{Deserialize, Serialize, U256}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # SetNewPrevHash (Server -> Client, broadcast) +/// Message used by upstream to share or distribute the latest block hash. /// -/// Prevhash is distributed whenever a new block is detected in the network by an upstream node. -/// This message MAY be shared by all downstream nodes (sent only once to each channel group). -/// Clients MUST immediately start to mine on the provided prevhash. When a client receives this -/// message, only the job referenced by Job ID is valid. The remaining jobs already queued by the -/// client have to be made invalid. -/// Note: There is no need for block height in this message. +/// This message may be shared by all downstream nodes (sent only once to each channel group). +/// +/// Downstream must immediately start to mine on the provided [`SetNewPrevHash::prevhash`]. +/// +/// When a downstream receives this message, only the job referenced by [`SetNewPrevHash::job_id`] +/// is valid. Remaining jobs have to be dropped. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetNewPrevHash<'decoder> { /// Group channel or channel that this prevhash is valid for. pub channel_id: u32, - /// ID of a job that is to be used for mining with this prevhash. A pool may - /// have provided multiple jobs for the next block height (e.g. an empty - /// block or a block with transactions that are complementary to the set of - /// transactions present in the current block template). + /// Job identfier that is to be used for mining. + /// + /// A pool may have provided multiple jobs for the next block height (e.g. an empty block or a + /// block with transactions that are complementary to the set of transactions present in the + /// current block template). pub job_id: u32, - /// Previous block’s hash, block header field. + /// Latest block hash observed by the Template Provider. #[cfg_attr(feature = "with_serde", serde(borrow))] pub prev_hash: U256<'decoder>, - /// Smallest nTime value available for hashing. + /// Smallest `nTime` value available for hashing. pub min_ntime: u32, /// Block header field. pub nbits: u32, diff --git a/protocols/v2/subprotocols/mining/src/set_target.rs b/protocols/v2/subprotocols/mining/src/set_target.rs index 672233118a..b25ec73ba9 100644 --- a/protocols/v2/subprotocols/mining/src/set_target.rs +++ b/protocols/v2/subprotocols/mining/src/set_target.rs @@ -6,23 +6,23 @@ use binary_sv2::{Deserialize, Serialize, U256}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # SetTarget (Server -> Client) +/// Message used by upstream to control the downstream submission rate by adjusting the difficulty +/// target on a specified channel. /// -/// The server controls the submission rate by adjusting the difficulty target on a specified -/// channel. All submits leading to hashes higher than the specified target will be rejected by the -/// server. -/// Maximum target is valid until the next *SetTarget* message is sent and is applicable for all -/// jobs received on the channel in the future or already received with flag *future_job=True*. The -/// message is not applicable for alrea +/// All submits leading to hashes higher than the specified target are expected to be rejected by +/// the upstream. /// -/// When SetTarget is sent to a group channel, the maximum target is applicable to all channels in -/// the group. +/// [`SetTarget::maximum_target`] is valid until the next [`SetTarget`] message is sent and is +/// applicable for all jobs received on the channel in the future or already received with flag +/// `future_job=true`. +/// +/// When this message is sent to a group channel, the maximum target is applicable to all channels +/// in the group. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SetTarget<'decoder> { /// Channel identifier. pub channel_id: u32, - /// Maximum value of produced hash that will be accepted by a server to - /// accept shares. + /// Maximum value of produced hash that will be accepted by a upstream to accept shares. #[cfg_attr(feature = "with_serde", serde(borrow))] pub maximum_target: U256<'decoder>, } diff --git a/protocols/v2/subprotocols/mining/src/submit_shares.rs b/protocols/v2/subprotocols/mining/src/submit_shares.rs index 5c8bea64f6..4ecdcf9203 100644 --- a/protocols/v2/subprotocols/mining/src/submit_shares.rs +++ b/protocols/v2/subprotocols/mining/src/submit_shares.rs @@ -6,68 +6,75 @@ use binary_sv2::{Deserialize, Serialize, Str0255, B032}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # SubmitSharesStandard (Client -> Server) -/// -/// Client sends result of its hashing work to the server. +/// Message used by downstream to send result of its hashing work to an upstream. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SubmitSharesStandard { /// Channel identification. pub channel_id: u32, /// Unique sequential identifier of the submit within the channel. pub sequence_number: u32, - /// Identifier of the job as provided by *NewMiningJob* or - /// *NewExtendedMiningJob* message. + /// Identifier of the job as provided by [`NewMiningJob`] or [`NewExtendedMiningJob`] message. + /// + /// [`NewMiningJob`]: crate::NewMiningJob + /// [`NewExtendedMiningJob`]: crate::NewExtendedMiningJob pub job_id: u32, /// Nonce leading to the hash being submitted. pub nonce: u32, - /// The nTime field in the block header. This MUST be greater than or equal - /// to the header_timestamp field in the latest SetNewPrevHash message - /// and lower than or equal to that value plus the number of seconds since - /// the receipt of that message. + /// The `nTime` field in the block header. This must be greater than or equal to the + /// `header_timestamp` field in the latest [`SetNewPrevHash`] message and lower than or equal + /// to that value plus the number of seconds since the receipt of that message. + /// + /// [`SetNewPrevHash`]: crate::SetNewPrevHash pub ntime: u32, - /// Full nVersion field. + /// Full `nVersion` field. pub version: u32, } -/// # SubmitSharesExtended (Client -> Server) -/// Only relevant for extended channels. The message is the same as SubmitShares, with the -/// following additional field: -/// * extranonce + +/// Message used by downstream to send result of its hashing work to an upstream. +/// +/// The message is the same as [`SubmitShares`], but with an additional field, +/// [`SubmitSharesExtended::extranonce`]. +/// +/// Only relevant for Extended Channels. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SubmitSharesExtended<'decoder> { /// Channel identification. pub channel_id: u32, /// Unique sequential identifier of the submit within the channel. pub sequence_number: u32, - /// Identifier of the job as provided by *NewMiningJob* or - /// *NewExtendedMiningJob* message. + /// Identifier of the job as provided by [`NewMiningJob`] or [`NewExtendedMiningJob`] message. + /// + /// [`NewMiningJob`]: crate::NewMiningJob + /// [`NewExtendedMiningJob`]: crate::NewExtendedMiningJob pub job_id: u32, /// Nonce leading to the hash being submitted. pub nonce: u32, - /// The nTime field in the block header. This MUST be greater than or equal - /// to the header_timestamp field in the latest SetNewPrevHash message - /// and lower than or equal to that value plus the number of seconds since - /// the receipt of that message. + /// The nTime field in the block header. This must be greater than or equal to the + /// `header_timestamp` field in the latest [`SetNewPrevHash`] message and lower than or equal + /// to that value plus the number of seconds since the receipt of that message. + /// + /// [`SetNewPrevHash`]: crate::SetNewPrevHash pub ntime: u32, /// Full nVersion field. pub version: u32, - /// Extranonce bytes which need to be added to coinbase to form a fully - /// valid submission (full coinbase = coinbase_tx_prefix + - /// extranonce_prefix + extranonce + coinbase_tx_suffix). The size of the - /// provided extranonce MUST be equal to the negotiated extranonce size - /// from channel opening. + /// Extranonce bytes which need to be added to the coinbase tx to form a fully valid submission + /// (`full coinbase = coinbase_tx_prefix + extranonce_prefix + extranonce + + /// coinbase_tx_suffix`). + /// + /// The size of the provided extranonce must be equal to the negotiated extranonce size from + /// channel opening flow. #[cfg_attr(feature = "with_serde", serde(borrow))] pub extranonce: B032<'decoder>, } -/// # SubmitShares.Success (Server -> Client) +/// Message used by upstream to accept [`SubmitSharesStandard`] or [`SubmitSharesExtended`]. /// -/// Response to SubmitShares or SubmitSharesExtended, accepting results from the miner. -/// Because it is a common case that shares submission is successful, this response can be -/// provided for multiple SubmitShare messages aggregated together. +/// Because it is a common case that shares submission is successful, this response can be provided +/// for multiple [`SubmitShare`] messages aggregated together. /// -/// The server doesn’t have to double check that the sequence numbers sent by a client are -/// actually increasing. It can simply use the last one received when sending a response. It is the -/// client’s responsibility to keep the sequence numbers correct/useful. +/// The upstream doesn’t have to double check that the sequence numbers sent by a downstream are +/// actually increasing. It can use the last one received when sending a response. It is the +/// downstream’s responsibility to keep the sequence numbers correct/useful. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SubmitSharesSuccess { /// Channel identifier. @@ -80,22 +87,25 @@ pub struct SubmitSharesSuccess { pub new_shares_sum: u64, } -/// # SubmitShares.Error (Server -> Client) -/// -/// An error is immediately submitted for every incorrect submit attempt. In case the server is not -/// able to immediately validate the submission, the error is sent as soon as the result is known. -/// This delayed validation can occur when a miner gets faster updates about a new prevhash than -/// the server does (see NewPrevHash message for details). +/// Message used by upstream to reject [`SubmitSharesStandard`] or [`SubmitSharesExtended`]. /// -/// Possible error codes: -/// * ‘invalid-channel-id’ -/// * ‘stale-share’ -/// * ‘difficulty-too-low’ -/// * 'invalid-job-id' +/// In case the upstream is not able to immediately validate the submission, the error is sent as +/// soon as the result is known. This delayed validation can occur when a miner gets faster +/// updates about a new `prevhash` than the upstream does. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct SubmitSharesError<'decoder> { + /// Channel identification. pub channel_id: u32, + /// Unique sequential identifier of the submit within the channel. pub sequence_number: u32, + /// Rejection reason. + /// + /// Possible error codes: + /// + /// - invalid-channel-id + /// - stale-share + /// - difficulty-too-low + /// - invalid-job-id #[cfg_attr(feature = "with_serde", serde(borrow))] pub error_code: Str0255<'decoder>, } diff --git a/protocols/v2/subprotocols/mining/src/update_channel.rs b/protocols/v2/subprotocols/mining/src/update_channel.rs index a8843213c9..e656ed5f18 100644 --- a/protocols/v2/subprotocols/mining/src/update_channel.rs +++ b/protocols/v2/subprotocols/mining/src/update_channel.rs @@ -6,41 +6,49 @@ use binary_sv2::{Deserialize, Serialize, Str0255, U256}; #[cfg(not(feature = "with_serde"))] use core::convert::TryInto; -/// # UpdateChannel (Client -> Server) +/// Message used by downstream to notify an upstream about changes on a specified channel. /// -/// Client notifies the server about changes on the specified channel. If a client performs -/// device/connection aggregation (i.e. it is a proxy), it MUST send this message when downstream -/// channels change. This update can be debounced so that it is not sent more often than once in a -/// second (for a very busy proxy). +/// If a downstream performs device/connection aggregation (i.e. it is a proxy), it must send this +/// message when downstream channels change. /// -/// This message is an extended channel only message. Using it in other kind if channels should -/// raise an error +/// Only relevant for Extended Channels. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct UpdateChannel<'decoder> { /// Channel identification. pub channel_id: u32, - /// See Open*Channel for details. + /// Expected hash rate of the device (or cumulative hashrate on the channel if multiple devices + /// are connected downstream) in h/s. + /// + /// Depending on upstream’s target setting policy, this value can be used for setting a + /// reasonable target for the channel. + /// + /// Proxy must send 0.0f when there are no mining devices connected yet. pub nominal_hash_rate: f32, - /// Maximum target is changed by server by sending SetTarget. This - /// field is understood as device’s request. There can be some delay - /// between UpdateChannel and corresponding SetTarget messages, - /// based on new job readiness on the server. + /// As there can be some delay between [`UpdateChannel`] and corresponding [`SetTarget`] + /// messages, based on new job readiness on the server, this field is understood as + /// downstream’s request. + /// + /// When maximum target is smaller than currently used maximum target for the channel, + /// upstream node must reflect the downstreams’s request (and send appropriate [`SetTarget`] + /// message). /// - /// When maximum_target is smaller than currently used maximum target for the channel, - /// upstream node MUST reflect the client’s request (and send appropriate SetTarget message). + /// Upstream can change maximum target by sending [`SetTarget`] message. + /// + /// [`SetTarget`]: crate::SetTarget #[cfg_attr(feature = "with_serde", serde(borrow))] pub maximum_target: U256<'decoder>, } -/// # Update.Error (Server -> Client) +/// Message used by upstream to notify downstream about an error in the [`UpdateChannel`] message. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct UpdateChannelError<'decoder> { /// Channel identification. pub channel_id: u32, - /// Human-readable error code(s). + /// Reason for channel update error. + /// /// Possible error codes: - /// * ‘max-target-out-of-range’ - /// * ‘invalid-channel-id’ + /// - max-target-out-of-range + /// - invalid-channel-id #[cfg_attr(feature = "with_serde", serde(borrow))] pub error_code: Str0255<'decoder>, }