UNPKG

btq-nomp

Version:

BicoinQuark (Equihash) stratum mining pool based on NOMP

351 lines (323 loc) 13.3 kB
<style> #topCharts{ padding: 18px; } #topCharts > div > div > svg{ display: block; height: 280px; } .chartWrapper{ border: solid 1px #c7c7c7; border-radius: 5px; padding: 5px; margin-bottom: 18px; } .chartLabel{ font-size: 1.2em; text-align: center; padding: 4px; } .chartHolder{ } #boxesLower { margin: 0 9px; } #boxesLower > div { display: flex; } #boxesLower > div > div { flex: 1 1 auto; margin: 0 9px 18px 9px; padding: 10px; display: flex; flex-direction: column; } .boxLowerHeader{ font-size: 1.3em; margin: 0 0 5px 10px; } #boxStatsLeft{ color: black; background-color: #cccccc; } #boxStatsRight{ color: black; background-color: #cccccc; } .boxStats{ color: white; } .boxStatsList{ display: flex; flex-flow: row wrap; justify-content: space-around; opacity: 0.77; margin-bottom: 5px; flex: 1 1 auto; align-content: center; } .boxStatsList i.fa{ height: 15px; width: 33px; text-align: center; } .boxStatsList > div{ padding: 5px 20px; } .boxStatsList > div > div{ padding: 3px; } div.tooltip { position: absolute; text-align: center; width: 60px; height: 28px; padding: 2px; font: 12px sans-serif; background: lightsteelblue; border: 0px; border-radius: 8px; pointer-events: none; } #tooltip.hidden { opacity: 0; } </style> <div id="topCharts"> <div class="chartWrapper"> <div class="chartLabel">Pool Historical Hashrate</div> <div class="chartHolder"><svg id="poolHashrate"/></div> </div> </div> {{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }} {{ function readableDate(a){ return new Date(parseInt(a)).toString(); } }} <div class="pure-g-r" id="boxesLower"> {{ for(var pool in it.stats.pools) { }} <div class="pure-u-1-2"> <div class="boxStats" id="boxStatsLeft"> <div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Pool Stats</div> <div class="boxStatsList"> <div> <div><i class="fa fa-users"></i><span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</div> <div><i class="fa fa-rocket"></i><span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</div> <div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</div> <div><i class="fa fa-tachometer"></i><span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</div> <div><i class="fa fa-gavel"></i>Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</div> </div> </div> </div> </div> <div class="pure-u-1-2"> <div class="boxStats" id="boxStatsRight"> <div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Network Stats</div> <div class="boxStatsList"> <div> <div><i class="fa fa-bars" aria-hidden="true"></i><small>Block Height:</small> <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></div> <div><i class="fa fa-tachometer"></i><small>Network Hash/s:</small> <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></div> <div><i class="fa fa-unlock-alt" aria-hidden="true"></i><small>Difficulty:</small> <span id="statsNetworkDiff{{=pool}}">{{=it.stats.pools[pool].poolStats.networkDiff}}</span></div> <div><i class="fa fa-users"></i><small>Node Connections:</small> <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></div> </div> </div> </div> </div> {{ } }} </div> {{ for(var pool in it.stats.pools) { }} {{ var blockscomb = new Array; }} <div class="pure-g-r" id="boxesLower"> <div class="pure-u-1-1"> <div class="boxStats" id="boxStatsRight"> <div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Blocks Found &nbsp;&nbsp; <span style="float:right;"><small> <i class="fa fa-bars"></i> <span id="statsValidBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.validBlocks}}</span> Blocks &nbsp;&nbsp; <i class="fa fa-money"></i> Paid: <span id="statsTotalPaid{{=pool}}">{{=(parseFloat(it.stats.pools[pool].poolStats.totalPaid)).toFixed(8)}}</span> {{=it.stats.pools[pool].symbol}}</small>&nbsp;&nbsp;</span> </div> <div class="boxStatsList" style="margin-top: 9px;"> <!--<div id="{{=it.stats.pools[pool].name}}NewBlocks"></div>--> {{ for(var b in it.stats.pools[pool].pending.blocks) { }} {{ var block = it.stats.pools[pool].pending.blocks[b].split(":"); }} <div style="margin-bottom: 9px; background-color: #eeeeee; min-width:600px;"><i class="fa fa-bars"></i> <small>Block:</small> {{if (String(it.stats.pools[pool].name).startsWith("zcash")) { }} <a href="https://explorer.zcha.in/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a> {{ } else if (String(it.stats.pools[pool].name).startsWith("zclassic")) { }} <a href="https://classic.zcha.in/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a> {{ } else if (String(it.stats.pools[pool].name).startsWith("hush")) { }} <a href="https://explorer.myhush.org/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a> {{ } else { }} {{=block[2]}} {{ } }} {{if (block[4] != null) { }} <span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span> {{ } }} {{if (it.stats.pools[pool].pending.confirms) { }} {{if (it.stats.pools[pool].pending.confirms[block[0]]) { }} <span style="float:right; color: red;"><small>{{=it.stats.pools[pool].pending.confirms[block[0]]}} of 100</small></span> {{ } else { }} <span style="float:right; color: red;"><small>*PENDING*</small></span> {{ } }} {{ } else { }} <span style="float:right; color: red;"><small>*PENDING*</small></span> {{ } }} <div><i class="fa fa-gavel"></i><small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3]}}</a></div> </div> {{ blockscomb.push(block);}} {{ } }} {{ var i=0; for(var b in it.stats.pools[pool].confirmed.blocks) { }} {{ if (i < 8) { i++; }} {{ var block = it.stats.pools[pool].confirmed.blocks[b].split(":"); }} <div style="margin-bottom: 9px; background-color: #eeeeee; min-width:600px;"><i class="fa fa-bars"></i> <small>Block:</small> {{if (String(it.stats.pools[pool].name).startsWith("zcash")) { }} <a href="https://explorer.zcha.in/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a> {{ } else if (String(it.stats.pools[pool].name).startsWith("zclassic")) { }} <a href="https://classic.zcha.in/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a> {{ } else { }} {{=block[2]}} {{ } }} {{if (block[4] != null) { }} <span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span> {{ } }} <span style="float:right; padding-left: 18px; color: green;"><small>*PAID*</small></span> <div><i class="fa fa-gavel"></i><small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3]}}</a></div> </div> {{blockscomb.push(block);}} {{ } }} {{ } }} <!--{{=JSON.stringify(blockscomb)}}--> <script> var blockscomb = ({{=JSON.stringify(blockscomb)}}) </script> </div> </div> </div> </div> </div> <center><div id="bottomCharts{{=pool}}" style="text-align:center;" align="center"> <div class="chartWrapper" style="text-align:center;"> <div class="chartLabel">Finders of the last {{=blockscomb.length}} blocks</div> <div class="hidden" id="tooltip{{=pool}}"><p><span id="value{{=pool}}"></span> blocks found by <span id="finderr{{=pool}}"></span></p></div> <div class="chartHolder" id="pie{{=pool}}"><svg id="blocksPie{{=pool}}" style="display: block; margin: auto; text-align:center;"/></div> </div> </div></center> <script> var groupedByFinder = {}; var data = []; for (var i=0; i < blockscomb.length; i++) { finder=blockscomb[i][3]; // if other doesn 't already have a property for the current letter // create it and assign it to a new empty array if (!(finder in groupedByFinder)) groupedByFinder[finder] = []; groupedByFinder[finder].push(blockscomb[i]); } Object.keys(groupedByFinder).forEach(function(i) { var obj = {}; obj.label = i obj.value = groupedByFinder[i].length data.push(obj) }); console.log(JSON.stringify(data)) var w = 400; var h = 400; var r = h/2; var legendRectSize = 18; var legendSpacing = 5; var color = d3.scale.category20c(); var div = d3.select("#pie{{=pool}}").append("div") .attr("class", "tooltip") .style("opacity", 0); var vis = d3.select('#blocksPie{{=pool}}') .data([data]) .attr("width", 1000) .attr("height", h) .attr("style", "display: block; margin: auto;") .attr("preserveAspectRatio", "xMidYMin") .append("svg:g") .attr("transform", "translate(" + r + "," + r + ")"); var pie = d3.layout.pie().value(function(d){return d.value;}); // declare an arc generator function var arc = d3.svg.arc().outerRadius(r); // select paths, use arc generator to draw var arcs = vis.selectAll("g.slice{{=pool}}") .data(pie) .enter() .append("svg:g") .attr("class", "slice{{=pool}}") .attr("id", "slice") .on("mouseover", function(d){ d3.select("#tooltip{{=pool}}") .style("left", d3.event.pageX + "px") .style("top", d3.event.pageY + "px") .style("opacity", 1) .select("#value{{=pool}}") .text(d.data.value); d3.select("#tooltip{{=pool}}") .select("#finderr{{=pool}}") .text(d.data.label); }); arcs.append("svg:path") .attr("fill", function(d, i){ return color(i); }) .attr("d", function (d) { return arc(d); }); var legend = vis.selectAll('.legend') .data(color.domain()) .enter() .append('g') .attr('class', 'legend') .attr('id', {{=JSON.stringify(pool)}}) .attr('transform', function(d, i) { var height = legendRectSize + legendSpacing; var offset = height * color.domain().length / 2; var horz = 12 * legendRectSize; var vert = i * height; return 'translate(' + horz + ',' + vert + ')'; }); legend.append('rect') .attr('width', legendRectSize) .attr('height', legendRectSize) .style('fill', color) .style('stroke', color); legend.append('text') .attr('x', legendRectSize + legendSpacing) .attr('y', legendRectSize - legendSpacing) .text(function(d, i) { return data[i].label; }); </script> {{ } }} <script> document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js'; </script> <script> window.statsSource = new EventSource("/api/live_stats"); $(function() { statsSource.addEventListener('message', function (e) { var stats = JSON.parse(e.data); for (var pool in stats.pools) { $('#statsMiners' + pool).text(stats.pools[pool].minerCount); $('#statsWorkers' + pool).text(stats.pools[pool].workerCount); $('#statsHashrate' + pool).text(stats.pools[pool].hashrateString); $('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool))); $('#statsLuckDays' + pool).text(stats.pools[pool].luckDays); $('#statsValidBlocks' + pool).text(stats.pools[pool].poolStats.validBlocks); $('#statsTotalPaid' + pool).text((parseFloat(stats.pools[pool].poolStats.totalPaid)).toFixed(8)); $('#statsNetworkBlocks' + pool).text(stats.pools[pool].poolStats.networkBlocks); $('#statsNetworkDiff' + pool).text(stats.pools[pool].poolStats.networkDiff); $('#statsNetworkSols' + pool).text(getReadableNetworkHashRateString(stats.pools[pool].poolStats.networkSols)); $('#statsNetworkConnections' + pool).text(stats.pools[pool].poolStats.networkConnections); } }); }); function getReadableNetworkHashRateString(hashrate){ hashrate = (hashrate * 1000000); if (hashrate < 1000000) return '0 Sol'; var byteUnits = [ ' Sol/s', ' KSol/s', ' MSol/s', ' GSol/s', ' TSol/s', ' PSol/s' ]; var i = Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1); hashrate = (hashrate/1000) / Math.pow(1000, i + 1); return hashrate.toFixed(2) + byteUnits[i]; } </script>