@@ -155,57 +155,65 @@ async function printStatistics(dataSize, typedApi) {
155155 const avgTxsPerBlock = totalBlocksInRange > 0 ? ( numTxs / totalBlocksInRange ) . toFixed ( 2 ) : 'N/A' ;
156156
157157 // Fetch block timestamps for all blocks in range
158+ // Query at the last known block to ensure all previous blocks are visible
159+ const lastKnownBlockHash = stats . blockHashes [ endBlock ] ;
158160 const blockTimestamps = { } ;
159161 for ( let blockNum = startBlock ; blockNum <= endBlock ; blockNum ++ ) {
160162 try {
161- // Get block hash - either from our stored hashes or query the chain
163+ // Get block hash - either from stored or query at last known block
162164 let blockHash = stats . blockHashes [ blockNum ] ;
163165 if ( ! blockHash ) {
164- const queriedHash = await typedApi . query . System . BlockHash . getValue ( blockNum ) ;
165- // Handle different hash formats (string, Binary, Uint8Array)
166- // PAPI Binary objects have asHex() method, fall back to toString()
167- const hashStr = typeof queriedHash === 'string'
168- ? queriedHash
169- : ( queriedHash ?. asHex ?. ( ) || queriedHash ?. toHex ?. ( ) || queriedHash ?. toString ?. ( ) || '' ) ;
170- // Check if hash is not empty (all zeros means pruned/unavailable)
171- if ( hashStr && ! hashStr . match ( / ^ ( 0 x ) ? 0 + $ / ) ) {
172- blockHash = queriedHash ;
173- }
166+ blockHash = await typedApi . query . System . BlockHash . getValue ( blockNum , { at : lastKnownBlockHash } ) ;
174167 }
175- if ( blockHash ) {
176- const timestamp = await typedApi . query . Timestamp . Now . getValue ( { at : blockHash } ) ;
177- blockTimestamps [ blockNum ] = timestamp ;
168+ // Convert Binary/Uint8Array to hex string for PAPI's at parameter
169+ const blockHashHex = typeof blockHash === 'string'
170+ ? blockHash
171+ : ( blockHash ?. asHex ?. ( ) || blockHash ?. toHex ?. ( ) || '0x' + Buffer . from ( blockHash ) . toString ( 'hex' ) ) ;
172+ // Skip blocks with zero hash (pruned)
173+ if ( blockHashHex . match ( / ^ ( 0 x ) ? 0 + $ / ) ) {
174+ continue ;
178175 }
176+ const timestamp = await typedApi . query . Timestamp . Now . getValue ( { at : blockHashHex } ) ;
177+ blockTimestamps [ blockNum ] = timestamp ;
179178 } catch ( e ) {
180179 console . error ( `Failed to fetch timestamp for block #${ blockNum } :` , e . message ) ;
181180 }
182181 }
183182
184183 console . log ( '\n' ) ;
185- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
186- console . log ( ' 📊 STORAGE STATISTICS ' ) ;
187- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
184+ // Calculate average block time from timestamps
185+ const startTimestamp = blockTimestamps [ startBlock ] ;
186+ const endTimestamp = blockTimestamps [ endBlock ] ;
187+ const avgBlockTime = ( startTimestamp && endTimestamp && blocksElapsed > 0 )
188+ ? ( Number ( endTimestamp ) - Number ( startTimestamp ) ) / blocksElapsed
189+ : null ;
190+
191+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
192+ console . log ( '📊 STORAGE STATISTICS' ) ;
193+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
188194 console . log ( `│ File size │ ${ formatBytes ( dataSize ) . padEnd ( 25 ) } │` ) ;
189195 console . log ( `│ Chunk/TX size │ ${ formatBytes ( CHUNK_SIZE ) . padEnd ( 25 ) } │` ) ;
190196 console . log ( `│ Number of chunks │ ${ numTxs . toString ( ) . padEnd ( 25 ) } │` ) ;
191- console . log ( `│ Avg txs per block │ ${ `${ avgTxsPerBlock } (${ numTxs } /${ totalBlocksInRange } )` . padEnd ( 25 ) } │` ) ;
197+ console . log ( `│ Avg txs per block │ ${ `${ avgTxsPerBlock } (${ numTxs } txs in #${ startBlock } → #${ endBlock } )` . padEnd ( 25 ) } │` ) ;
198+ console . log ( `│ Avg block time │ ${ ( avgBlockTime ? formatDuration ( avgBlockTime ) : 'N/A' ) . padEnd ( 25 ) } │` ) ;
192199 console . log ( `│ Time elapsed │ ${ formatDuration ( elapsed ) . padEnd ( 25 ) } │` ) ;
193200 console . log ( `│ Blocks elapsed │ ${ `${ blocksElapsed } (#${ startBlock } → #${ endBlock } )` . padEnd ( 25 ) } │` ) ;
194- console . log ( `│ Throughput │ ${ formatBytes ( dataSize / ( elapsed / 1000 ) ) . padEnd ( 22 ) } /s │` ) ;
195- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
196- console . log ( ' 📦 TRANSACTIONS PER BLOCK ' ) ;
197- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════' ) ;
198- console . log ( '│ Block │ Time │ TXs │ Size │ Bar │' ) ;
199- console . log ( '├─────────────┼─────────────────────────┼─────┼──────────────┼──────────────────────┤' ) ;
201+ console . log ( `│ Throughput/sec │ ${ ( formatBytes ( dataSize / ( elapsed / 1000 ) ) + '/s' ) . padEnd ( 25 ) } │` ) ;
202+ console . log ( `│ Throughput/block │ ${ ( formatBytes ( dataSize / totalBlocksInRange ) + '/block' ) . padEnd ( 25 ) } │` ) ;
203+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
204+ console . log ( '📦 TRANSACTIONS PER BLOCK' ) ;
205+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
206+ console . log ( '│ Block │ Time │ TXs │ Size │ Bar │' ) ;
207+ console . log ( '├─────────────┼─────────────────────┼─────┼──────────────┼──────────────────────┤' ) ;
200208 for ( let blockNum = startBlock ; blockNum <= endBlock ; blockNum ++ ) {
201209 const count = txsPerBlock [ blockNum ] || 0 ;
202210 const size = count > 0 ? formatBytes ( count * CHUNK_SIZE ) : '-' ;
203211 const bar = count > 0 ? '█' . repeat ( Math . min ( count , 20 ) ) : '' ;
204212 const timestamp = blockTimestamps [ blockNum ] ;
205- const timeStr = timestamp ? new Date ( Number ( timestamp ) ) . toISOString ( ) . replace ( 'T' , ' ' ) . replace ( 'Z' , '' ) : '-' ;
206- console . log ( `│ #${ blockNum . toString ( ) . padEnd ( 10 ) } │ ${ timeStr . padEnd ( 23 ) } │ ${ count . toString ( ) . padStart ( 3 ) } │ ${ size . padEnd ( 12 ) } │ ${ bar . padEnd ( 20 ) } │` ) ;
213+ const timeStr = timestamp ? new Date ( Number ( timestamp ) ) . toISOString ( ) . replace ( 'T' , ' ' ) . slice ( 0 , 19 ) : '-' ;
214+ console . log ( `│ #${ blockNum . toString ( ) . padEnd ( 10 ) } │ ${ timeStr . padEnd ( 19 ) } │ ${ count . toString ( ) . padStart ( 3 ) } │ ${ size . padEnd ( 12 ) } │ ${ bar . padEnd ( 20 ) } │` ) ;
207215 }
208- console . log ( '════════════════════════════════════════════════════════════════════════════════════════════════════════ ' ) ;
216+ console . log ( '════════════════════════════════════════════════════════════════════════════════' ) ;
209217 console . log ( '\n' ) ;
210218}
211219
0 commit comments