@@ -15,6 +15,22 @@ const {
1515
1616const REAL_ETH_STYLE_PORT = 8645 ;
1717const INSTANCE_ID_PID_MASK = ( 1 << 22 ) - 1 ;
18+ const XTM_T_MINING_HASH_OFFSET = 3 ;
19+ const XTM_T_MINING_HASH_SIZE = 32 ;
20+ const XTM_T_NONCE_OFFSET = XTM_T_MINING_HASH_OFFSET + XTM_T_MINING_HASH_SIZE ;
21+ const XTM_T_NONCE_SIZE = 8 ;
22+ const XTM_T_MINER_NONCE_OFFSET = XTM_T_NONCE_OFFSET + 4 ;
23+ const XTM_T_POW_ALGO_OFFSET = XTM_T_NONCE_OFFSET + XTM_T_NONCE_SIZE ;
24+ const XTM_T_POW_DATA_OFFSET = XTM_T_POW_ALGO_OFFSET + 1 ;
25+ const XTM_T_POW_DATA_SIZE = 32 ;
26+ const XTM_T_RANDOMXT_POW_ALGO = 2 ;
27+ const TARI_SOURCE_CANDIDATES = [
28+ process . env . POOL_TEST_TARI_SOURCE_DIR ,
29+ process . env . TARI_SOURCE_DIR ,
30+ "/usr/local/src/tari" ,
31+ "/usr/local/src/tari-src" ,
32+ process . env . HOME ? path . join ( process . env . HOME , "tari" ) : ""
33+ ] . filter ( Boolean ) ;
1834
1935function withPatchedPid ( pid , fn ) {
2036 const originalDescriptor = Object . getOwnPropertyDescriptor ( process , "pid" ) ;
@@ -56,6 +72,42 @@ function createInstanceIdWord(poolId, pid) {
5672 }
5773}
5874
75+ function createXtmTMiningBlob ( miningHash , nonce , powData ) {
76+ const powBytes = Buffer . alloc ( XTM_T_POW_DATA_SIZE ) ;
77+ if ( powData ) Buffer . from ( powData ) . copy ( powBytes , 0 , 0 , XTM_T_POW_DATA_SIZE ) ;
78+ const blob = Buffer . concat ( [
79+ Buffer . alloc ( XTM_T_MINING_HASH_OFFSET ) ,
80+ miningHash ,
81+ Buffer . alloc ( XTM_T_NONCE_SIZE ) ,
82+ Buffer . from ( [ XTM_T_RANDOMXT_POW_ALGO ] ) ,
83+ powBytes
84+ ] ) ;
85+
86+ blob . writeBigUInt64BE ( BigInt ( nonce ) , XTM_T_NONCE_OFFSET ) ;
87+ return blob ;
88+ }
89+
90+ function reconstructXtmTMiningBlob ( miningHash , submittedBlock ) {
91+ const powData = submittedBlock . header . pow && submittedBlock . header . pow . pow_data
92+ ? submittedBlock . header . pow . pow_data
93+ : [ ] ;
94+ return createXtmTMiningBlob ( miningHash , BigInt ( submittedBlock . header . nonce ) , powData ) ;
95+ }
96+
97+ function findTariSourceFile ( relativePath ) {
98+ for ( const root of TARI_SOURCE_CANDIDATES ) {
99+ const candidate = path . join ( root , relativePath ) ;
100+ if ( fs . existsSync ( candidate ) ) return candidate ;
101+ }
102+ return null ;
103+ }
104+
105+ function readRustIntegerConst ( source , name ) {
106+ const match = source . match ( new RegExp ( "\\bconst\\s+" + name + "\\s*:\\s*[^=]+\\s*=\\s*(\\d+)\\s*;" ) ) ;
107+ assert . notEqual ( match , null , "missing Tari source const " + name ) ;
108+ return Number ( match [ 1 ] ) ;
109+ }
110+
59111test . describe ( "pool coin helpers: submitters" , { concurrency : false } , ( ) => {
60112test . beforeEach ( ( ) => {
61113 installTestGlobals ( ) ;
@@ -377,11 +429,78 @@ test("erg mining.submit parser falls back to nonce suffix for standard submits",
377429 assert . equal ( params . nonce , "5b3ec51d640c" ) ;
378430} ) ;
379431
432+ test ( "xtm-t SubmitBlock payload roundtrips the miner's Tari RandomXT blob" , ( ) => {
433+ const coinFuncs = global . coinFuncs . __realCoinFuncs ;
434+ const xtmTPool = coinFuncs . getPoolSettings ( "XTM-T" ) ;
435+ const miningHash = Buffer . from ( "31" . repeat ( XTM_T_MINING_HASH_SIZE ) , "hex" ) ;
436+ const xtmBlock = {
437+ header : {
438+ nonce : "0" ,
439+ pow : { pow_data : [ 7 , 7 , 7 ] }
440+ }
441+ } ;
442+ const blockTemplate = new coinFuncs . BlockTemplate ( {
443+ blocktemplate_blob : createXtmTMiningBlob ( miningHash , 0n ) . toString ( "hex" ) ,
444+ coin : "XTM-T" ,
445+ difficulty : 1 ,
446+ height : 271620 ,
447+ port : 18146 ,
448+ reserved_offset : XTM_T_NONCE_OFFSET ,
449+ reward : 1 ,
450+ seed_hash : "22" . repeat ( 32 ) ,
451+ xtm_block : xtmBlock
452+ } ) ;
453+ const calls = [ ] ;
454+ const minerBlob = Buffer . from ( blockTemplate . nextBlobHex ( ) , "hex" ) ;
455+
456+ minerBlob . writeUInt32BE ( 0x01020304 , XTM_T_MINER_NONCE_OFFSET ) ;
457+
458+ xtmTPool . submitBlockRpc . call ( xtmTPool , {
459+ blockData : minerBlob ,
460+ blockTemplate,
461+ replyFn ( ) { } ,
462+ support : {
463+ rpcPortDaemon ( port , method , params ) {
464+ calls . push ( { port, method, params } ) ;
465+ }
466+ }
467+ } ) ;
468+
469+ assert . equal ( calls . length , 1 ) ;
470+ assert . equal ( calls [ 0 ] . port , 18146 ) ;
471+ assert . equal ( calls [ 0 ] . method , "SubmitBlock" ) ;
472+ assert . equal ( calls [ 0 ] . params . header . nonce , minerBlob . readBigUInt64BE ( XTM_T_NONCE_OFFSET ) . toString ( 10 ) ) ;
473+ assert . deepEqual ( calls [ 0 ] . params . header . pow . pow_data , [ ] ) ;
474+ assert . equal ( reconstructXtmTMiningBlob ( miningHash , calls [ 0 ] . params ) . equals ( minerBlob ) , true ) ;
475+ assert . notStrictEqual ( calls [ 0 ] . params , xtmBlock ) ;
476+ assert . equal ( xtmBlock . header . nonce , "0" ) ;
477+ assert . deepEqual ( xtmBlock . header . pow . pow_data , [ 7 , 7 , 7 ] ) ;
478+ } ) ;
479+
480+ test ( "xtm-t layout matches Tari source constants when source is available" , ( t ) => {
481+ const innerPath = findTariSourceFile ( path . join ( "applications" , "minotari_node" , "src" , "xmrig_proxy" , "inner.rs" ) ) ;
482+ if ( ! innerPath ) {
483+ t . skip ( "Tari source tree not available; set POOL_TEST_TARI_SOURCE_DIR to enable this contract check." ) ;
484+ return ;
485+ }
486+
487+ const innerSource = fs . readFileSync ( innerPath , "utf8" ) ;
488+ assert . equal ( readRustIntegerConst ( innerSource , "TARI_BLOB_RESERVED_OFFSET" ) , XTM_T_NONCE_OFFSET ) ;
489+ assert . equal ( readRustIntegerConst ( innerSource , "TARI_MINING_BLOB_SIZE" ) , XTM_T_POW_DATA_OFFSET + XTM_T_POW_DATA_SIZE ) ;
490+ assert . equal ( readRustIntegerConst ( innerSource , "POW_ALGO_RANDOMXT" ) , XTM_T_RANDOMXT_POW_ALGO ) ;
491+
492+ const helpersPath = findTariSourceFile ( path . join ( "base_layer" , "core" , "src" , "proof_of_work" , "monero_rx" , "helpers.rs" ) ) ;
493+ if ( ! helpersPath ) return ;
494+ const helpersSource = fs . readFileSync ( helpersPath , "utf8" ) ;
495+ assert . match ( helpersSource , / n o n c e \. t o _ b e _ b y t e s \( \) / ) ;
496+ assert . match ( helpersSource , / p o w \. t o _ b y t e s \( \) / ) ;
497+ } ) ;
498+
380499test ( "xtm submit and verify handlers preserve the pre-refactor special-case tari semantics" , ( ) => {
381500 const coinFuncs = global . coinFuncs . __realCoinFuncs ;
382501 const xtmTPool = coinFuncs . getPoolSettings ( "XTM-T" ) ;
383502 const xtmCPool = coinFuncs . getPoolSettings ( "XTM-C" ) ;
384- const blockDataRx = Buffer . alloc ( 48 , 0 ) ;
503+ const blockDataRx = Buffer . alloc ( 76 , 0 ) ;
385504 const blockDataC29 = Buffer . alloc ( 8 , 0 ) ;
386505 const xtmRxCalls = [ ] ;
387506 const xtmC29Calls = [ ] ;
@@ -394,9 +513,22 @@ test("xtm submit and verify handlers preserve the pre-refactor special-case tari
394513 Buffer . from ( "aabbccdd" , "hex" )
395514 ] ) ;
396515 const job = { blob_type_num : 107 } ;
516+ const xtmRxBlock = {
517+ header : {
518+ nonce : "" ,
519+ pow : { pow_data : [ 99 ] }
520+ }
521+ } ;
522+ const xtmC29Block = {
523+ header : {
524+ nonce : "" ,
525+ pow : { pow_data : [ 88 ] }
526+ }
527+ } ;
397528
529+ blockDataRx . writeUInt32BE ( 7 , 3 + 32 ) ;
398530 blockDataRx . writeUInt32BE ( 1234 , 3 + 32 + 4 ) ;
399- Buffer . from ( [ 9 , 8 , 7 , 6 ] ) . copy ( blockDataRx , 3 + 32 + 8 + 1 ) ;
531+ blockDataRx [ 3 + 32 + 8 ] = 2 ;
400532 blockDataC29 . writeBigUInt64BE ( 15n , 0 ) ;
401533
402534 xtmTPool . resolveSubmittedBlockHash ( {
@@ -413,12 +545,7 @@ test("xtm submit and verify handlers preserve the pre-refactor special-case tari
413545 blockData : blockDataRx ,
414546 blockTemplate : {
415547 port : 18146 ,
416- xtm_block : {
417- header : {
418- nonce : "" ,
419- pow : { pow_data : [ ] }
420- }
421- }
548+ xtm_block : xtmRxBlock
422549 } ,
423550 replyFn ( ) { } ,
424551 support : {
@@ -498,12 +625,7 @@ test("xtm submit and verify handlers preserve the pre-refactor special-case tari
498625 blockData : blockDataC29 ,
499626 blockTemplate : {
500627 port : 18148 ,
501- xtm_block : {
502- header : {
503- nonce : "" ,
504- pow : { pow_data : [ ] }
505- }
506- }
628+ xtm_block : xtmC29Block
507629 } ,
508630 job,
509631 replyFn ( ) { } ,
@@ -525,8 +647,11 @@ test("xtm submit and verify handlers preserve the pre-refactor special-case tari
525647 assert . equal ( xtmRxCalls . length , 1 ) ;
526648 assert . equal ( xtmRxCalls [ 0 ] . port , 18146 ) ;
527649 assert . equal ( xtmRxCalls [ 0 ] . method , "SubmitBlock" ) ;
528- assert . equal ( xtmRxCalls [ 0 ] . params . header . nonce , "1234" ) ;
529- assert . deepEqual ( xtmRxCalls [ 0 ] . params . header . pow . pow_data , [ 9 , 8 , 7 , 6 ] ) ;
650+ assert . equal ( xtmRxCalls [ 0 ] . params . header . nonce , ( ( 7n << 32n ) | 1234n ) . toString ( 10 ) ) ;
651+ assert . deepEqual ( xtmRxCalls [ 0 ] . params . header . pow . pow_data , [ ] ) ;
652+ assert . notStrictEqual ( xtmRxCalls [ 0 ] . params , xtmRxBlock ) ;
653+ assert . equal ( xtmRxBlock . header . nonce , "" ) ;
654+ assert . deepEqual ( xtmRxBlock . header . pow . pow_data , [ 99 ] ) ;
530655
531656 assert . deepEqual ( job . c29_packed_edges , [ 0xab , 0xcd ] ) ;
532657 assert . equal ( verifyArgs [ 0 ] , 77n ) ;
@@ -540,5 +665,8 @@ test("xtm submit and verify handlers preserve the pre-refactor special-case tari
540665 assert . equal ( xtmC29Calls [ 0 ] . method , "SubmitBlock" ) ;
541666 assert . equal ( xtmC29Calls [ 0 ] . params . header . nonce , "15" ) ;
542667 assert . deepEqual ( xtmC29Calls [ 0 ] . params . header . pow . pow_data , [ 0xab , 0xcd ] ) ;
668+ assert . notStrictEqual ( xtmC29Calls [ 0 ] . params , xtmC29Block ) ;
669+ assert . equal ( xtmC29Block . header . nonce , "" ) ;
670+ assert . deepEqual ( xtmC29Block . header . pow . pow_data , [ 88 ] ) ;
543671} ) ;
544672} ) ;
0 commit comments