Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
312fa2f
add basic skeleton of channel manager to tproxy
bit-aloo May 26, 2025
9655119
commenting out test for now
bit-aloo May 26, 2025
e01402e
add current prevhash to channel manager
bit-aloo May 26, 2025
5fe637e
migrate bridge from harbouring Prevhash and future job
bit-aloo May 26, 2025
fd0d968
add share submit logic
bit-aloo May 26, 2025
00e8886
added submit share logic in bridge
bit-aloo May 26, 2025
998befd
remove redundant submit logic in bridge
bit-aloo May 26, 2025
69fd46c
restructure the upstream module
bit-aloo May 27, 2025
2684464
move all upstream channel manager methods inside message_handler and …
bit-aloo May 27, 2025
cee5f4e
refactor the upstream module
bit-aloo May 27, 2025
c0ed377
refactor bridges more
bit-aloo May 27, 2025
e56604e
remove proxy channel factory from bridge and make use of only channel…
bit-aloo May 27, 2025
9593290
remove extranonce channel
bit-aloo May 27, 2025
6b96c77
remove last_job_id from translator
bit-aloo May 27, 2025
b961621
We are removing job_id field in upstream struct, as its only use was …
bit-aloo May 27, 2025
122f7d6
removed extranonce prefix and channel id from upstream struct, and
bit-aloo May 27, 2025
37b2442
removing all the unit test as they relayed on previous channel factor…
bit-aloo May 27, 2025
1558818
refactored channel manager module
bit-aloo May 27, 2025
917765d
removed all channel dependence to channel manager from upstream module
bit-aloo May 27, 2025
f496998
remove upstream difficulty config from downstream
bit-aloo May 27, 2025
ffde090
remove downstream difficulty management from downstream module and us…
bit-aloo May 27, 2025
0d6e655
fix bug
bit-aloo May 27, 2025
a65b874
add share validation
bit-aloo May 27, 2025
8b5bfce
add aggregation and non-aggregation cases in tproxy
bit-aloo May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
575 changes: 575 additions & 0 deletions roles/translator/src/lib/channel_manager/mod.rs

Large diffs are not rendered by default.

442 changes: 180 additions & 262 deletions roles/translator/src/lib/downstream_sv1/diff_management.rs

Large diffs are not rendered by default.

302 changes: 29 additions & 273 deletions roles/translator/src/lib/downstream_sv1/downstream.rs

Large diffs are not rendered by default.

195 changes: 195 additions & 0 deletions roles/translator/src/lib/downstream_sv1/message_handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
use crate::downstream_sv1;

use super::{Downstream, DownstreamMessages, SubmitShareWithChannelId};

use roles_logic_sv2::common_properties::{IsDownstream, IsMiningDownstream};

use tracing::{debug, info};
use v1::{
client_to_server, json_rpc, server_to_client,
utils::{Extranonce, HexU32Be},
IsServer,
};

/// Implements `IsServer` for `Downstream` to handle the SV1 messages.
impl IsServer<'static> for Downstream {
/// Handles the incoming SV1 `mining.configure` message.
///
/// This message is received after `mining.subscribe` and `mining.authorize`.
/// It allows the miner to negotiate capabilities, particularly regarding
/// version rolling. This method processes the version rolling mask and
/// minimum bit count provided by the client.
///
/// Returns a tuple containing:
/// 1. `Option<server_to_client::VersionRollingParams>`: The version rolling parameters
/// negotiated by the server (proxy).
/// 2. `Option<bool>`: A boolean indicating whether the server (proxy) supports version rolling
/// (always `Some(false)` for TProxy according to the SV1 spec when not supporting work
/// selection).
fn handle_configure(
&mut self,
request: &client_to_server::Configure,
) -> (Option<server_to_client::VersionRollingParams>, Option<bool>) {
info!("Down: Configuring");
debug!("Down: Handling mining.configure: {:?}", &request);

// TODO 0x1FFFE000 should be configured
// = 11111111111111110000000000000
// this is a reasonable default as it allows all 16 version bits to be used
// If the tproxy/pool needs to use some version bits this needs to be configurable
// so upstreams can negotiate with downstreams. When that happens this should consider
// the min_bit_count in the mining.configure message
self.version_rolling_mask = request
.version_rolling_mask()
.map(|mask| HexU32Be(mask & 0x1FFFE000));
self.version_rolling_min_bit = request.version_rolling_min_bit_count();

debug!(
"Negotiated version_rolling_mask is {:?}",
self.version_rolling_mask
);
(
Some(server_to_client::VersionRollingParams::new(
self.version_rolling_mask.clone().unwrap_or(HexU32Be(0)),
self.version_rolling_min_bit.clone().unwrap_or(HexU32Be(0)),
).expect("Version mask invalid, automatic version mask selection not supported, please change it in carte::downstream_sv1::mod.rs")),
Some(false),
)
}

/// Handles the incoming SV1 `mining.subscribe` message.
///
/// This is typically the first message received from a new client. In the SV1
/// protocol, it's used to subscribe to job notifications and receive session
/// details like extranonce1 and extranonce2 size. This method acknowledges the subscription and
/// provides the necessary details derived from the upstream SV2 connection (extranonce1 and
/// extranonce2 size). It also provides subscription IDs for the
/// `mining.set_difficulty` and `mining.notify` methods.
fn handle_subscribe(&self, request: &client_to_server::Subscribe) -> Vec<(String, String)> {
info!("Down: Subscribing");
debug!("Down: Handling mining.subscribe: {:?}", &request);

let set_difficulty_sub = (
"mining.set_difficulty".to_string(),
downstream_sv1::new_subscription_id(),
);
let notify_sub = (
"mining.notify".to_string(),
"ae6812eb4cd7735a302a8a9dd95cf71f".to_string(),
);

vec![set_difficulty_sub, notify_sub]
}

/// Any numbers of workers may be authorized at any time during the session. In this way, a
/// large number of independent Mining Devices can be handled with a single SV1 connection.
/// https://bitcoin.stackexchange.com/questions/29416/how-do-pool-servers-handle-multiple-workers-sharing-one-connection-with-stratum
fn handle_authorize(&self, request: &client_to_server::Authorize) -> bool {
info!("Down: Authorizing");
debug!("Down: Handling mining.authorize: {:?}", &request);
true
}

/// Handles the incoming SV1 `mining.submit` message.
///
/// This message is sent by the miner when they find a share that meets
/// their current difficulty target. It contains the job ID, ntime, nonce,
/// and extranonce2.
///
/// This method processes the submitted share, potentially validates it
/// against the downstream target (although this might happen in the Bridge
/// or difficulty management logic), translates it into a
/// [`SubmitShareWithChannelId`], and sends it to the Bridge for
/// translation to SV2 and forwarding upstream if it meets the upstream target.
fn handle_submit(&self, request: &client_to_server::Submit<'static>) -> bool {
info!("Down: Submitting Share {:?}", request);
debug!("Down: Handling mining.submit: {:?}", &request);

// TODO: Check if receiving valid shares by adding diff field to Downstream

let (tx, _rx) = async_channel::unbounded::<bool>();

let to_send = SubmitShareWithChannelId {
connection_id: self.connection_id,
channel_id: self.channel_id,
share: request.clone(),
extranonce: self.extranonce1.clone(),
extranonce2_len: self.extranonce2_len,
version_rolling_mask: self.version_rolling_mask.clone(),
verdict_sender: tx,
};

self.tx_sv1_bridge
.try_send(DownstreamMessages::SubmitShares(to_send))
.unwrap();
true
}

/// Indicates to the server that the client supports the mining.set_extranonce method.
fn handle_extranonce_subscribe(&self) {}

/// Checks if a Downstream role is authorized.
fn is_authorized(&self, name: &str) -> bool {
self.authorized_names.contains(&name.to_string())
}

/// Authorizes a Downstream role.
fn authorize(&mut self, name: &str) {
self.authorized_names.push(name.to_string());
}

/// Sets the `extranonce1` field sent in the SV1 `mining.notify` message to the value specified
/// by the SV2 `OpenExtendedMiningChannelSuccess` message sent from the Upstream role.
fn set_extranonce1(
&mut self,
_extranonce1: Option<Extranonce<'static>>,
) -> Extranonce<'static> {
self.extranonce1.clone().try_into().unwrap()
}

/// Returns the `Downstream`'s `extranonce1` value.
fn extranonce1(&self) -> Extranonce<'static> {
self.extranonce1.clone().try_into().unwrap()
}

/// Sets the `extranonce2_size` field sent in the SV1 `mining.notify` message to the value
/// specified by the SV2 `OpenExtendedMiningChannelSuccess` message sent from the Upstream role.
fn set_extranonce2_size(&mut self, _extra_nonce2_size: Option<usize>) -> usize {
self.extranonce2_len
}

/// Returns the `Downstream`'s `extranonce2_size` value.
fn extranonce2_size(&self) -> usize {
self.extranonce2_len
}

/// Returns the version rolling mask.
fn version_rolling_mask(&self) -> Option<HexU32Be> {
self.version_rolling_mask.clone()
}

/// Sets the version rolling mask.
fn set_version_rolling_mask(&mut self, mask: Option<HexU32Be>) {
self.version_rolling_mask = mask;
}

/// Sets the minimum version rolling bit.
fn set_version_rolling_min_bit(&mut self, mask: Option<HexU32Be>) {
self.version_rolling_min_bit = mask
}

fn notify(&mut self) -> Result<json_rpc::Message, v1::error::Error> {
unreachable!()
}
}

// Can we remove this?
impl IsMiningDownstream for Downstream {}
// Can we remove this?
impl IsDownstream for Downstream {
fn get_downstream_mining_data(
&self,
) -> roles_logic_sv2::common_properties::CommonDownstreamData {
todo!()
}
}
9 changes: 8 additions & 1 deletion roles/translator/src/lib/downstream_sv1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
//! - [`diff_management`]: (Declared here, likely contains downstream difficulty logic)
//! - [`downstream`]: Defines the core [`Downstream`] struct and its functionalities.

use async_channel::Sender;
use roles_logic_sv2::mining_sv2::Target;
use v1::{client_to_server::Submit, utils::HexU32Be};
pub mod diff_management;
pub mod downstream;
pub mod message_handler;
pub use downstream::Downstream;

use crate::channel_manager::Sv1ChannelId;

/// This constant defines a timeout duration. It is used to enforce
/// that clients sending a `mining.subscribe` message must follow up
/// with a `mining.authorize` within this period. This prevents
Expand All @@ -37,20 +41,23 @@ pub enum DownstreamMessages {

/// wrapper around a `mining.submit` with extra channel informationfor the Bridge to
/// process
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct SubmitShareWithChannelId {
pub connection_id: Sv1ChannelId,
pub channel_id: u32,
pub share: Submit<'static>,
pub extranonce: Vec<u8>,
pub extranonce2_len: usize,
pub version_rolling_mask: Option<HexU32Be>,
pub verdict_sender: Sender<bool>,
}

/// message for notifying the bridge that a downstream target has updated
/// so the Bridge can process the update
#[derive(Debug)]
pub struct SetDownstreamTarget {
pub channel_id: u32,
pub connection_id: Sv1ChannelId,
pub new_target: Target,
}

Expand Down
Loading