Skip to content

Commit

Permalink
header_timestamp_value_assertion_in_new_extended_mining_job test addi…
Browse files Browse the repository at this point in the history
…tion

header_timestamp_value_assertion_in_new_extended_mining_job test addition
  • Loading branch information
GitGab19 committed Jan 7, 2025
1 parent 4c97af4 commit 2ef340f
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 18 deletions.
9 changes: 5 additions & 4 deletions protocols/v2/roles-logic-sv2/src/job_creator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,10 +211,11 @@ fn new_extended_job(
extranonce_len,
);

let min_ntime = match new_template.future_template {
true => binary_sv2::Sv2Option::new(None),
false => binary_sv2::Sv2Option::new(ntime),
};
let min_ntime = binary_sv2::Sv2Option::new(if new_template.future_template {
None
} else {
ntime
});

let new_extended_mining_job: NewExtendedMiningJob<'static> = NewExtendedMiningJob {
channel_id: 0,
Expand Down
16 changes: 9 additions & 7 deletions roles/tests-integration/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,21 @@ pub struct TemplateProvider {
}

impl TemplateProvider {
pub fn start(port: u16) -> Self {
pub fn start(port: u16, sv2_interval: u32) -> Self {
let temp_dir = PathBuf::from("/tmp/.template-provider");
let mut conf = Conf::default();
let staticdir = format!(".bitcoin-{}", port);
conf.staticdir = Some(temp_dir.join(staticdir));
let port = format!("-sv2port={}", port);
let port_arg = format!("-sv2port={}", port);
let sv2_interval_arg = format!("-sv2interval={}", sv2_interval);
conf.args.extend(vec![
"-txindex=1",
"-sv2",
&port,
&port_arg,
"-debug=rpc",
"-debug=sv2",
"-sv2interval=20",
"-sv2feedelta=1000",
&sv2_interval_arg,
"-sv2feedelta=0",
"-loglevel=sv2:trace",
"-logtimemicros=1",
]);
Expand Down Expand Up @@ -284,8 +285,9 @@ pub async fn start_pool(
pool
}

pub async fn start_template_provider(tp_port: u16) -> TemplateProvider {
let template_provider = TemplateProvider::start(tp_port);
pub async fn start_template_provider(tp_port: u16, sv2_interval: Option<u32>) -> TemplateProvider {
let sv2_interval = sv2_interval.unwrap_or(20);
let template_provider = TemplateProvider::start(tp_port, sv2_interval);
template_provider.generate_blocks(16);
template_provider
}
Expand Down
112 changes: 106 additions & 6 deletions roles/tests-integration/tests/pool_integration.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
mod common;

use std::convert::TryInto;

use common::{InterceptMessage, MessageDirection};
use const_sv2::{
MESSAGE_TYPE_NEW_TEMPLATE, MESSAGE_TYPE_SETUP_CONNECTION_ERROR, MESSAGE_TYPE_SET_NEW_PREV_HASH,
MESSAGE_TYPE_NEW_EXTENDED_MINING_JOB, MESSAGE_TYPE_NEW_TEMPLATE,
MESSAGE_TYPE_SETUP_CONNECTION_ERROR,
};
use roles_logic_sv2::{
common_messages_sv2::{Protocol, SetupConnection, SetupConnectionError},
parsers::{CommonMessages, PoolMessages, TemplateDistribution},
parsers::{AnyMessage, CommonMessages, Mining, PoolMessages, TemplateDistribution},
};
use std::convert::TryInto;

// This test starts a Template Provider and a Pool, and checks if they exchange the correct
// messages upon connection.
Expand All @@ -20,7 +20,7 @@ async fn success_pool_template_provider_connection() {
let sniffer_addr = common::get_available_address();
let tp_addr = common::get_available_address();
let pool_addr = common::get_available_address();
let _tp = common::start_template_provider(tp_addr.port()).await;
let _tp = common::start_template_provider(tp_addr.port(), None).await;
let sniffer_identifier =
"success_pool_template_provider_connection tp_pool sniffer".to_string();
let sniffer_check_on_drop = true;
Expand Down Expand Up @@ -64,12 +64,112 @@ async fn success_pool_template_provider_connection() {
assert_tp_message!(sniffer.next_message_from_upstream(), SetNewPrevHash);
}

// This test starts a Template Provider, a Pool, and a Translator Proxy, and verifies the
// correctness of the exchanged messages during connection and operation.
//
// Two Sniffers are used:
// - Between the Template Provider and the Pool.
// - Between the Pool and the Translator Proxy.
//
// The test ensures that:
// - The Template Provider sends valid `SetNewPrevHash` and `NewTemplate` messages.
// - The `minntime` field in the second `NewExtendedMiningJob` message sent to the Translator Proxy
// matches the `header_timestamp` from the `SetNewPrevHash` message, addressing a bug that
// occurred with non-future jobs.
//
// Related issue: https://github.com/stratum-mining/stratum/issues/1324
#[tokio::test]
async fn header_timestamp_value_assertion_in_new_extended_mining_job() {
let tp_pool_sniffer_addr = common::get_available_address();
let pool_translator_sniffer_addr = common::get_available_address();
let tp_addr = common::get_available_address();
let pool_addr = common::get_available_address();
let sv2_interval = Some(5);
let _tp = common::start_template_provider(tp_addr.port(), sv2_interval).await;
let tp_pool_sniffer_identifier =
"header_timestamp_value_assertion_in_new_extended_mining_job tp_pool sniffer".to_string();
let tp_pool_sniffer = common::start_sniffer(
tp_pool_sniffer_identifier,
tp_pool_sniffer_addr,
tp_addr,
false,
None,
)
.await;
let _ = common::start_pool(Some(pool_addr), Some(tp_pool_sniffer_addr)).await;
let pool_translator_sniffer_identifier =
"header_timestamp_value_assertion_in_new_extended_mining_job pool_translator sniffer"
.to_string();
let pool_translator_sniffer = common::start_sniffer(
pool_translator_sniffer_identifier,
pool_translator_sniffer_addr,
pool_addr,
false,
None,
)
.await;
let _tproxy_addr = common::start_sv2_translator(pool_translator_sniffer_addr).await;
assert_common_message!(
&tp_pool_sniffer.next_message_from_upstream(),
SetupConnectionSuccess
);
// Wait for a NewTemplate message from the Template Provider
tp_pool_sniffer
.wait_for_message_type(MessageDirection::ToDownstream, MESSAGE_TYPE_NEW_TEMPLATE)
.await;
assert_tp_message!(&tp_pool_sniffer.next_message_from_upstream(), NewTemplate);
// Extract header timestamp from SetNewPrevHash message
let header_timestamp_to_check = match tp_pool_sniffer.next_message_from_upstream() {
Some((_, AnyMessage::TemplateDistribution(TemplateDistribution::SetNewPrevHash(msg)))) => {
msg.header_timestamp
}
_ => panic!("SetNewPrevHash not found!"),
};
// Assertions of messages between Pool and Translator Proxy (these are not necessary for the test itself, but they are used to pop from the sniffer's message queue)
assert_common_message!(
&pool_translator_sniffer.next_message_from_upstream(),
SetupConnectionSuccess
);
assert_mining_message!(
&pool_translator_sniffer.next_message_from_upstream(),
OpenExtendedMiningChannelSuccess
);
assert_mining_message!(
&pool_translator_sniffer.next_message_from_upstream(),
NewExtendedMiningJob
);
assert_mining_message!(
&pool_translator_sniffer.next_message_from_upstream(),
SetNewPrevHash
);
// Wait for a second NewExtendedMiningJob message
pool_translator_sniffer
.wait_for_message_type(
MessageDirection::ToDownstream,
MESSAGE_TYPE_NEW_EXTENDED_MINING_JOB,
)
.await;
// Extract min_ntime from the second NewExtendedMiningJob message
let second_job_ntime = match pool_translator_sniffer.next_message_from_upstream() {
Some((_, AnyMessage::Mining(Mining::NewExtendedMiningJob(job)))) => {
job.min_ntime.into_inner()
}
_ => panic!("Second NewExtendedMiningJob not found!"),
};
// Assert that min_ntime matches header_timestamp
assert_eq!(
second_job_ntime,
Some(header_timestamp_to_check),
"The `minntime` field of the second NewExtendedMiningJob does not match the `header_timestamp`!"
);
}

#[tokio::test]
async fn test_sniffer_interrupter() {
let sniffer_addr = common::get_available_address();
let tp_addr = common::get_available_address();
let pool_addr = common::get_available_address();
let _tp = common::start_template_provider(tp_addr.port()).await;
let _tp = common::start_template_provider(tp_addr.port(), None).await;
use const_sv2::MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS;
let message =
PoolMessages::Common(CommonMessages::SetupConnectionError(SetupConnectionError {
Expand Down
3 changes: 2 additions & 1 deletion roles/tests-integration/tests/translator_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ async fn translation_proxy() {
None,
)
.await;
let _tp = common::start_template_provider(tp_addr.port()).await;
let sv2_interval = 20;
let _tp = common::start_template_provider(tp_addr.port(), sv2_interval).await;
let _pool = common::start_pool(Some(pool_addr), Some(tp_addr)).await;
let tproxy_addr = common::start_sv2_translator(pool_translator_sniffer_addr).await;
let _mining_device = common::start_mining_device_sv1(tproxy_addr).await;
Expand Down

0 comments on commit 2ef340f

Please sign in to comment.