github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/client/www/templates/miners.html (about) 1 <style> 2 td.bl_ver { 3 font-family: monospace; 4 text-align:right; 5 } 6 td.bl_cnt { 7 text-align:right; 8 } 9 td.bl_perc { 10 text-align:right; 11 } 12 td.mi_unkn { 13 font-style:italic; 14 font-size:80%; 15 } 16 td.mi_netshare { 17 font-family: monospace; 18 text-align:right; 19 font-weight:bold; 20 } 21 td.mi_hashrate { 22 font-family: monospace; 23 text-align:right; 24 font-style:italic; 25 font-size:90%; 26 white-space:nowrap; 27 } 28 td.mi_bsize { 29 font-family: monospace; 30 text-align:right; 31 font-size:90%; 32 font-weight:bold; 33 } 34 td.mi_tot { 35 text-align:right; 36 color:purple; 37 font-style:italic; 38 font-weight:bold; 39 } 40 td.mi_vers { 41 text-align:right; 42 color:brown; 43 font-style:italic; 44 font-weight:bold; 45 } 46 tr.ver_others { 47 font-weight:bold; 48 font-style:italic; 49 } 50 caption { 51 margin-bottom:6px; 52 } 53 #verinfo { 54 left:0px; 55 top:0px; 56 z-index:1000; 57 width:800px; 58 background-color:#e0e0e0; 59 overflow-x:auto; 60 } 61 </style> 62 63 <script> 64 65 const avg_blocks_pr_day = 146.7 // average between #722125 and 822125 66 const estimated_block_vsize = 999500 67 68 var last_block_height = 0 69 70 function printable(str) { 71 //return str.replace(/[^\x20-\x7E]/g, '') 72 return str.replace(/[^ -~]+/g, '.'); 73 } 74 function show_versions(row, id) { 75 var s = "*** Blocks mined by " + id + ' ***' 76 77 var vrs = new Array() 78 row["vers"].forEach(function(cnt, ver, m) { 79 vrs.push([ver, cnt]) 80 }) 81 vrs.sort(function(a,b){ 82 return (a[1]>b[1]) ? -1 : ((a[1]==b[1]) ? 0 : 1); 83 }) 84 s += "\n\n Version Cnt\n" 85 s += " ================\n" 86 for (var i=0; i<vrs.length; i++) { 87 s += " " + vrs[i][0].toString(16) + (" " + vrs[i][1]).slice(-5) + "\n" 88 } 89 90 s += "\n\n Height Version Length Fees BTC SPB Coinbase Strings\n" 91 s += " =======================================================================================================\n" 92 var mbs = row["mbs"] 93 for (var i=0; i<mbs.length; i++) { 94 var str = mbs[i].Strings 95 if (str.length > 6) { 96 // ignore block height for sig_script strings 97 var bh_len = str.charCodeAt(0) 98 if (bh_len >= 3 && bh_len <= 5) str = str.substr(bh_len+1) 99 } 100 s += (" "+mbs[i].Height).slice(-8) + 101 " " + mbs[i].Version.toString(16) + 102 (" "+mbs[i].Length).slice(-9) + 103 (" " + val2str_pad(mbs[i].Fees, true)).slice(-12) + 104 (" " + (mbs[i].Fees / mbs[i].Length).toFixed(1)).slice(-7) + 105 " " + str.replace(/[^ -~]+/g, ' ') + "\n" 106 } 107 108 verinfo.innerText = s 109 } 110 111 function refresh_mining_info() { 112 function onc(c, id) { 113 c.onclick = function() {show_versions(c, id)} 114 } 115 116 var aj = ajax() 117 aj.onerror=function() { 118 setTimeout(refreshblocks, 1000) 119 } 120 aj.onload=function() { 121 try { 122 var cs = JSON.parse(aj.responseText) 123 var height_min, height_max 124 var heights = new Array() 125 el_min_hrs.innerText = cs.MiningStatHours 126 el_first_block_time.innerText = tim2str(cs.FirstBlockTime, false) 127 el_block_cnt.innerText = cs.BlockCount 128 el_blocks_per_hour.innerText = parseFloat(cs.AvgBlocksPerHour).toFixed(2) 129 el_avg_hashrate.innerText = bignum(cs.AvgHashrate)+'H/s' 130 el_avg_diff.innerText = bignum(cs.AvgDifficulty) 131 el_diff_change_in.innerText = (parseInt(last_block_height/2016)+1)*2016 - last_block_height 132 133 var per = (parseInt(last_block_height/210e3)+1) * 210e3 134 next_halving_days.innerText = Math.round((per - last_block_height) / avg_blocks_pr_day) 135 next_halving_weeks.innerText = Math.round((per - last_block_height) / avg_blocks_pr_day/7) 136 next_halving_months.innerText = Math.round((per - last_block_height) / avg_blocks_pr_day/(365/12)) 137 next_halving_years.innerText = ((per - last_block_height) / avg_blocks_pr_day/365.25).toFixed(1) 138 139 while (minerstab.rows.length>1) minerstab.deleteRow(1) 140 141 var totfees=0, totbts=0, bu_cnt=0, sw_cnt=0, ny_cnt=0 142 for (var i=0; i<cs.Miners.length; i++) { 143 var m = cs.Miners[i] 144 var td, row = minerstab.insertRow(-1) 145 146 row.className = 'hand' 147 row["mbs"] = m.MinedBlocks 148 onc(row, m.Name) 149 150 td = row.insertCell(-1) 151 if (m.Unknown) td.className = 'mi_unkn' 152 td.innerText = m.Name 153 154 td = row.insertCell(-1) 155 td.className = 'mi_netshare' 156 var frac = parseFloat(m.Blocks/cs.BlockCount) 157 td.innerText = parseFloat(100.0*frac).toFixed(1) + '%' 158 159 td = row.insertCell(-1) 160 td.className = 'mi_tot' 161 td.innerText = m.MinedBlocks.length 162 163 // parse MinedBlocks array 164 var vers = new Map() 165 for (var j=0; j<m.MinedBlocks.length; j++) { 166 var b = m.MinedBlocks[j] 167 var cnt = 0 168 169 if (vers.has(b.Version)) { 170 cnt = vers.get(b.Version) 171 } 172 vers.set(b.Version, cnt+1) 173 174 if (heights.length==0) { 175 height_min = height_max = b.Height 176 } else { 177 if (height_min > b.Height) height_min = b.Height 178 else if (height_max < b.Height) height_max = b.Height 179 } 180 heights[b.Height] = b.Version 181 if (b.Length>1e6) ny_cnt++ 182 } 183 184 row["vers"] = vers 185 td = row.insertCell(-1) 186 td.className = 'mi_vers' 187 td.innerText = vers.size 188 189 td = row.insertCell(-1) 190 td.className = 'mi_hashrate' 191 var frac = parseFloat(m.Blocks/cs.BlockCount) 192 td.innerText = bignum(frac*cs.AvgHashrate)+'H/s' 193 194 td = row.insertCell(-1) 195 td.className = 'mi_bsize' 196 td.innerText = parseFloat(m.TotalBytes/m.Blocks).toFixed(0) 197 198 td = row.insertCell(-1) 199 td.className = 'blreward' 200 td.innerText = val2str_pad(m.TotalFees, true) 201 202 td = row.insertCell(-1) 203 td.className = 'blspb' 204 td.innerText = parseFloat(m.TotalFees/(m.Blocks*estimated_block_vsize)).toFixed(0) 205 206 totfees += m.TotalFees 207 totbts += m.TotalBytes 208 } 209 blockver_tab_n.innerHTML = height_max-height_min+1 210 block_short_history_td.style.display = 'table-cell' 211 var vvs = [] 212 for (var h=height_min; h<=height_max; h++) vvs.push([h, heights[h]]) 213 do_versions("short", vvs, height_max, height_min) 214 215 el_avg_block_size.innerText = parseFloat(totbts/cs.BlockCount).toFixed(0) 216 el_total_fees.innerText = (totfees/1e8).toFixed(2) 217 el_avg_fpblock.innerText = (totfees/cs.BlockCount/1e8).toFixed(3) 218 if (ny_cnt > 0) 219 el_avg_fpbyte.innerText = parseFloat(totfees/(ny_cnt*estimated_block_vsize)).toFixed(0) 220 else 221 el_avg_fpbyte.innerText = '???' 222 223 loading_icon.style.display = 'none' 224 mining_info_div.style.display = 'block' 225 } catch(e) { 226 console.log(e) 227 } 228 } 229 aj.open("GET","miners.json",true) 230 aj.send(null) 231 } 232 233 234 </script> 235 <table><tr> 236 <td valign="top" width="800"><img id="loading_icon" src="webui/loading.gif" style="display:inline"><div id="mining_info_div" style="display:none"> 237 <div style="margin-bottom:8px"> 238 Data from last <b id="el_min_hrs"></b> hours. 239 The oldest block starting at <b id="el_first_block_time"></b><br> 240 Total number of blocks was <b id="el_block_cnt"></b>, 241 making average of <b id="el_blocks_per_hour" class="size120"></b> per hour, 242 with the size of <b id="el_avg_block_size"></b><br> 243 Network's rate of <b id="el_avg_hashrate"></b>, 244 at average difficulty <b id="el_avg_diff"></b>, 245 which changes in <b id="el_diff_change_in" class="size120"></b> blocks<br> 246 247 Total mining fees amount to <b id="el_total_fees"></b> BTC 248 with the average of <b id="el_avg_fpblock" class="size120"></b> BTC/block or estimated <b id="el_avg_fpbyte"></b> SPB 249 </div> 250 <table id="minerstab" class="bord" width="100%"> 251 <tr> 252 <th width="120" align="left">Miner 253 <th width="80" align="right">Share 254 <th width="40" align="right" title="Total blocks mined">Blks 255 <th width="40" align="right" title="Unique version values">Vers 256 <th width="100" align="right">Hashrate 257 <th width="80" align="right" title="Average Block Length">Average 258 <th width="100" align="right">Fees BTC 259 <th width="60" align="right" title="Satoshis per byte">SPB 260 </tr> 261 </table> 262 <br> 263 <table width="100%" border="0" cellspacing="0"> 264 <tr> 265 <td colspan="2"> 266 The next halving is estimated to happen in 267 268 <b id="next_halving_days">...</b> days 269 • 270 <b id="next_halving_weeks">...</b> weeks 271 • 272 <b id="next_halving_months">...</b> months 273 • 274 <b id="next_halving_years">...</b> years. 275 </td> 276 </tr> 277 </table> 278 279 </div> 280 281 <pre id="verinfo" class="mono"></pre> 282 283 </td> 284 <td valign="top" id="block_short_history_td" style="display:none"> 285 <table class="bord" id="blockver_tab_short" align="right"> 286 <caption>Last <b id="blockver_tab_n">n</b> blocks</caption> 287 <tr><th>Version<th>Count<th>Share 288 </table> 289 </td> 290 291 <td valign="top" id="block_history_td" style="display:none"> 292 <table class="bord" id="blockver_tab_1000" align="right"> 293 <caption>Last 1000 blocks</caption> 294 <tr><th>Version<th>Count<th>Share 295 </table> 296 297 <br> 298 <table class="bord" id="blockver_tab_curr" align="right"> 299 <caption>Current period</caption> 300 <tr><th>Version<th>Count<th>Share 301 </table> 302 303 <br> 304 <table class="bord" id="blockver_tab_past" align="right"> 305 <caption>Past period</caption> 306 <tr><th>Version<th>Count<th>Share 307 </table> 308 </td> 309 310 </tr> 311 </table> 312 313 <script> 314 function do_versions(tabid, block_versions, max_block_number, min_block_number) { 315 var key, st = new Array() 316 var counted = 0; 317 for (var i=0; i<block_versions.length; i++) { 318 if (block_versions[i][0] > max_block_number) continue; 319 if (block_versions[i][0] < min_block_number) continue; 320 counted++; 321 var ver = block_versions[i][1] 322 key = ver+"" 323 if (isNaN(st[key])) { 324 st[key] = 1 325 } else { 326 st[key]++ 327 } 328 } 329 var sorted = new Array() 330 for (key in st) { 331 sorted.push({ver:parseInt(key), cnt:st[key]}) 332 } 333 334 sorted.sort(function(a,b){ 335 if (a.cnt>b.cnt) return -1; 336 else if (a.cnt==b.cnt) return 0; 337 else return 1; 338 }) 339 340 var blockver_tab = document.getElementById("blockver_tab_" + tabid) 341 while (blockver_tab.rows.length>1) blockver_tab.deleteRow(1) 342 343 var perc 344 for (var i=0; i<sorted.length; i++) { 345 var row = blockver_tab.insertRow(-1) 346 var c = row.insertCell(-1) 347 348 if (sorted[i].cnt==1) { 349 row.className = 'ver_others' 350 c.innerText = 'Others' 351 c = row.insertCell(-1) 352 c.className = 'bl_cnt' 353 var cc = sorted.length-i 354 c.innerText = cc 355 c = row.insertCell(-1) 356 c.className = 'bl_perc' 357 perc = cc*100/counted 358 c.innerText = (block_versions.length<1000 ? perc.toFixed(1) : Math.round(perc) ) + '%' 359 break 360 } 361 362 c.className = 'bl_ver' 363 c.innerText = leftpad(sorted[i].ver.toString(16), '0', 8) 364 365 c = row.insertCell(-1) 366 c.className = 'bl_cnt' 367 c.innerText = sorted[i].cnt 368 369 c = row.insertCell(-1) 370 c.className = 'bl_perc' 371 perc = sorted[i].cnt*100/counted 372 c.innerText = (block_versions.length<1000 ? perc.toFixed(1) : Math.round(perc)) + '%' 373 } 374 } 375 376 function blocks_version_stats() { 377 var aj = ajax() 378 aj.onerror=function() { 379 setTimeout(refreshblocks, 1000) 380 } 381 aj.onload=function() { 382 try { 383 var block_versions = JSON.parse(aj.responseText) 384 var top_block_height = block_versions[0][0] 385 var last_epoch_change = Math.floor(top_block_height/2016) * 2016 386 387 do_versions("1000", block_versions, top_block_height, top_block_height-999) 388 do_versions("curr", block_versions, top_block_height, last_epoch_change) 389 do_versions("past", block_versions, last_epoch_change-1, last_epoch_change-2016) 390 391 block_history_td.style.display = 'table-cell' 392 393 } catch (e) { 394 blockver_tab.style.display='none' 395 } 396 } 397 aj.open("GET","blkver.json",true) 398 aj.send(null) 399 } 400 401 // reaload page on new block 402 blno.addEventListener("lastblock", function(e) { 403 if (e.block.Height!=last_block_height) { 404 last_block_height = e.block.Height 405 refresh_mining_info() 406 //blocks_version_stats() 407 } 408 }) 409 </script>