Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 6 additions & 6 deletions integration-tests/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "integration_tests_sv2"
version = "0.4.0"
version = "0.5.0"
authors = ["The Stratum V2 Developers"]
edition = "2021"
description = "Sv2 Integration Tests Framework"
Expand All @@ -14,10 +14,10 @@ keywords = ["stratum", "mining", "bitcoin", "protocol"]
exclude = ["resources/high_diff_chain.tar.gz"]

[dependencies]
stratum-apps = { version = "0.6.0", path = "../stratum-apps", features = ["network", "config", "payout", "bitcoin-core-sv2"] }
jd_client_sv2 = { version = "0.4.0", path = "../miner-apps/jd-client" }
pool_sv2 = { version = "0.5.0", path = "../pool-apps/pool" }
translator_sv2 = { version = "0.4.0", path = "../miner-apps/translator" }
stratum-apps = { version = "0.7.0", path = "../stratum-apps", features = ["network", "config", "payout", "bitcoin-core-sv2"] }
jd_client_sv2 = { version = "0.5.0", path = "../miner-apps/jd-client" }
pool_sv2 = { version = "0.6.0", path = "../pool-apps/pool" }
translator_sv2 = { version = "0.5.0", path = "../miner-apps/translator" }
async-channel = { version = "1.5.1", default-features = false }
corepc-node = { version = "0.7.0", default-features = false, features = ["28_0"] }
minreq = { version = "2.12.0", default-features = false, features = ["https"] }
Expand Down
55 changes: 42 additions & 13 deletions integration-tests/tests/translator_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,53 @@ async fn translator_mines_when_payout_matches_address_or_donation_identity() {
partial_donation_coinbase_tx_suffix.extend(serialize(&vec![
TxOut {
value: Amount::from_sat(500_000_000),
script_pubkey: pool_script_pubkey,
script_pubkey: pool_script_pubkey.clone(),
},
TxOut {
value: Amount::from_sat(4_500_000_000),
script_pubkey: miner_script_pubkey,
script_pubkey: miner_script_pubkey.clone(),
},
]));
partial_donation_coinbase_tx_suffix.extend([0, 0, 0, 0]);

for (identifier, user_identity, coinbase_tx_suffix) in [
// Simulates pools that leave extra coinbase scriptSig bytes after the extranonce.
let mut suffix_with_remaining_scriptsig_bytes =
hex::decode("2f4e65787573506f6f6c2ffeffffff").unwrap();
suffix_with_remaining_scriptsig_bytes.extend(serialize(&vec![
TxOut {
value: Amount::from_sat(4_955_000_000),
script_pubkey: miner_script_pubkey,
},
TxOut {
value: Amount::from_sat(45_000_000),
script_pubkey: pool_script_pubkey,
},
]));
suffix_with_remaining_scriptsig_bytes.extend([0, 0, 0, 0]);

let default_coinbase_tx_prefix = hex::decode("02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff225200162f5374726174756d2056322053524920506f6f6c2f2f08").unwrap();
// Extra `/NexusPool/` scriptSig bytes increase the prefix scriptSig length from 0x22 to 0x2d.
let coinbase_tx_prefix_with_remaining_scriptsig_bytes = hex::decode("02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff2d5200162f5374726174756d2056322053524920506f6f6c2f2f08").unwrap();

for (identifier, user_identity, coinbase_tx_prefix, coinbase_tx_suffix) in [
(
"payout-address",
PAYOUT_VERIFICATION_MINER_ADDRESS.to_string(),
default_coinbase_tx_prefix.clone(),
legacy_solo_coinbase_tx_suffix,
),
(
"payout-donation",
format!("sri/donate/10/{PAYOUT_VERIFICATION_MINER_ADDRESS}/worker"),
default_coinbase_tx_prefix,
partial_donation_coinbase_tx_suffix,
),
(
"payout-address-scriptsig-suffix",
PAYOUT_VERIFICATION_MINER_ADDRESS.to_string(),
coinbase_tx_prefix_with_remaining_scriptsig_bytes,
suffix_with_remaining_scriptsig_bytes,
),
] {
let mock_upstream_addr = get_available_address();
let send_to_tproxy = MockUpstream::new(
Expand Down Expand Up @@ -211,16 +238,18 @@ async fn translator_mines_when_payout_matches_address_or_donation_identity() {
.unwrap();

send_to_tproxy
.send(AnyMessage::Mining(parsers_sv2::Mining::NewExtendedMiningJob(NewExtendedMiningJob {
channel_id: 0,
job_id: 1,
min_ntime: Sv2Option::new(None),
version: 0x20000000,
version_rolling_allowed: true,
merkle_path: Seq0255::new(vec![]).unwrap(),
coinbase_tx_prefix: hex::decode("02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff225200162f5374726174756d2056322053524920506f6f6c2f2f08").unwrap().try_into().unwrap(),
coinbase_tx_suffix: coinbase_tx_suffix.try_into().unwrap(),
})))
.send(AnyMessage::Mining(
parsers_sv2::Mining::NewExtendedMiningJob(NewExtendedMiningJob {
channel_id: 0,
job_id: 1,
min_ntime: Sv2Option::new(None),
version: 0x20000000,
version_rolling_allowed: true,
merkle_path: Seq0255::new(vec![]).unwrap(),
coinbase_tx_prefix: coinbase_tx_prefix.try_into().unwrap(),
coinbase_tx_suffix: coinbase_tx_suffix.try_into().unwrap(),
}),
))
.await
.unwrap();
sniffer
Expand Down
6 changes: 3 additions & 3 deletions miner-apps/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions miner-apps/jd-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jd_client_sv2"
version = "0.4.0"
version = "0.5.0"
authors = ["The Stratum V2 Developers"]
edition = "2021"
description = "Job Declarator Client (JDC) role"
Expand All @@ -16,7 +16,7 @@ name = "jd_client_sv2"
path = "src/lib/mod.rs"

[dependencies]
stratum-apps = { version = "0.6.0", path = "../../stratum-apps", features = ["jd_client"] }
stratum-apps = { version = "0.7.0", path = "../../stratum-apps", features = ["jd_client"] }
async-channel = "1.5.1"
serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] }
tokio = { version = "1.44.1", features = ["full"] }
Expand Down
4 changes: 2 additions & 2 deletions miner-apps/translator/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "translator_sv2"
version = "0.4.0"
version = "0.5.0"
authors = ["The Stratum V2 Developers"]
edition = "2021"
description = "SV1 to SV2 translation proxy"
Expand All @@ -20,7 +20,7 @@ name = "translator_sv2"
path = "src/main.rs"

[dependencies]
stratum-apps = { version = "0.6.0", path = "../../stratum-apps", features = ["translator"] }
stratum-apps = { version = "0.7.0", path = "../../stratum-apps", features = ["translator"] }
async-channel = "1.5.1"
serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] }
serde_json = { version = "1.0.64", default-features = false, features = ["alloc"] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,6 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager {
_tlv_fields: Option<&[Tlv]>,
) -> Result<(), Self::Error> {
info!("Received: {}", m);
if let Some(expected_payout_distribution) = self.expected_payout_distribution() {
expected_payout_distribution
.validate_coinbase_tx_suffix(m.coinbase_tx_suffix.as_bytes())
.map_err(|e| {
error!("NewExtendedMiningJob failed payout verification: {e}");
TproxyError::fallback(TproxyErrorKind::PayoutVerificationFailed(e.to_string()))
})?;
}
let m_static = m.clone().into_static();

// we update the channel states and keep track of the messages that need to be sent to the
Expand All @@ -565,11 +557,16 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager {
// are we in aggregated mode?
if self.mode.is_aggregated() {
// Validate that the message is for the aggregated channel or its group
let aggregated_channel_id = self
.extended_channels
.get(&AGGREGATED_CHANNEL_ID)
.ok_or(TproxyError::fallback(TproxyErrorKind::ChannelNotFound))?
.get_channel_id();
let (aggregated_channel_id, full_extranonce_size) = {
let aggregated_channel = self
.extended_channels
.get(&AGGREGATED_CHANNEL_ID)
.ok_or(TproxyError::fallback(TproxyErrorKind::ChannelNotFound))?;
(
aggregated_channel.get_channel_id(),
aggregated_channel.get_full_extranonce_size(),
)
};

// here, we are assuming that since we are in aggregated mode, there should
// be only one single group channel and the
Expand All @@ -586,6 +583,8 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager {
if aggregated_channel_id == m_static.channel_id
|| group_channel_id == m_static.channel_id
{
self.verify_payout_distribution(&m_static, full_extranonce_size)?;

// update all extended channel states
for mut extended_channel in self.extended_channels.iter_mut() {
extended_channel
Expand Down Expand Up @@ -617,6 +616,13 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager {
// we're not in aggregated mode
// was the message sent to a group channel?
} else if let Some(mut group_channel) = self.group_channels.get_mut(&m.channel_id) {
let full_extranonce_size =
group_channel.get_full_extranonce_size().ok_or_else(|| {
error!("Group channel {} has no full extranonce size", m.channel_id);
TproxyError::fallback(TproxyErrorKind::ChannelNotFound)
})?;
self.verify_payout_distribution(&m_static, full_extranonce_size)?;

// update group channel state
group_channel.on_new_extended_mining_job(m_static.clone());

Expand Down Expand Up @@ -658,6 +664,8 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager {
return Err(TproxyError::log(TproxyErrorKind::ChannelNotFound));
};

self.verify_payout_distribution(&m_static, channel.get_full_extranonce_size())?;

// update channel state
channel
.on_new_extended_mining_job(m_static.clone())
Expand Down Expand Up @@ -1102,3 +1110,27 @@ impl HandleMiningMessagesFromServerAsync for ChannelManager {
Ok(())
}
}

impl ChannelManager {
#[allow(clippy::result_large_err)]
fn verify_payout_distribution(
&self,
job: &NewExtendedMiningJob<'_>,
full_extranonce_size: usize,
) -> Result<(), TproxyError<error::ChannelManager>> {
if let Some(expected_payout_distribution) = self.expected_payout_distribution() {
expected_payout_distribution
.validate_coinbase_tx_parts(
job.coinbase_tx_prefix.as_bytes(),
job.coinbase_tx_suffix.as_bytes(),
full_extranonce_size,
)
.map_err(|e| {
error!("NewExtendedMiningJob failed payout verification: {e}");
TproxyError::fallback(TproxyErrorKind::PayoutVerificationFailed(e.to_string()))
})?;
}

Ok(())
}
}
6 changes: 3 additions & 3 deletions pool-apps/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pool-apps/jd-server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "jd_server_sv2"
version = "0.4.0"
version = "0.5.0"
authors = ["The Stratum V2 Developers"]
edition = "2021"
description = "Sv2 Job Declaration Server"
Expand All @@ -16,7 +16,7 @@ name = "jd_server_sv2"
path = "src/lib/mod.rs"

[dependencies]
stratum-apps = { version = "0.6.0", path = "../../stratum-apps", features = ["jd_server"] }
stratum-apps = { version = "0.7.0", path = "../../stratum-apps", features = ["jd_server"] }
async-channel = "1.5.1"
serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false }
tracing = { version = "0.1" }
Expand Down
6 changes: 3 additions & 3 deletions pool-apps/pool/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pool_sv2"
version = "0.5.0"
version = "0.6.0"
authors = ["The Stratum V2 Developers"]
edition = "2021"
description = "SV2 pool role"
Expand All @@ -17,14 +17,14 @@ name = "pool_sv2"
path = "src/lib/mod.rs"

[dependencies]
stratum-apps = { version = "0.6.0", path = "../../stratum-apps", features = ["pool"] }
stratum-apps = { version = "0.7.0", path = "../../stratum-apps", features = ["pool"] }
async-channel = "1.5.1"
serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false }
tokio = { version = "1.44.1", features = ["full"] }
ext-config = { version = "0.14.0", features = ["toml"], package = "config" }
tracing = { version = "0.1" }
clap = { version = "4.5.39", features = ["derive"] }
jd_server_sv2 = { version = "0.4.0", path = "../jd-server" }
jd_server_sv2 = { version = "0.5.0", path = "../jd-server" }
hex = "0.4.3"
hotpath = "0.14.0"

Expand Down
2 changes: 1 addition & 1 deletion stratum-apps/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading