@@ -148,57 +148,65 @@ async function printStatistics(dataSize, typedApi) {
148148 const avgTxsPerBlock = totalBlocksInRange > 0 ? ( numTxs / totalBlocksInRange ) . toFixed ( 2 ) : 'N/A' ;
149149
150150 // Fetch block timestamps for all blocks in range
151+ // Query at the last known block to ensure all previous blocks are visible
152+ const lastKnownBlockHash = stats . blockHashes [ endBlock ] ;
151153 const blockTimestamps = { } ;
152154 for ( let blockNum = startBlock ; blockNum <= endBlock ; blockNum ++ ) {
153155 try {
154- // Get block hash - either from our stored hashes or query the chain
156+ // Get block hash - either from stored or query at last known block
155157 let blockHash = stats . blockHashes [ blockNum ] ;
156158 if ( ! blockHash ) {
157- const queriedHash = await typedApi . query . System . BlockHash . getValue ( blockNum ) ;
158- // Handle different hash formats (string, Binary, Uint8Array)
159- // PAPI Binary objects have asHex() method, fall back to toString()
160- const hashStr = typeof queriedHash === 'string'
161- ? queriedHash
162- : ( queriedHash ?. asHex ?. ( ) || queriedHash ?. toHex ?. ( ) || queriedHash ?. toString ?. ( ) || '' ) ;
163- // Check if hash is not empty (all zeros means pruned/unavailable)
164- if ( hashStr && ! hashStr . match ( / ^ ( 0 x ) ? 0 + $ / ) ) {
165- blockHash = queriedHash ;
166- }
159+ blockHash = await typedApi . query . System . BlockHash . getValue ( blockNum , { at : lastKnownBlockHash } ) ;
167160 }
168- if ( blockHash ) {
169- const timestamp = await typedApi . query . Timestamp . Now . getValue ( { at : blockHash } ) ;
170- blockTimestamps [ blockNum ] = timestamp ;
161+ // Convert Binary/Uint8Array to hex string for PAPI's at parameter
162+ const blockHashHex = typeof blockHash === 'string'
163+ ? blockHash
164+ : ( blockHash ?. asHex ?. ( ) || blockHash ?. toHex ?. ( ) || '0x' + Buffer . from ( blockHash ) . toString ( 'hex' ) ) ;
165+ // Skip blocks with zero hash (pruned)
166+ if ( blockHashHex . match ( / ^ ( 0 x ) ? 0 + $ / ) ) {
167+ continue ;
171168 }
169+ const timestamp = await typedApi . query . Timestamp . Now . getValue ( { at : blockHashHex } ) ;
170+ blockTimestamps [ blockNum ] = timestamp ;
172171 } catch ( e ) {
173172 console . error ( `Failed to fetch timestamp for block #${ blockNum } :` , e . message ) ;
174173 }
175174 }
176175
177176 console . log ( '\n' ) ;
178- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
179- console . log ( ' 📊 STORAGE STATISTICS ' ) ;
180- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
177+ // Calculate average block time from timestamps
178+ const startTimestamp = blockTimestamps [ startBlock ] ;
179+ const endTimestamp = blockTimestamps [ endBlock ] ;
180+ const avgBlockTime = ( startTimestamp && endTimestamp && blocksElapsed > 0 )
181+ ? ( Number ( endTimestamp ) - Number ( startTimestamp ) ) / blocksElapsed
182+ : null ;
183+
184+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
185+ console . log ( '📊 STORAGE STATISTICS' ) ;
186+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
181187 console . log ( `│ File size │ ${ formatBytes ( dataSize ) . padEnd ( 25 ) } │` ) ;
182188 console . log ( `│ Chunk/TX size │ ${ formatBytes ( CHUNK_SIZE ) . padEnd ( 25 ) } │` ) ;
183189 console . log ( `│ Number of chunks │ ${ numTxs . toString ( ) . padEnd ( 25 ) } │` ) ;
184- console . log ( `│ Avg txs per block │ ${ `${ avgTxsPerBlock } (${ numTxs } /${ totalBlocksInRange } )` . padEnd ( 25 ) } │` ) ;
190+ console . log ( `│ Avg txs per block │ ${ `${ avgTxsPerBlock } (${ numTxs } txs in #${ startBlock } → #${ endBlock } )` . padEnd ( 25 ) } │` ) ;
191+ console . log ( `│ Avg block time │ ${ ( avgBlockTime ? formatDuration ( avgBlockTime ) : 'N/A' ) . padEnd ( 25 ) } │` ) ;
185192 console . log ( `│ Time elapsed │ ${ formatDuration ( elapsed ) . padEnd ( 25 ) } │` ) ;
186193 console . log ( `│ Blocks elapsed │ ${ `${ blocksElapsed } (#${ startBlock } → #${ endBlock } )` . padEnd ( 25 ) } │` ) ;
187- console . log ( `│ Throughput │ ${ formatBytes ( dataSize / ( elapsed / 1000 ) ) . padEnd ( 22 ) } /s │` ) ;
188- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
189- console . log ( ' 📦 TRANSACTIONS PER BLOCK ' ) ;
190- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
191- console . log ( '│ Block │ Time │ TXs │ Size │ Bar │' ) ;
192- console . log ( '├─────────────┼─────────────────────────┼─────┼──────────────┼──────────────────────┤' ) ;
194+ console . log ( `│ Throughput/sec │ ${ ( formatBytes ( dataSize / ( elapsed / 1000 ) ) + '/s' ) . padEnd ( 25 ) } │` ) ;
195+ console . log ( `│ Throughput/block │ ${ ( formatBytes ( dataSize / totalBlocksInRange ) + '/block' ) . padEnd ( 25 ) } │` ) ;
196+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
197+ console . log ( '📦 TRANSACTIONS PER BLOCK' ) ;
198+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
199+ console . log ( '│ Block │ Time │ TXs │ Size │ Bar │' ) ;
200+ console . log ( '├─────────────┼─────────────────────┼─────┼──────────────┼──────────────────────┤' ) ;
193201 for ( let blockNum = startBlock ; blockNum <= endBlock ; blockNum ++ ) {
194202 const count = txsPerBlock [ blockNum ] || 0 ;
195203 const size = count > 0 ? formatBytes ( count * CHUNK_SIZE ) : '-' ;
196204 const bar = count > 0 ? '█' . repeat ( Math . min ( count , 20 ) ) : '' ;
197205 const timestamp = blockTimestamps [ blockNum ] ;
198- const timeStr = timestamp ? new Date ( Number ( timestamp ) ) . toISOString ( ) . replace ( 'T' , ' ' ) . replace ( 'Z' , '' ) : '-' ;
199- console . log ( `│ #${ blockNum . toString ( ) . padEnd ( 10 ) } │ ${ timeStr . padEnd ( 23 ) } │ ${ count . toString ( ) . padStart ( 3 ) } │ ${ size . padEnd ( 12 ) } │ ${ bar . padEnd ( 20 ) } │` ) ;
206+ const timeStr = timestamp ? new Date ( Number ( timestamp ) ) . toISOString ( ) . replace ( 'T' , ' ' ) . slice ( 0 , 19 ) : '-' ;
207+ console . log ( `│ #${ blockNum . toString ( ) . padEnd ( 10 ) } │ ${ timeStr . padEnd ( 19 ) } │ ${ count . toString ( ) . padStart ( 3 ) } │ ${ size . padEnd ( 12 ) } │ ${ bar . padEnd ( 20 ) } │` ) ;
200208 }
201- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════ ' ) ;
209+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
202210 console . log ( '\n' ) ;
203211}
204212
0 commit comments