Skip to content

Commit

Permalink
Improve Template Distribution subprotocol docs
Browse files Browse the repository at this point in the history
  • Loading branch information
jbesraa committed Dec 7, 2024
1 parent 0bdf1de commit b651522
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 122 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,30 @@ use binary_sv2::{Deserialize, Serialize};
#[cfg(not(feature = "with_serde"))]
use core::convert::TryInto;

/// ## CoinbaseOutputDataSize (Client -> Server)
/// Ultimately, the pool is responsible for adding coinbase transaction outputs for payouts and
/// other uses, and thus the Template Provider will need to consider this additional block size
/// when selecting transactions for inclusion in a block (to not create an invalid, oversized
/// block). Thus, this message is used to indicate that some additional space in the block/coinbase
/// transaction be reserved for the pool’s use (while always assuming the pool will use the entirety
/// of available coinbase space).
/// The Job Declarator MUST discover the maximum serialized size of the additional outputs which
/// will be added by the pool(s) it intends to use this work. It then MUST communicate the
/// maximum such size to the Template Provider via this message. The Template Provider MUST
/// NOT provide NewWork messages which would represent consensus-invalid blocks once this
/// additional size — along with a maximally-sized (100 byte) coinbase field — is added. Further,
/// the Template Provider MUST consider the maximum additional bytes required in the output
/// count variable-length integer in the coinbase transaction when complying with the size limits.
/// Message used by a downstream to indicate the size of the additional bytes they will need in
/// coinbase transaction outputs.
///
/// As the pool is responsible for adding coinbase transaction outputs for payouts and other uses,
/// the Template Provider will need to consider this reserved space when selecting transactions for
/// inclusion in a block(to avoid an invalid, oversized block). Thus, this message indicates that
/// additional space in the block/coinbase transaction must be reserved for, assuming they will use
/// the entirety of this space.
///
/// The Job Declarator **must** discover the maximum serialized size of the additional outputs which
/// will be added by the pools it intends to use this work. It then **must** communicate the sum of
/// such size to the Template Provider via this message.
///
/// The Template Provider **must not** provide [`NewTemplate`] messages which would represent
/// consensus-invalid blocks once this additional size — along with a maximally-sized (100 byte)
/// coinbase field — is added. Further, the Template Provider **must** consider the maximum
/// additional bytes required in the output count variable-length integer in the coinbase
/// transaction when complying with the size limits.
///
/// [`NewTemplate`]: crate::NewTemplate
#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct CoinbaseOutputDataSize {
/// The maximum additional serialized bytes which the pool will add in
/// coinbase transaction outputs.
/// Additional serialized bytes needed in coinbase transaction outputs.
pub coinbase_output_max_additional_size: u32,
}

Expand Down
41 changes: 21 additions & 20 deletions protocols/v2/subprotocols/template-distribution/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
//! # Stratum V2 Template Distribution Protocol Messages Crate
//!
//!
//! `template_distribution_sv2` is a Rust crate that implements a set of messages defined in the
//! Template Distribution Protocol of Stratum V2. The Template Distribution protocol can be used
//! to receive updates of the block templates to use in mining.
//!
//! ## Build Options
//! This crate can be built with the following features:
//! - `std`: Enables support for standard library features.
//! - `with_serde`: Enables support for serialization and deserialization using Serde.
//! - `prop_test`: Enables support for property testing.
//!
//! *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.*
//!
//! For further information about the messages, please refer to [Stratum V2 documentation - Job
//! Distribution](https://stratumprotocol.org/specification/07-Template-Distribution-Protocol/).
#![cfg_attr(feature = "no_std", no_std)]

//! # Template Distribution Protocol
//! The Template Distribution protocol is used to receive updates of the block template to use in
//! mining the next block. It effectively replaces BIPs [22] and [23] (getblocktemplate) and
//! provides a much more efficient API which allows Bitcoin Core (or some other full node software)
//! to push template updates at more appropriate times as well as provide a template which may be
//! mined on quickly for the block-after-next. While not recommended, the template update
//! protocol can be a remote server, and is thus authenticated and signed in the same way as all
//! other protocols ([using the same SetupConnection handshake]).
//! Like the [Job Declaration] and [Job Distribution] (sub)protocols, all Template Distribution
//! messages have the channel_msg bit unset, and there is no concept of channels. After the initial
//! common handshake, the client MUST immediately send a [`CoinbaseOutputDataSize`] message to
//! indicate the space it requires for coinbase output addition, to which the server MUST
//! immediately reply with the current best block template it has available to the client.
//! Thereafter, the server SHOULD push new block templates to the client whenever the total fee in
//! the current block template increases materially, and MUST send updated block templates whenever
//! it learns of a new block.
//! Template Providers MUST attempt to broadcast blocks which are mined using work they
//! provided, and thus MUST track the work which they provided to clients.
extern crate alloc;

#[cfg(feature = "prop_test")]
Expand All @@ -32,7 +31,7 @@ mod new_template;
mod request_transaction_data;
mod set_new_prev_hash;
mod submit_solution;
//

pub use coinbase_output_data_size::CoinbaseOutputDataSize;
#[cfg(not(feature = "with_serde"))]
pub use new_template::CNewTemplate;
Expand All @@ -49,9 +48,11 @@ pub use set_new_prev_hash::SetNewPrevHash;
pub use submit_solution::CSubmitSolution;
pub use submit_solution::SubmitSolution;

/// Exports the [`CoinbaseOutputDataSize`] struct to C.
#[no_mangle]
pub extern "C" fn _c_export_coinbase_out(_a: CoinbaseOutputDataSize) {}

/// Exports the [`RequestTransactionData`] struct to C.
#[no_mangle]
pub extern "C" fn _c_export_req_tx_data(_a: RequestTransactionData) {}

Expand Down
60 changes: 34 additions & 26 deletions protocols/v2/subprotocols/template-distribution/src/new_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,51 +10,57 @@ use core::convert::TryInto;
#[cfg(all(feature = "with_serde", not(feature = "no_std")))]
use std::convert::TryInto;

/// ## NewTemplate (Server -> Client)
/// The primary template-providing function. Note that the coinbase_tx_outputs bytes will appear
/// as is at the end of the coinbase transaction.
/// Message used by an upstream(Template Provider) to provide a new template for downstream to mine
/// on.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct NewTemplate<'decoder> {
/// Server’s identification of the template. Strictly increasing, the
/// current UNIX time may be used in place of an ID.
/// Upstream’s identification of the template.
///
/// Should be strictly increasing.
pub template_id: u64,
/// True if the template is intended for future [`crate::SetNewPrevHash`]
/// message sent on the channel. If False, the job relates to the last
/// sent [`crate::SetNewPrevHash`] message on the channel and the miner
/// should start to work on the job immediately.
/// If `True`, the template is intended for future [`crate::SetNewPrevHash`] message sent on
/// the channel.
///
/// If `False`, the job relates to the last sent [`crate::SetNewPrevHash`] message on the
/// channel and the miner should start to work on the job immediately.
pub future_template: bool,
/// Valid header 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.
/// Valid header version field that reflects the current network consensus.
///
/// The general purpose bits, as specified in
/// [BIP320](https://github.com/bitcoin/bips/blob/master/bip-0320.mediawiki), can be freely
/// manipulated by the downstream node.
///
/// The downstream **must not** rely on the upstream to set the
/// [BIP320](https://github.com/bitcoin/bips/blob/master/bip-0320.mediawiki) bits to any
/// particular value.
pub version: 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.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub coinbase_prefix: B0255<'decoder>,
///bug
/// The coinbase transaction input’s nSequence field.
/// The coinbase transaction input’s `nSequence` field.
pub coinbase_tx_input_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 downstream.
///
/// Includes both transaction fees and block subsidy.
pub coinbase_tx_value_remaining: u64,
/// The number of transaction outputs included in coinbase_tx_outputs.
/// The number of transaction outputs included in [`NewTemplate::coinbase_tx_outputs`].
pub coinbase_tx_outputs_count: u32,
/// Bitcoin transaction outputs to be included as the last outputs in the
/// coinbase transaction.
/// Bitcoin transaction outputs to be included as the last outputs in the coinbase transaction.
///
/// Note that those bytes will appear as is at the end of the coinbase transaction.
#[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>>,
}

/// C representation of [`NewTemplate`].
#[repr(C)]
#[cfg(not(feature = "with_serde"))]
pub struct CNewTemplate {
Expand All @@ -71,6 +77,7 @@ pub struct CNewTemplate {
merkle_path: CVec2,
}

/// Drops the [`CNewTemplate`] object.
#[no_mangle]
#[cfg(not(feature = "with_serde"))]
pub extern "C" fn free_new_template(s: CNewTemplate) {
Expand Down Expand Up @@ -107,6 +114,7 @@ impl<'a> From<NewTemplate<'a>> for CNewTemplate {

#[cfg(not(feature = "with_serde"))]
impl<'a> CNewTemplate {
/// Converts from C to Rust representation.
#[cfg(not(feature = "with_serde"))]
#[allow(clippy::wrong_self_convention)]
pub fn to_rust_rep_mut(&'a mut self) -> Result<NewTemplate<'a>, Error> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,53 @@ use binary_sv2::{Deserialize, Seq064K, Serialize, Str0255, B016M, B064K};
#[cfg(not(feature = "with_serde"))]
use core::convert::TryInto;

/// ## RequestTransactionData (Client -> Server)
/// A request sent by the Job Declarator to the Template Provider which requests the set of
/// transaction data for all transactions (excluding the coinbase transaction) included in a block,
/// as well as any additional data which may be required by the Pool to validate the work.
/// Message used by a downstream to request data about all transactions in a block template.
///
/// Data includes the full transaction data and any additional data required to block validation.
///
/// Note that the coinbase transaction is excluded from this data.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Copy)]
#[repr(C)]
pub struct RequestTransactionData {
/// The template_id corresponding to a NewTemplate message.
/// Identifier of the template that the downstream node is requesting transaction data for.
///
/// This must be identical to previously exchanged [`crate::NewTemplate::template_id`].
pub template_id: u64,
}

/// ## RequestTransactionData.Success (Server->Client)
/// Message used by an upstream(Template Provider) to respond successfully to a
/// [`RequestTransactionData`] message.
///
/// A response to [`RequestTransactionData`] which contains the set of full transaction data and
/// excess data required for validation. For practical purposes, the excess data is usually the
/// SegWit commitment, however the Job Declarator MUST NOT parse or interpret the excess data
/// in any way. Note that the transaction data MUST be treated as opaque blobs and MUST include
/// any SegWit or other data which the Pool may require to verify the transaction. For practical
/// excess data required for block validation. For practical purposes, the excess data is usually
/// the SegWit commitment, however the Job Declarator **must not** have any assumptions about it.
///
/// Note that the transaction data **must** be treated as opaque blobs and **must** include any
/// SegWit or other data which the downstream may require to verify the transaction. For practical
/// purposes, the transaction data is likely the witness-encoded transaction today. However, to
/// ensure backward compatibility, the transaction data MAY be encoded in a way that is different
/// from the consensus serialization of Bitcoin transactions.
/// Ultimately, having some method of negotiating the specific format of transactions between the
/// Template Provider and the Pool’s Template verification node would be overly burdensome,
/// thus the following requirements are made explicit. The RequestTransactionData.Success
/// sender MUST ensure that the data is provided in a forwards- and backwards-compatible way to
/// ensure the end receiver of the data can interpret it, even in the face of new,
/// consensus-optional data. This allows significantly more flexibility on both the
/// RequestTransactionData.Success-generating and -interpreting sides during upgrades, at the
/// ensure backward compatibility, the transaction data **may** be encoded in a way that is
/// different from the consensus serialization of Bitcoin transactions.
///
/// The [`RequestTransactionDataSuccess`] sender **must** ensure that provided data is forward and
/// backward compatible. This way the receiver of the data can interpret it, even in the face of
/// new, consensus-optional data. This allows significantly more flexibility on both the
/// [`RequestTransactionDataSuccess`] generating and interpreting sides during upgrades, at the
/// cost of breaking some potential optimizations which would require version negotiation to
/// provide support for previous versions. For practical purposes, and as a non-normative
/// suggested implementation for Bitcoin Core, this implies that additional consensus-optional
/// data be appended at the end of transaction data. It will simply be ignored by versions which do
/// not understand it.
/// provide support for previous versions.
///
/// Having some method of negotiating the specific format of transactions between the Template
/// Provider and the downstream would be helpful but overly burdensome, thus the above requirements
/// are made explicit.
///
/// As a result, and as a non-normative suggested implementation for Bitcoin Core, this implies
/// that additional consensus-optional data appended at the end of transaction data will simply be
/// ignored by versions which do not understand it.
///
/// To work around the limitation of not being able to negotiate e.g. a transaction compression
/// scheme, the format of the opaque data in RequestTransactionData.Success messages MAY be
/// changed in non-compatible ways at the time a fork activates, given sufficient time from
/// code-release to activation (as any sane fork would have to have) and there being some
/// in-Template Declaration Protocol signaling of support for the new fork (e.g. for soft-forks
/// activated using [BIP 9]).
/// scheme, the format of the opaque data in [`RequestTransactionDataSuccess`] messages **may** be
/// changed in a non-compatible way at the time of fork activation, given sufficient time from
/// code-release to activation and there being in protocol(Template Declaration) signaling of
/// support for the new fork (e.g. for soft-forks activated using [BIP 9]).
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct RequestTransactionDataSuccess<'decoder> {
/// The template_id corresponding to a NewTemplate/RequestTransactionData message.
Expand All @@ -58,6 +67,7 @@ pub struct RequestTransactionDataSuccess<'decoder> {
pub transaction_list: Seq064K<'decoder, B016M<'decoder>>,
}

/// C representation of [`RequestTransactionDataSuccess`].
#[repr(C)]
#[cfg(not(feature = "with_serde"))]
pub struct CRequestTransactionDataSuccess {
Expand All @@ -68,6 +78,7 @@ pub struct CRequestTransactionDataSuccess {

#[cfg(not(feature = "with_serde"))]
impl<'a> CRequestTransactionDataSuccess {
/// Converts C struct to Rust struct.
#[cfg(not(feature = "with_serde"))]
#[allow(clippy::wrong_self_convention)]
pub fn to_rust_rep_mut(&'a mut self) -> Result<RequestTransactionDataSuccess<'a>, Error> {
Expand All @@ -86,6 +97,7 @@ impl<'a> CRequestTransactionDataSuccess {
}
}

/// Drops the CRequestTransactionDataSuccess object.
#[no_mangle]
#[cfg(not(feature = "with_serde"))]
pub extern "C" fn free_request_tx_data_success(s: CRequestTransactionDataSuccess) {
Expand All @@ -111,17 +123,21 @@ impl<'a> From<RequestTransactionDataSuccess<'a>> for CRequestTransactionDataSucc
}
}

/// Message used by an upstream(Template Provider) to respond with an error to a
/// [`RequestTransactionData`] message.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct RequestTransactionDataError<'decoder> {
/// The template_id corresponding to a NewTemplate/RequestTransactionData message.
/// Identifier of the template that the downstream node is requesting transaction data for.
pub template_id: u64,
/// Reason why no transaction data has been provided
/// Reason why no transaction data has been provided.
///
/// Possible error codes:
/// * template-id-not-found
/// - template-id-not-found
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub error_code: Str0255<'decoder>,
}

/// C representation of [`RequestTransactionDataError`].
#[repr(C)]
#[cfg(not(feature = "with_serde"))]
pub struct CRequestTransactionDataError {
Expand All @@ -131,6 +147,7 @@ pub struct CRequestTransactionDataError {

#[cfg(not(feature = "with_serde"))]
impl<'a> CRequestTransactionDataError {
/// Converts C struct to Rust struct.
#[cfg(not(feature = "with_serde"))]
#[allow(clippy::wrong_self_convention)]
pub fn to_rust_rep_mut(&'a mut self) -> Result<RequestTransactionDataError<'a>, Error> {
Expand All @@ -142,6 +159,7 @@ impl<'a> CRequestTransactionDataError {
}
}

/// Drops the CRequestTransactionDataError object.
#[no_mangle]
#[cfg(not(feature = "with_serde"))]
pub extern "C" fn free_request_tx_data_error(s: CRequestTransactionDataError) {
Expand Down
Loading

0 comments on commit b651522

Please sign in to comment.