@@ -12,12 +12,15 @@ use stratum_apps::{
1212 custom_mutex:: Mutex ,
1313 fallback_coordinator:: FallbackCoordinator ,
1414 stratum_core:: {
15- channels_sv2:: client:: { extended:: ExtendedChannel , group:: GroupChannel } ,
15+ channels_sv2:: {
16+ client:: { extended:: ExtendedChannel , group:: GroupChannel } ,
17+ extranonce_manager:: ExtranonceAllocator ,
18+ } ,
1619 codec_sv2:: StandardSv2Frame ,
1720 extensions_sv2:: { EXTENSION_TYPE_WORKER_HASHRATE_TRACKING , TLV_FIELD_TYPE_USER_IDENTITY } ,
1821 framing_sv2,
1922 handlers_sv2:: { HandleExtensionsFromServerAsync , HandleMiningMessagesFromServerAsync } ,
20- mining_sv2:: { ExtendedExtranonce , OpenExtendedMiningChannelSuccess } ,
23+ mining_sv2:: OpenExtendedMiningChannelSuccess ,
2124 parsers_sv2:: { AnyMessage , Mining , Tlv , TlvList } ,
2225 } ,
2326 task_manager:: TaskManager ,
@@ -73,8 +76,10 @@ pub struct ChannelManager {
7376 pub share_sequence_counters : Arc < DashMap < u32 , u32 > > ,
7477 /// Extensions that have been successfully negotiated with the upstream server
7578 pub negotiated_extensions : Arc < Mutex < Vec < u16 > > > ,
76- /// Extranonce factories containing per channel extranonces
77- pub extranonce_factories : Arc < DashMap < ChannelId , ExtendedExtranonce > > ,
79+ /// Extranonce allocators containing per channel extranonce management
80+ pub extranonce_allocators : Arc < DashMap < ChannelId , ExtranonceAllocator > > ,
81+ /// Mapping of channel_id → local_prefix_id for freeing extranonces on channel close
82+ pub channel_to_prefix_id : Arc < DashMap < ChannelId , usize > > ,
7883}
7984
8085#[ cfg_attr( not( test) , hotpath:: measure_all) ]
@@ -121,7 +126,8 @@ impl ChannelManager {
121126 group_channels : Arc :: new ( DashMap :: new ( ) ) ,
122127 share_sequence_counters : Arc :: new ( DashMap :: new ( ) ) ,
123128 negotiated_extensions : Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) ,
124- extranonce_factories : Arc :: new ( DashMap :: new ( ) ) ,
129+ extranonce_allocators : Arc :: new ( DashMap :: new ( ) ) ,
130+ channel_to_prefix_id : Arc :: new ( DashMap :: new ( ) ) ,
125131 }
126132 }
127133
@@ -172,7 +178,8 @@ impl ChannelManager {
172178 self . group_channels. clear( ) ;
173179 self . share_sequence_counters. clear( ) ;
174180 self . negotiated_extensions. super_safe_lock( |data| data. clear( ) ) ;
175- self . extranonce_factories. clear( ) ;
181+ self . extranonce_allocators. clear( ) ;
182+ self . channel_to_prefix_id. clear( ) ;
176183 break ;
177184 }
178185 res = self . clone( ) . handle_upstream_frame( ) => {
@@ -301,18 +308,22 @@ impl ChannelManager {
301308 . get ( & AGGREGATED_CHANNEL_ID )
302309 . map ( |ch| * ch. get_target ( ) )
303310 . unwrap ( ) ;
304- let new_extranonce_prefix = self
305- . extranonce_factories
311+ let alloc_result = self
312+ . extranonce_allocators
306313 . get_mut ( & AGGREGATED_CHANNEL_ID )
307- . unwrap ( )
308- . next_prefix_extended ( open_channel_msg. min_extranonce_size . into ( ) )
309- . ok ( ) ;
314+ . and_then ( |mut allocator| {
315+ allocator
316+ . allocate_extended ( open_channel_msg. min_extranonce_size . into ( ) )
317+ . ok ( )
318+ } ) ;
310319 let new_extranonce_size = self
311- . extranonce_factories
312- . get_mut ( & AGGREGATED_CHANNEL_ID )
313- . unwrap ( )
314- . get_range2_len ( ) ;
315- if let Some ( new_extranonce_prefix) = new_extranonce_prefix {
320+ . extranonce_allocators
321+ . get ( & AGGREGATED_CHANNEL_ID )
322+ . map ( |allocator| allocator. rollable_extranonce_size ( ) )
323+ . unwrap_or ( 0 ) ;
324+ if let Some ( prefix) = alloc_result {
325+ let new_extranonce_prefix = prefix. as_bytes ( ) . to_vec ( ) ;
326+ let local_prefix_id = prefix. local_prefix_id ( ) ;
316327 if new_extranonce_size >= open_channel_msg. min_extranonce_size as usize
317328 {
318329 // Find max channel ID, excluding AGGREGATED_CHANNEL_ID (u32::MAX)
@@ -323,14 +334,12 @@ impl ChannelManager {
323334 . filter ( |x| * x. key ( ) != AGGREGATED_CHANNEL_ID )
324335 . fold ( 0 , |acc, x| std:: cmp:: max ( acc, * x. key ( ) ) ) ;
325336 let next_channel_id = channel_id + 1 ;
337+ self . channel_to_prefix_id
338+ . insert ( next_channel_id, local_prefix_id) ;
326339 let new_downstream_extended_channel = ExtendedChannel :: new (
327340 next_channel_id,
328341 user_identity. clone ( ) ,
329- new_extranonce_prefix
330- . clone ( )
331- . into_b032 ( )
332- . into_static ( )
333- . to_vec ( ) ,
342+ new_extranonce_prefix. clone ( ) ,
334343 target,
335344 hashrate,
336345 true ,
@@ -344,7 +353,10 @@ impl ChannelManager {
344353 channel_id : next_channel_id,
345354 target : target. to_le_bytes ( ) . into ( ) ,
346355 extranonce_size : new_extranonce_size as u16 ,
347- extranonce_prefix : new_extranonce_prefix. clone ( ) . into ( ) ,
356+ extranonce_prefix : new_extranonce_prefix
357+ . clone ( )
358+ . try_into ( )
359+ . expect ( "valid prefix" ) ,
348360 group_channel_id : 0 , /* use a dummy value, this shouldn't
349361 * matter for the Sv1 server */
350362 } ,
@@ -513,16 +525,17 @@ impl ChannelManager {
513525 . extended_channels
514526 . get ( & m. channel_id )
515527 . map ( |channel| channel. get_extranonce_prefix ( ) . clone ( ) ) ;
516- // Get the length of the upstream prefix (range0)
517- let range0_len = self
518- . extranonce_factories
528+ // Get the length of the upstream prefix
529+ let upstream_prefix_len = self
530+ . extranonce_allocators
519531 . get ( & AGGREGATED_CHANNEL_ID )
520- . unwrap ( )
521- . get_range0_len ( ) ;
532+ . map ( |allocator| allocator . upstream_prefix_len ( ) )
533+ . unwrap_or ( 0 ) ;
522534 if let Some ( downstream_extranonce_prefix) = downstream_extranonce_prefix {
523- // Skip the upstream prefix (range0) and take the remaining
535+ // Skip the upstream prefix and take the remaining
524536 // bytes (translator proxy prefix)
525- let translator_prefix = & downstream_extranonce_prefix[ range0_len..] ;
537+ let translator_prefix =
538+ & downstream_extranonce_prefix[ upstream_prefix_len..] ;
526539 // Create new extranonce: translator proxy prefix + miner's
527540 // extranonce
528541 let mut new_extranonce = translator_prefix. to_vec ( ) ;
@@ -540,21 +553,22 @@ impl ChannelManager {
540553 // counter
541554 m. sequence_number = self . next_share_sequence_number ( m. channel_id ) ;
542555
543- // Check if we have a per-channel factory for extranonce adjustment
544- let channel_factory = self . extranonce_factories . get ( & m. channel_id ) ;
556+ // Check if we have a per-channel allocator for extranonce adjustment
557+ let channel_allocator = self . extranonce_allocators . get ( & m. channel_id ) ;
545558
546- if let Some ( factory ) = channel_factory {
559+ if let Some ( allocator ) = channel_allocator {
547560 // We need to adjust the extranonce for this channel
548561 let downstream_extranonce_prefix = self
549562 . extended_channels
550563 . get ( & m. channel_id )
551564 . map ( |channel| channel. get_extranonce_prefix ( ) . clone ( ) ) ;
552- let range0_len = factory . get_range0_len ( ) ;
565+ let upstream_prefix_len = allocator . upstream_prefix_len ( ) ;
553566 if let Some ( downstream_extranonce_prefix) = downstream_extranonce_prefix
554567 {
555- // Skip the upstream prefix (range0) and take the remaining
568+ // Skip the upstream prefix and take the remaining
556569 // bytes (translator proxy prefix)
557- let translator_prefix = & downstream_extranonce_prefix[ range0_len..] ;
570+ let translator_prefix =
571+ & downstream_extranonce_prefix[ upstream_prefix_len..] ;
558572 // Create new extranonce: translator proxy prefix + miner's
559573 // extranonce
560574 let mut new_extranonce = translator_prefix. to_vec ( ) ;
@@ -691,6 +705,21 @@ impl ChannelManager {
691705 debug ! ( "Removed channel {} from group channel before sending CloseChannel to upstream" , m. channel_id) ;
692706 }
693707 }
708+ // Free the extranonce prefix for reuse
709+ if let Some ( ( _, prefix_id) ) = self . channel_to_prefix_id . remove ( & m. channel_id ) {
710+ // In aggregated mode, free from AGGREGATED_CHANNEL_ID allocator
711+ if is_aggregated ( ) {
712+ if let Some ( mut allocator) =
713+ self . extranonce_allocators . get_mut ( & AGGREGATED_CHANNEL_ID )
714+ {
715+ allocator. free ( prefix_id) ;
716+ }
717+ } else if let Some ( mut allocator) =
718+ self . extranonce_allocators . get_mut ( & m. channel_id )
719+ {
720+ allocator. free ( prefix_id) ;
721+ }
722+ }
694723
695724 let message = Mining :: CloseChannel ( m) ;
696725 let sv2_frame: Sv2Frame = AnyMessage :: Mining ( message)
0 commit comments