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  				&nbsp;&nbsp;
   268  				<b id="next_halving_days">...</b> days
   269  				&nbsp;&nbsp;&bull;&nbsp;&nbsp;
   270  				<b id="next_halving_weeks">...</b> weeks
   271  				&nbsp;&nbsp;&bull;&nbsp;&nbsp;
   272  				<b id="next_halving_months">...</b> months
   273  				&nbsp;&nbsp;&bull;&nbsp;&nbsp;
   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  	&nbsp;&nbsp;&nbsp;&nbsp;<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  	&nbsp;&nbsp;&nbsp;&nbsp;<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>