Skip to main content

template_distribution_sv2/
lib.rs

1//! # Stratum V2 Template Distribution Protocol Messages Crate
2//!
3//!
4//! `template_distribution_sv2` is a Rust crate that implements a set of messages defined in the
5//! Template Distribution Protocol of Stratum V2. The Template Distribution protocol can be used
6//! to receive updates of the block templates to use in mining.
7//!
8//! ## Build Options
9//! This crate can be built with the following features:
10//! - `std`: Enables support for standard library features.
11//! - `prop_test`: Enables support for property testing.
12//!
13//! For further information about the messages, please refer to [Stratum V2 documentation - Job
14//! Distribution](https://stratumprotocol.org/specification/07-Template-Distribution-Protocol/).
15
16#![no_std]
17
18extern crate alloc;
19
20#[cfg(feature = "prop_test")]
21use alloc::vec;
22#[cfg(feature = "prop_test")]
23use core::convert::TryInto;
24#[cfg(feature = "prop_test")]
25use quickcheck::{Arbitrary, Gen};
26
27mod coinbase_output_constraints;
28mod new_template;
29mod request_transaction_data;
30mod set_new_prev_hash;
31mod submit_solution;
32
33pub use coinbase_output_constraints::CoinbaseOutputConstraints;
34pub use new_template::NewTemplate;
35pub use request_transaction_data::{
36    RequestTransactionData, RequestTransactionDataError, RequestTransactionDataSuccess,
37};
38pub use set_new_prev_hash::SetNewPrevHash;
39pub use submit_solution::SubmitSolution;
40
41// Template Distribution Protocol message types.
42pub const MESSAGE_TYPE_COINBASE_OUTPUT_CONSTRAINTS: u8 = 0x70;
43pub const MESSAGE_TYPE_NEW_TEMPLATE: u8 = 0x71;
44pub const MESSAGE_TYPE_SET_NEW_PREV_HASH: u8 = 0x72;
45pub const MESSAGE_TYPE_REQUEST_TRANSACTION_DATA: u8 = 0x73;
46pub const MESSAGE_TYPE_REQUEST_TRANSACTION_DATA_SUCCESS: u8 = 0x74;
47pub const MESSAGE_TYPE_REQUEST_TRANSACTION_DATA_ERROR: u8 = 0x75;
48pub const MESSAGE_TYPE_SUBMIT_SOLUTION: u8 = 0x76;
49
50// For the Template Distribution protocol, the channel bit is always unset.
51pub const CHANNEL_BIT_COINBASE_OUTPUT_CONSTRAINTS: bool = false;
52pub const CHANNEL_BIT_NEW_TEMPLATE: bool = false;
53pub const CHANNEL_BIT_SET_NEW_PREV_HASH: bool = false;
54pub const CHANNEL_BIT_REQUEST_TRANSACTION_DATA: bool = false;
55pub const CHANNEL_BIT_REQUEST_TRANSACTION_DATA_SUCCESS: bool = false;
56pub const CHANNEL_BIT_REQUEST_TRANSACTION_DATA_ERROR: bool = false;
57pub const CHANNEL_BIT_SUBMIT_SOLUTION: bool = false;
58
59#[cfg(feature = "prop_test")]
60impl NewTemplate<'static> {
61    pub fn from_gen(g: &mut Gen) -> Self {
62        let mut coinbase_prefix_gen = Gen::new(255);
63        let mut coinbase_prefix: vec::Vec<u8> = vec::Vec::new();
64        coinbase_prefix.resize_with(255, || u8::arbitrary(&mut coinbase_prefix_gen));
65        let coinbase_prefix: binary_sv2::B0255 = coinbase_prefix.try_into().unwrap();
66
67        let mut coinbase_tx_outputs_gen = Gen::new(64);
68        let mut coinbase_tx_outputs: vec::Vec<u8> = vec::Vec::new();
69        coinbase_tx_outputs.resize_with(64, || u8::arbitrary(&mut coinbase_tx_outputs_gen));
70        let coinbase_tx_outputs: binary_sv2::B064K = coinbase_tx_outputs.try_into().unwrap();
71
72        let mut merkle_path_inner_gen = Gen::new(32);
73        let mut merkle_path_inner: vec::Vec<u8> = vec::Vec::new();
74        merkle_path_inner.resize_with(32, || u8::arbitrary(&mut merkle_path_inner_gen));
75        let merkle_path_inner: binary_sv2::U256 = merkle_path_inner.try_into().unwrap();
76
77        let merkle_path: binary_sv2::Seq0255<binary_sv2::U256> = vec![merkle_path_inner].into();
78        NewTemplate {
79            template_id: u64::arbitrary(g),
80            future_template: bool::arbitrary(g),
81            version: u32::arbitrary(g),
82            coinbase_tx_version: u32::arbitrary(g),
83            coinbase_prefix,
84            coinbase_tx_input_sequence: u32::arbitrary(g),
85            coinbase_tx_value_remaining: u64::arbitrary(g),
86            coinbase_tx_outputs_count: u32::arbitrary(g),
87            coinbase_tx_outputs,
88            coinbase_tx_locktime: u32::arbitrary(g),
89            merkle_path,
90        }
91    }
92}
93#[cfg(feature = "prop_test")]
94impl CoinbaseOutputConstraints {
95    pub fn from_gen(g: &mut Gen) -> Self {
96        CoinbaseOutputConstraints {
97            coinbase_output_max_additional_size: u32::arbitrary(g),
98            coinbase_output_max_additional_sigops: u16::arbitrary(g),
99        }
100    }
101}
102
103#[cfg(feature = "prop_test")]
104impl RequestTransactionData {
105    pub fn from_gen(g: &mut Gen) -> Self {
106        RequestTransactionData {
107            template_id: u64::arbitrary(g),
108        }
109    }
110}
111
112#[cfg(feature = "prop_test")]
113impl RequestTransactionDataError<'static> {
114    pub fn from_gen(g: &mut Gen) -> Self {
115        let mut error_code_gen = Gen::new(255);
116        let mut error_code: vec::Vec<u8> = vec::Vec::new();
117        error_code.resize_with(255, || u8::arbitrary(&mut error_code_gen));
118        let error_code: binary_sv2::Str0255 = error_code.try_into().unwrap();
119
120        RequestTransactionDataError {
121            template_id: u64::arbitrary(g),
122            error_code,
123        }
124    }
125}
126
127#[cfg(feature = "prop_test")]
128impl RequestTransactionDataSuccess<'static> {
129    pub fn from_gen(g: &mut Gen) -> Self {
130        let excess_data: binary_sv2::B064K = vec::Vec::<u8>::arbitrary(g).try_into().unwrap();
131        let transaction_list_inner = binary_sv2::B016M::from_gen(g);
132        let transaction_list: binary_sv2::Seq064K<binary_sv2::B016M> =
133            vec![transaction_list_inner].into();
134
135        RequestTransactionDataSuccess {
136            template_id: u64::arbitrary(g),
137            excess_data,
138            transaction_list,
139        }
140    }
141}
142
143#[cfg(feature = "prop_test")]
144impl SetNewPrevHash<'static> {
145    pub fn from_gen(g: &mut Gen) -> Self {
146        let prev_hash = binary_sv2::U256::from_gen(g);
147        let target = binary_sv2::U256::from_gen(g);
148        SetNewPrevHash {
149            template_id: u64::arbitrary(g),
150            prev_hash,
151            header_timestamp: u32::arbitrary(g),
152            n_bits: u32::arbitrary(g),
153            target,
154        }
155    }
156}
157
158#[cfg(feature = "prop_test")]
159impl SubmitSolution<'static> {
160    pub fn from_gen(g: &mut Gen) -> Self {
161        let coinbase_tx: binary_sv2::B064K = vec::Vec::<u8>::arbitrary(g).try_into().unwrap();
162        SubmitSolution {
163            template_id: u64::arbitrary(g),
164            version: u32::arbitrary(g),
165            header_timestamp: u32::arbitrary(g),
166            header_nonce: u32::arbitrary(g),
167            coinbase_tx,
168        }
169    }
170}