@@ -59,6 +59,88 @@ async fn jds_should_not_panic_if_jdc_shutsdown() {
5959 shutdown_all ! ( jdc_1, pool) ;
6060}
6161
62+ // This test verifies that mode state is isolated per JDC instance.
63+ //
64+ // We start one JDC in solo mining mode (no upstreams) and then start another
65+ // JDC in full template mode (with upstream). The solo instance must not start
66+ // behaving like full-template mode after the second instance activates.
67+ #[ tokio:: test]
68+ async fn multiple_jdc_sessions ( ) {
69+ start_tracing ( ) ;
70+ let ( tp, tp_addr) = start_template_provider ( Some ( 1 ) , DifficultyLevel :: Low ) ;
71+ let ( pool, pool_addr, jds_addr, _) =
72+ start_pool_with_jds ( tp. bitcoin_core ( ) , vec ! [ ] , vec ! [ ] , false ) . await ;
73+
74+ let ( solo_tp_sniffer, solo_tp_sniffer_addr) =
75+ start_sniffer ( "solo-jdc-tp" , tp_addr, false , vec ! [ ] , None ) ;
76+ let ( solo_jdc, solo_jdc_addr, _) = start_jdc (
77+ & [ ] ,
78+ sv2_tp_config ( solo_tp_sniffer_addr) ,
79+ vec ! [ ] ,
80+ vec ! [ ] ,
81+ false ,
82+ Some ( jd_client_sv2:: config:: ConfigJDCMode :: SoloMining ) ,
83+ ) ;
84+ let _solo_downstream = MockDownstream :: new (
85+ solo_jdc_addr,
86+ WithSetup :: yes_with_defaults ( Protocol :: MiningProtocol , 0 ) ,
87+ )
88+ . start ( )
89+ . await ;
90+
91+ solo_tp_sniffer
92+ . wait_for_message_type ( MessageDirection :: ToUpstream , MESSAGE_TYPE_SETUP_CONNECTION )
93+ . await ;
94+ solo_tp_sniffer
95+ . wait_for_message_type (
96+ MessageDirection :: ToDownstream ,
97+ MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS ,
98+ )
99+ . await ;
100+ solo_tp_sniffer. clean_queue ( MessageDirection :: ToUpstream ) ;
101+ solo_tp_sniffer. clean_queue ( MessageDirection :: ToDownstream ) ;
102+
103+ let ( full_jds_sniffer, full_jds_sniffer_addr) =
104+ start_sniffer ( "full-jdc-jds" , jds_addr, false , vec ! [ ] , None ) ;
105+ let ( full_jdc, _full_jdc_addr, _) = start_jdc (
106+ & [ ( pool_addr, full_jds_sniffer_addr) ] ,
107+ sv2_tp_config ( tp_addr) ,
108+ vec ! [ ] ,
109+ vec ! [ ] ,
110+ false ,
111+ Some ( jd_client_sv2:: config:: ConfigJDCMode :: FullTemplate ) ,
112+ ) ;
113+
114+ full_jds_sniffer
115+ . wait_for_message_type ( MessageDirection :: ToUpstream , MESSAGE_TYPE_SETUP_CONNECTION )
116+ . await ;
117+ full_jds_sniffer
118+ . wait_for_message_type (
119+ MessageDirection :: ToDownstream ,
120+ MESSAGE_TYPE_SETUP_CONNECTION_SUCCESS ,
121+ )
122+ . await ;
123+
124+ // Trigger post-start template updates; using two blocks reduces timing flakiness.
125+ tp. generate_blocks ( 1 ) ;
126+ tp. generate_blocks ( 1 ) ;
127+
128+ // RequestTransactionData is FullTemplate-only. If mode leaked process-wide,
129+ // the solo JDC would emit this after the full-template JDC activates.
130+ assert ! (
131+ solo_tp_sniffer
132+ . assert_message_not_present(
133+ MessageDirection :: ToUpstream ,
134+ MESSAGE_TYPE_REQUEST_TRANSACTION_DATA ,
135+ std:: time:: Duration :: from_secs( 2 ) ,
136+ )
137+ . await ,
138+ "Solo-mode JDC should not request transaction data after another JDC activates full-template mode"
139+ ) ;
140+
141+ shutdown_all ! ( solo_jdc, full_jdc, pool) ;
142+ }
143+
62144// This test verifies that jd-client exchange SetupConnection messages with a Template Provider.
63145//
64146// Note that jd-client starts to exchange messages with the Template Provider after it has accepted
0 commit comments