diff --git a/stratum-v1/Cargo.toml b/stratum-v1/Cargo.toml index 861da42..19235d3 100644 --- a/stratum-v1/Cargo.toml +++ b/stratum-v1/Cargo.toml @@ -2,25 +2,21 @@ # SPDX-License-Identifier: GPL-3.0-or-later [package] -name = "stratum-v1" -version = "0.1.0" +categories = ["embedded", "no-std"] description = """Stratum v1 client. This provides a `#[no_std]` library to implement a Stratum v1 client.""" -categories = [ - "embedded", - "no-std", -] -homepage.workspace = true edition = "2021" +homepage.workspace = true license = "GPL-3.0-or-later AND GPL-3.0-only" +name = "stratum-v1" +version = "0.1.0" [dependencies] bitcoin = { version = "0.32", default-features = false } bitcoin_hashes = { workspace = true } defmt = { workspace = true, optional = true } derive_more = { workspace = true, features = ["from"] } -embedded-io = { workspace = true } embedded-io-async = { workspace = true } faster-hex = { version = "0.9", default-features = false, git = "https://github.com/Georges760/faster-hex.git", branch = "no-alloc-error-partialeq" } heapless = { workspace = true, features = ["serde"] } @@ -28,17 +24,20 @@ log = { workspace = true, optional = true } serde = { workspace = true } serde-json-core = { workspace = true, features = ["custom-error-messages"] } -[dev-dependencies] -tokio = { version = "1", features = ["full"] } -embedded-io-adapters = { version = "0.6", features = ["tokio-1"] } -env_logger = "0.10.1" -log = { workspace = true } - [features] default = [] -defmt = ["dep:defmt", "heapless/defmt-03"] -log = ["dep:log"] +defmt-03 = [ + "dep:defmt", + "embedded-io-async/defmt-03", + "heapless/defmt-03" +] + +[dev-dependencies] +embedded-io = { workspace = true, features = ["std"] } +env_logger = "0.11" +inquire = "0.7" +tokio = { version = "1", features = ["full"] } [[example]] -name = "tokio-cli" +name = "stratum-v1-cli" path = "examples/tokio-cli.rs" diff --git a/stratum-v1/examples/tokio-cli.rs b/stratum-v1/examples/tokio-cli.rs index 3fa2849..2fc0e73 100644 --- a/stratum-v1/examples/tokio-cli.rs +++ b/stratum-v1/examples/tokio-cli.rs @@ -3,14 +3,15 @@ #![allow(static_mut_refs)] +use stratum_v1::{Client, Extensions, Share, VersionRolling, Work}; + +use heapless::{spsc::Queue, String, Vec}; +use inquire::Select; use std::{ net::{Ipv4Addr, SocketAddr}, str::FromStr, time::Duration, }; - -use heapless::{spsc::Queue, String, Vec}; -use stratum_v1::{Client, Extensions, Share, VersionRolling, Work}; use tokio::{ io::{ReadHalf, WriteHalf}, net::TcpStream, @@ -20,9 +21,14 @@ use tokio::{ async fn main() -> Result<(), Box<dyn std::error::Error>> { env_logger::init(); - let addr = SocketAddr::new(Ipv4Addr::new(68, 235, 52, 36).into(), 21496); // PP + let pool = + Select::new("Which Pool should be used?", vec!["Public-Pool", "Braiins"]).prompt()?; - // let addr = SocketAddr::new(Ipv4Addr::new(64, 225, 5, 77).into(), 3333); // braiins + let addr = match pool { + "Public-Pool" => SocketAddr::new(Ipv4Addr::new(68, 235, 52, 36).into(), 21496), + "Braiins" => SocketAddr::new(Ipv4Addr::new(64, 225, 5, 77).into(), 3333), + _ => unreachable!(), + }; let stream = TcpStream::connect(addr).await?; let (stream_reader, stream_writer) = tokio::io::split(stream); @@ -90,9 +96,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> { tokio::time::sleep(Duration::from_millis(1000)).await; client_tx .send_authorize( - String::<64>::from_str("1HLQGxzAQWnLore3fWHc2W8UP1CgMv1GKQ.miner1").unwrap(), - // String::<32>::from_str("slush.miner1").unwrap(), - String::<64>::from_str("password").unwrap(), + match pool { + "Public-Pool" => { + String::<64>::from_str("1HLQGxzAQWnLore3fWHc2W8UP1CgMv1GKQ.miner1").unwrap() + } + "Braiins" => String::<64>::from_str("slush.miner1").unwrap(), + _ => unreachable!(), + }, + String::<64>::from_str("x").unwrap(), ) .await .unwrap(); diff --git a/stratum-v1/src/client/job.rs b/stratum-v1/src/client/job.rs index 77ce953..ff9185c 100644 --- a/stratum-v1/src/client/job.rs +++ b/stratum-v1/src/client/job.rs @@ -9,7 +9,7 @@ use bitcoin::{ use heapless::{String, Vec}; #[derive(Debug)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +// #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Job { pub job_id: u64, pub extranonce2: Vec<u8, 8>, @@ -19,7 +19,7 @@ pub struct Job { //TODO: implement defmt::Format manually because Header does not implement it #[derive(Debug, Default)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub(crate) struct JobCreator { job_id: u64, last_job_id: String<32>, diff --git a/stratum-v1/src/client/mod.rs b/stratum-v1/src/client/mod.rs index 417862b..19f1028 100644 --- a/stratum-v1/src/client/mod.rs +++ b/stratum-v1/src/client/mod.rs @@ -20,14 +20,14 @@ use heapless::{ }; #[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Client<R: Read, W: Write, const RX_BUF_SIZE: usize, const TX_BUF_SIZE: usize> { phantom_read: core::marker::PhantomData<R>, phantom_write: core::marker::PhantomData<W>, } // #[derive(Debug)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +// #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct ClientRx<R: Read, const BUF_SIZE: usize> { network_reader: R, buf: [u8; BUF_SIZE], @@ -47,7 +47,7 @@ pub struct ClientRx<R: Read, const BUF_SIZE: usize> { } // #[derive(Debug, PartialEq)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +// #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct ClientTx<W: Write, const BUF_SIZE: usize> { network_writer: W, buf: [u8; BUF_SIZE], diff --git a/stratum-v1/src/client/notification.rs b/stratum-v1/src/client/notification.rs index 54247dd..519e94f 100644 --- a/stratum-v1/src/client/notification.rs +++ b/stratum-v1/src/client/notification.rs @@ -9,7 +9,7 @@ use serde::Deserialize; use super::request::Request; #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Work { pub job_id: String<32>, pub prev_hash: [u8; 32], @@ -23,7 +23,7 @@ pub struct Work { } #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub enum Notification { SetVersionMask, Notify, @@ -32,7 +32,7 @@ pub enum Notification { pub(crate) fn parse_method(resp: &[u8]) -> Result<Notification> { #[derive(Debug, Deserialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct MethodOnly { method: String<32>, } @@ -65,7 +65,7 @@ pub(crate) fn parse_set_version_mask(resp: &[u8]) -> Result<u32> { pub(crate) fn parse_notify(resp: &[u8]) -> Result<Work> { #[derive(Debug, Deserialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct WorkRaw( // Job ID. This is included when miners submit a results so work can be matched with proper transactions. String<32>, diff --git a/stratum-v1/src/client/request.rs b/stratum-v1/src/client/request.rs index 90c2a33..df43566 100644 --- a/stratum-v1/src/client/request.rs +++ b/stratum-v1/src/client/request.rs @@ -7,7 +7,7 @@ use heapless::{String, Vec}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub(crate) enum ReqKind { Configure, Connect, @@ -16,7 +16,7 @@ pub(crate) enum ReqKind { } #[derive(Debug, Clone)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub(crate) struct ReqIdKind(pub(crate) u64, pub(crate) ReqKind); ///Request representation. @@ -31,7 +31,7 @@ pub(crate) struct ReqIdKind(pub(crate) u64, pub(crate) ReqKind); ///- `T` - specifies textual type. By default it uses static buffer of 32 bytes, which is more than enough in normal cases. #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] #[serde(deny_unknown_fields)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Request<P> { #[serde(skip_serializing_if = "Option::is_none")] ///An identifier established by the Client. @@ -49,7 +49,7 @@ pub struct Request<P> { } #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct VersionRolling { /// Bits set to 1 can be changed by the miner. /// If a miner changes bits with mask value 0, the server will reject the submit. @@ -59,7 +59,7 @@ pub struct VersionRolling { } #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Info { /// Exact URL used by the mining software to connect to the stratum server. pub connection_url: Option<String<32>>, @@ -72,7 +72,7 @@ pub struct Info { } #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Extensions { /// This extension allows the miner to change the value of some bits in the version field /// in the block header. Currently there are no standard bits used for version rolling @@ -95,7 +95,7 @@ pub(crate) fn configure(id: u64, exts: Extensions, buf: &mut [u8]) -> Result<usi type ExtList = Vec<String<32>, 4>; #[derive(Debug, Serialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct ExtParams { #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "version-rolling.mask")] @@ -127,7 +127,7 @@ pub(crate) fn configure(id: u64, exts: Extensions, buf: &mut [u8]) -> Result<usi } #[derive(Debug, Serialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct ConfigureParams(ExtList, ExtParams); let mut ext_list = Vec::new(); @@ -223,7 +223,7 @@ pub(crate) fn authorize( } #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Share { pub job_id: String<64>, pub extranonce2: Vec<u8, 8>, diff --git a/stratum-v1/src/client/response.rs b/stratum-v1/src/client/response.rs index e89624b..136e3dd 100644 --- a/stratum-v1/src/client/response.rs +++ b/stratum-v1/src/client/response.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Deserializer}; pub(crate) fn parse_id(resp: &[u8]) -> Result<Option<u64>> { #[derive(Debug, Deserialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct IdOnly { id: Option<u64>, } @@ -33,7 +33,7 @@ pub(crate) fn parse_id(resp: &[u8]) -> Result<Option<u64>> { /// ///- `R` - Type of payload for successful response #[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct Response<R> { ///An identifier established by the Client. /// @@ -52,7 +52,7 @@ impl<'de, R: Deserialize<'de>> Deserialize<'de> for Response<R> { use serde::de::{self, Visitor}; #[derive(Debug, Deserialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct RespErr(isize, String<32>, Option<String<32>>); impl From<RespErr> for Error { @@ -183,7 +183,7 @@ impl<'de, R: Deserialize<'de>> Deserialize<'de> for Response<R> { pub(crate) fn parse_configure(resp: &[u8]) -> Result<Extensions> { #[derive(Debug, Deserialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct ConfigureRespRaw { #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "version-rolling")] @@ -283,7 +283,7 @@ pub(crate) fn parse_configure(resp: &[u8]) -> Result<Extensions> { pub type Subscription = Vec<String<32>, 2>; #[derive(Debug, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub struct ConnectResp { pub subscriptions: Vec<Subscription, 2>, pub extranonce1: Vec<u8, 8>, @@ -292,7 +292,7 @@ pub struct ConnectResp { pub(crate) fn parse_connect(resp: &[u8]) -> Result<ConnectResp> { #[derive(Debug, Deserialize)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] + #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] struct ConnectRespRaw( // Subscriptions details - 2-tuple with name of subscribed notification and subscription ID. Theoretically it may be used for unsubscribing, but obviously miners won't use it. Vec<Vec<String<32>, 2>, 2>, diff --git a/stratum-v1/src/error.rs b/stratum-v1/src/error.rs index b8810ec..d8c6652 100644 --- a/stratum-v1/src/error.rs +++ b/stratum-v1/src/error.rs @@ -7,7 +7,7 @@ use heapless::String; pub type Result<T> = core::result::Result<T, Error>; #[derive(Debug, Clone, From, PartialEq)] -// #[cfg_attr(feature = "defmt", derive(defmt::Format))] +// #[cfg_attr(feature = "defmt-03", derive(defmt::Format))] pub enum Error { /// Client is already configured against the Pool AlreadyConfigured, diff --git a/stratum-v1/src/fmt.rs b/stratum-v1/src/fmt.rs index 0669708..1d91499 100644 --- a/stratum-v1/src/fmt.rs +++ b/stratum-v1/src/fmt.rs @@ -1,15 +1,15 @@ #![macro_use] #![allow(unused_macros)] -#[cfg(all(feature = "defmt", feature = "log"))] +#[cfg(all(feature = "defmt-03", feature = "log"))] compile_error!("You may not enable both `defmt` and `log` features."); macro_rules! assert { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::assert!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::assert!($($x)*); } }; @@ -18,9 +18,9 @@ macro_rules! assert { macro_rules! assert_eq { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::assert_eq!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::assert_eq!($($x)*); } }; @@ -29,9 +29,9 @@ macro_rules! assert_eq { macro_rules! assert_ne { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::assert_ne!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::assert_ne!($($x)*); } }; @@ -40,9 +40,9 @@ macro_rules! assert_ne { macro_rules! debug_assert { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::debug_assert!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::debug_assert!($($x)*); } }; @@ -51,9 +51,9 @@ macro_rules! debug_assert { macro_rules! debug_assert_eq { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::debug_assert_eq!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::debug_assert_eq!($($x)*); } }; @@ -62,9 +62,9 @@ macro_rules! debug_assert_eq { macro_rules! debug_assert_ne { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::debug_assert_ne!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::debug_assert_ne!($($x)*); } }; @@ -73,9 +73,9 @@ macro_rules! debug_assert_ne { macro_rules! todo { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::todo!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::todo!($($x)*); } }; @@ -84,9 +84,9 @@ macro_rules! todo { macro_rules! unreachable { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::unreachable!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::unreachable!($($x)*); } }; @@ -95,9 +95,9 @@ macro_rules! unreachable { macro_rules! panic { ($($x:tt)*) => { { - #[cfg(not(feature = "defmt"))] + #[cfg(not(feature = "defmt-03"))] ::core::panic!($($x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::panic!($($x)*); } }; @@ -108,9 +108,9 @@ macro_rules! trace { { #[cfg(feature = "log")] ::log::trace!($s $(, $x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::trace!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] + #[cfg(not(any(feature = "log", feature="defmt-03")))] let _ = ($( & $x ),*); } }; @@ -121,9 +121,9 @@ macro_rules! debug { { #[cfg(feature = "log")] ::log::debug!($s $(, $x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::debug!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] + #[cfg(not(any(feature = "log", feature="defmt-03")))] let _ = ($( & $x ),*); } }; @@ -134,9 +134,9 @@ macro_rules! info { { #[cfg(feature = "log")] ::log::info!($s $(, $x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::info!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] + #[cfg(not(any(feature = "log", feature="defmt-03")))] let _ = ($( & $x ),*); } }; @@ -147,9 +147,9 @@ macro_rules! warn { { #[cfg(feature = "log")] ::log::warn!($s $(, $x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::warn!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] + #[cfg(not(any(feature = "log", feature="defmt-03")))] let _ = ($( & $x ),*); } }; @@ -160,22 +160,22 @@ macro_rules! error { { #[cfg(feature = "log")] ::log::error!($s $(, $x)*); - #[cfg(feature = "defmt")] + #[cfg(feature = "defmt-03")] ::defmt::error!($s $(, $x)*); - #[cfg(not(any(feature = "log", feature="defmt")))] + #[cfg(not(any(feature = "log", feature="defmt-03")))] let _ = ($( & $x ),*); } }; } -#[cfg(feature = "defmt")] +#[cfg(feature = "defmt-03")] macro_rules! unwrap { ($($x:tt)*) => { ::defmt::unwrap!($($x)*) }; } -#[cfg(not(feature = "defmt"))] +#[cfg(not(feature = "defmt-03"))] macro_rules! unwrap { ($arg:expr) => { match $crate::fmt::Try::into_result($arg) { @@ -198,6 +198,7 @@ macro_rules! unwrap { #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct NoneError; +#[allow(dead_code)] pub trait Try { type Ok; type Error; diff --git a/stratum-v1/src/lib.rs b/stratum-v1/src/lib.rs index 321446f..ad680a0 100644 --- a/stratum-v1/src/lib.rs +++ b/stratum-v1/src/lib.rs @@ -5,12 +5,11 @@ //! //! This library provides client side functions to create requests and parse responses for Stratum v1 protocol. -#![macro_use] #![no_std] -#![allow(dead_code)] #![allow(static_mut_refs)] #![allow(stable_features)] // remove this once rust 1.81 is stable #![feature(error_in_core)] +#![macro_use] pub(crate) mod fmt; mod client;