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
2 changes: 2 additions & 0 deletions protocols/v2/roles-logic-sv2/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ pub enum Error {
NoActiveJob,
FailedToSendSolution,
FailedToSetCustomMiningJob(ExtendedChannelError),
FailedToDeserializeCoinbaseOutputs,
}

impl From<BinarySv2Error> for Error {
Expand Down Expand Up @@ -256,6 +257,7 @@ impl Display for Error {
FailedToProcessNewTemplateStandardChannel(e) => write!(f, "Failed to process NewTemplate: {e:?}"),
FailedToProcessSetNewPrevHashExtendedChannel(e) => write!(f, "Failed to process SetNewPrevHash: {e:?}"),
FailedToProcessSetNewPrevHashStandardChannel(e) => write!(f, "Failed to process SetNewPrevHash: {e:?}"),
FailedToDeserializeCoinbaseOutputs => write!(f, "Failed to deserialize coinbase outputs"),
}
}
}
Expand Down
33 changes: 29 additions & 4 deletions roles/pool/src/lib/mining_pool/message_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{
sync::{Arc, RwLock},
};
use stratum_common::roles_logic_sv2::{
bitcoin::Amount,
bitcoin::{consensus::Decodable, transaction::TxOut, Amount},
channels::server::{
error::{ExtendedChannelError, StandardChannelError},
extended::ExtendedChannel,
Expand Down Expand Up @@ -884,10 +884,35 @@ impl ParseMiningMessagesFromDownstream<()> for Downstream {
// this is a naive implementation, but ideally we should check the SetCustomMiningJob
// message parameters, especially:
// - the mining_job_token
// - the coinbase reward outputs
// - the amount of the pool payout output

// some of these checks are actually pending on spec discussion of
// https://github.com/stratum-mining/sv2-spec/issues/133
let custom_job_coinbase_outputs = Vec::<TxOut>::consensus_decode(
&mut m.coinbase_tx_outputs.inner_as_ref().to_vec().as_slice(),
)
.map_err(|_| Error::FailedToDeserializeCoinbaseOutputs)?;

// check that all script_pubkeys from self.empty_pool_coinbase_outputs are present in the
// custom job coinbase outputs
let missing_script = self.empty_pool_coinbase_outputs.iter().find(|pool_output| {
!custom_job_coinbase_outputs
.iter()
.any(|custom_output| custom_output.script_pubkey == pool_output.script_pubkey)
});

if missing_script.is_some() {
error!("SetCustomMiningJobError: pool-payout-script-missing");

let error = SetCustomMiningJobError {
request_id: m.request_id,
channel_id: m.channel_id,
error_code: "pool-payout-script-missing"
.to_string()
.try_into()
.expect("error code must be valid string"),
};

return Ok(SendTo::Respond(Mining::SetCustomMiningJobError(error)));
}

let channel_id = m.channel_id;
if !self.extended_channels.contains_key(&channel_id) {
Expand Down
Loading