Skip to content

Commit b907454

Browse files
committed
add non_aggregated_translator_handles_set_group_channel_message Integration Test
1 parent 835f232 commit b907454

File tree

2 files changed

+230
-4
lines changed

2 files changed

+230
-4
lines changed

integration-tests/lib/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub mod sv1_minerd;
3737
pub mod sv1_sniffer;
3838
pub mod template_provider;
3939
pub mod types;
40-
pub(crate) mod utils;
40+
pub mod utils;
4141

4242
const SHARES_PER_MINUTE: f32 = 120.0;
4343

integration-tests/tests/translator_integration.rs

Lines changed: 229 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
// This file contains integration tests for the `TranslatorSv2` module.
22
use integration_tests_sv2::{
33
interceptor::{IgnoreMessage, MessageDirection, ReplaceMessage},
4+
mock_roles::MockUpstream,
45
template_provider::DifficultyLevel,
6+
utils::get_available_address,
57
*,
68
};
79
use stratum_apps::stratum_core::mining_sv2::*;
810

911
use std::collections::HashSet;
1012
use stratum_apps::stratum_core::{
13+
binary_sv2::{Seq0255, Sv2Option},
1114
common_messages_sv2::{
12-
SetupConnectionError, MESSAGE_TYPE_SETUP_CONNECTION, MESSAGE_TYPE_SETUP_CONNECTION_ERROR,
13-
MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS,
15+
SetupConnectionError, SetupConnectionSuccess, MESSAGE_TYPE_SETUP_CONNECTION,
16+
MESSAGE_TYPE_SETUP_CONNECTION_ERROR, MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS,
1417
},
1518
mining_sv2::{
1619
OpenMiningChannelError, MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL,
1720
MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL_SUCCESS,
1821
},
19-
parsers_sv2::{self, AnyMessage},
22+
parsers_sv2::{self, AnyMessage, CommonMessages},
2023
template_distribution_sv2::MESSAGE_TYPE_SUBMIT_SOLUTION,
2124
};
2225

@@ -727,3 +730,226 @@ async fn non_aggregated_translator_correctly_deals_with_group_channels() {
727730
}
728731
}
729732
}
733+
734+
#[tokio::test]
735+
async fn non_aggregated_translator_handles_set_group_channel_message() {
736+
start_tracing();
737+
738+
let mock_upstream_addr = get_available_address();
739+
let mock_upstream = MockUpstream::new(mock_upstream_addr);
740+
let send_to_tproxy = mock_upstream.start().await;
741+
742+
let (sniffer, sniffer_addr) = start_sniffer("", mock_upstream_addr, false, vec![], None);
743+
744+
let (_tproxy, tproxy_addr) = start_sv2_translator(&[sniffer_addr], false, vec![], vec![]).await;
745+
746+
sniffer
747+
.wait_for_message_type_and_clean_queue(
748+
MessageDirection::ToUpstream,
749+
MESSAGE_TYPE_SETUP_CONNECTION,
750+
)
751+
.await;
752+
753+
let setup_connection_success = AnyMessage::Common(CommonMessages::SetupConnectionSuccess(
754+
SetupConnectionSuccess {
755+
used_version: 2,
756+
flags: 0,
757+
},
758+
));
759+
send_to_tproxy.send(setup_connection_success).await.unwrap();
760+
761+
const N_EXTENDED_CHANNELS: u32 = 6;
762+
const GROUP_CHANNEL_ID_A: u32 = 100;
763+
const GROUP_CHANNEL_ID_B: u32 = 200;
764+
765+
// we need to keep references to each minerd
766+
// otherwise they would be dropped
767+
let mut minerd_vec = Vec::new();
768+
769+
// spawn minerd processes to force opening N_EXTENDED_CHANNELS extended channels
770+
for i in 0..N_EXTENDED_CHANNELS {
771+
let (minerd_process, _minerd_addr) = start_minerd(tproxy_addr, None, None, false).await;
772+
minerd_vec.push(minerd_process);
773+
774+
sniffer
775+
.wait_for_message_type(
776+
MessageDirection::ToUpstream,
777+
MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL,
778+
)
779+
.await;
780+
let open_extended_mining_channel: OpenExtendedMiningChannel = loop {
781+
match sniffer.next_message_from_downstream() {
782+
Some((
783+
_,
784+
AnyMessage::Mining(parsers_sv2::Mining::OpenExtendedMiningChannel(msg)),
785+
)) => {
786+
break msg;
787+
}
788+
_ => continue,
789+
};
790+
};
791+
792+
let open_extended_mining_channel_success =
793+
AnyMessage::Mining(parsers_sv2::Mining::OpenExtendedMiningChannelSuccess(
794+
OpenExtendedMiningChannelSuccess {
795+
request_id: open_extended_mining_channel.request_id,
796+
channel_id: i,
797+
target: hex::decode(
798+
"0000137c578190689425e3ecf8449a1af39db0aed305d9206f45ac32fe8330fc",
799+
)
800+
.unwrap()
801+
.try_into()
802+
.unwrap(),
803+
// full extranonce has a total of 8 bytes
804+
extranonce_size: 4,
805+
extranonce_prefix: vec![0x00, 0x01, 0x00, i as u8].try_into().unwrap(),
806+
group_channel_id: GROUP_CHANNEL_ID_A,
807+
},
808+
));
809+
send_to_tproxy
810+
.send(open_extended_mining_channel_success)
811+
.await
812+
.unwrap();
813+
814+
sniffer
815+
.wait_for_message_type_and_clean_queue(
816+
MessageDirection::ToDownstream,
817+
MESSAGE_TYPE_OPEN_EXTENDED_MINING_CHANNEL_SUCCESS,
818+
)
819+
.await;
820+
821+
let new_extended_mining_job = AnyMessage::Mining(parsers_sv2::Mining::NewExtendedMiningJob(NewExtendedMiningJob {
822+
channel_id: i,
823+
job_id: 1,
824+
min_ntime: Sv2Option::new(None),
825+
version: 0x20000000,
826+
version_rolling_allowed: true,
827+
merkle_path: Seq0255::new(vec![]).unwrap(),
828+
// scriptSig for a total of 8 bytes of extranonce
829+
coinbase_tx_prefix: hex::decode("02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff225200162f5374726174756d2056322053524920506f6f6c2f2f08").unwrap().try_into().unwrap(),
830+
coinbase_tx_suffix: hex::decode("feffffff0200f2052a01000000160014ebe1b7dcc293ccaa0ee743a86f89df8258c208fc0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf901000000").unwrap().try_into().unwrap(),
831+
}));
832+
833+
send_to_tproxy.send(new_extended_mining_job).await.unwrap();
834+
sniffer
835+
.wait_for_message_type_and_clean_queue(
836+
MessageDirection::ToDownstream,
837+
MESSAGE_TYPE_NEW_EXTENDED_MINING_JOB,
838+
)
839+
.await;
840+
841+
let set_new_prev_hash =
842+
AnyMessage::Mining(parsers_sv2::Mining::SetNewPrevHash(SetNewPrevHash {
843+
channel_id: i,
844+
job_id: 1,
845+
prev_hash: hex::decode(
846+
"3ab7089cd2cd30f133552cfde82c4cb239cd3c2310306f9d825e088a1772cc39",
847+
)
848+
.unwrap()
849+
.try_into()
850+
.unwrap(),
851+
min_ntime: 1766782170,
852+
nbits: 0x207fffff,
853+
}));
854+
855+
send_to_tproxy.send(set_new_prev_hash).await.unwrap();
856+
sniffer
857+
.wait_for_message_type_and_clean_queue(
858+
MessageDirection::ToDownstream,
859+
MESSAGE_TYPE_MINING_SET_NEW_PREV_HASH,
860+
)
861+
.await;
862+
}
863+
864+
// half of the channels belong to GROUP_CHANNEL_ID_A
865+
let group_channel_a_ids = (0..N_EXTENDED_CHANNELS)
866+
.filter(|i| i % 2 != 0)
867+
.collect::<Vec<_>>();
868+
869+
// half of the channels belong to GROUP_CHANNEL_ID_B
870+
let group_channel_b_ids = (0..N_EXTENDED_CHANNELS)
871+
.filter(|i| i % 2 == 0)
872+
.collect::<Vec<_>>();
873+
874+
// send a SetGroupChannel message to set GROUP_CHANNEL_ID_B
875+
let set_group_channel =
876+
AnyMessage::Mining(parsers_sv2::Mining::SetGroupChannel(SetGroupChannel {
877+
channel_ids: group_channel_b_ids.clone().into(),
878+
group_channel_id: GROUP_CHANNEL_ID_B,
879+
}));
880+
send_to_tproxy.send(set_group_channel).await.unwrap();
881+
882+
// send a NewExtendedMiningJob + SetNewPrevHash message pair ONLY to GROUP_CHANNEL_ID_B
883+
let new_extended_mining_job = AnyMessage::Mining(parsers_sv2::Mining::NewExtendedMiningJob(NewExtendedMiningJob {
884+
channel_id: GROUP_CHANNEL_ID_B,
885+
job_id: 2,
886+
min_ntime: Sv2Option::new(None),
887+
version: 0x20000000,
888+
version_rolling_allowed: true,
889+
merkle_path: Seq0255::new(vec![]).unwrap(),
890+
// scriptSig for a total of 8 bytes of extranonce
891+
coinbase_tx_prefix: hex::decode("02000000010000000000000000000000000000000000000000000000000000000000000000ffffffff225300162f5374726174756d2056322053524920506f6f6c2f2f08").unwrap().try_into().unwrap(),
892+
coinbase_tx_suffix: hex::decode("feffffff0200f2052a01000000160014ebe1b7dcc293ccaa0ee743a86f89df8258c208fc0000000000000000266a24aa21a9ede2f61c3f71d1defd3fa999dfa36953755c690689799962b48bebd836974e8cf901000000").unwrap().try_into().unwrap(),
893+
}));
894+
895+
send_to_tproxy.send(new_extended_mining_job).await.unwrap();
896+
sniffer
897+
.wait_for_message_type_and_clean_queue(
898+
MessageDirection::ToDownstream,
899+
MESSAGE_TYPE_NEW_EXTENDED_MINING_JOB,
900+
)
901+
.await;
902+
903+
let set_new_prev_hash =
904+
AnyMessage::Mining(parsers_sv2::Mining::SetNewPrevHash(SetNewPrevHash {
905+
channel_id: GROUP_CHANNEL_ID_B,
906+
job_id: 2,
907+
prev_hash: hex::decode(
908+
"2089973501ad229333ae0e9c52fa160f95616890db364a71ccfb77773a8b54cb",
909+
)
910+
.unwrap()
911+
.try_into()
912+
.unwrap(),
913+
min_ntime: 1766782171,
914+
nbits: 0x207fffff,
915+
}));
916+
send_to_tproxy.send(set_new_prev_hash).await.unwrap();
917+
sniffer
918+
.wait_for_message_type_and_clean_queue(
919+
MessageDirection::ToDownstream,
920+
MESSAGE_TYPE_MINING_SET_NEW_PREV_HASH,
921+
)
922+
.await;
923+
924+
// all channels in GROUP_CHANNEL_ID_B must submit at least one share with job_id = 2
925+
// channels in GROUP_CHANNEL_ID_A must NOT submit any shares with job_id = 2
926+
let mut channels_submitted_to: HashSet<u32> = group_channel_b_ids.clone().into_iter().collect();
927+
loop {
928+
sniffer
929+
.wait_for_message_type(
930+
MessageDirection::ToUpstream,
931+
MESSAGE_TYPE_SUBMIT_SHARES_EXTENDED,
932+
)
933+
.await;
934+
let submit_shares_extended = match sniffer.next_message_from_downstream() {
935+
Some((_, AnyMessage::Mining(parsers_sv2::Mining::SubmitSharesExtended(msg)))) => msg,
936+
msg => panic!("Expected SubmitSharesExtended message, found: {:?}", msg),
937+
};
938+
939+
if submit_shares_extended.job_id != 2 {
940+
continue;
941+
}
942+
943+
if group_channel_a_ids.contains(&submit_shares_extended.channel_id) {
944+
panic!(
945+
"Channel {} should not have submitted a share with job_id = 2",
946+
submit_shares_extended.channel_id
947+
);
948+
}
949+
950+
channels_submitted_to.remove(&submit_shares_extended.channel_id);
951+
if channels_submitted_to.is_empty() {
952+
break;
953+
}
954+
}
955+
}

0 commit comments

Comments
 (0)