diff --git a/common/Cargo.lock b/common/Cargo.lock index 93c2609315..613baeac84 100644 --- a/common/Cargo.lock +++ b/common/Cargo.lock @@ -562,6 +562,19 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "handlers_sv2" +version = "0.1.0" +dependencies = [ + "binary_sv2", + "common_messages_sv2", + "job_declaration_sv2", + "mining_sv2", + "parsers_sv2", + "template_distribution_sv2", + "trait-variant", +] + [[package]] name = "hashbrown" version = "0.15.4" @@ -956,6 +969,7 @@ dependencies = [ "channels_sv2", "codec_sv2", "common_messages_sv2", + "handlers_sv2", "hex-conservative 0.3.0", "job_declaration_sv2", "mining_sv2", @@ -1013,7 +1027,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "bitcoin_hashes 0.13.0", + "bitcoin_hashes 0.14.0", "secp256k1-sys 0.10.1", ] @@ -1254,6 +1268,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" version = "1.18.0" diff --git a/protocols/Cargo.toml b/protocols/Cargo.toml index 3380c8827c..2b4c8727e5 100644 --- a/protocols/Cargo.toml +++ b/protocols/Cargo.toml @@ -17,7 +17,8 @@ members = [ "v2/sv2-ffi", "v2/roles-logic-sv2", "v2/channels-sv2", - "v2/parsers-sv2", + "v2/parsers-sv2", + "v2/handlers-sv2", ] [profile.dev] diff --git a/protocols/v2/handlers-sv2/Cargo.toml b/protocols/v2/handlers-sv2/Cargo.toml new file mode 100644 index 0000000000..492f8bcc69 --- /dev/null +++ b/protocols/v2/handlers-sv2/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "handlers_sv2" +version = "0.1.0" +authors = ["The Stratum V2 Developers"] +edition = "2018" +readme = "README.md" +description = "Sv2 Message handlers" +documentation = "https://docs.rs/handlers_sv2" +license = "MIT OR Apache-2.0" +repository = "https://github.com/stratum-mining/stratum" +homepage = "https://stratumprotocol.org" +keywords = ["stratum", "mining", "bitcoin", "protocol"] + +[dependencies] +trait-variant = "0.1.2" +parsers_sv2 = { path = "../parsers-sv2", version = "^0.1.0"} +binary_sv2 = { path = "../binary-sv2", version = "^3.0.0" } +common_messages_sv2 = { path = "../subprotocols/common-messages", version = "^5.0.0" } +mining_sv2 = { path = "../subprotocols/mining", version = "^4.0.0" } +template_distribution_sv2 = { path = "../subprotocols/template-distribution", version = "^3.0.0" } +job_declaration_sv2 = { path = "../subprotocols/job-declaration", version = "^4.0.0" } diff --git a/protocols/v2/handlers-sv2/src/common.rs b/protocols/v2/handlers-sv2/src/common.rs new file mode 100644 index 0000000000..b45a685734 --- /dev/null +++ b/protocols/v2/handlers-sv2/src/common.rs @@ -0,0 +1,156 @@ +use crate::error::HandlerError as Error; +use common_messages_sv2::{ + ChannelEndpointChanged, Reconnect, SetupConnectionError, SetupConnectionSuccess, *, +}; +use core::convert::TryInto; +use parsers_sv2::CommonMessages; + +pub trait HandleCommonMessagesFromServerSync { + fn handle_common_message(&mut self, message_type: u8, payload: &mut [u8]) -> Result<(), Error> { + let parsed: CommonMessages<'_> = (message_type, payload).try_into()?; + self.dispatch_common_message(parsed) + } + + fn dispatch_common_message(&mut self, message: CommonMessages<'_>) -> Result<(), Error> { + match message { + CommonMessages::SetupConnectionSuccess(msg) => { + self.handle_setup_connection_success(msg) + } + CommonMessages::SetupConnectionError(msg) => self.handle_setup_connection_error(msg), + CommonMessages::ChannelEndpointChanged(msg) => { + self.handle_channel_endpoint_changed(msg) + } + CommonMessages::Reconnect(msg) => self.handle_reconnect(msg), + + CommonMessages::SetupConnection(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_SETUP_CONNECTION)) + } + } + } + + fn handle_setup_connection_success(&mut self, msg: SetupConnectionSuccess) + -> Result<(), Error>; + + fn handle_setup_connection_error(&mut self, msg: SetupConnectionError) -> Result<(), Error>; + + fn handle_channel_endpoint_changed(&mut self, msg: ChannelEndpointChanged) + -> Result<(), Error>; + + fn handle_reconnect(&mut self, msg: Reconnect) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleCommonMessagesFromServerAsync { + async fn handle_common_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result, _> = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_common_message(parsed).await + } + } + + async fn dispatch_common_message(&mut self, message: CommonMessages<'_>) -> Result<(), Error> { + async move { + match message { + CommonMessages::SetupConnectionSuccess(msg) => { + self.handle_setup_connection_success(msg).await + } + CommonMessages::SetupConnectionError(msg) => { + self.handle_setup_connection_error(msg).await + } + CommonMessages::ChannelEndpointChanged(msg) => { + self.handle_channel_endpoint_changed(msg).await + } + CommonMessages::Reconnect(msg) => self.handle_reconnect(msg).await, + + CommonMessages::SetupConnection(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_SETUP_CONNECTION)) + } + } + } + } + + async fn handle_setup_connection_success( + &mut self, + msg: SetupConnectionSuccess, + ) -> Result<(), Error>; + + async fn handle_setup_connection_error( + &mut self, + msg: SetupConnectionError, + ) -> Result<(), Error>; + + async fn handle_channel_endpoint_changed( + &mut self, + msg: ChannelEndpointChanged, + ) -> Result<(), Error>; + + async fn handle_reconnect(&mut self, msg: Reconnect) -> Result<(), Error>; +} + +pub trait HandleCommonMessagesFromClientSync { + fn handle_common_message(&mut self, message_type: u8, payload: &mut [u8]) -> Result<(), Error> { + let parsed: CommonMessages<'_> = (message_type, payload).try_into()?; + self.dispatch_common_message(parsed) + } + + fn dispatch_common_message(&mut self, message: CommonMessages<'_>) -> Result<(), Error> { + match message { + CommonMessages::SetupConnectionSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS, + )), + CommonMessages::SetupConnectionError(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SETUP_CONNECTION_ERROR, + )), + CommonMessages::ChannelEndpointChanged(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_CHANNEL_ENDPOINT_CHANGED, + )), + CommonMessages::Reconnect(_) => Err(Error::UnexpectedMessage(MESSAGE_TYPE_RECONNECT)), + + CommonMessages::SetupConnection(msg) => self.handle_setup_connection(msg), + } + } + + fn handle_setup_connection(&mut self, msg: SetupConnection) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleCommonMessagesFromClientAsync { + async fn handle_common_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result, _> = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_common_message(parsed).await + } + } + + async fn dispatch_common_message(&mut self, message: CommonMessages<'_>) -> Result<(), Error> { + async move { + match message { + CommonMessages::SetupConnectionSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS, + )), + CommonMessages::SetupConnectionError(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SETUP_CONNECTION_ERROR, + )), + CommonMessages::ChannelEndpointChanged(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_CHANNEL_ENDPOINT_CHANGED, + )), + CommonMessages::Reconnect(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_RECONNECT)) + } + CommonMessages::SetupConnection(msg) => self.handle_setup_connection(msg).await, + } + } + } + + async fn handle_setup_connection(&mut self, msg: SetupConnection) -> Result<(), Error>; +} diff --git a/protocols/v2/handlers-sv2/src/error.rs b/protocols/v2/handlers-sv2/src/error.rs new file mode 100644 index 0000000000..d2fdb13b4a --- /dev/null +++ b/protocols/v2/handlers-sv2/src/error.rs @@ -0,0 +1,14 @@ +use parsers_sv2::ParserError; + +#[derive(Debug)] +pub enum HandlerError { + UnexpectedMessage(u8), + ParserError(ParserError), + External(Box), +} + +impl From for HandlerError { + fn from(value: ParserError) -> HandlerError { + HandlerError::ParserError(value) + } +} diff --git a/protocols/v2/handlers-sv2/src/job_declaration.rs b/protocols/v2/handlers-sv2/src/job_declaration.rs new file mode 100644 index 0000000000..d92dd547a7 --- /dev/null +++ b/protocols/v2/handlers-sv2/src/job_declaration.rs @@ -0,0 +1,238 @@ +use crate::error::HandlerError as Error; +use core::convert::TryInto; +use job_declaration_sv2::{ + MESSAGE_TYPE_ALLOCATE_MINING_JOB_TOKEN, MESSAGE_TYPE_ALLOCATE_MINING_JOB_TOKEN_SUCCESS, + MESSAGE_TYPE_DECLARE_MINING_JOB, MESSAGE_TYPE_DECLARE_MINING_JOB_ERROR, + MESSAGE_TYPE_DECLARE_MINING_JOB_SUCCESS, MESSAGE_TYPE_PROVIDE_MISSING_TRANSACTIONS, + MESSAGE_TYPE_PROVIDE_MISSING_TRANSACTIONS_SUCCESS, MESSAGE_TYPE_PUSH_SOLUTION, *, +}; +use parsers_sv2::JobDeclaration; + +pub trait HandleJobDeclarationMessagesFromServerSync { + fn handle_job_declaration_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: JobDeclaration<'_> = (message_type, payload).try_into()?; + self.dispatch_job_declaration(parsed) + } + + fn dispatch_job_declaration(&mut self, message: JobDeclaration<'_>) -> Result<(), Error> { + match message { + JobDeclaration::AllocateMiningJobTokenSuccess(msg) => { + self.handle_allocate_mining_job_token_success(msg) + } + JobDeclaration::DeclareMiningJobSuccess(msg) => { + self.handle_declare_mining_job_success(msg) + } + JobDeclaration::DeclareMiningJobError(msg) => self.handle_declare_mining_job_error(msg), + JobDeclaration::ProvideMissingTransactions(msg) => { + self.handle_provide_missing_transactions(msg) + } + JobDeclaration::AllocateMiningJobToken(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_ALLOCATE_MINING_JOB_TOKEN, + )), + JobDeclaration::DeclareMiningJob(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_DECLARE_MINING_JOB)) + } + JobDeclaration::ProvideMissingTransactionsSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_PROVIDE_MISSING_TRANSACTIONS_SUCCESS, + )), + JobDeclaration::PushSolution(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_PUSH_SOLUTION)) + } + } + } + + fn handle_allocate_mining_job_token_success( + &mut self, + msg: AllocateMiningJobTokenSuccess, + ) -> Result<(), Error>; + + fn handle_declare_mining_job_success( + &mut self, + msg: DeclareMiningJobSuccess, + ) -> Result<(), Error>; + + fn handle_declare_mining_job_error(&mut self, msg: DeclareMiningJobError) -> Result<(), Error>; + + fn handle_provide_missing_transactions( + &mut self, + msg: ProvideMissingTransactions, + ) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleJobDeclarationMessagesFromServerAsync { + async fn handle_job_declaration_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result, _> = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_job_declaration(parsed).await + } + } + + async fn dispatch_job_declaration(&mut self, message: JobDeclaration<'_>) -> Result<(), Error> { + async move { + match message { + JobDeclaration::AllocateMiningJobTokenSuccess(msg) => { + self.handle_allocate_mining_job_token_success(msg).await + } + JobDeclaration::DeclareMiningJobSuccess(msg) => { + self.handle_declare_mining_job_success(msg).await + } + JobDeclaration::DeclareMiningJobError(msg) => { + self.handle_declare_mining_job_error(msg).await + } + JobDeclaration::ProvideMissingTransactions(msg) => { + self.handle_provide_missing_transactions(msg).await + } + JobDeclaration::AllocateMiningJobToken(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_ALLOCATE_MINING_JOB_TOKEN, + )), + JobDeclaration::DeclareMiningJob(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_DECLARE_MINING_JOB)) + } + JobDeclaration::ProvideMissingTransactionsSuccess(_) => Err( + Error::UnexpectedMessage(MESSAGE_TYPE_PROVIDE_MISSING_TRANSACTIONS_SUCCESS), + ), + JobDeclaration::PushSolution(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_PUSH_SOLUTION)) + } + } + } + } + + async fn handle_allocate_mining_job_token_success( + &mut self, + msg: AllocateMiningJobTokenSuccess, + ) -> Result<(), Error>; + + async fn handle_declare_mining_job_success( + &mut self, + msg: DeclareMiningJobSuccess, + ) -> Result<(), Error>; + + async fn handle_declare_mining_job_error( + &mut self, + msg: DeclareMiningJobError, + ) -> Result<(), Error>; + + async fn handle_provide_missing_transactions( + &mut self, + msg: ProvideMissingTransactions, + ) -> Result<(), Error>; +} + +pub trait HandleJobDeclarationMessagesFromClientSync { + fn handle_job_declaration_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: JobDeclaration<'_> = (message_type, payload).try_into()?; + self.dispatch_job_declaration(parsed) + } + + fn dispatch_job_declaration(&mut self, message: JobDeclaration<'_>) -> Result<(), Error> { + match message { + JobDeclaration::AllocateMiningJobToken(msg) => { + self.handle_allocate_mining_job_token(msg) + } + JobDeclaration::DeclareMiningJob(msg) => self.handle_declare_mining_job(msg), + JobDeclaration::ProvideMissingTransactionsSuccess(msg) => { + self.handle_provide_missing_transactions_success(msg) + } + JobDeclaration::PushSolution(msg) => self.handle_push_solution(msg), + + JobDeclaration::AllocateMiningJobTokenSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_ALLOCATE_MINING_JOB_TOKEN_SUCCESS, + )), + JobDeclaration::DeclareMiningJobSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_DECLARE_MINING_JOB_SUCCESS, + )), + JobDeclaration::DeclareMiningJobError(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_DECLARE_MINING_JOB_ERROR, + )), + JobDeclaration::ProvideMissingTransactions(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_PROVIDE_MISSING_TRANSACTIONS, + )), + } + } + + fn handle_allocate_mining_job_token( + &mut self, + msg: AllocateMiningJobToken, + ) -> Result<(), Error>; + + fn handle_declare_mining_job(&mut self, msg: DeclareMiningJob) -> Result<(), Error>; + + fn handle_provide_missing_transactions_success( + &mut self, + msg: ProvideMissingTransactionsSuccess, + ) -> Result<(), Error>; + + fn handle_push_solution(&mut self, msg: PushSolution) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleJobDeclarationMessagesFromClientAsync { + async fn handle_job_declaration_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result, _> = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_job_declaration(parsed).await + } + } + + async fn dispatch_job_declaration(&mut self, message: JobDeclaration<'_>) -> Result<(), Error> { + async move { + match message { + JobDeclaration::AllocateMiningJobToken(msg) => { + self.handle_allocate_mining_job_token(msg).await + } + JobDeclaration::DeclareMiningJob(msg) => self.handle_declare_mining_job(msg).await, + JobDeclaration::ProvideMissingTransactionsSuccess(msg) => { + self.handle_provide_missing_transactions_success(msg).await + } + JobDeclaration::PushSolution(msg) => self.handle_push_solution(msg).await, + + JobDeclaration::AllocateMiningJobTokenSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_ALLOCATE_MINING_JOB_TOKEN_SUCCESS, + )), + JobDeclaration::DeclareMiningJobSuccess(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_DECLARE_MINING_JOB_SUCCESS, + )), + JobDeclaration::DeclareMiningJobError(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_DECLARE_MINING_JOB_ERROR, + )), + JobDeclaration::ProvideMissingTransactions(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_PROVIDE_MISSING_TRANSACTIONS, + )), + } + } + } + + async fn handle_allocate_mining_job_token( + &mut self, + msg: AllocateMiningJobToken, + ) -> Result<(), Error>; + + async fn handle_declare_mining_job(&mut self, msg: DeclareMiningJob) -> Result<(), Error>; + + async fn handle_provide_missing_transactions_success( + &mut self, + msg: ProvideMissingTransactionsSuccess, + ) -> Result<(), Error>; + + async fn handle_push_solution(&mut self, msg: PushSolution) -> Result<(), Error>; +} diff --git a/protocols/v2/handlers-sv2/src/lib.rs b/protocols/v2/handlers-sv2/src/lib.rs new file mode 100644 index 0000000000..1c602fbe2a --- /dev/null +++ b/protocols/v2/handlers-sv2/src/lib.rs @@ -0,0 +1,29 @@ +mod common; +mod error; +mod job_declaration; +mod mining; +mod template_distribution; + +pub use error::HandlerError; + +pub use common::{ + HandleCommonMessagesFromClientAsync, HandleCommonMessagesFromClientSync, + HandleCommonMessagesFromServerAsync, HandleCommonMessagesFromServerSync, +}; + +pub use mining::{ + HandleMiningMessagesFromClientAsync, HandleMiningMessagesFromClientSync, + HandleMiningMessagesFromServerAsync, HandleMiningMessagesFromServerSync, SupportedChannelTypes, +}; + +pub use template_distribution::{ + HandleTemplateDistributionMessagesFromClientAsync, + HandleTemplateDistributionMessagesFromClientSync, + HandleTemplateDistributionMessagesFromServerAsync, + HandleTemplateDistributionMessagesFromServerSync, +}; + +pub use job_declaration::{ + HandleJobDeclarationMessagesFromClientAsync, HandleJobDeclarationMessagesFromClientSync, + HandleJobDeclarationMessagesFromServerAsync, HandleJobDeclarationMessagesFromServerSync, +}; diff --git a/protocols/v2/handlers-sv2/src/mining.rs b/protocols/v2/handlers-sv2/src/mining.rs new file mode 100644 index 0000000000..0dd742f67b --- /dev/null +++ b/protocols/v2/handlers-sv2/src/mining.rs @@ -0,0 +1,508 @@ +use crate::error::HandlerError as Error; +use binary_sv2::Str0255; +use mining_sv2::{ + CloseChannel, NewExtendedMiningJob, NewMiningJob, OpenExtendedMiningChannel, + OpenExtendedMiningChannelSuccess, OpenMiningChannelError, OpenStandardMiningChannel, + OpenStandardMiningChannelSuccess, SetCustomMiningJob, SetCustomMiningJobError, + SetCustomMiningJobSuccess, SetExtranoncePrefix, SetGroupChannel, SetNewPrevHash, SetTarget, + SubmitSharesError, SubmitSharesExtended, SubmitSharesStandard, SubmitSharesSuccess, + UpdateChannel, UpdateChannelError, +}; +use parsers_sv2::Mining; +use std::convert::TryInto; + +use mining_sv2::*; + +#[derive(PartialEq, Eq)] +pub enum SupportedChannelTypes { + Standard, + Extended, + Group, + GroupAndExtended, +} + +pub trait HandleMiningMessagesFromClientSync { + fn get_channel_type(&self) -> SupportedChannelTypes; + fn is_work_selection_enabled(&self) -> bool; + + fn is_downstream_authorized(&self, user_identity: &Str0255) -> Result; + + fn handle_mining_message(&mut self, message_type: u8, payload: &mut [u8]) -> Result<(), Error> { + let parsed: Mining = (message_type, payload).try_into()?; + self.dispatch_mining_message(parsed) + } + + fn dispatch_mining_message(&mut self, message: Mining) -> Result<(), Error> { + let (channel_type, work_selection) = + (self.get_channel_type(), self.is_work_selection_enabled()); + + use Mining::*; + match message { + OpenStandardMiningChannel(m) => match channel_type { + SupportedChannelTypes::Standard + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_standard_mining_channel(m) + } + SupportedChannelTypes::Extended => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_STANDARD_MINING_CHANNEL, + )), + }, + OpenExtendedMiningChannel(m) => match channel_type { + SupportedChannelTypes::Extended | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_extended_mining_channel(m) + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL, + )), + }, + UpdateChannel(m) => self.handle_update_channel(m), + + SubmitSharesStandard(m) => match channel_type { + SupportedChannelTypes::Standard + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => self.handle_submit_shares_standard(m), + SupportedChannelTypes::Extended => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SUBMIT_SHARES_STANDARD, + )), + }, + + SubmitSharesExtended(m) => match channel_type { + SupportedChannelTypes::Extended | SupportedChannelTypes::GroupAndExtended => { + self.handle_submit_shares_extended(m) + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SUBMIT_SHARES_EXTENDED, + )), + }, + + SetCustomMiningJob(m) => match (channel_type, work_selection) { + (SupportedChannelTypes::Extended, true) + | (SupportedChannelTypes::GroupAndExtended, true) => { + self.handle_set_custom_mining_job(m) + } + _ => Err(Error::UnexpectedMessage(MESSAGE_TYPE_SET_CUSTOM_MINING_JOB)), + }, + CloseChannel(m) => self.handle_close_channel(m), + + _ => Err(Error::UnexpectedMessage(0)), + } + } + + fn handle_close_channel(&mut self, msg: CloseChannel) -> Result<(), Error>; + + fn handle_open_standard_mining_channel( + &mut self, + msg: OpenStandardMiningChannel, + ) -> Result<(), Error>; + + fn handle_open_extended_mining_channel( + &mut self, + msg: OpenExtendedMiningChannel, + ) -> Result<(), Error>; + + fn handle_update_channel(&mut self, msg: UpdateChannel) -> Result<(), Error>; + + fn handle_submit_shares_standard(&mut self, msg: SubmitSharesStandard) -> Result<(), Error>; + + fn handle_submit_shares_extended(&mut self, msg: SubmitSharesExtended) -> Result<(), Error>; + + fn handle_set_custom_mining_job(&mut self, msg: SetCustomMiningJob) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleMiningMessagesFromClientAsync { + fn get_channel_type(&self) -> SupportedChannelTypes; + fn is_work_selection_enabled(&self) -> bool; + + async fn handle_mining_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_mining_message(parsed).await + } + } + + async fn dispatch_mining_message(&mut self, message: Mining) -> Result<(), Error> { + let (channel_type, work_selection) = + (self.get_channel_type(), self.is_work_selection_enabled()); + + async move { + use Mining::*; + match message { + OpenStandardMiningChannel(m) => match channel_type { + SupportedChannelTypes::Standard + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_standard_mining_channel(m).await + } + SupportedChannelTypes::Extended => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_STANDARD_MINING_CHANNEL, + )), + }, + OpenExtendedMiningChannel(m) => match channel_type { + SupportedChannelTypes::Extended | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_extended_mining_channel(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL, + )), + }, + UpdateChannel(m) => self.handle_update_channel(m).await, + + SubmitSharesStandard(m) => match channel_type { + SupportedChannelTypes::Standard + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => { + self.handle_submit_shares_standard(m).await + } + SupportedChannelTypes::Extended => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SUBMIT_SHARES_STANDARD, + )), + }, + + SubmitSharesExtended(m) => match channel_type { + SupportedChannelTypes::Extended | SupportedChannelTypes::GroupAndExtended => { + self.handle_submit_shares_extended(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SUBMIT_SHARES_EXTENDED, + )), + }, + + SetCustomMiningJob(m) => match (channel_type, work_selection) { + (SupportedChannelTypes::Extended, true) + | (SupportedChannelTypes::GroupAndExtended, true) => { + self.handle_set_custom_mining_job(m).await + } + _ => Err(Error::UnexpectedMessage(MESSAGE_TYPE_SET_CUSTOM_MINING_JOB)), + }, + CloseChannel(m) => self.handle_close_channel(m).await, + + _ => Err(Error::UnexpectedMessage(0)), + } + } + } + + async fn handle_close_channel(&mut self, msg: CloseChannel) -> Result<(), Error>; + + async fn handle_open_standard_mining_channel( + &mut self, + msg: OpenStandardMiningChannel, + ) -> Result<(), Error>; + + async fn handle_open_extended_mining_channel( + &mut self, + msg: OpenExtendedMiningChannel, + ) -> Result<(), Error>; + + async fn handle_update_channel(&mut self, msg: UpdateChannel) -> Result<(), Error>; + + async fn handle_submit_shares_standard( + &mut self, + msg: SubmitSharesStandard, + ) -> Result<(), Error>; + + async fn handle_submit_shares_extended( + &mut self, + msg: SubmitSharesExtended, + ) -> Result<(), Error>; + + async fn handle_set_custom_mining_job(&mut self, msg: SetCustomMiningJob) -> Result<(), Error>; +} + +pub trait HandleMiningMessagesFromServerSync { + fn get_channel_type(&self) -> SupportedChannelTypes; + fn is_work_selection_enabled(&self) -> bool; + + fn handle_mining_message(&mut self, message_type: u8, payload: &mut [u8]) -> Result<(), Error> { + let parsed: Mining = (message_type, payload).try_into()?; + self.dispatch_mining_message(parsed) + } + + fn dispatch_mining_message(&mut self, message: Mining) -> Result<(), Error> { + let (channel_type, work_selection) = + (self.get_channel_type(), self.is_work_selection_enabled()); + + use Mining::*; + match message { + OpenStandardMiningChannelSuccess(m) => match channel_type { + SupportedChannelTypes::Standard + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_standard_mining_channel_success(m) + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_STANDARD_MINING_CHANNEL_SUCCESS, + )), + }, + + OpenExtendedMiningChannelSuccess(m) => match channel_type { + SupportedChannelTypes::Extended | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_extended_mining_channel_success(m) + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL_SUCCESS, + )), + }, + + OpenMiningChannelError(m) => self.handle_open_mining_channel_error(m), + UpdateChannelError(m) => self.handle_update_channel_error(m), + CloseChannel(m) => self.handle_close_channel(m), + SetExtranoncePrefix(m) => self.handle_set_extranonce_prefix(m), + SubmitSharesSuccess(m) => self.handle_submit_shares_success(m), + SubmitSharesError(m) => self.handle_submit_shares_error(m), + + NewMiningJob(m) => match channel_type { + SupportedChannelTypes::Standard => self.handle_new_mining_job(m), + _ => Err(Error::UnexpectedMessage(MESSAGE_TYPE_NEW_MINING_JOB)), + }, + + NewExtendedMiningJob(m) => match channel_type { + SupportedChannelTypes::Extended + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => self.handle_new_extended_mining_job(m), + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_NEW_EXTENDED_MINING_JOB, + )), + }, + + SetNewPrevHash(m) => self.handle_set_new_prev_hash(m), + + SetCustomMiningJobSuccess(m) => match (channel_type, work_selection) { + (SupportedChannelTypes::Extended, true) + | (SupportedChannelTypes::GroupAndExtended, true) => { + self.handle_set_custom_mining_job_success(m) + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SET_CUSTOM_MINING_JOB_SUCCESS, + )), + }, + + SetCustomMiningJobError(m) => match (channel_type, work_selection) { + (SupportedChannelTypes::Extended, true) + | (SupportedChannelTypes::Group, true) + | (SupportedChannelTypes::GroupAndExtended, true) => { + self.handle_set_custom_mining_job_error(m) + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SET_CUSTOM_MINING_JOB_ERROR, + )), + }, + + SetTarget(m) => self.handle_set_target(m), + + SetGroupChannel(m) => match channel_type { + SupportedChannelTypes::Group | SupportedChannelTypes::GroupAndExtended => { + self.handle_set_group_channel(m) + } + _ => Err(Error::UnexpectedMessage(MESSAGE_TYPE_SET_GROUP_CHANNEL)), + }, + + _ => Err(Error::UnexpectedMessage(0)), + } + } + + fn handle_open_standard_mining_channel_success( + &mut self, + msg: OpenStandardMiningChannelSuccess, + ) -> Result<(), Error>; + + fn handle_open_extended_mining_channel_success( + &mut self, + msg: OpenExtendedMiningChannelSuccess, + ) -> Result<(), Error>; + + fn handle_open_mining_channel_error( + &mut self, + msg: OpenMiningChannelError, + ) -> Result<(), Error>; + + fn handle_update_channel_error(&mut self, msg: UpdateChannelError) -> Result<(), Error>; + + fn handle_close_channel(&mut self, msg: CloseChannel) -> Result<(), Error>; + + fn handle_set_extranonce_prefix(&mut self, msg: SetExtranoncePrefix) -> Result<(), Error>; + + fn handle_submit_shares_success(&mut self, msg: SubmitSharesSuccess) -> Result<(), Error>; + + fn handle_submit_shares_error(&mut self, msg: SubmitSharesError) -> Result<(), Error>; + + fn handle_new_mining_job(&mut self, msg: NewMiningJob) -> Result<(), Error>; + + fn handle_new_extended_mining_job(&mut self, msg: NewExtendedMiningJob) -> Result<(), Error>; + + fn handle_set_new_prev_hash(&mut self, msg: SetNewPrevHash) -> Result<(), Error>; + + fn handle_set_custom_mining_job_success( + &mut self, + msg: SetCustomMiningJobSuccess, + ) -> Result<(), Error>; + + fn handle_set_custom_mining_job_error( + &mut self, + msg: SetCustomMiningJobError, + ) -> Result<(), Error>; + + fn handle_set_target(&mut self, msg: SetTarget) -> Result<(), Error>; + + fn handle_set_group_channel(&mut self, msg: SetGroupChannel) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleMiningMessagesFromServerAsync { + fn get_channel_type(&self) -> SupportedChannelTypes; + fn is_work_selection_enabled(&self) -> bool; + + async fn handle_mining_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_mining_message(parsed).await + } + } + + async fn dispatch_mining_message(&mut self, message: Mining) -> Result<(), Error> { + let (channel_type, work_selection) = + (self.get_channel_type(), self.is_work_selection_enabled()); + + async move { + use Mining::*; + match message { + OpenStandardMiningChannelSuccess(m) => match channel_type { + SupportedChannelTypes::Standard + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_standard_mining_channel_success(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_STANDARD_MINING_CHANNEL_SUCCESS, + )), + }, + + OpenExtendedMiningChannelSuccess(m) => match channel_type { + SupportedChannelTypes::Extended | SupportedChannelTypes::GroupAndExtended => { + self.handle_open_extended_mining_channel_success(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL_SUCCESS, + )), + }, + + OpenMiningChannelError(m) => self.handle_open_mining_channel_error(m).await, + UpdateChannelError(m) => self.handle_update_channel_error(m).await, + CloseChannel(m) => self.handle_close_channel(m).await, + SetExtranoncePrefix(m) => self.handle_set_extranonce_prefix(m).await, + SubmitSharesSuccess(m) => self.handle_submit_shares_success(m).await, + SubmitSharesError(m) => self.handle_submit_shares_error(m).await, + + NewMiningJob(m) => match channel_type { + SupportedChannelTypes::Standard => self.handle_new_mining_job(m).await, + _ => Err(Error::UnexpectedMessage(MESSAGE_TYPE_NEW_MINING_JOB)), + }, + + NewExtendedMiningJob(m) => match channel_type { + SupportedChannelTypes::Extended + | SupportedChannelTypes::Group + | SupportedChannelTypes::GroupAndExtended => { + self.handle_new_extended_mining_job(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_NEW_EXTENDED_MINING_JOB, + )), + }, + + SetNewPrevHash(m) => self.handle_set_new_prev_hash(m).await, + + SetCustomMiningJobSuccess(m) => match (channel_type, work_selection) { + (SupportedChannelTypes::Extended, true) + | (SupportedChannelTypes::GroupAndExtended, true) => { + self.handle_set_custom_mining_job_success(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SET_CUSTOM_MINING_JOB_SUCCESS, + )), + }, + + SetCustomMiningJobError(m) => match (channel_type, work_selection) { + (SupportedChannelTypes::Extended, true) + | (SupportedChannelTypes::Group, true) + | (SupportedChannelTypes::GroupAndExtended, true) => { + self.handle_set_custom_mining_job_error(m).await + } + _ => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_SET_CUSTOM_MINING_JOB_ERROR, + )), + }, + + SetTarget(m) => self.handle_set_target(m).await, + + SetGroupChannel(m) => match channel_type { + SupportedChannelTypes::Group | SupportedChannelTypes::GroupAndExtended => { + self.handle_set_group_channel(m).await + } + _ => Err(Error::UnexpectedMessage(MESSAGE_TYPE_SET_GROUP_CHANNEL)), + }, + _ => Err(Error::UnexpectedMessage(0)), + } + } + } + + async fn handle_open_standard_mining_channel_success( + &mut self, + msg: OpenStandardMiningChannelSuccess, + ) -> Result<(), Error>; + + async fn handle_open_extended_mining_channel_success( + &mut self, + msg: OpenExtendedMiningChannelSuccess, + ) -> Result<(), Error>; + + async fn handle_open_mining_channel_error( + &mut self, + msg: OpenMiningChannelError, + ) -> Result<(), Error>; + + async fn handle_update_channel_error(&mut self, msg: UpdateChannelError) -> Result<(), Error>; + + async fn handle_close_channel(&mut self, msg: CloseChannel) -> Result<(), Error>; + + async fn handle_set_extranonce_prefix(&mut self, msg: SetExtranoncePrefix) + -> Result<(), Error>; + + async fn handle_submit_shares_success(&mut self, msg: SubmitSharesSuccess) + -> Result<(), Error>; + + async fn handle_submit_shares_error(&mut self, msg: SubmitSharesError) -> Result<(), Error>; + + async fn handle_new_mining_job(&mut self, msg: NewMiningJob) -> Result<(), Error>; + + async fn handle_new_extended_mining_job( + &mut self, + msg: NewExtendedMiningJob, + ) -> Result<(), Error>; + + async fn handle_set_new_prev_hash(&mut self, msg: SetNewPrevHash) -> Result<(), Error>; + + async fn handle_set_custom_mining_job_success( + &mut self, + msg: SetCustomMiningJobSuccess, + ) -> Result<(), Error>; + + async fn handle_set_custom_mining_job_error( + &mut self, + msg: SetCustomMiningJobError, + ) -> Result<(), Error>; + + async fn handle_set_target(&mut self, msg: SetTarget) -> Result<(), Error>; + + async fn handle_set_group_channel(&mut self, msg: SetGroupChannel) -> Result<(), Error>; +} diff --git a/protocols/v2/handlers-sv2/src/template_distribution.rs b/protocols/v2/handlers-sv2/src/template_distribution.rs new file mode 100644 index 0000000000..14708cd2ff --- /dev/null +++ b/protocols/v2/handlers-sv2/src/template_distribution.rs @@ -0,0 +1,213 @@ +use crate::error::HandlerError as Error; +use parsers_sv2::TemplateDistribution; +use template_distribution_sv2::{ + CoinbaseOutputConstraints, NewTemplate, RequestTransactionData, RequestTransactionDataError, + RequestTransactionDataSuccess, SetNewPrevHash, SubmitSolution, +}; + +use core::convert::TryInto; +use template_distribution_sv2::*; + +pub trait HandleTemplateDistributionMessagesFromServerSync { + fn handle_template_distribution_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: TemplateDistribution<'_> = (message_type, payload).try_into()?; + self.dispatch_template_distribution(parsed) + } + + fn dispatch_template_distribution( + &mut self, + message: TemplateDistribution<'_>, + ) -> Result<(), Error> { + match message { + TemplateDistribution::NewTemplate(m) => self.handle_new_template(m), + TemplateDistribution::SetNewPrevHash(m) => self.handle_set_new_prev_hash(m), + TemplateDistribution::RequestTransactionDataSuccess(m) => { + self.handle_request_tx_data_success(m) + } + TemplateDistribution::RequestTransactionDataError(m) => { + self.handle_request_tx_data_error(m) + } + + TemplateDistribution::CoinbaseOutputConstraints(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_COINBASE_OUTPUT_CONSTRAINTS, + )), + TemplateDistribution::RequestTransactionData(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_REQUEST_TRANSACTION_DATA, + )), + TemplateDistribution::SubmitSolution(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_SUBMIT_SOLUTION)) + } + } + } + fn handle_new_template(&mut self, msg: NewTemplate) -> Result<(), Error>; + + fn handle_set_new_prev_hash(&mut self, msg: SetNewPrevHash) -> Result<(), Error>; + + fn handle_request_tx_data_success( + &mut self, + msg: RequestTransactionDataSuccess, + ) -> Result<(), Error>; + + fn handle_request_tx_data_error( + &mut self, + msg: RequestTransactionDataError, + ) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleTemplateDistributionMessagesFromServerAsync { + async fn handle_template_distribution_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result, _> = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_template_distribution(parsed).await + } + } + + async fn dispatch_template_distribution( + &mut self, + message: TemplateDistribution<'_>, + ) -> Result<(), Error> { + async move { + match message { + TemplateDistribution::NewTemplate(m) => self.handle_new_template(m).await, + TemplateDistribution::SetNewPrevHash(m) => self.handle_set_new_prev_hash(m).await, + TemplateDistribution::RequestTransactionDataSuccess(m) => { + self.handle_request_tx_data_success(m).await + } + TemplateDistribution::RequestTransactionDataError(m) => { + self.handle_request_tx_data_error(m).await + } + + TemplateDistribution::CoinbaseOutputConstraints(_) => Err( + Error::UnexpectedMessage(MESSAGE_TYPE_COINBASE_OUTPUT_CONSTRAINTS), + ), + TemplateDistribution::RequestTransactionData(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_REQUEST_TRANSACTION_DATA, + )), + TemplateDistribution::SubmitSolution(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_SUBMIT_SOLUTION)) + } + } + } + } + async fn handle_new_template(&mut self, msg: NewTemplate) -> Result<(), Error>; + + async fn handle_set_new_prev_hash(&mut self, msg: SetNewPrevHash) -> Result<(), Error>; + + async fn handle_request_tx_data_success( + &mut self, + msg: RequestTransactionDataSuccess, + ) -> Result<(), Error>; + + async fn handle_request_tx_data_error( + &mut self, + msg: RequestTransactionDataError, + ) -> Result<(), Error>; +} + +pub trait HandleTemplateDistributionMessagesFromClientSync { + fn handle_template_distribution_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: TemplateDistribution<'_> = (message_type, payload).try_into()?; + self.dispatch_template_distribution(parsed) + } + + fn dispatch_template_distribution( + &mut self, + message: TemplateDistribution<'_>, + ) -> Result<(), Error> { + match message { + TemplateDistribution::CoinbaseOutputConstraints(m) => { + self.handle_coinbase_output_constraints(m) + } + TemplateDistribution::RequestTransactionData(m) => self.handle_request_tx_data(m), + TemplateDistribution::SubmitSolution(m) => self.handle_submit_solution(m), + + TemplateDistribution::NewTemplate(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_NEW_TEMPLATE)) + } + TemplateDistribution::SetNewPrevHash(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_SET_NEW_PREV_HASH)) + } + TemplateDistribution::RequestTransactionDataSuccess(_) => Err( + Error::UnexpectedMessage(MESSAGE_TYPE_REQUEST_TRANSACTION_DATA_SUCCESS), + ), + TemplateDistribution::RequestTransactionDataError(_) => Err(Error::UnexpectedMessage( + MESSAGE_TYPE_REQUEST_TRANSACTION_DATA_ERROR, + )), + } + } + + fn handle_coinbase_output_constraints( + &mut self, + msg: CoinbaseOutputConstraints, + ) -> Result<(), Error>; + + fn handle_request_tx_data(&mut self, msg: RequestTransactionData) -> Result<(), Error>; + fn handle_submit_solution(&mut self, msg: SubmitSolution) -> Result<(), Error>; +} + +#[trait_variant::make(Send)] +pub trait HandleTemplateDistributionMessagesFromClientAsync { + async fn handle_template_distribution_message( + &mut self, + message_type: u8, + payload: &mut [u8], + ) -> Result<(), Error> { + let parsed: Result, _> = (message_type, payload).try_into(); + async move { + let parsed = parsed?; + self.dispatch_template_distribution(parsed).await + } + } + + async fn dispatch_template_distribution( + &mut self, + message: TemplateDistribution<'_>, + ) -> Result<(), Error> { + async move { + match message { + TemplateDistribution::CoinbaseOutputConstraints(m) => { + self.handle_coinbase_output_constraints(m).await + } + TemplateDistribution::RequestTransactionData(m) => { + self.handle_request_tx_data(m).await + } + TemplateDistribution::SubmitSolution(m) => self.handle_submit_solution(m).await, + + TemplateDistribution::NewTemplate(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_NEW_TEMPLATE)) + } + TemplateDistribution::SetNewPrevHash(_) => { + Err(Error::UnexpectedMessage(MESSAGE_TYPE_SET_NEW_PREV_HASH)) + } + TemplateDistribution::RequestTransactionDataSuccess(_) => Err( + Error::UnexpectedMessage(MESSAGE_TYPE_REQUEST_TRANSACTION_DATA_SUCCESS), + ), + TemplateDistribution::RequestTransactionDataError(_) => Err( + Error::UnexpectedMessage(MESSAGE_TYPE_REQUEST_TRANSACTION_DATA_ERROR), + ), + } + } + } + + async fn handle_coinbase_output_constraints( + &mut self, + msg: CoinbaseOutputConstraints, + ) -> Result<(), Error>; + + async fn handle_request_tx_data(&mut self, msg: RequestTransactionData) -> Result<(), Error>; + async fn handle_submit_solution(&mut self, msg: SubmitSolution) -> Result<(), Error>; +} diff --git a/protocols/v2/roles-logic-sv2/Cargo.toml b/protocols/v2/roles-logic-sv2/Cargo.toml index 15826acc37..b03ecc2276 100644 --- a/protocols/v2/roles-logic-sv2/Cargo.toml +++ b/protocols/v2/roles-logic-sv2/Cargo.toml @@ -16,6 +16,7 @@ keywords = ["stratum", "mining", "bitcoin", "protocol"] bitcoin = { version = "0.32.5" } channels_sv2 = { path = "../channels-sv2", version = "^0.1.0" } parsers_sv2 = { path = "../parsers-sv2", version = "^0.1.0" } +handlers_sv2 = { path = "../handlers-sv2", version = "^0.1.0" } common_messages_sv2 = { path = "../../../protocols/v2/subprotocols/common-messages", version = "^5.0.0" } mining_sv2 = { path = "../../../protocols/v2/subprotocols/mining", version = "^4.0.0" } template_distribution_sv2 = { path = "../../../protocols/v2/subprotocols/template-distribution", version = "^3.0.0" } diff --git a/protocols/v2/roles-logic-sv2/src/lib.rs b/protocols/v2/roles-logic-sv2/src/lib.rs index 9d12f3975d..99968d6edb 100644 --- a/protocols/v2/roles-logic-sv2/src/lib.rs +++ b/protocols/v2/roles-logic-sv2/src/lib.rs @@ -28,6 +28,7 @@ pub use channels_sv2; pub use codec_sv2; pub use common_messages_sv2; pub use errors::Error; +pub use handlers_sv2; pub use job_declaration_sv2; pub use mining_sv2; pub use parsers_sv2; diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 287a081fb8..e42b2a82a0 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -1186,6 +1186,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "handlers_sv2" +version = "0.1.0" +dependencies = [ + "binary_sv2", + "common_messages_sv2", + "job_declaration_sv2", + "mining_sv2", + "parsers_sv2", + "template_distribution_sv2", + "trait-variant", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -2209,6 +2222,7 @@ dependencies = [ "channels_sv2", "codec_sv2", "common_messages_sv2", + "handlers_sv2", "hex-conservative 0.3.0", "job_declaration_sv2", "mining_sv2", @@ -2763,6 +2777,17 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "translator_sv2" version = "1.0.0" diff --git a/test/integration-tests/Cargo.lock b/test/integration-tests/Cargo.lock index 49cd487d44..89aaa42a25 100644 --- a/test/integration-tests/Cargo.lock +++ b/test/integration-tests/Cargo.lock @@ -1040,6 +1040,19 @@ dependencies = [ "tracing", ] +[[package]] +name = "handlers_sv2" +version = "0.1.0" +dependencies = [ + "binary_sv2", + "common_messages_sv2", + "job_declaration_sv2", + "mining_sv2", + "parsers_sv2", + "template_distribution_sv2", + "trait-variant", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -2036,6 +2049,7 @@ dependencies = [ "channels_sv2", "codec_sv2", "common_messages_sv2", + "handlers_sv2", "hex-conservative 0.3.0", "job_declaration_sv2", "mining_sv2", @@ -2616,6 +2630,17 @@ dependencies = [ "tracing-log", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "translator_sv2" version = "1.0.0" diff --git a/utils/Cargo.lock b/utils/Cargo.lock index 88519c07bb..23c26c7012 100644 --- a/utils/Cargo.lock +++ b/utils/Cargo.lock @@ -575,6 +575,19 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" +[[package]] +name = "handlers_sv2" +version = "0.1.0" +dependencies = [ + "binary_sv2", + "common_messages_sv2", + "job_declaration_sv2", + "mining_sv2", + "parsers_sv2", + "template_distribution_sv2", + "trait-variant", +] + [[package]] name = "hashbrown" version = "0.7.2" @@ -1038,6 +1051,7 @@ dependencies = [ "channels_sv2", "codec_sv2", "common_messages_sv2", + "handlers_sv2", "hex-conservative 0.3.0", "job_declaration_sv2", "mining_sv2", @@ -1294,6 +1308,17 @@ dependencies = [ "once_cell", ] +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "typenum" version = "1.18.0"