@@ -488,27 +488,31 @@ test("xtm-t SubmitBlock payload roundtrips the miner's Tari RandomXT blob", () =
488488 assert . deepEqual ( xtmBlock . header . pow . pow_data , [ 7 , 7 , 7 ] ) ;
489489} ) ;
490490
491- test ( "xtm-t legacy nonce read reports non-integer indexed values " , ( ) => {
491+ test ( "xtm-t legacy nonce submit uses backing bytes when Buffer uint32 reads are unsafe " , ( ) => {
492492 const coinFuncs = global . coinFuncs . __realCoinFuncs ;
493493 const xtmTPool = coinFuncs . getPoolSettings ( "XTM-T" ) ;
494494 const miningHash = Buffer . from ( "31" . repeat ( XTM_T_MINING_HASH_SIZE ) , "hex" ) ;
495495 const blockData = createXtmTMiningBlob ( miningHash , 0n , [ 4 , 5 , 6 ] ) ;
496+ const calls = [ ] ;
497+ const originalConsoleWarn = console . warn ;
498+ const warnings = [ ] ;
499+ const emails = global . support . emails ;
496500 const spoofedBlockData = new Proxy ( blockData , {
497501 get ( target , prop ) {
498502 if ( prop === "slice" ) return target . slice . bind ( target ) ;
499- if ( prop === String ( XTM_T_MINER_NONCE_OFFSET ) ) return 0xa5 ;
500- if ( prop === String ( XTM_T_MINER_NONCE_OFFSET + 1 ) ) return 0x1e ;
501- if ( prop === String ( XTM_T_MINER_NONCE_OFFSET + 2 ) ) return 0x01 ;
502- if ( prop === String ( XTM_T_MINER_NONCE_OFFSET + 3 ) ) return 255.99999856948853 ;
503+ if ( prop === String ( XTM_T_MINER_NONCE_OFFSET ) ) return 130.99999999999991 ;
503504 return Reflect . get ( target , prop , target ) ;
504505 }
505506 } ) ;
506507
507- Buffer . from ( "a51e0200 " , "hex" ) . copy ( blockData , XTM_T_MINER_NONCE_OFFSET ) ;
508+ Buffer . from ( "83304400 " , "hex" ) . copy ( blockData , XTM_T_MINER_NONCE_OFFSET ) ;
508509 assert . equal ( Buffer . isBuffer ( spoofedBlockData ) , true ) ;
509510 assert . equal ( Number . isInteger ( spoofedBlockData . readUInt32BE ( XTM_T_MINER_NONCE_OFFSET ) ) , false ) ;
511+ console . warn = function captureWarn ( message ) {
512+ warnings . push ( message ) ;
513+ } ;
510514
511- assert . throws ( function submitSpoofedXtmBlob ( ) {
515+ try {
512516 xtmTPool . submitBlockRpc . call ( xtmTPool , {
513517 blockData : spoofedBlockData ,
514518 blockTemplate : {
@@ -518,21 +522,89 @@ test("xtm-t legacy nonce read reports non-integer indexed values", () => {
518522 } ,
519523 replyFn ( ) { } ,
520524 support : {
521- rpcPortDaemon ( ) {
522- throw new Error ( "non-integer legacy nonce read must fail before submit" ) ;
525+ rpcPortDaemon ( port , method , params ) {
526+ calls . push ( { port , method , params } ) ;
523527 }
524528 }
525529 } ) ;
526- } , function checkError ( error ) {
527- assert . match ( error . message , / X T M l e g a c y n o n c e r e a d X T M - T r e t u r n e d n o n - i n t e g e r u i n t 3 2 / ) ;
528- assert . match ( error . message , / l o = 2 7 7 0 2 0 7 2 3 1 \. 9 9 9 9 9 8 6 / ) ;
529- assert . match ( error . message , / i s B u f f e r : t r u e / ) ;
530- assert . match ( error . message , / r e a d U I n t 3 2 B E I s B u f f e r P r o t o : t r u e / ) ;
531- assert . match ( error . message , / 4 2 : n u m b e r : 2 5 5 \. 9 9 9 9 9 8 5 6 9 4 8 8 5 3 : i n t e g e r = f a l s e / ) ;
532- assert . match ( error . message , / b a c k i n g D a t a V i e w L o = 2 7 7 0 2 0 7 2 3 2 / ) ;
533- assert . match ( error . message , / b a c k i n g B y t e s = 0 , 0 , 0 , 0 , 1 6 5 , 3 0 , 2 , 0 / ) ;
534- return true ;
535- } ) ;
530+ } finally {
531+ console . warn = originalConsoleWarn ;
532+ }
533+
534+ assert . equal ( calls . length , 1 ) ;
535+ assert . equal ( calls [ 0 ] . port , 18146 ) ;
536+ assert . equal ( calls [ 0 ] . method , "SubmitBlock" ) ;
537+ assert . equal ( calls [ 0 ] . params . header . nonce , blockData . readBigUInt64BE ( XTM_T_NONCE_OFFSET ) . toString ( 10 ) ) ;
538+ assert . deepEqual ( calls [ 0 ] . params . header . pow . pow_data , [ ...blockData . subarray ( XTM_T_POW_DATA_OFFSET ) ] ) ;
539+ assert . match ( warnings . join ( "\n" ) , / i s P r o x y : t r u e / ) ;
540+ assert . equal ( emails . length , 1 ) ;
541+ assert . equal ( emails [ 0 ] . key , "coins:xtm-legacy-nonce-read:XTM legacy nonce read XTM-T" ) ;
542+ assert . equal ( emails [ 0 ] . subject , "FYI: XTM legacy nonce read mismatch" ) ;
543+ assert . match ( emails [ 0 ] . body , / i s P r o x y : t r u e / ) ;
544+ assert . match ( emails [ 0 ] . body , / l e g a c y L o 1 = 2 2 0 0 9 7 8 4 3 1 \. 9 9 9 9 9 8 6 / ) ;
545+ assert . match ( emails [ 0 ] . body , / l e g a c y L o 2 = 2 2 0 0 9 7 8 4 3 1 \. 9 9 9 9 9 8 6 / ) ;
546+ assert . match ( emails [ 0 ] . body , / i n d e x e d C a l c L o : 2 2 0 0 9 7 8 4 3 1 \. 9 9 9 9 9 8 6 / ) ;
547+ } ) ;
548+
549+ test ( "xtm-t legacy nonce submit does not depend on Buffer readUInt32BE" , ( ) => {
550+ const coinFuncs = global . coinFuncs . __realCoinFuncs ;
551+ const xtmTPool = coinFuncs . getPoolSettings ( "XTM-T" ) ;
552+ const miningHash = Buffer . from ( "31" . repeat ( XTM_T_MINING_HASH_SIZE ) , "hex" ) ;
553+ const blockData = createXtmTMiningBlob ( miningHash , 0n , [ 4 , 5 , 6 ] ) ;
554+ const originalReadUInt32BE = Buffer . prototype . readUInt32BE ;
555+ const originalConsoleWarn = console . warn ;
556+ const calls = [ ] ;
557+ const warnings = [ ] ;
558+ const emails = global . support . emails ;
559+ let returnedBadNonceRead = false ;
560+
561+ Buffer . from ( "83304400" , "hex" ) . copy ( blockData , XTM_T_MINER_NONCE_OFFSET ) ;
562+ Buffer . prototype . readUInt32BE = function patchedReadUInt32BE ( offset , ...args ) {
563+ if ( this === blockData && offset === XTM_T_MINER_NONCE_OFFSET && ! returnedBadNonceRead ) {
564+ returnedBadNonceRead = true ;
565+ return 2200978431.9999986 ;
566+ }
567+ return originalReadUInt32BE . call ( this , offset , ...args ) ;
568+ } ;
569+ console . warn = function captureWarn ( message ) {
570+ warnings . push ( message ) ;
571+ } ;
572+
573+ try {
574+ xtmTPool . submitBlockRpc . call ( xtmTPool , {
575+ blockData,
576+ blockTemplate : {
577+ port : 18146 ,
578+ reserved_offset : XTM_T_POOL_RESERVED_OFFSET ,
579+ xtm_block : { header : { nonce : "0" , pow : { pow_data : [ ] } } }
580+ } ,
581+ replyFn ( ) { } ,
582+ support : {
583+ rpcPortDaemon ( port , method , params ) {
584+ calls . push ( { port, method, params } ) ;
585+ }
586+ }
587+ } ) ;
588+ } finally {
589+ Buffer . prototype . readUInt32BE = originalReadUInt32BE ;
590+ console . warn = originalConsoleWarn ;
591+ }
592+
593+ assert . equal ( calls . length , 1 ) ;
594+ assert . equal ( returnedBadNonceRead , true ) ;
595+ assert . equal ( calls [ 0 ] . params . header . nonce , blockData . readBigUInt64BE ( XTM_T_NONCE_OFFSET ) . toString ( 10 ) ) ;
596+ assert . equal ( calls [ 0 ] . params . header . nonce , "2200978432" ) ;
597+ assert . match ( warnings . join ( "\n" ) , / i s P r o x y : f a l s e / ) ;
598+ assert . match ( warnings . join ( "\n" ) , / i n d e x e d = \[ 3 5 : n u m b e r : 0 : i n t e g e r = t r u e / ) ;
599+ assert . equal ( emails . length , 1 ) ;
600+ assert . equal ( emails [ 0 ] . key , "coins:xtm-legacy-nonce-read:XTM legacy nonce read XTM-T" ) ;
601+ assert . equal ( emails [ 0 ] . subject , "FYI: XTM legacy nonce read mismatch" ) ;
602+ assert . match ( emails [ 0 ] . body , / l e g a c y L o 1 = 2 2 0 0 9 7 8 4 3 1 \. 9 9 9 9 9 8 6 / ) ;
603+ assert . match ( emails [ 0 ] . body , / l e g a c y L o 2 = 2 2 0 0 9 7 8 4 3 2 / ) ;
604+ assert . match ( emails [ 0 ] . body , / i s P r o x y : f a l s e / ) ;
605+ assert . match ( emails [ 0 ] . body , / i n d e x e d = \[ 3 5 : n u m b e r : 0 : i n t e g e r = t r u e / ) ;
606+ assert . match ( emails [ 0 ] . body , / i n d e x e d C a l c L o : 2 2 0 0 9 7 8 4 3 2 / ) ;
607+ assert . match ( emails [ 0 ] . body , / r e a d U I n t 3 2 B E I s O r i g i n a l : f a l s e / ) ;
536608} ) ;
537609
538610test ( "xtm-t SubmitBlock rejects a blob with a corrupted pow_algo byte" , ( ) => {
0 commit comments