use crate::{
downstream::Downstream,
error::{self, PoolError, PoolErrorKind},
};
use std::{convert::TryInto, sync::atomic::Ordering};
use stratum_apps::{
stratum_core::{
common_messages_sv2::{
has_requires_std_job, has_work_selection, Protocol, SetupConnection,
SetupConnectionError, SetupConnectionSuccess,
},
handlers_sv2::HandleCommonMessagesFromClientAsync,
parsers_sv2::{AnyMessage, Tlv},
},
utils::types::Sv2Frame,
};
use tracing::info;
#[cfg_attr(not(test), hotpath::measure_all)]
impl HandleCommonMessagesFromClientAsync for Downstream {
type Error = PoolError<error::Downstream>;
fn get_negotiated_extensions_with_client(
&self,
_client_id: Option<usize>,
) -> Result<Vec<u16>, Self::Error> {
Ok(self
.downstream_data
.super_safe_lock(|data| data.negotiated_extensions.clone()))
}
async fn handle_setup_connection(
&mut self,
client_id: Option<usize>,
msg: SetupConnection<'_>,
_tlv_fields: Option<&[Tlv]>,
) -> Result<(), Self::Error> {
info!(
"Received `SetupConnection`: version={}, flags={:b}",
msg.min_version, msg.flags
);
let downstream_id = client_id.expect("downstream id should be present");
if msg.protocol != Protocol::MiningProtocol {
info!("Rejecting connection from {downstream_id}: SetupConnection asking for other protocols than mining protocol.");
let response = SetupConnectionError {
flags: 0,
error_code: "unsupported-protocol"
.to_string()
.try_into()
.expect("error code must be valid string"),
};
let frame: Sv2Frame = AnyMessage::Common(response.into_static().into())
.try_into()
.map_err(PoolError::shutdown)?;
self.downstream_channel
.downstream_sender
.send(frame)
.await
.map_err(|_| {
PoolError::disconnect(PoolErrorKind::ChannelErrorSender, downstream_id)
})?;
return Err(PoolError::disconnect(
PoolErrorKind::UnsupportedProtocol,
downstream_id,
));
}
self.requires_custom_work
.store(has_work_selection(msg.flags), Ordering::SeqCst);
self.requires_standard_jobs
.store(has_requires_std_job(msg.flags), Ordering::SeqCst);
let mut response_flags: u32 = 0;
if has_work_selection(msg.flags) {
response_flags |= 0x02; }
let response = SetupConnectionSuccess {
used_version: 2,
flags: response_flags,
};
let frame: Sv2Frame = AnyMessage::Common(response.into_static().into())
.try_into()
.map_err(PoolError::shutdown)?;
self.downstream_channel
.downstream_sender
.send(frame)
.await
.map_err(|_| {
PoolError::disconnect(PoolErrorKind::ChannelErrorSender, self.downstream_id)
})?;
Ok(())
}
}