@@ -8,7 +8,10 @@ use roles_logic_sv2::{
88 parsers:: Mining ,
99 utils:: { GroupId , Mutex } ,
1010} ;
11- use std:: sync:: Arc ;
11+ use std:: sync:: {
12+ atomic:: { AtomicU32 , Ordering } ,
13+ Arc ,
14+ } ;
1215use sv1_api:: { client_to_server:: Submit , server_to_client, utils:: HexU32Be } ;
1316use tokio:: sync:: broadcast;
1417
@@ -23,8 +26,13 @@ use crate::{
2326 proxy_state:: { ProxyState , TranslatorState , UpstreamType } ,
2427 shared:: utils:: AbortOnDrop ,
2528} ;
29+ use lazy_static:: lazy_static;
2630use roles_logic_sv2:: { channel_logic:: channel_factory:: OnNewShare , Error as RolesLogicError } ;
27- use tracing:: { debug, error, info} ;
31+ use tracing:: { debug, error, info, warn} ;
32+
33+ lazy_static ! {
34+ static ref SUBMIT_FAIL_COUNTER : AtomicU32 = AtomicU32 :: new( 0 ) ;
35+ }
2836
2937/// Bridge between the SV2 `Upstream` and SV1 `Downstream` responsible for the following messaging
3038/// translation:
@@ -78,7 +86,6 @@ impl Bridge {
7886 ) -> Result < Arc < Mutex < Self > > , Error < ' static > > {
7987 info ! ( "Creating new bridge for up_id {}:" , up_id) ;
8088 let ids = Arc :: new ( Mutex :: new ( GroupId :: new ( ) ) ) ;
81- let share_per_min = 1.0 ;
8289 let upstream_target: [ u8 ; 32 ] = target. safe_lock ( |t| {
8390 t. clone ( ) . try_into ( ) . expect ( "Internal error: this operation can not fail because Vec<U8> can always be converted into [u8; 32]" )
8491} ) . map_err ( |e| Error :: TargetError ( RolesLogicError :: PoisonLock ( e. to_string ( ) ) ) ) ?;
@@ -91,7 +98,7 @@ impl Bridge {
9198 ids,
9299 extranonces,
93100 None ,
94- share_per_min ,
101+ crate :: SHARE_PER_MIN ,
95102 ExtendedChannelKind :: Proxy { upstream_target } ,
96103 None ,
97104 up_id,
@@ -254,29 +261,33 @@ impl Bridge {
254261 let res = self_
255262 . safe_lock ( |s| {
256263 s. channel_factory . set_target ( & mut upstream_target) ;
257- let sv2_submit = match s. translate_submit (
264+ match s. translate_submit (
258265 share. channel_id ,
259266 share. share ,
260267 share. version_rolling_mask ,
261268 ) {
262- Ok ( submit_shares_extended) => submit_shares_extended,
269+ Ok ( submit_shares_extended) => {
270+ // Ordering::Relaxed is safe here because we only need simple counter updates.
271+ // No need for strict ordering since it just tracks failures.
272+ SUBMIT_FAIL_COUNTER . store ( 0 , Ordering :: Relaxed ) ; // Reset on success
273+ s. channel_factory . on_submit_shares_extended ( submit_shares_extended)
274+ } ,
263275 Err ( e) => {
264- error ! ( "Failed to Translates SV1 mining.submit message to SV2 SubmitSharesExtended message" ) ;
265- return Err ( e ) ; // Error will be handled by the caller
276+ error ! ( "Failed to Translates SV1 mining.submit message to SV2 SubmitSharesExtended message: {e} " ) ;
277+ Err ( roles_logic_sv2 :: Error :: NoValidJob ) // Error will be handled by the caller
266278 }
267- } ;
268- Ok ( s. channel_factory . on_submit_shares_extended ( sv2_submit) )
279+ }
269280 } )
270281 . map_err ( |_| Error :: BridgeMutexPoisoned ) ?;
271282
272283 match res {
273- Ok ( Ok ( OnNewShare :: SendErrorDownstream ( e) ) ) => {
284+ Ok ( OnNewShare :: SendErrorDownstream ( e) ) => {
274285 let error_code = std:: str:: from_utf8 ( & e. error_code . to_vec ( ) [ ..] )
275286 . unwrap_or ( "unparsable error code" )
276287 . to_string ( ) ;
277288 error ! ( "Submit share error {}" , error_code) ;
278289 }
279- Ok ( Ok ( OnNewShare :: SendSubmitShareUpstream ( ( share, _) ) ) ) => {
290+ Ok ( OnNewShare :: SendSubmitShareUpstream ( ( share, _) ) ) => {
280291 info ! ( "SHARE MEETS UPSTREAM TARGET channel id: {}" , channel_id) ;
281292 match share {
282293 Share :: Extended ( share) => {
@@ -290,19 +301,26 @@ impl Bridge {
290301 }
291302 }
292303 // We are in an extended channel this variant is group channle only
293- Ok ( Ok ( OnNewShare :: RelaySubmitShareUpstream ) ) => unreachable ! ( ) ,
294- Ok ( Ok ( OnNewShare :: ShareMeetDownstreamTarget ) ) => {
304+ Ok ( OnNewShare :: RelaySubmitShareUpstream ) => unreachable ! ( ) ,
305+ Ok ( OnNewShare :: ShareMeetDownstreamTarget ) => {
295306 info ! ( "SHARE MEETS DOWNSTREAM TARGET channel id {}" , channel_id) ;
296307 }
297308 // Proxy do not have JD capabilities
298- Ok ( Ok ( OnNewShare :: ShareMeetBitcoinTarget ( ..) ) ) => unreachable ! ( ) ,
299- Ok ( Err ( e) ) => {
300- error ! ( "{}" , e) ;
301- return Err ( Error :: RolesSv2Logic ( e) ) ;
309+ Ok ( OnNewShare :: ShareMeetBitcoinTarget ( ..) ) => unreachable ! ( ) ,
310+ Err ( roles_logic_sv2:: Error :: NoValidJob ) => {
311+ let count = SUBMIT_FAIL_COUNTER . fetch_add ( 1 , Ordering :: Relaxed ) + 1 ;
312+ if count >= 10 {
313+ error ! ( "Failed to translate SV1 mining.submit message to SV2 SubmitSharesExtended message after 10 attempts" ) ;
314+ return Err ( Error :: RolesSv2Logic ( roles_logic_sv2:: Error :: NoValidJob ) ) ;
315+ } else {
316+ warn ! (
317+ "Failed to translate SV1 mining.submit message to SV2 SubmitSharesExtended message, attempt {}" ,
318+ count
319+ ) ;
320+ }
302321 }
303322 Err ( e) => {
304- error ! ( "{}" , e) ;
305- return Err ( e) ;
323+ return Err ( Error :: RolesSv2Logic ( e) ) ;
306324 }
307325 }
308326 Ok ( ( ) )
0 commit comments