185 |
206 |
207 |
208 |
209 |
210 |
211 |
What Our Pools Feature
212 |
213 |
214 |
215 |
216 |
They're Fast
217 |
Speed is key when it comes to mining. So we chose hardware that can provide just that! Giving our users the best connection possible!
218 |
219 |
220 |
221 |
222 |
They're Protected
223 |
Don't like downtime? Neither do we! So we take measures to protect our site from any malicious attacks that could disrupt mining!
224 |
225 |
226 |
227 |
228 |
They Have Low Fees
229 |
We're not here to make profit. So we keep our fees low! Why have any at all you may ask? We gotta pay bills for the website somehow.
230 |
231 |
232 |
233 |
234 |
It's All Easy To Use
235 |
No matter your experience, you can mine using our pool! We make make mining easy! Head over to Getting Started to learn more!
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
Current Global Stats
247 |
248 |
249 |
250 |
251 |
Total Miners
252 | {{ var count = 0; }}
253 | {{ for(var pool in it.stats.pools) { }}
254 | {{ count += it.stats.pools[pool].workerCount; }}
255 | {{ } }}
256 |
{{=count}}
257 |
258 |
259 |
260 |
261 |
Total Hashrate
262 | {{ var hashrate = 0; }}
263 | {{ for(var pool in it.stats.pools) { }}
264 | {{ hashrate += it.stats.pools[pool].hashrate; }}
265 | {{ } }}
266 | {{ var byteUnits = [' KH/s', ' MH/s', ' GH/s', ' TH/s', ' PH/s']; }}
267 | {{ var i = -1; }}
268 | {{ do { }}
269 | {{ hashrate = hashrate / 1024; }}
270 | {{ i++; }}
271 | {{ } while (hashrate > 1024); }}
272 |
{{=Math.round(hashrate) + byteUnits[i]}}
273 |
274 |
275 |
276 |
277 |
Algorithms Supported
278 |
{{=Object.keys(it.stats.algos).length}}
279 |
280 |
281 |
282 |
283 |
Pools Hosted
284 |
{{=Object.keys(it.stats.pools).length}}
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
307 |
--------------------------------------------------------------------------------
/website/pages/learn_more.html:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
32 |
Cryptocurrency Mining
33 |
You may have heard about Cryptocurrency or Bitcoin mining on the news, through a friend, or even just on a random search. No matter how you heard about it, you may be asking yourself what exactly is it? Is it something that I could start
34 | doing at home? Is it even worth my time? This page will give you a better understanding of what cryptocurrency mining is, and even show you how to get started!
35 |
36 |
37 |
38 |
39 |
So, What Is It?
40 |
41 | "Cryptocurrency mining is the process by which transactions are verified and added to the public ledger, known as the block chain, and the means through which new coins are released. Anyone with access to the internet
42 | and suitable hardware can participate in mining. The mining process involves compiling recent transactions into blocks and trying to solve a computationally difficult puzzle. The participant who first solves the
43 | puzzle gets to place the next block on the block chain and claim the rewards. The rewards, which incentivize mining, are both the transaction fees associated with the transactions compiled in the block as well as
44 | newly released coins."
45 |
46 |
47 |
48 |
49 |
50 |
51 |
Can I Mine with My Computer?
52 |
Anyone can mine; the only limiting factor being the hardware which you wish to mine from. If you have a GPU (Graphics Processing Unit) or a compatable CPU (Central Processing Unit), and mining software which supports your GPU/CPU as well as the algorithm of the coin you are trying to mine then
53 | you should have no issues! Don't know what mining software or algorithms are? Don't worry, we will cover that shortly!
54 |
55 |
56 |
57 |
58 |
What Is Mining Software?
59 |
Mining software, are applications, usually command line, that allows users to connect to the block chain or pool, receive work, and use hardware to solve work given. There are two very popular choices when it comes to software, CCMiner
60 | for Nvidia GPU's , SGMiner for AMD GPU's , CPU-OPT Miner for CPU's . A quick search online will give you more information about these programs, though look carefully, there could be malicious content; for safety we recommend find the source code for the
61 | project before downloading.
62 |
63 |
64 |
65 |
66 |
What Is an Algorithm?
67 |
An algorithm is defined as "a process or set of rules to be followed in calculations or other problem-solving operations, especially by a computer" . Cryptocurrencies miners use cryptographic algorithms such as SHA-2, Scrypt,
68 | and Equihash to generate hashes for the block chain. Each algorithm has positive and negatives for each given hardware setup, so researching your hardware prior to chosing a coin to mine, can make your venture much more profitable.
69 |
70 |
71 |
72 |
73 |
How Do I Start?
74 |
75 | Well firstly, you need to pick a mining software which is compatable with your system. While I will not be providing links to any mining software, if you refer back to popular choices I mentioned above, a quick online search will
76 | show you the software needed.
77 | Pick a coin you wish to mine. Remember each coin has an algorithm which needs to be accounted for, as you will need to verify that your mining software supports it. There is a README file usually included with most mining software,
78 | and inside you can see each supported algorithm, as well as other useful options.
79 | After you decided which coin, you need to get a wallet. Each coin provides it's own wallet software which you can download from the coin's website or project repository. Download the wallet, open it, let it sync (this could take
80 | a while), once it's syncs, find your wallet address and hold it for the next step.
81 | Inside of the folder of your mining software application, create a .bat or .cmd file. Edit the file and use our configuration generator on the Getting Started page to generate a personalized configuration, copy and paste the results
82 | into your file. Save it, and you should now be able to double click the file to start the miner. Good luck mining!
83 |
84 |
85 |
86 |
87 |
88 |
Having Trouble?
89 |
Don't worry! Join our Discord channel for more assistance!
90 |
91 |
92 |
93 |
96 |
--------------------------------------------------------------------------------
/website/pages/miner_stats.html:
--------------------------------------------------------------------------------
1 |
70 |
71 |
72 |
73 |
Account Details
74 |
75 |
78 |
92 |
93 |
94 |
Worker Hashrate HistoryColors are random! If you don't like the ones given, simply refresh the page!
95 |
96 |
97 |
98 |
101 |
102 |
103 |
114 |
--------------------------------------------------------------------------------
/website/pages/mining_key.html:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 | This script run client-side (in your browser). For maximum security download the script and run it locally and
18 | offline in a modern web browser.
19 |
20 |
21 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/website/pages/pool_stats.html:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | General Information
21 | Pool Information
22 | Network Information
23 |
24 |
25 |
26 | {{ for(var pool in it.stats.pools) { }}
27 | {{ if(pool !== it.stats.coin) continue; }}
28 |
29 | Coin:
30 |
31 | Port:
32 | {{ for(var pool in it.poolsConfigs) { }}
33 | {{ if(pool !== it.stats.coin) continue; }}
34 | {{=Object.keys(it.poolsConfigs[pool].ports)}}
35 | {{ break; }}
36 | {{ } }}
37 | Hashrate:
38 | {{=it.stats.pools[pool].hashrateString}}
39 | Pending:
40 | {{=it.stats.pools[pool].blocks.pending}}
41 | Connections:
42 | {{=it.stats.pools[pool].poolStats.networkConnections}}
43 | Difficulty:
44 | {{=Number(Math.round(it.stats.pools[pool].poolStats.networkDiff + 'e' + 4) + 'e-' + 4)}}
45 |
46 |
47 | Name:
48 | {{=(String(it.stats.coin).charAt(0).toUpperCase() + String(it.stats.coin).slice(1))}}
49 | Workers:
50 | {{=it.stats.pools[pool].workerCount}}
51 | Valid Shares:
52 | {{=it.stats.pools[pool].poolStats.validShares}}
53 | Confirmed:
54 | {{=it.stats.pools[pool].blocks.confirmed}}
55 | Hashrate:
56 | {{=it.stats.pools[pool].poolStats.networkSolsString}}
57 | Height:
58 | {{=it.stats.pools[pool].poolStats.networkBlocks}}
59 |
60 | {{ break; }}
61 | {{ } }}
62 |
63 |
64 |
65 |
66 |
67 |
68 |
Hashrate History
69 |
70 |
71 |
72 |
73 |
74 |
Worker History
75 |
76 |
77 |
78 |
79 |
80 |
Pending Block History
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
98 |
--------------------------------------------------------------------------------
/website/pages/pools.html:
--------------------------------------------------------------------------------
1 |
2 |
Quick Start Commands (GPU Algorithms):
3 |
4 | ccminer -a <ALGORITHM> -o stratum+tcp://us1.cryptosharkspool.com:<PORT> -u <WALLET.OPTIONAL_WORKER> -p <ANYTHING>
5 |
6 |
7 | sgminer -k <ALGORITHM> -o stratum+tcp://us1.cryptosharkspool.com:<PORT> -u <WALLET.OPTIONAL_WORKER> -p <ANYTHING>
8 |
9 |
Doesn't make sense? Head over to Getting Started for more help!
10 |
11 |
12 |
13 |
14 |
15 | Port
16 | Symbol
17 | Coin
18 | Algorithm
19 | Workers
20 | Hash Rate
21 | Fee
22 |
23 |
24 |
25 | {{ for(var pool in it.stats.pools) { }}
26 | {{=Object.keys(it.poolsConfigs[pool].ports)[0]}}
27 | {{=it.stats.pools[pool].symbol}}
28 | {{=it.stats.pools[pool].name.charAt(0).toUpperCase() + it.stats.pools[pool].name.slice(1)}}
29 | {{=it.stats.pools[pool].algorithm}}
30 | {{=it.stats.pools[pool].workerCount}}
31 | {{=it.stats.pools[pool].hashrateString}}
32 | {{ var total = 0.0; }}
33 | {{ var rewardRecipients = it.stats.pools[pool].rewardRecipients || {}; }}
34 | {{ for (var r in rewardRecipients) { }}
35 | {{ total += rewardRecipients[r]; }}
36 | {{ } }}
37 | {{=total}}%
38 |
39 | {{ } }}
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/website/pages/stats.html:
--------------------------------------------------------------------------------
1 |
30 |
31 |
32 |
33 |
34 |
Top 5 Pool Workers
35 |
36 |
37 |
38 |
39 |
Top 5 Pool Hashrates (MH/s)
40 |
41 |
42 |
43 |
44 |
45 |
Top 5 Blocks Pending Per Pool
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
56 |
--------------------------------------------------------------------------------
/website/pages/tbs.html:
--------------------------------------------------------------------------------
1 |
34 |
35 |
36 |
37 |
38 | Pool
39 | Algo
40 | Workers
41 | Valid Shares
42 | Invalid Shares
43 | Total Blocks
44 | Pending
45 | Confirmed
46 | Orphaned
47 | Hashrate
48 |
49 |
50 | {{ for(var pool in it.stats.pools) { }}
51 |
52 | {{=it.stats.pools[pool].name}}
53 | {{=it.stats.pools[pool].algorithm}}
54 | {{=Object.keys(it.stats.pools[pool].workers).length}}
55 | {{=it.stats.pools[pool].poolStats.validShares}}
56 | {{=it.stats.pools[pool].poolStats.invalidShares}}
57 | {{=it.stats.pools[pool].poolStats.validBlocks}}
58 | {{=it.stats.pools[pool].blocks.pending}}
59 | {{=it.stats.pools[pool].blocks.confirmed}}
60 | {{=it.stats.pools[pool].blocks.orphaned}}
61 | {{=it.stats.pools[pool].hashrateString}}
62 |
63 | {{ } }}
64 |
65 |
--------------------------------------------------------------------------------
/website/static/admin.js:
--------------------------------------------------------------------------------
1 | var docCookies = {
2 | getItem: function (sKey) {
3 | return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
4 | },
5 | setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
6 | if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; }
7 | var sExpires = "";
8 | if (vEnd) {
9 | switch (vEnd.constructor) {
10 | case Number:
11 | sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
12 | break;
13 | case String:
14 | sExpires = "; expires=" + vEnd;
15 | break;
16 | case Date:
17 | sExpires = "; expires=" + vEnd.toUTCString();
18 | break;
19 | }
20 | }
21 | document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
22 | return true;
23 | },
24 | removeItem: function (sKey, sPath, sDomain) {
25 | if (!sKey || !this.hasItem(sKey)) { return false; }
26 | document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : "");
27 | return true;
28 | },
29 | hasItem: function (sKey) {
30 | return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
31 | }
32 | };
33 |
34 | var password = docCookies.getItem('password');
35 |
36 |
37 | function showLogin(){
38 | $('#adminCenter').hide();
39 | $('#passwordForm').show();
40 | }
41 |
42 | function showAdminCenter(){
43 | $('#passwordForm').hide();
44 | $('#adminCenter').show();
45 | }
46 |
47 | function tryLogin(){
48 | apiRequest('pools', {}, function(response){
49 | showAdminCenter();
50 | displayMenu(response.result)
51 | });
52 | }
53 |
54 | function displayMenu(pools){
55 | $('#poolList').after(Object.keys(pools).map(function(poolName){
56 | return '';
57 | }).join(''));
58 | }
59 |
60 | function apiRequest(func, data, callback){
61 | var httpRequest = new XMLHttpRequest();
62 | httpRequest.onreadystatechange = function(){
63 | if (httpRequest.readyState === 4 && httpRequest.responseText){
64 | if (httpRequest.status === 401){
65 | docCookies.removeItem('password');
66 | $('#password').val('');
67 | showLogin();
68 | alert('Incorrect Password');
69 | }
70 | else{
71 | var response = JSON.parse(httpRequest.responseText);
72 | callback(response);
73 | }
74 | }
75 | };
76 | httpRequest.open('POST', '/api/admin/' + func);
77 | data.password = password;
78 | httpRequest.setRequestHeader('Content-Type', 'application/json');
79 | httpRequest.send(JSON.stringify(data));
80 | }
81 |
82 | if (password){
83 | tryLogin();
84 | }
85 | else{
86 | showLogin();
87 | }
88 |
89 | $('#passwordForm').submit(function(event){
90 | event.preventDefault();
91 | password = $('#password').val();
92 | if (password){
93 | if ($('#remember').is(':checked'))
94 | docCookies.setItem('password', password, Infinity);
95 | else
96 | docCookies.setItem('password', password);
97 | tryLogin();
98 | }
99 | return false;
100 | });
101 |
--------------------------------------------------------------------------------
/website/static/dashboard.js:
--------------------------------------------------------------------------------
1 | var statData;
2 | var poolKeys;
3 |
4 | //this function is executed when the page's dom is loaded
5 | // assumes jQuery is loaded already
6 | $(function(){
7 | var dataTable = $("#walletTable").DataTable({
8 | "order": [[ 0, "desc" ]],
9 | "pageLength": 5,
10 | "bLengthChange": false,
11 | "iDisplayLength": 5
12 | });
13 | var cachedWallets = Cookies.get('wallets');
14 | if(cachedWallets && cachedWallets.length > 0){
15 | cachedWallets = JSON.parse(cachedWallets);
16 | for(w in cachedWallets) {
17 | var wallet = cachedWallets[w].split(',');
18 | var coin = wallet[0];
19 | var address = wallet[1];
20 | dataTable.row.add([
21 | "
" + address + "",
22 | "
Delete "
23 | ]).draw(false);
24 | $('#' + address).click(function(event) {
25 | if(confirm("Are you sure you want to delete address: " + address)){
26 | cachedWallets.splice(w, 1);
27 | Cookies.remove('wallets');
28 | Cookies.set('wallets', cachedWallets, { expires: 30 });
29 | location.reload();
30 | }
31 | });
32 | }
33 | }
34 | //binds the myFormOnSubmit method below to run as part of your form's onsubmit method
35 | $('#searchButton').click(myFormOnSubmit);
36 |
37 | //runs when the form is trying to submit
38 | function myFormOnSubmit(event) {
39 | var f = $(this);
40 | // note, you have to match on attribute selectors
41 | // you may want to give each of these fields an id=".." attribute as well to select against #IdName
42 | var search = $('#searchBar').val();
43 | var isValid = false;
44 |
45 | var coin = "";
46 | var wallets = Cookies.get('wallets');
47 | var stored = false;
48 | if(wallets) {
49 | wallets = JSON.parse(wallets);
50 | for(w in wallets) {
51 | if(wallets[w].split(',')[1] === search) {
52 | stored = true;
53 | break;
54 | }
55 | }
56 | }
57 | if(stored){
58 | alert('Address Already Stored!');
59 | event.preventDefault(); //stop submit
60 | return;
61 | }
62 | if(!wallets){
63 | wallets = [];
64 | }
65 | $.each(statData.pools, function(i, v) {
66 | if(!isValid){
67 | for(worker in v.workers){
68 | worker = worker.split('.')[0];
69 | if(worker === search){
70 | isValid = true;
71 | wallets.push(String(i + ',' + worker));
72 | break;
73 | }
74 | }
75 | }
76 | });
77 | if (!isValid) {
78 | alert('No Address Found!');
79 | event.preventDefault(); //stop submit
80 | return;
81 | } else {
82 | Cookies.remove('wallets');
83 | Cookies.set('wallets', wallets, { expires: 30 });
84 | }
85 | }
86 | });
87 |
88 |
89 |
90 | $.getJSON('/api/stats', function(data) {
91 | statData = data;
92 | });
93 |
--------------------------------------------------------------------------------
/website/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/favicon.png
--------------------------------------------------------------------------------
/website/static/icons/aced.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/aced.png
--------------------------------------------------------------------------------
/website/static/icons/dixicoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/dixicoin.png
--------------------------------------------------------------------------------
/website/static/icons/methuselah.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/methuselah.png
--------------------------------------------------------------------------------
/website/static/icons/qbiccoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/qbiccoin.png
--------------------------------------------------------------------------------
/website/static/icons/qudex.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/qudex.png
--------------------------------------------------------------------------------
/website/static/icons/ravencoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/ravencoin.png
--------------------------------------------------------------------------------
/website/static/icons/scribe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/scribe.png
--------------------------------------------------------------------------------
/website/static/icons/wavicoin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/icons/wavicoin.png
--------------------------------------------------------------------------------
/website/static/img/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/img/favicon.png
--------------------------------------------------------------------------------
/website/static/img/my-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/img/my-banner.png
--------------------------------------------------------------------------------
/website/static/img/noto-hash-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cryptosharks131/NiceNOMP/15fde8b7a3acc2088248aa2ad2f62c9500286155/website/static/img/noto-hash-banner.png
--------------------------------------------------------------------------------
/website/static/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/website/static/main.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 |
3 | var hotSwap = function(page, pushSate){
4 | if (pushSate) history.pushState(null, null, '/' + page);
5 | $('.pure-menu-selected').removeClass('pure-menu-selected');
6 | $('a[href="/' + page + '"]').parent().addClass('pure-menu-selected');
7 | $.get("/get_page", {id: page}, function(data){
8 | $('main').html(data);
9 | }, 'html')
10 | };
11 |
12 | $('.hot-swapper').click(function(event){
13 | if (event.which !== 1) return;
14 | var pageId = $(this).attr('href').slice(1);
15 | hotSwap(pageId, true);
16 | event.preventDefault();
17 | return false;
18 | });
19 |
20 | window.addEventListener('load', function() {
21 | setTimeout(function() {
22 | window.addEventListener("popstate", function(e) {
23 | hotSwap(location.pathname.slice(1));
24 | });
25 | }, 0);
26 | });
27 |
28 | window.statsSource = new EventSource("/api/live_stats");
29 |
30 | });
31 |
--------------------------------------------------------------------------------
/website/static/methods.js:
--------------------------------------------------------------------------------
1 | function calculateExpMovingAvg(mArray, mRange) {
2 | var k = 2/ (mRange + 1);
3 | // first item is just the same as the first item in the input
4 | emaArray = [[mArray[0][0], mArray[0][1]]];
5 | // for the rest of the items, they are computed with the previous one
6 | for (var i = 1; i < mArray.length; i++) {
7 | var height = mArray[i][1] * k + emaArray[i - 1][1] * (1 - k);
8 | emaArray.push([mArray[i][0], height]);
9 | }
10 | return emaArray;
11 | }
12 |
13 | function capFirst(s) {
14 | return s.charAt(0).toUpperCase() + s.slice(1);
15 | }
16 |
17 | function getRandomInt(min, max) {
18 | return Math.floor(Math.random() * (max - min)) + min;
19 | }
20 |
21 | function generateName(){
22 | var name1 = ['raging', 'mad', 'hashing', 'cool', 'rich', 'honorable', 'king',
23 | 'fast', 'killer', 'sweet'];
24 |
25 | var name2 = ['cromulon', 'computer', 'hasher', 'PC', 'rig', 'miner', 'otter',
26 | 'cronenberg', 'gazorpazorp'];
27 |
28 | var name = name1[Math.floor(Math.random() * name1.length)].toLowerCase() + name2[Math.floor(Math.random() * name2.length)].toLowerCase();
29 | return name;
30 |
31 | }
32 |
33 | function getRandomColor() {
34 | var letters = '0123456789ABCDEF'.split('');
35 | var color = '#';
36 | for (var i = 0; i < 6; i++ ) {
37 | color += letters[Math.floor(Math.random() * 16)];
38 | }
39 | return color;
40 | }
41 |
42 | function getRandomPastelColor() {
43 | var r = (Math.round(Math.random() * 127) + 127).toString(16);
44 | var g = (Math.round(Math.random() * 127) + 127).toString(16);
45 | var b = (Math.round(Math.random() * 127) + 127).toString(16);
46 | return '#' + r + g + b;
47 | }
48 |
49 | function addChartData(chart, dataset, data, update) {
50 | dataset.data.shift();
51 | dataset.data.push(data);
52 | if(update){
53 | chart.update();
54 | }
55 | }
56 |
57 | this.getReadableHashRate = function(hashrate) {
58 | hashrate = (hashrate * 1000000);
59 | if(hashrate < 1000000){
60 | hashrate = hashrate * 100000;
61 | }
62 | var i = Math.max(0, Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1));
63 | hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
64 | return hashrate.toFixed(2);
65 | };
66 |
67 | this.getScaledHashrate = function(hashrate, i) {
68 | hashrate = (hashrate * 1000000);
69 | if(hashrate < 1000000){
70 | hashrate = hashrate * 100000;
71 | }
72 | hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
73 | return hashrate.toFixed(2);
74 | };
75 |
76 | this.getReadableHashRateString = function(hashrate) {
77 | hashrate = (hashrate * 1000000);
78 | if(hashrate < 1000000){
79 | hashrate = hashrate * 100000;
80 | }
81 | var byteUnits = [' H/s', ' KH/s', ' MH/s', ' GH/s', ' TH/s', ' PH/s'];
82 | var i = Math.max(0, Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1));
83 | hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
84 |
85 | return hashrate.toFixed(2) + ' ' + byteUnits[i];
86 | };
87 |
88 | this.getReadableHashRatePair = function(hashrate) {
89 | hashrate = (hashrate * 1000000);
90 | if(hashrate < 1000000){
91 | hashrate = hashrate * 100000;
92 | }
93 | var byteUnits = [' H/s', ' KH/s', ' MH/s', ' GH/s', ' TH/s', ' PH/s'];
94 | var i = Math.max(0, Math.floor((Math.log(hashrate/1000) / Math.log(1000)) - 1));
95 | hashrate = (hashrate/1000) / Math.pow(1000, i + 1);
96 |
97 | return [hashrate.toFixed(2), byteUnits[i], i];
98 | };
99 |
100 | function createDefaultLineChart(ctx, datasets, xLabel, yLabel) {
101 | return createLineChart(ctx, datasets, xLabel, yLabel, { beginAtZero: true });
102 | }
103 |
104 | function createLineChart(ctx, datasets, xLabel, yLabel, ticks) {
105 | return new Chart(ctx, {
106 | type: 'line',
107 | data: {
108 | datasets: datasets
109 | },
110 | options: {
111 | spanGaps: true,
112 | animation: {
113 | easing: 'easeInExpo',
114 | duration: 1000,
115 | xAxis: true,
116 | yAxis: true,
117 | },
118 | responsive: true,
119 | maintainAspectRatio: false,
120 | elements: {
121 | point: { radius: 0 }
122 | },
123 | scales: {
124 | xAxes: [{
125 | type: 'time'
126 | }],
127 | yAxes: [{
128 | ticks: ticks,
129 | display: true,
130 | scaleLabel: {
131 | display: true,
132 | labelString: yLabel
133 | }
134 | }]
135 | }
136 | }
137 | });
138 | }
139 |
--------------------------------------------------------------------------------
/website/static/miner_stats.js:
--------------------------------------------------------------------------------
1 | var workerHashrateData;
2 | var workerHashrateChart;
3 | var workerHistoryMax = 160;
4 |
5 | var statData;
6 | var totalHash;
7 | var totalImmature;
8 | var totalBal;
9 | var totalPaid;
10 | var totalShares;
11 | var alerted = false;
12 | var shareGage;
13 | var invalidGage;
14 | var workerGage;
15 | var hashGage;
16 |
17 | function getWorkerNameFromAddress(w) {
18 | var worker = w;
19 | if (w.split(".").length > 1) {
20 | worker = w.split(".")[1];
21 | if (worker == null || worker.length < 1) {
22 | worker = "noname";
23 | }
24 | } else {
25 | worker = "noname";
26 | }
27 | return worker;
28 | }
29 |
30 | function displayCharts() {
31 | var stats = getWorkerStats(_miner);
32 | shareGage = new JustGage({
33 | id: "gauge",
34 | value: stats.currRoundShares > 0 ? Math.floor((stats.currRoundShares / stats.currRoundPoolShares) * 100) : 0,
35 | min: 0,
36 | max: 100,
37 | symbol: '%',
38 | pointer: true,
39 | pointerOptions: {
40 | toplength: -15,
41 | bottomlength: 10,
42 | bottomwidth: 12,
43 | color: '#8e8e93',
44 | stroke: '#ffffff',
45 | stroke_width: 3,
46 | stroke_linecap: 'round'
47 | },
48 | title: "Shares This Round",
49 | gaugeWidthScale: 0.6,
50 | levelColors:["#e8e84c", "#6cdb5e"]
51 | });
52 | invalidGage = new JustGage({
53 | id: "validShare",
54 | value: Math.min(stats.invalidShares, 100),
55 | min: 0,
56 | max: 100,
57 | symbol: '%',
58 | pointer: true,
59 | pointerOptions: {
60 | toplength: -15,
61 | bottomlength: 10,
62 | bottomwidth: 12,
63 | color: '#8e8e93',
64 | stroke: '#ffffff',
65 | stroke_width: 3,
66 | stroke_linecap: 'round'
67 | },
68 | title: "Recent Invalid Shares",
69 | gaugeWidthScale: 0.6,
70 | levelColors:["#e8e84c", "#f73d3d"]
71 | });
72 | workerGage= new JustGage({
73 | id: "workerDominance",
74 | value: stats.miners ? (Object.keys(stats.miners).length / stats.poolSize) * 100 : 0,
75 | min: 0,
76 | max: 100,
77 | symbol: '%',
78 | pointer: true,
79 | pointerOptions: {
80 | toplength: -15,
81 | bottomlength: 10,
82 | bottomwidth: 12,
83 | color: '#8e8e93',
84 | stroke: '#ffffff',
85 | stroke_width: 3,
86 | stroke_linecap: 'round'
87 | },
88 | title: "Worker Dominance",
89 | gaugeWidthScale: 0.6,
90 | levelColors:["#e8e84c", "#6cdb5e"]
91 | });
92 | var high = 0;
93 | console.log(stats.hashrate);
94 | hashGage = new JustGage({
95 | id: "hashDominance",
96 | value: stats.hashrate > 0 ? (stats.hashrate / stats.poolHashrate) * 100 : 0,
97 | min: 0,
98 | max: 100,
99 | symbol: '%',
100 | title: "Hashrate Dominance",
101 | levelColors:["#e8e84c", "#6cdb5e"],
102 | pointer: true,
103 | pointerOptions: {
104 | toplength: -15,
105 | bottomlength: 10,
106 | bottomwidth: 12,
107 | color: '#8e8e93',
108 | stroke: '#ffffff',
109 | stroke_width: 3,
110 | stroke_linecap: 'round'
111 | },
112 | gaugeWidthScale: 0.6
113 | });
114 | var maxScale = 0;
115 | var label = 'H/s';
116 | for (var w in stats.miners) {
117 | var pair = getReadableHashRatePair(Math.max.apply(null, stats.miners[w].hashrate.map(x => x[1])));
118 | var i = pair[2];
119 | if (maxScale < i) {
120 | maxScale = i;
121 | label = pair[1];
122 | }
123 | }
124 | var dataset = [];
125 | for (var d in stats.miners) {
126 | var data = stats.miners[d];
127 | var color = getRandomPastelColor();
128 | var o = {
129 | label: data.key,
130 | fill: false,
131 | data: data.hashrate.map(x => {
132 | return {
133 | t: x[0],
134 | y: getScaledHashrate(x[1], i)
135 | }
136 | }),
137 | borderWidth: 2,
138 | backgroundColor: color,
139 | borderColor: color
140 | };
141 | dataset.push(o);
142 | }
143 |
144 | workerHashrateChart = createDefaultLineChart(
145 | document.getElementById("workerHashChart").getContext('2d'),
146 | dataset,
147 | 'Time',
148 | label
149 | );
150 | }
151 |
152 | function updateStats() {
153 | var stats = getWorkerStats(_miner);
154 | totalHash = stats.hashrate;
155 | totalPaid = stats.paid;
156 | totalBal = stats.balance;
157 | totalImmature = stats.immature;
158 | totalShares = stats.totalShares;
159 | // update miner stats
160 | $("#statsHashrate").text(getReadableHashRateString(totalHash));
161 | $("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageHashrate(null)));
162 | $("#statsTotalImmature").text(totalImmature);
163 | $("#statsTotalBal").text(totalBal);
164 | $("#statsTotalPaid").text(totalPaid);
165 | }
166 |
167 | function updateWorkerStats() {
168 | var stats = getWorkerStats(_miner);
169 | // update worker stats
170 | var i = 0;
171 | for (var w in stats.miners) {
172 | i++;
173 | var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
174 | var saneWorkerName = getWorkerNameFromAddress(w);
175 | console.log(stats.miners[w]);
176 | $("#statsHashrate" + htmlSafeWorkerName).text(getReadableHashRateString(stats.miners[w].hashrate[stats.miners[w].hashrate.length - 1] || 0));
177 | $("#statsHashrateAvg" + htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageHashrate(saneWorkerName)));
178 | }
179 | }
180 |
181 | function addWorkerToDisplay(name, htmlSafeName, workerObj) {
182 | var htmlToAdd = "";
183 | htmlToAdd = '
';
184 | htmlToAdd += '
';
185 | htmlToAdd += '
' + getReadableHashRateString(workerObj.hashrate[workerObj.hashrate.length - 1][1] || 0) + ' (Now)
';
186 | htmlToAdd += '
' + getReadableHashRateString(calculateAverageHashrate(name)) + ' (Avg)
';
187 | htmlToAdd += '
';
188 | $("#boxesWorkers").html($("#boxesWorkers").html() + htmlToAdd);
189 | }
190 |
191 | function calculateAverageHashrate(worker) {
192 | var stats = getWorkerStats(_miner);
193 | var count = 0;
194 | var total = 1;
195 | var avg = 0;
196 | for (w in stats.miners) {
197 | count = 0;
198 | for (var ii = 0; ii < stats.miners[w].hashrate.length; ii++) {
199 | if (worker == null || stats.miners[w].key === worker) {
200 | count++;
201 | avg += parseFloat(stats.miners[w].hashrate[ii][1]);
202 | }
203 | }
204 | if (count > total)
205 | total = count;
206 | }
207 | avg = avg / total;
208 | return avg;
209 | }
210 |
211 |
212 | function rebuildWorkerDisplay() {
213 | var stats = getWorkerStats(_miner);
214 | $("#boxesWorkers").html("");
215 | var i = 0;
216 | for (var w in stats.miners) {
217 | i++;
218 | var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, '');
219 | var saneWorkerName = getWorkerNameFromAddress(w);
220 | addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, stats.miners[w]);
221 | }
222 | }
223 |
224 |
225 | // grab initial stats
226 | $.getJSON('/api/worker_stats?' + _miner, function(data) {
227 | if (document.hidden) return;
228 | $.getJSON('/api/pool_stats', function(statData) {
229 | addWorkerToTracker(statData, data, _miner, function(){
230 | var stats = getWorkerStats(_miner);
231 | statData = data;
232 | for (var w in statData.workers) {
233 | _workerCount++;
234 | }
235 | displayCharts();
236 | rebuildWorkerDisplay();
237 | updateStats();
238 |
239 | $('#total-paid-label').append(stats.paid.toFixed(8) + ' ' + stats.symbol);
240 | });
241 | });
242 | });
243 |
244 |
245 | // live stat updates
246 | statsSource.addEventListener('message', function(e) {
247 | var stats = JSON.parse(e.data);
248 | $.getJSON('/api/worker_stats?' + _miner, function(data) {
249 | //$('#total-paid-label').empty();
250 | //$('#total-paid-label').append(total.toFixed(8) + ' ' + symbol);
251 | });
252 | });
253 |
--------------------------------------------------------------------------------
/website/static/nvd3.css:
--------------------------------------------------------------------------------
1 | .chartWrap{margin:0;padding:0;overflow:hidden}.nvtooltip.with-3d-shadow,.with-3d-shadow .nvtooltip{-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nvtooltip{position:absolute;background-color:rgba(255,255,255,1);padding:1px;border:1px solid rgba(0,0,0,.2);z-index:10000;font-family:Arial;font-size:13px;text-align:left;pointer-events:none;white-space:nowrap;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.nvtooltip.with-transitions,.with-transitions .nvtooltip{transition:opacity 250ms linear;-moz-transition:opacity 250ms linear;-webkit-transition:opacity 250ms linear;transition-delay:250ms;-moz-transition-delay:250ms;-webkit-transition-delay:250ms}.nvtooltip.x-nvtooltip,.nvtooltip.y-nvtooltip{padding:8px}.nvtooltip h3{margin:0;padding:4px 14px;line-height:18px;font-weight:400;background-color:rgba(247,247,247,.75);text-align:center;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.nvtooltip p{margin:0;padding:5px 14px;text-align:center}.nvtooltip span{display:inline-block;margin:2px 0}.nvtooltip table{margin:6px;border-spacing:0}.nvtooltip table td{padding:2px 9px 2px 0;vertical-align:middle}.nvtooltip table td.key{font-weight:400}.nvtooltip table td.value{text-align:right;font-weight:700}.nvtooltip table tr.highlight td{padding:1px 9px 1px 0;border-bottom-style:solid;border-bottom-width:1px;border-top-style:solid;border-top-width:1px}.nvtooltip table td.legend-color-guide div{width:8px;height:8px;vertical-align:middle}.nvtooltip .footer{padding:3px;text-align:center}.nvtooltip-pending-removal{position:absolute;pointer-events:none}svg{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:block;width:100%;height:100%}svg text{font:400 12px Arial}svg .title{font:700 14px Arial}.nvd3 .nv-background{fill:#fff;fill-opacity:0}.nvd3.nv-noData{font-size:18px;font-weight:700}.nv-brush .extent{fill-opacity:.125;shape-rendering:crispEdges}.nvd3 .nv-legend .nv-series{cursor:pointer}.nvd3 .nv-legend .disabled circle{fill-opacity:0}.nvd3 .nv-axis{pointer-events:none}.nvd3 .nv-axis path{fill:none;stroke:#000;stroke-opacity:.75;shape-rendering:crispEdges}.nvd3 .nv-axis path.domain{stroke-opacity:.75}.nvd3 .nv-axis.nv-x path.domain{stroke-opacity:0}.nvd3 .nv-axis line{fill:none;stroke:#e5e5e5;shape-rendering:crispEdges}.nvd3 .nv-axis .zero line,.nvd3 .nv-axis line.zero{stroke-opacity:.75}.nvd3 .nv-axis .nv-axisMaxMin text{font-weight:700}.nvd3 .x .nv-axis .nv-axisMaxMin text,.nvd3 .x2 .nv-axis .nv-axisMaxMin text,.nvd3 .x3 .nv-axis .nv-axisMaxMin text{text-anchor:middle}.nv-brush .resize path{fill:#eee;stroke:#666}.nvd3 .nv-bars .negative rect{zfill:brown}.nvd3 .nv-bars rect{zfill:#4682b4;fill-opacity:.75;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-bars rect.hover{fill-opacity:1}.nvd3 .nv-bars .hover rect{fill:#add8e6}.nvd3 .nv-bars text{fill:rgba(0,0,0,0)}.nvd3 .nv-bars .hover text{fill:rgba(0,0,0,1)}.nvd3 .nv-multibar .nv-groups rect,.nvd3 .nv-multibarHorizontal .nv-groups rect,.nvd3 .nv-discretebar .nv-groups rect{stroke-opacity:0;transition:fill-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear}.nvd3 .nv-multibar .nv-groups rect:hover,.nvd3 .nv-multibarHorizontal .nv-groups rect:hover,.nvd3 .nv-discretebar .nv-groups rect:hover{fill-opacity:1}.nvd3 .nv-discretebar .nv-groups text,.nvd3 .nv-multibarHorizontal .nv-groups text{font-weight:700;fill:rgba(0,0,0,1);stroke:rgba(0,0,0,0)}.nvd3.nv-pie path{stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-pie .nv-slice text{stroke:#000;stroke-width:0}.nvd3.nv-pie path{stroke:#fff;stroke-width:1px;stroke-opacity:1}.nvd3.nv-pie .hover path{fill-opacity:.7}.nvd3.nv-pie .nv-label{pointer-events:none}.nvd3.nv-pie .nv-label rect{fill-opacity:0;stroke-opacity:0}.nvd3 .nv-groups path.nv-line{fill:none;stroke-width:1.5px}.nvd3 .nv-groups path.nv-line.nv-thin-line{stroke-width:1px}.nvd3 .nv-groups path.nv-area{stroke:none}.nvd3 .nv-line.hover path{stroke-width:6px}.nvd3.nv-line .nvd3.nv-scatter .nv-groups .nv-point{fill-opacity:0;stroke-opacity:0}.nvd3.nv-scatter.nv-single-point .nv-groups .nv-point{fill-opacity:.5!important;stroke-opacity:.5!important}.with-transitions .nvd3 .nv-groups .nv-point{transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-moz-transition:stroke-width 250ms linear,stroke-opacity 250ms linear;-webkit-transition:stroke-width 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-scatter .nv-groups .nv-point.hover,.nvd3 .nv-groups .nv-point.hover{stroke-width:7px;fill-opacity:.95!important;stroke-opacity:.95!important}.nvd3 .nv-point-paths path{stroke:#aaa;stroke-opacity:0;fill:#eee;fill-opacity:0}.nvd3 .nv-indexLine{cursor:ew-resize}.nvd3 .nv-distribution{pointer-events:none}.nvd3 .nv-groups .nv-point.hover{stroke-width:20px;stroke-opacity:.5}.nvd3 .nv-scatter .nv-point.hover{fill-opacity:1}.nvd3.nv-stackedarea path.nv-area{fill-opacity:.7;stroke-opacity:0;transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-moz-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear;-webkit-transition:fill-opacity 250ms linear,stroke-opacity 250ms linear}.nvd3.nv-stackedarea path.nv-area.hover{fill-opacity:.9}.nvd3.nv-stackedarea .nv-groups .nv-point{stroke-opacity:0;fill-opacity:0}.nvd3.nv-linePlusBar .nv-bar rect{fill-opacity:.75}.nvd3.nv-linePlusBar .nv-bar rect:hover{fill-opacity:1}.nvd3.nv-bullet{font:10px sans-serif}.nvd3.nv-bullet .nv-measure{fill-opacity:.8}.nvd3.nv-bullet .nv-measure:hover{fill-opacity:1}.nvd3.nv-bullet .nv-marker{stroke:#000;stroke-width:2px}.nvd3.nv-bullet .nv-markerTriangle{stroke:#000;fill:#fff;stroke-width:1.5px}.nvd3.nv-bullet .nv-tick line{stroke:#666;stroke-width:.5px}.nvd3.nv-bullet .nv-range.nv-s0{fill:#eee}.nvd3.nv-bullet .nv-range.nv-s1{fill:#ddd}.nvd3.nv-bullet .nv-range.nv-s2{fill:#ccc}.nvd3.nv-bullet .nv-title{font-size:14px;font-weight:700}.nvd3.nv-bullet .nv-subtitle{fill:#999}.nvd3.nv-bullet .nv-range{fill:#bababa;fill-opacity:.4}.nvd3.nv-bullet .nv-range:hover{fill-opacity:.7}.nvd3.nv-sparkline path{fill:none}.nvd3.nv-sparklineplus g.nv-hoverValue{pointer-events:none}.nvd3.nv-sparklineplus .nv-hoverValue line{stroke:#333;stroke-width:1.5px}.nvd3.nv-sparklineplus,.nvd3.nv-sparklineplus g{pointer-events:all}.nvd3 .nv-hoverArea{fill-opacity:0;stroke-opacity:0}.nvd3.nv-sparklineplus .nv-xValue,.nvd3.nv-sparklineplus .nv-yValue{stroke-width:0;font-size:.9em;font-weight:400}.nvd3.nv-sparklineplus .nv-yValue{stroke:#f66}.nvd3.nv-sparklineplus .nv-maxValue{stroke:#2ca02c;fill:#2ca02c}.nvd3.nv-sparklineplus .nv-minValue{stroke:#d62728;fill:#d62728}.nvd3.nv-sparklineplus .nv-currentValue{font-weight:700;font-size:1.1em}.nvd3.nv-ohlcBar .nv-ticks .nv-tick{stroke-width:2px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.hover{stroke-width:4px}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.positive{stroke:#2ca02c}.nvd3.nv-ohlcBar .nv-ticks .nv-tick.negative{stroke:#d62728}.nvd3.nv-historicalStockChart .nv-axis .nv-axislabel{font-weight:700}.nvd3.nv-historicalStockChart .nv-dragTarget{fill-opacity:0;stroke:none;cursor:move}.nvd3 .nv-brush .extent{fill-opacity:0!important}.nvd3 .nv-brushBackground rect{stroke:#000;stroke-width:.4;fill:#fff;fill-opacity:.7}.nvd3.nv-indentedtree .name{margin-left:5px}.nvd3.nv-indentedtree .clickable{color:#08C;cursor:pointer}.nvd3.nv-indentedtree span.clickable:hover{color:#005580;text-decoration:underline}.nvd3.nv-indentedtree .nv-childrenCount{display:inline-block;margin-left:5px}.nvd3.nv-indentedtree .nv-treeicon{cursor:pointer}.nvd3.nv-indentedtree .nv-treeicon.nv-folded{cursor:pointer}.nvd3 .background path{fill:none;stroke:#ccc;stroke-opacity:.4;shape-rendering:crispEdges}.nvd3 .foreground path{fill:none;stroke:#4682b4;stroke-opacity:.7}.nvd3 .brush .extent{fill-opacity:.3;stroke:#fff;shape-rendering:crispEdges}.nvd3 .axis line,.axis path{fill:none;stroke:#000;shape-rendering:crispEdges}.nvd3 .axis text{text-shadow:0 1px 0 #fff}.nvd3 .nv-interactiveGuideLine{pointer-events:none}.nvd3 line.nv-guideline{stroke:#ccc}
--------------------------------------------------------------------------------
/website/static/pool_stats.js:
--------------------------------------------------------------------------------
1 | var poolWorkerChart;
2 | var poolHashrateChart;
3 | var poolBlockChart;
4 |
5 | function displayCharts() {
6 | var stats = getPoolStats(poolName);
7 | var maxScale = getReadableHashRatePair(Math.max.apply(null, stats.hashrate.map(x => x[1])));
8 | poolHashrateChart = createDefaultLineChart(
9 | document.getElementById("poolHashChart").getContext('2d'),
10 | [{
11 | label: 'Actual',
12 | fill: false,
13 | data: stats.hashrate.map(x => {
14 | return {
15 | t: x[0],
16 | y: getScaledHashrate(x[1], maxScale[2])
17 | }
18 | }),
19 | borderWidth: 2,
20 | backgroundColor: '#348EA9',
21 | borderColor: '#348EA9'
22 | },
23 | {
24 | label: 'Averaged',
25 | fill: false,
26 | data: stats.averagedHashrate.map(x => {
27 | return {
28 | t: x[0],
29 | y: getScaledHashrate(x[1], maxScale[2])
30 | }
31 | }),
32 | borderWidth: 2,
33 | backgroundColor: '#E81D62',
34 | borderColor: '#E81D62'
35 | }],
36 | 'Time',
37 | maxScale[1]
38 | );
39 | poolWorkerChart = createLineChart(
40 | document.getElementById("poolWorkerChart").getContext('2d'),
41 | [{
42 | label: 'Actual',
43 | fill: false,
44 | data: stats.workers.map(x => {
45 | return {
46 | t: x[0],
47 | y: x[1]
48 | }
49 | }),
50 | borderWidth: 2,
51 | backgroundColor: '#0061B5',
52 | borderColor: '#0061B5'
53 | },
54 | {
55 | label: 'Averaged',
56 | fill: false,
57 | data: stats.averagedWorkers.map(x => {
58 | return {
59 | t: x[0],
60 | y: x[1]
61 | }
62 | }),
63 | borderWidth: 2,
64 | backgroundColor: '#FF9400',
65 | borderColor: '#FF9400'
66 | }],
67 | 'Time',
68 | 'Workers',
69 | {
70 | beginAtZero: true,
71 | fixedStepSize: 1
72 | }
73 | );
74 | poolBlockChart = createLineChart(
75 | document.getElementById("blockChart").getContext('2d'),
76 | [{
77 | label: 'Currently Pending',
78 | fill: true,
79 | steppedLine: true,
80 | data: stats.blocks.map(x => {
81 | return {
82 | t: x[0],
83 | y: x[1]
84 | }
85 | }),
86 | borderWidth: 1,
87 | backgroundColor: '#FBA41F',
88 | borderColor: '#FBA41F'
89 | }],
90 | 'Time',
91 | 'Blocks',
92 | {
93 | beginAtZero: true,
94 | fixedStepSize: 1
95 | }
96 | );
97 | }
98 |
99 | $.getJSON('/api/pool_stats', function(data) {
100 | if (document.hidden) return;
101 | //Add pool to tracker
102 | addPoolToTracker(data, poolName, function() {
103 | displayCharts();
104 | });
105 | });
106 |
107 | statsSource.addEventListener('message', function(e) {
108 | var stats = JSON.parse(e.data);
109 | updatePoolData(stats, poolName, function(pool) {
110 | var max = Math.max.apply(null, pool.hashrate.map(x => x[1]));
111 | var pair = getReadableHashRatePair(max);
112 | var hash = getScaledHashrate(poolName in stats.pools ? stats.pools[poolName].hashrate : 0, pair[2]);
113 | $("#validShares").text(poolName in stats.pools ? stats.pools[poolName].poolStats.validShares : 0);
114 | $("#poolHashRate").text((!isNaN(hash) ? hash : 0) + ' ' + (pair[1] ? pair[1] : 'H/s'));
115 | $("#poolWorkers").text(poolName in stats.pools ? stats.pools[poolName].workerCount : 0);
116 | $("#pendingBlocks").text(poolName in stats.pools ? stats.pools[poolName].blocks.pending : 0);
117 | $("#confirmedBlocks").text(poolName in stats.pools ? stats.pools[poolName].blocks.confirmed : 0);
118 | var time = stats.time * 1000;
119 | var avg = pool.averagedHashrate;
120 | addChartData(poolHashrateChart, poolHashrateChart.data.datasets[0], {t: time, y: hash}, false);
121 | addChartData(poolHashrateChart, poolHashrateChart.data.datasets[1], {t: time, y: getScaledHashrate(avg[avg.length - 1][1], pair[2])}, true);
122 | addChartData(poolBlockChart, poolBlockChart.data.datasets[0], {t: time, y: poolName in stats.pools ? stats.pools[poolName].blocks.pending : 0}, true);
123 | });
124 | }, false);
125 |
--------------------------------------------------------------------------------
/website/static/stat_tracker.js:
--------------------------------------------------------------------------------
1 | //The stat object to hold everything we are tracking
2 | var stats = {};
3 |
4 | //Gets the desired pool stats stored in our cache
5 | var getPoolStats = function(key) {
6 | return stats['p_' + key];
7 | }
8 |
9 | //Gets the desired worker stats stored in our cache
10 | var getWorkerStats = function(address) {
11 | return stats['w_' + address];
12 | }
13 |
14 | //Adds a worker to the stat tracker
15 | var addWorkerToTracker = function(statData, workerData, address, callback) {
16 | if (stats['w_' + address]) {
17 | updateWorkerData(statData, workerData, address, callback);
18 | } else {
19 | buildWorkerData(statData, workerData, address, callback);
20 | }
21 | }
22 |
23 | //Adds a pool to the stat tracker
24 | var addPoolToTracker = function(poolData, poolName, callback) {
25 | if (stats['p_' + poolName]) {
26 | updatePoolData(poolData, poolName, callback);
27 | } else {
28 | buildPoolData(poolData, poolName, callback);
29 | }
30 | }
31 |
32 | /*
33 | Updates the stat cache at the given key.
34 | @param key the stat key to update
35 | @param value the value to update stat with
36 | @param index the index in our stat object to set value for
37 | */
38 | var update = function(key, value, index = 0) {
39 | var stats = stats[key];
40 | if (stats) {
41 | var statsValues = stats.values[index];
42 | if (statsValues) {
43 | statsValues.shift();
44 | statsValues.push(value);
45 | }
46 | }
47 | }
48 |
49 | //builds the initial stat data object for a worker
50 | var buildWorkerData = function(statData, workerData, address, callback = null) {
51 | if (!address || !workerData) {
52 | return;
53 | }
54 | var account = {
55 | paid: workerData.paid,
56 | balance: workerData.balances,
57 | hashrate: 0,
58 | poolHashrate: 0,
59 | shares: workerData.totalShares,
60 | currRoundShares: 0,
61 | symbol: '',
62 | pool: '',
63 | poolSize: 0,
64 | currRoundPoolShares: 0,
65 | invalidShares: 0,
66 | miners: {}
67 | };
68 | $.getJSON('/api/stats', function(data) {
69 | for (var p in data.pools) {
70 | for (var w in data.pools[p].workers) {
71 | var worker = getWorkerNameFromAddress(w);
72 | if (w.split(".")[0] === _miner) {
73 | var a = account.miners[w] = (account.miners[worker] || {
74 | key: worker,
75 | paid: data.pools[p].workers[w].paid,
76 | balance: data.pools[p].workers[w].paid,
77 | hashrate: [],
78 | validShares: data.pools[p].workers[w].shares,
79 | currRoundShares: data.pools[p].workers[w].currRoundShares,
80 | invalidShares: data.pools[p].workers[w].invalidshares
81 | });
82 | account.invalidShares += data.pools[p].workers[w].invalidshares;
83 | account.currRoundShares += data.pools[p].workers[w].currRoundShares;
84 | account.hashrate += data.pools[p].workers[w].hashrate;
85 | if (account.symbol.length < 1) {
86 | account.symbol = data.pools[p].symbol;
87 | account.poolSize = data.pools[p].workers ? Object.keys(data.pools[p].workers).length : 0;
88 | account.pool = p;
89 | }
90 | }
91 | }
92 | }
93 | if(data.pools[account.pool] && data.pools[account.pool].workers){
94 | for (var w in data.pools[account.pool].workers) {
95 | account.poolHashrate += data.pools[account.pool].workers[w].hashrate;
96 | account.currRoundPoolShares += data.pools[account.pool].workers[w].currRoundShares;
97 | }
98 | }
99 | for (var w in workerData.history) {
100 | var worker = getWorkerNameFromAddress(w);
101 | var a = account.miners[w] = (account.miners[worker] || {
102 | key: worker,
103 | paid: 0,
104 | balance: 0,
105 | hashrate: [],
106 | validShares: 0,
107 | currRoundShares: 0,
108 | invalidShares: 0
109 | });
110 | for (var wh in workerData.history[w]) {
111 | a.hashrate.push([workerData.history[w][wh].time * 1000, workerData.history[w][wh].hashrate]);
112 | }
113 | }
114 | var key = 'w_' + address;
115 | stats[key] = account;
116 | if (callback != null) {
117 | callback();
118 | }
119 | });
120 | }
121 |
122 | //builds the initial stat data object for a pool
123 | var buildPoolData = function(statData, poolName, callback = null) {
124 | if (!poolName || !statData) {
125 | return;
126 | }
127 | $.getJSON('/api/pool_stats', function(data) {
128 | var pool = {
129 | hashrate: [],
130 | averagedHashrate: [],
131 | workers: [],
132 | averagedWorkers: [],
133 | blocks: []
134 | };
135 | var totalHashrate = 0;
136 | var totalWorkers = 0;
137 | var count = 0;
138 | for (var i = 0; i < statData.length; i++) {
139 | var time = statData[i].time * 1000;
140 | if (!statData[i].pools) {
141 | continue;
142 | }
143 | if (poolName in statData[i].pools) {
144 | var hash = statData[i].pools[poolName].hashrate;
145 | var workers = statData[i].pools[poolName].workerCount;
146 | totalHashrate += hash;
147 | totalWorkers += workers;
148 | count++;
149 | var averaged = (totalHashrate > 0 && count > 1) ? totalHashrate / count : hash;
150 | var averagedWorkers = (totalWorkers > 0 && count > 1) ? totalWorkers / count : workers;
151 | pool.hashrate.push([time, hash]);
152 | pool.averagedHashrate.push([time, averaged]);
153 | pool.workers.push([time, workers]);
154 | pool.averagedWorkers.push([time, averagedWorkers]);
155 | pool.blocks.push([time, statData[i].pools[poolName].blocks.pending])
156 | } else {
157 | pool.hashrate.push([time, 0]);
158 | pool.workers.push([time, 0]);
159 | pool.averagedWorkers.push([time, 0]);
160 | pool.blocks.push([time, 0])
161 | }
162 | }
163 | var key = 'p_' + poolName;
164 | stats[key] = pool;
165 | if (callback != null) {
166 | callback();
167 | }
168 | });
169 | }
170 |
171 | //updates stat data objects for pools stored within the cache
172 | var updatePoolData = function(statData, poolName, callback = null) {
173 | var pool = stats['p_' + poolName];
174 | if (pool) {
175 | var time = statData.time * 1000;
176 | if (poolName in statData.pools) {
177 | var hash = statData.pools[poolName].hashrate;
178 | pool.hashrate.push([time, hash]);
179 | pool.averagedHashrate.push([time, pool.hashrate.reduce(function(a, b) {
180 | return a[1] + b[1];
181 | }) / pool.hashrate.length]);
182 | pool.workers.push([time, statData.pools[poolName].workerCount]);
183 | pool.blocks.push([time, statData.pools[poolName].blocks.pending])
184 | } else {
185 | pool.hashrate.push([time, 0]);
186 | pool.workers.push([time, 0]);
187 | pool.blocks.push([time, 0])
188 | }
189 | if (callback != null) {
190 | callback(pool);
191 | }
192 | } else {
193 | buildPoolData(statData, poolName, callback);
194 | }
195 | }
196 |
197 | //updates stat data objects for workers stored within the cache
198 | var updateWorkerData = function(statData, workerData, address, callback = null) {
199 | //TODO
200 | }
201 |
202 | function getWorkerNameFromAddress(w) {
203 | var worker = w;
204 | if (w.split(".").length > 1) {
205 | worker = w.split(".")[1];
206 | if (worker == null || worker.length < 1) {
207 | worker = "noname";
208 | }
209 | } else {
210 | worker = "noname";
211 | }
212 | return worker;
213 | }
214 |
--------------------------------------------------------------------------------
/website/static/stats.js:
--------------------------------------------------------------------------------
1 | var poolWorkerData;
2 | var poolHashrateData;
3 | var poolBlockData;
4 |
5 | var poolWorkerChart;
6 | var poolHashrateChart;
7 | var poolBlockChart;
8 |
9 | var statData;
10 | var poolKeys;
11 |
12 | function buildChartData() {
13 |
14 | var pools = {};
15 |
16 | poolKeys = [];
17 | for (var i = 0; i < statData.length; i++) {
18 | for (var pool in statData[i].pools) {
19 | if (poolKeys.indexOf(pool) === -1)
20 | poolKeys.push(pool);
21 | }
22 | }
23 |
24 |
25 | for (var i = 0; i < statData.length; i++) {
26 | var time = statData[i].time * 1000;
27 | for (var f = 0; f < poolKeys.length; f++) {
28 | var pName = poolKeys[f];
29 | var a = pools[pName] = (pools[pName] || {
30 | hashrate: [],
31 | workers: []
32 | //blocks: []
33 | });
34 | if (pName in statData[i].pools) {
35 | a.hashrate.push([time, statData[i].pools[pName].hashrate]);
36 | a.workers.push([time, statData[i].pools[pName].workerCount]);
37 | a.blocks.push({ t: new Date(time), y: statData[i].pools[pName].blocks.pending})
38 | } else {
39 | a.hashrate.push([time, 0]);
40 | a.workers.push([time, 0]);
41 | a.blocks.push({x: time, y: 0})
42 | }
43 | }
44 | }
45 |
46 | poolWorkerData = [];
47 | poolHashrateData = [];
48 | poolBlockData = [];
49 |
50 | for (var pool in pools) {
51 | poolWorkerData.push({
52 | label: pool,
53 | value: pools[pool].workers[pools[pool].workers.length - 1][1]
54 | });
55 | poolHashrateData.push({
56 | label: pool,
57 | value: parseInt(pools[pool].hashrate[pools[pool].hashrate.length - 1][1] / 2048)
58 | });
59 | poolBlockData.push({
60 | label: pool,
61 | value: pools[pool].blocks
62 | });
63 | }
64 | }
65 |
66 | function getReadableHashRateString(hashrate) {
67 | var i = -1;
68 | var byteUnits = [' KH', ' MH', ' GH', ' TH', ' PH'];
69 | do {
70 | hashrate = hashrate / 1024;
71 | i++;
72 | } while (hashrate > 1024);
73 | return Math.round(hashrate) + byteUnits[i];
74 | }
75 |
76 | function timeOfDayFormat(timestamp) {
77 | var dStr = d3.time.format('%I:%M %p')(new Date(timestamp));
78 | if (dStr.indexOf('0') === 0) dStr = dStr.slice(1);
79 | return dStr;
80 | }
81 |
82 | function displayCharts() {
83 | var chartColors = [
84 | '#1976D2',
85 | '#388E3C',
86 | '#FBC02D',
87 | '#512DA8',
88 | '#C2185B'
89 | ];
90 | poolWorkerChart = new Chart($("#workerChart"), {
91 | type: 'pie',
92 | data: {
93 | labels: poolWorkerData.slice(0, 5).map(x => x.label),
94 | datasets: [{
95 | data: poolWorkerData.slice(0, 5).map(x => x.value),
96 | backgroundColor: chartColors
97 | }],
98 | },
99 | options: {
100 | responsive: true
101 | }
102 | });
103 |
104 | poolHashrateChart = new Chart($("#hashChart"), {
105 | type: 'pie',
106 | data: {
107 | labels: poolHashrateData.slice(0, 5).map(x => x.label),
108 | datasets: [{
109 | data: poolHashrateData.slice(0, 5).map(x => x.value),
110 | backgroundColor: chartColors
111 | }]
112 | },
113 | options: {
114 | responsive: true
115 | }
116 | });
117 |
118 | var blockData = [];
119 | var labels = poolBlockData.slice(0, 5).map(x => x.label);
120 | var values = poolBlockData.slice(0, 5).map(x => x.value);
121 | for(var i = 0; i < poolBlockData.length; i++) {
122 | blockData.push(
123 | {
124 | label: labels[i],
125 | data: values[i],
126 | backgroundColor: chartColors[i],
127 | borderColor: chartColors[i]
128 | }
129 | );
130 | }
131 | $("#blockChart").height = 200;
132 | poolBlockChart = new Chart($("#blockChart"), {
133 | type: 'line',
134 | data: {
135 | datasets: blockData
136 | },
137 | options: {
138 | maintainAspectRatio: false,
139 | responsive: true,
140 | scales: {
141 | xAxes: [{
142 | time: {
143 | unit: 'minute'
144 | }
145 | }]
146 | }
147 | }
148 | });
149 |
150 | }
151 |
152 | function pastelColors() {
153 | var r = (Math.round(Math.random() * 127) + 127).toString(16);
154 | var g = (Math.round(Math.random() * 127) + 127).toString(16);
155 | var b = (Math.round(Math.random() * 127) + 127).toString(16);
156 | return '#' + r + g + b;
157 | }
158 |
159 | function TriggerChartUpdates() {
160 | poolWorkerChart.update();
161 | poolHashrateChart.update();
162 | poolBlockChart.update();
163 | }
164 |
165 | $.getJSON('/api/pool_stats', function(data) {
166 | statData = data;
167 | buildChartData();
168 | displayCharts();
169 | });
170 |
171 | statsSource.addEventListener('message', function(e) {
172 | var stats = JSON.parse(e.data);
173 | statData.push(stats);
174 |
175 | var newPoolAdded = (function() {
176 | for (var p in stats.pools) {
177 | if (poolKeys.indexOf(p) === -1)
178 | return true;
179 | }
180 | return false;
181 | })();
182 |
183 | if (newPoolAdded || Object.keys(stats.pools).length > poolKeys.length) {
184 | buildChartData();
185 | displayCharts();
186 | } else {
187 | var time = stats.time * 1000;
188 | for (var f = 0; f < poolKeys.length; f++) {
189 | var pool = poolKeys[f];
190 | for (var i = 0; i < poolWorkerData.length; i++) {
191 | if (poolWorkerData[i].key === pool) {
192 | poolWorkerData[i].values.shift();
193 | poolWorkerData[i].values.push([time, pool in stats.pools ? stats.pools[pool].workerCount : 0]);
194 | break;
195 | }
196 | }
197 | for (var i = 0; i < poolHashrateData.length; i++) {
198 | if (poolHashrateData[i].key === pool) {
199 | poolHashrateData[i].values.shift();
200 | poolHashrateData[i].values.push([time, pool in stats.pools ? stats.pools[pool].hashrate : 0]);
201 | break;
202 | }
203 | }
204 | for (var i = 0; i < poolBlockData.length; i++) {
205 | if (poolBlockData[i].key === pool) {
206 | poolBlockData[i].values.shift();
207 | poolBlockData[i].values.push([time, pool in stats.pools ? stats.pools[pool].blocks.pending : 0]);
208 | break;
209 | }
210 | }
211 | }
212 | TriggerChartUpdates();
213 | }
214 |
215 |
216 | });
217 |
--------------------------------------------------------------------------------
/website/static/style.css:
--------------------------------------------------------------------------------
1 | html, button, input, select, textarea, .pure-g [class *= "pure-u"], .pure-g-r [class *= "pure-u"]{
2 | font-family: 'Open Sans', sans-serif;
3 | }
4 |
5 | html{
6 | background: #2d2d2d;
7 | overflow-y: scroll;
8 | }
9 |
10 | body{
11 | display: flex;
12 | flex-direction: column;
13 | max-width: 1160px;
14 | margin: 0 auto;
15 | }
16 |
17 | header > .home-menu{
18 | background: inherit !important;
19 | height: 54px;
20 | display: flex;
21 | }
22 |
23 | header > .home-menu > a.pure-menu-heading, header > .home-menu > ul, header > .home-menu > ul > li{
24 | display: flex !important;
25 | align-items: center;
26 | justify-content: center;
27 | line-height: normal !important;
28 | }
29 |
30 | header > .home-menu > a.pure-menu-heading{
31 | color: white;
32 | font-size: 1.5em;}
33 |
34 | header > .home-menu > ul > li > a{
35 | color: #ced4d9;
36 | }
37 |
38 | header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li > a:focus{
39 | background: inherit !important;
40 | }
41 |
42 | header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li.pure-menu-selected > a{
43 | color: white;
44 | }
45 |
46 | main{
47 | background-color: #ebf4fa;
48 | position: relative;
49 | }
50 |
51 | footer{
52 | text-align: center;
53 | color: #b3b3b3;
54 | text-decoration: none;
55 | font-size: 0.8em;
56 | padding: 15px;
57 | line-height: 24px;
58 | }
59 |
60 | footer a{
61 | color: #fff;
62 | text-decoration: none;
63 | }
64 |
65 | footer iframe{
66 | vertical-align: middle;
67 | }
68 |
69 | .footer_container {
70 | display: flex;
71 | flex-direction: column;
72 | align-items: center;
73 | }
74 |
--------------------------------------------------------------------------------