forked from jahway603/knomp
jahway603
3 years ago
36 changed files with 77 additions and 4880 deletions
@ -1,8 +1,9 @@ |
|||
node_modules/ |
|||
.idea/ |
|||
config.json |
|||
pool_configs/ |
|||
!pool_configs/komodo.json |
|||
!pool_configs/ |
|||
pool_configs/* |
|||
!pool_configs/hushsolo.json |
|||
!pool_configs/solo-wsb.json |
|||
website/piratepool.io/static/*.txt |
|||
redis-data/ |
|||
.vscode/ |
|||
|
@ -1,20 +0,0 @@ |
|||
{ |
|||
// Use IntelliSense to learn about possible attributes. |
|||
// Hover to view descriptions of existing attributes. |
|||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 |
|||
"version": "0.2.0", |
|||
"configurations": [ |
|||
{ |
|||
"type": "node", |
|||
"request": "launch", |
|||
"name": "Launch via NPM", |
|||
"runtimeExecutable": "npm", |
|||
"runtimeArgs": [ |
|||
"run-script", |
|||
"debug" |
|||
], |
|||
"port": 9229, |
|||
"useWSL": true |
|||
} |
|||
] |
|||
} |
@ -1,11 +0,0 @@ |
|||
# Changelog |
|||
|
|||
### 20161127 |
|||
* Fixed payment processor crashes |
|||
* Fixed varDiff and set default to 0.125 |
|||
* Fixed merkleRoot issue with multiple transactions in each block |
|||
* Fixed incorrect hashrates |
|||
* Begin compatibility testing with Node 7+ |
|||
* Added t_address -> z_address -> t_address coin transfer function |
|||
|
|||
|
@ -1,7 +0,0 @@ |
|||
Copyright (c) <year> <copyright holders> |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -1,164 +0,0 @@ |
|||
# Zcash® and Zclassic - Node Open Mining Portal |
|||
|
|||
**[Click here for the official - Zcash® and Zclassic Stratum Mining Pool Installation Guide](https://zdeveloper.org/wiki:z-nomp_install)** |
|||
|
|||
This is a Equihash mining pool based off of Node Open Mining Portal. |
|||
|
|||
Donations for development are greatly appreciated! |
|||
* BTC: 18vHMxVzotQ9EPyESrf7Z1hNM9AwJeVHgD |
|||
* ZCL: zcXDWbgReztLLXSTUMT2nEumiDM6zTzUXFb7vUnx9JNfJDVqbodyxwEQwgDkFw7Dp128tBU8n8rmVxT43DshmeTEM4LHcdz |
|||
|
|||
#### Production Usage Notice |
|||
This is beta software. All of the following are things that can change and break an existing Z-NOMP setup: functionality of any feature, structure of configuration files and structure of redis data. If you use this software in production then *DO NOT* pull new code straight into production usage because it can and often will break your setup and require you to tweak things like config files or redis data. *Only tagged releases are considered stable.* |
|||
|
|||
#### Paid Solution |
|||
Usage of this software requires abilities with sysadmin, database admin, coin daemons, and sometimes a bit of programming. Running a production pool can literally be more work than a full-time job. |
|||
|
|||
|
|||
### Community / Support |
|||
IRC |
|||
* Support / general discussion join: https://gitter.im/zclassicorg/z-nomp |
|||
|
|||
If your pool uses Z-NOMP let us know and we will list your website here. |
|||
|
|||
### Some pools using Z-NOMP or node-stratum-module: |
|||
|
|||
http://mineflowpool.pl Z-nomp based pool. Custom frontend and API. |
|||
|
|||
http://luckpool.org Zcash Pool with Custom Frontend w/Miner's Jackpot |
|||
|
|||
http://zclassic.miningspeed.com Custom frontend and 0% fee |
|||
|
|||
http://miningpool.io/ |
|||
|
|||
https://lucky-mining.com.ua/ Running MPOS and no fee, [vot][zcl][zen][hush][btg].lucky-mining.com.ua <-- Ukraine |
|||
|
|||
Usage |
|||
===== |
|||
|
|||
|
|||
#### Requirements |
|||
* Coin daemon(s) (find the coin's repo and build latest version from source) |
|||
* [Node.js](http://nodejs.org/) v7+ ([follow these installation instructions](https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager)) |
|||
* [Redis](http://redis.io/) key-value store v2.6+ ([follow these instructions](http://redis.io/topics/quickstart)) |
|||
|
|||
##### Seriously |
|||
Those are legitimate requirements. If you use old versions of Node.js or Redis that may come with your system package manager then you will have problems. Follow the linked instructions to get the last stable versions. |
|||
|
|||
|
|||
[**Redis security warning**](http://redis.io/topics/security): be sure firewall access to redis - an easy way is to |
|||
include `bind 127.0.0.1` in your `redis.conf` file. Also it's a good idea to learn about and understand software that |
|||
you are using - a good place to start with redis is [data persistence](http://redis.io/topics/persistence). |
|||
|
|||
|
|||
#### 0) Setting up coin daemon |
|||
Follow the build/install instructions for your coin daemon. Your coin.conf file should end up looking something like this: |
|||
``` |
|||
daemon=1 |
|||
rpcuser=zclassicrpc |
|||
rpcpassword=securepassword |
|||
rpcport=8232 |
|||
``` |
|||
For redundancy, its recommended to have at least two daemon instances running in case one drops out-of-sync or offline, |
|||
all instances will be polled for block/transaction updates and be used for submitting blocks. Creating a backup daemon |
|||
involves spawning a daemon using the `-datadir=/backup` command-line argument which creates a new daemon instance with |
|||
it's own config directory and coin.conf file. Learn about the daemon, how to use it and how it works if you want to be |
|||
a good pool operator. For starters be sure to read: |
|||
* https://en.bitcoin.it/wiki/Running_bitcoind |
|||
* https://en.bitcoin.it/wiki/Data_directory |
|||
* https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list |
|||
* https://en.bitcoin.it/wiki/Difficulty |
|||
|
|||
|
|||
#### 1) Downloading & Installing |
|||
|
|||
Clone the repository and run `npm update` for all the dependencies to be installed: |
|||
|
|||
```bash |
|||
sudo apt-get install build-essential libsodium-dev npm |
|||
sudo npm install n -g |
|||
sudo n stable |
|||
git clone https://github.com/joshuayabut/node-open-mining-portal.git z-nomp |
|||
cd z-nomp |
|||
npm update |
|||
npm install |
|||
``` |
|||
|
|||
##### Pool config |
|||
Take a look at the example json file inside the `pool_configs` directory. Rename it to `zclassic.json` and change the |
|||
example fields to fit your setup. |
|||
|
|||
``` |
|||
Please Note that: 1 Difficulty is actually 8192, 0.125 Difficulty is actually 1024. |
|||
|
|||
Whenever a miner submits a share, the pool counts the difficulty and keeps adding them as the shares. |
|||
|
|||
ie: Miner 1 mines at 0.1 difficulty and finds 10 shares, the pool sees it as 1 share. Miner 2 mines at 0.5 difficulty and finds 5 shares, the pool sees it as 2.5 shares. |
|||
``` |
|||
|
|||
|
|||
##### [Optional, recommended] Setting up blocknotify |
|||
1. In `config.json` set the port and password for `blockNotifyListener` |
|||
2. In your daemon conf file set the `blocknotify` command to use: |
|||
``` |
|||
node [path to cli.js] [coin name in config] [block hash symbol] |
|||
``` |
|||
Example: inside `zclassic.conf` add the line |
|||
``` |
|||
blocknotify=node /home/user/z-nomp/scripts/cli.js blocknotify zclassic %s |
|||
``` |
|||
|
|||
Alternatively, you can use a more efficient block notify script written in pure C. Build and usage instructions |
|||
are commented in [scripts/blocknotify.c](scripts/blocknotify.c). |
|||
|
|||
|
|||
#### 3) Start the portal |
|||
|
|||
```bash |
|||
npm start |
|||
``` |
|||
|
|||
###### Optional enhancements for your awesome new mining pool server setup: |
|||
* Use something like [forever](https://github.com/nodejitsu/forever) to keep the node script running |
|||
in case the master process crashes. |
|||
* Use something like [redis-commander](https://github.com/joeferner/redis-commander) to have a nice GUI |
|||
for exploring your redis database. |
|||
* Use something like [logrotator](http://www.thegeekstuff.com/2010/07/logrotate-examples/) to rotate log |
|||
output from Z-NOMP. |
|||
* Use [New Relic](http://newrelic.com/) to monitor your Z-NOMP instance and server performance. |
|||
|
|||
|
|||
#### Upgrading Z-NOMP |
|||
When updating Z-NOMP to the latest code its important to not only `git pull` the latest from this repo, but to also update |
|||
the `node-stratum-pool` and `node-multi-hashing` modules, and any config files that may have been changed. |
|||
* Inside your Z-NOMP directory (where the init.js script is) do `git pull` to get the latest Z-NOMP code. |
|||
* Remove the dependenices by deleting the `node_modules` directory with `rm -r node_modules`. |
|||
* Run `npm update` to force updating/reinstalling of the dependencies. |
|||
* Compare your `config.json` and `pool_configs/coin.json` configurations to the latest example ones in this repo or the ones in the setup instructions where each config field is explained. <b>You may need to modify or add any new changes.</b> |
|||
|
|||
|
|||
Credits |
|||
------- |
|||
### Z-NOMP |
|||
* [Joshua Yabut / movrcx](https://github.com/joshuayabut) |
|||
* [Aayan L / anarch3](https://github.com/aayanl) |
|||
* [hellcatz](https://github.com/hellcatz) |
|||
|
|||
### NOMP |
|||
* [Matthew Little / zone117x](https://github.com/zone117x) - developer of NOMP |
|||
* [Jerry Brady / mintyfresh68](https://github.com/bluecircle) - got coin-switching fully working and developed proxy-per-algo feature |
|||
* [Tony Dobbs](http://anthonydobbs.com) - designs for front-end and created the NOMP logo |
|||
* [LucasJones](//github.com/LucasJones) - got p2p block notify working and implemented additional hashing algos |
|||
* [vekexasia](//github.com/vekexasia) - co-developer & great tester |
|||
* [TheSeven](//github.com/TheSeven) - answering an absurd amount of my questions and being a very helpful gentleman |
|||
* [UdjinM6](//github.com/UdjinM6) - helped implement fee withdrawal in payment processing |
|||
* [Alex Petrov / sysmanalex](https://github.com/sysmanalex) - contributed the pure C block notify script |
|||
* [svirusxxx](//github.com/svirusxxx) - sponsored development of MPOS mode |
|||
* [icecube45](//github.com/icecube45) - helping out with the repo wiki |
|||
* [Fcases](//github.com/Fcases) - ordered me a pizza <3 |
|||
* Those that contributed to [node-stratum-pool](//github.com/zone117x/node-stratum-pool#credits) |
|||
|
|||
|
|||
License |
|||
------- |
|||
Released under the MIT License. See LICENSE file. |
@ -0,0 +1,36 @@ |
|||
{ |
|||
"enabled":true, |
|||
"coin": "hush.json", |
|||
"address": "t-address-#1", |
|||
"zAddress": "your-pool-z-address", |
|||
"tAddress": "t-address-#2", |
|||
"invalidAddress":"t-address-#3", |
|||
"walletInterval": 5, |
|||
"rewardRecipients": { |
|||
"pool-operators-t-address-with-1.5-percent": 1.5, |
|||
"2nd-pool-operators-t-address-with-0.5-percent": 0.5, |
|||
"can-remove-these-if-only-solo-mining": 0.1 |
|||
}, |
|||
"tlsOptions": { "enabled": false }, |
|||
"paymentProcessing": { "enabled": false, "daemon": false }, |
|||
"trackShares": { "disable": true }, |
|||
"ports": { |
|||
"3333": { |
|||
"diff": 262144 |
|||
} |
|||
}, |
|||
"daemons": [{ |
|||
"host": "127.0.0.1", |
|||
"port": 18031, |
|||
"user": "username-set-in-HUSH3.conf", |
|||
"password": "password-set-in-HUSH3.conf" |
|||
}], |
|||
|
|||
"p2p": { |
|||
"enabled": true, |
|||
"host": "127.0.0.1", |
|||
"port": 18030, |
|||
"disableTransactions": true |
|||
}, |
|||
"mposMode": { "enabled": false } |
|||
} |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 21 KiB |
@ -1,86 +0,0 @@ |
|||
<!doctype html> |
|||
|
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
|
|||
<link rel="shortcut icon" type="image/png" href="/static/kmdfavicon.svg"/> |
|||
|
|||
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'> |
|||
|
|||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.min.css"> |
|||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.min.css"> |
|||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/0.4.2/pure-min.css"> |
|||
|
|||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> |
|||
|
|||
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.min.js"></script> |
|||
<script src="/static/nvd3.js"></script> |
|||
<link rel="stylesheet" href="/static/nvd3.css"> |
|||
|
|||
<script src="/static/main.js"></script> |
|||
<link rel="stylesheet" href="/static/style.css"> |
|||
|
|||
<title>minerpond - komodo assetchains mining pool</title> |
|||
|
|||
</head> |
|||
|
|||
<body> |
|||
|
|||
<header> |
|||
<div class="home-menu pure-menu pure-menu-open pure-menu-horizontal"> |
|||
|
|||
<a class="pure-menu-heading hot-swapper" href="/"><i class="fa fa-home"></i> Home</a> |
|||
|
|||
<ul> |
|||
<li class="{{? it.selected === 'getting_started' }}pure-menu-selected{{?}}"> |
|||
<a class="hot-swapper" href="/getting_started"> |
|||
<i class="fa fa-rocket"></i> |
|||
Getting Started |
|||
</a> |
|||
</li> |
|||
<li class="{{? it.selected === 'stats' }}pure-menu-selected{{?}}"> |
|||
<a class="hot-swapper" href="/stats"> |
|||
<i class="fa fa-bar-chart-o"></i> |
|||
Graph Stats |
|||
</a> |
|||
</li> |
|||
<li class="{{? it.selected === 'tbs' }}pure-menu-selected{{?}}"> |
|||
<a class="hot-swapper" href="/tbs"> |
|||
<i class="fa fa-table"></i> |
|||
Tab Stats |
|||
</a> |
|||
</li> |
|||
<li class="{{? it.selected === 'workers' }}pure-menu-selected{{?}}"> |
|||
<a class="hot-swapper" href="/workers"> |
|||
<i class="fa fa-cogs"></i> |
|||
Workers Stats |
|||
</a> |
|||
</li> |
|||
<li class="{{? it.selected === 'payments' }}pure-menu-selected{{?}}"> |
|||
<a class="hot-swapper" href="/payments"> |
|||
<i class="fa fa-bitcoin"></i> |
|||
Payments |
|||
</a> |
|||
</li> |
|||
<li class="{{? it.selected === 'api' }}pure-menu-selected{{?}}"> |
|||
<a class="hot-swapper" href="/api"> |
|||
<i class="fa fa-code"></i> |
|||
API |
|||
</a> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</header> |
|||
|
|||
<main> |
|||
{{=it.page}} |
|||
</main> |
|||
|
|||
|
|||
<footer> |
|||
<3 <a href="https://webworker.sh" target="_blank">🐸</a> · <a href="https://github.com/webworker01/knomp" target="_blank">knomp on Github</a> · <a href="https://discord.gg/QaPwxKB" target="_blank" rel="nofollow noreferrer noopener">Discord Chat</a> |
|||
</footer> |
|||
|
|||
</body> |
|||
</html> |
File diff suppressed because it is too large
@ -1,50 +0,0 @@ |
|||
<div> |
|||
|
|||
<style> |
|||
#passwordForm, #adminCenter{ |
|||
display: none; |
|||
} |
|||
#adminCenter{ |
|||
display: flex; |
|||
flex-flow: row; |
|||
} |
|||
#leftMenu{ |
|||
flex: 0 0 200px; |
|||
} |
|||
#editForm{ |
|||
flex: 1 1 auto; |
|||
} |
|||
</style> |
|||
|
|||
<form class="pure-form pure-form-stacked" id="passwordForm"> |
|||
<fieldset> |
|||
<legend>Password</legend> |
|||
|
|||
<input id="password" type="password" placeholder="Password"> |
|||
|
|||
<label for="remember" class="pure-checkbox"> |
|||
<input id="remember" type="checkbox"> Stay Logged In |
|||
</label> |
|||
|
|||
<button type="submit" class="pure-button pure-button-primary">Log In</button> |
|||
</fieldset> |
|||
</form> |
|||
|
|||
<div id="adminCenter"> |
|||
|
|||
<div class="pure-menu pure-menu-open" id="leftMenu"> |
|||
<a class="pure-menu-heading">Administration</a> |
|||
<ul> |
|||
<li id="addPool"><a href="#">Add Pool</a></li> |
|||
<li class="pure-menu-heading" id="poolList">Current Pools</li> |
|||
</ul> |
|||
</div> |
|||
|
|||
<div id="editForm"></div> |
|||
|
|||
</div> |
|||
|
|||
|
|||
<script src="/static/admin.js"></script> |
|||
|
|||
</div> |
@ -1,11 +0,0 @@ |
|||
<div style="margin: 18px;"> |
|||
API - The API is work in progress and is subject to change during development. |
|||
<ul> |
|||
<li><a href="/api/stats">/api/stats</a> global pool stats</li> |
|||
<li><a href="/api/blocks">/api/blocks</a> global block stats</li> |
|||
<li><a href="/api/pool_stats">/api/pool_stats</a> - historical stats</li> |
|||
<li><a href="/api/payments">/api/payments</a> - payment history</li> |
|||
<li><a href="/api/worker_stats?taddr">/api/worker_stats?taddr</a> - historical time per pool json </li> |
|||
<li><a href="/api/live_stats">/api/live_stats</a> - live stats (websocket)</li> |
|||
</ul> |
|||
</div> |
@ -1,325 +0,0 @@ |
|||
<style> |
|||
#holder{ |
|||
display: flex; |
|||
flex-direction: row; |
|||
} |
|||
|
|||
.glow{ |
|||
box-shadow: inset 0 0 12px 4px #ff6c00; |
|||
} |
|||
|
|||
.hidden{ |
|||
display: none !important; |
|||
} |
|||
|
|||
#menu{ |
|||
background-color: #3d3d3d; |
|||
min-width: 170px; |
|||
} |
|||
|
|||
#menu > .menuHeader{ |
|||
color: #e3f7ff; |
|||
border-bottom: 1px solid #7f878b; |
|||
font-size: 1.2em; |
|||
padding: 16px 16px 4px 15px; |
|||
} |
|||
|
|||
.menuList{ |
|||
transition-duration: 200ms; |
|||
} |
|||
|
|||
.menuList > a:first-child{ |
|||
margin-top: 10px; |
|||
} |
|||
|
|||
.menuList > a{ |
|||
display: inline-block; |
|||
color: #e3f7ff; |
|||
text-decoration: none; |
|||
padding: 7px; |
|||
padding-left: 25px; |
|||
width:40px; |
|||
} |
|||
|
|||
.menuList > a:hover{ |
|||
color: #f69b3a; |
|||
} |
|||
|
|||
#main{ |
|||
flex: 1 1 auto; |
|||
display: flex; |
|||
flex-direction: column; |
|||
margin: 18px; |
|||
} |
|||
.miningOption{ |
|||
color: white; |
|||
/* display: flex; |
|||
flex: 1 1 auto; |
|||
flex-direction: row; |
|||
flex-wrap: wrap; */ |
|||
min-height: 215px; |
|||
justify-content: center; |
|||
align-items: center; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
a.miningOption:hover{ |
|||
color: #f69b3a; |
|||
} |
|||
|
|||
.miningOption:first-child{ |
|||
background-color: #0eafc7; |
|||
} |
|||
.miningOption:last-child{ |
|||
background-color: #b064e1; |
|||
} |
|||
.miningOptionNum{ |
|||
font-size: 6em; |
|||
padding-right: 20px; |
|||
width: 140px; |
|||
text-align: center; |
|||
} |
|||
.miningOptionInstructions{ |
|||
flex: 1 1 auto; |
|||
padding:10px; |
|||
} |
|||
|
|||
.miningOptionInstructions > div:first-child{ |
|||
font-size: 2.4em; |
|||
} |
|||
.miningOptionInstructions > div:last-child{ |
|||
margin-top: 20px; |
|||
font-size: 1.3em; |
|||
} |
|||
|
|||
#orHolder{ |
|||
height: 37px; |
|||
text-align: center; |
|||
} |
|||
#orLine{ |
|||
border-bottom: 1px solid #c2cacf; |
|||
height: 19px; |
|||
margin-bottom: -13px; |
|||
} |
|||
#orText{ |
|||
background-color: #ebf4fa; |
|||
color: #5c5c5c; |
|||
display: inline-block; |
|||
width: 35px; |
|||
font-style: italic; |
|||
} |
|||
|
|||
#coinInfoBackground{ |
|||
transition-duration: 400ms; |
|||
position: absolute; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background-color: black; |
|||
opacity: 0.0; |
|||
} |
|||
#coinInfo{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
color: white; |
|||
width: 750px; |
|||
min-height: 400px; |
|||
top: 50px; |
|||
left: 50%; |
|||
margin-left: -375px; |
|||
position: absolute; |
|||
background-color: #f06350; |
|||
} |
|||
#coinInfo .coinInfoName{ |
|||
text-transform: capitalize; |
|||
} |
|||
#coinInfo > div:first-of-type{ |
|||
font-size: 1.8em; |
|||
text-align: center; |
|||
margin-top: 40px; |
|||
margin-bottom: 35px; |
|||
} |
|||
#coinInfoRows{ |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: center; |
|||
flex: 1 1 auto; |
|||
margin-bottom: 70px; |
|||
} |
|||
#coinInfoRows > div{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: center; |
|||
} |
|||
#coinInfoRows > div > div{ |
|||
padding: 3px; |
|||
} |
|||
#coinInfoRowKeys{ |
|||
font-weight: bold; |
|||
padding-right: 30px; |
|||
} |
|||
#coinInfoRowKeys .coinInfoSubtle{ |
|||
font-weight: normal; |
|||
} |
|||
#coinInfoRowValues{ |
|||
|
|||
} |
|||
#coinInfoClose{ |
|||
position: absolute; |
|||
font-size: 3em; |
|||
top: 0; |
|||
right: 0; |
|||
width: 60px; |
|||
height: 60px; |
|||
text-align: center; |
|||
color: white; |
|||
text-decoration: none; |
|||
} |
|||
#coinInfoClose:hover{ |
|||
color: #50f0e3; |
|||
} |
|||
</style> |
|||
|
|||
<div id="holder"> |
|||
<a href="#" class="miningOption" id="coinGlowTrigger"> |
|||
<div class="miningOptionInstructions"> |
|||
<div>Select a coin for connection details</div> |
|||
<div>Configurations for each coin are available for advanced miners</div> |
|||
</div> |
|||
</a> |
|||
|
|||
<div id="menu"> |
|||
|
|||
{{? (function(){ |
|||
if (!it.portalConfig.switching) return false; |
|||
for (var p in it.portalConfig.switching){ |
|||
if (it.portalConfig.switching[p].enabled) |
|||
return true; |
|||
} |
|||
return false; |
|||
})() |
|||
}} |
|||
<div class="menuHeader">Coin-Switching Ports</div> |
|||
{{?}} |
|||
|
|||
<div class="menuList"> |
|||
{{ for (var p in it.portalConfig.switching){ |
|||
if (!it.portalConfig.switching[p].enabled) continue; |
|||
var info = { |
|||
algo: p, |
|||
ports: {}, |
|||
host: it.portalConfig.website.stratumHost |
|||
}; |
|||
info.ports[it.portalConfig.switching[p].port] = {diff: it.portalConfig.switching[p].diff}; |
|||
info = JSON.stringify(info).replace(/"/g, '"'); |
|||
}} |
|||
<a href="#" class="poolOption" data-info="{{=info}}">{{=p}}</a> |
|||
{{ } }} |
|||
</div> |
|||
|
|||
<div class="menuHeader">Coins</div> |
|||
<div class="menuList" id="coinList"> |
|||
{{ for(var pool in it.poolsConfigs) { |
|||
var info = JSON.stringify({ |
|||
coin: it.poolsConfigs[pool].coin, |
|||
algo: it.poolsConfigs[pool].coin.algorithm, |
|||
ports: it.poolsConfigs[pool].ports, |
|||
host: it.portalConfig.website.stratumHost |
|||
}).replace(/"/g, '"'); |
|||
}} |
|||
<a href="#" class="poolOption" data-info="{{=info}}">{{=pool}} {{=Object.keys(it.poolsConfigs[pool].ports)[0]}}</a> |
|||
{{ } }} |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- <div id="main"> |
|||
<a href="#" class="miningOption" id="nompAppDownload"> |
|||
<div class="miningOptionNum">1.</div> |
|||
<div class="miningOptionInstructions"> |
|||
<div>Download NOMP App</div> |
|||
<div>Our preconfigured app makes mining that easy</div> |
|||
</div> |
|||
</a> |
|||
<div id="orHolder"> |
|||
<div id="orLine"></div> |
|||
<div id="orText">or</div> |
|||
</div> |
|||
<a href="#" class="miningOption" id="coinGlowTrigger"> |
|||
<div class="miningOptionNum">2.</div> |
|||
<div class="miningOptionInstructions"> |
|||
<div>Select a coin for connection details</div> |
|||
<div>Configurations for each coin are available for advanced miners</div> |
|||
</div> |
|||
</a> |
|||
</div> --> |
|||
</div> |
|||
|
|||
<a href="#" id="coinInfoBackground" class="hidden"></a> |
|||
|
|||
<div id="coinInfo" class="hidden"> |
|||
<a href="#" id="coinInfoClose">×</a> |
|||
<div><span class="coinInfoName"></span> Configuration:</div> |
|||
<div id="coinInfoRows"> |
|||
<div id="coinInfoRowKeys"> |
|||
<div>Username:</div> |
|||
<div>Password:</div> |
|||
</div> |
|||
<div id="coinInfoRowValues"> |
|||
<div id="coinInfoUsername"></div> |
|||
<div>anything</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
|
|||
function showCoinConfig(info){ |
|||
|
|||
var htmlKeys = '<div class="coinInfoData">Algorithm:</div>'; |
|||
var htmlValues = '<div class="coinInfoData">' + info.algo + '</div>'; |
|||
|
|||
for (var port in info.ports){ |
|||
htmlKeys += '<div class="coinInfoData">URL <span class="coinInfoSubtle">(difficulty ' + info.ports[port].diff + ')</span>:</div>'; |
|||
htmlValues += '<div class="coinInfoData">stratum+tcp://' + info.host + ':' + port + '</div>'; |
|||
} |
|||
|
|||
if (info.coin) |
|||
$('#coinInfoUsername').text('your ' + info.coin.name + ' wallet address'); |
|||
else |
|||
$('#coinInfoUsername').text('your public key'); |
|||
$('.coinInfoData').remove(); |
|||
$('#coinInfoRowKeys').append(htmlKeys); |
|||
$('#coinInfoRowValues').append(htmlValues); |
|||
} |
|||
|
|||
$('#coinGlowTrigger').click(function(event){ |
|||
event.preventDefault(); |
|||
$('.menuList').addClass('glow'); |
|||
setTimeout(function(){ |
|||
$('.menuList').removeClass('glow'); |
|||
}, 200); |
|||
return false; |
|||
}); |
|||
|
|||
$('.poolOption').click(function(event){ |
|||
event.preventDefault(); |
|||
showCoinConfig($(this).data('info')); |
|||
$('#coinInfoBackground,#coinInfo').removeClass('hidden'); |
|||
$('#coinInfoBackground').css('opacity', 0.7); |
|||
return false; |
|||
}); |
|||
|
|||
$('#coinInfoBackground,#coinInfoClose').click(function(event){ |
|||
event.preventDefault(); |
|||
$('#coinInfoBackground,#coinInfo').addClass('hidden'); |
|||
$('#coinInfoBackground').css('opacity', 0.0); |
|||
return false; |
|||
}); |
|||
|
|||
$('#nompAppDownload').click(function(event){ |
|||
event.preventDefault(); |
|||
alert('NOMP App development still in progress...'); |
|||
return false; |
|||
}); |
|||
</script> |
@ -1,134 +0,0 @@ |
|||
<style> |
|||
#boxWelcome{ |
|||
background-color: #0eafc7; |
|||
color: white; |
|||
margin: 18px; |
|||
} |
|||
#logoImg{ |
|||
height: 285px; |
|||
margin: 55px; |
|||
} |
|||
#welcomeText{ |
|||
font-size: 2.7em; |
|||
margin: 50px 18px 10px 18px; |
|||
} |
|||
#welcomeItems{ |
|||
list-style-type: none; |
|||
font-size: 1.3em; |
|||
padding: 0 !important; |
|||
margin: 0 0 0 18px !important; |
|||
} |
|||
#welcomeItems > li{ |
|||
margin: 30px !important; |
|||
} |
|||
#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{ |
|||
background-color: #b064e1; |
|||
} |
|||
#boxStatsRight{ |
|||
background-color: #10bb9c; |
|||
} |
|||
.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; |
|||
} |
|||
|
|||
|
|||
</style> |
|||
|
|||
<div class="pure-g-r" id="boxWelcome"> |
|||
<!-- <img src="/static/komodo-logo-horizontal-01.png" style="margin: 0 auto; height:150px;"> --> |
|||
|
|||
<div class="pure-u-1"> |
|||
<div style="font-size: 2em; text-align:center; margin-bottom:10px;">MinerPond 🐸</div> |
|||
<div style="text-align:center; margin-bottom:10px;">Low 0.5% fee! Min payouts of 1!</div> |
|||
<div style="text-align:center; margin-bottom:10px;">KMDICE: Use a KMD compatible R address! Currently 15 minute payouts.</div> |
|||
<div style="text-align:center; margin-bottom:10px;">HUSH3Z: Use a zs1 sapling address! Currently 1 hour payouts.</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="pure-g-r" id="boxesLower"> |
|||
<div class="pure-u-1"> |
|||
<div class="boxStats" id="boxStatsLeft"> |
|||
<div class="boxLowerHeader">Global Stats</div> |
|||
<div class="boxStatsList"> |
|||
{{ for(var algo in it.stats.algos) { }} |
|||
<div> |
|||
<div><i class="fa fa-flask"></i>{{=algo}}</div> |
|||
<div><i class="fa fa-users"></i><span id="statsMiners{{=algo}}">{{=it.stats.algos[algo].workers}}</span> Miners</div> |
|||
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=algo}}">{{=it.stats.algos[algo].hashrateString}}</span></div> |
|||
</div> |
|||
{{ } }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="pure-u-1"> |
|||
<div class="boxStats" id="boxStatsRight"> |
|||
<div class="boxLowerHeader">Pools / Coins</div> |
|||
<div class="boxStatsList"> |
|||
{{ for(var pool in it.stats.pools) { }} |
|||
<div> |
|||
<div><i class="fa fa-dot-circle-o"></i>{{=pool}}</div> |
|||
<div><i class="fa fa-users"></i><span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Miners</div> |
|||
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span></div> |
|||
</div> |
|||
{{ } }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<script> |
|||
$(function() { |
|||
statsSource.addEventListener('message', function (e) { |
|||
var stats = JSON.parse(e.data); |
|||
for (algo in stats.algos) { |
|||
$('#statsMiners' + algo).text(stats.algos[algo].workers); |
|||
$('#statsHashrate' + algo).text(stats.algos[algo].hashrateString); |
|||
} |
|||
for (var pool in stats.pools) { |
|||
$('#statsMiners' + pool).text(stats.pools[pool].workerCount); |
|||
$('#statsHashrate' + pool).text(stats.pools[pool].hashrateString); |
|||
} |
|||
}); |
|||
}); |
|||
</script> |
@ -1,105 +0,0 @@ |
|||
<style> |
|||
#topCharts{ |
|||
padding-left: 18px; |
|||
padding-right: 18px; |
|||
padding-top: 18px; |
|||
padding-bottom: 0px; |
|||
} |
|||
#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{ |
|||
|
|||
} |
|||
|
|||
#boxesWorkers { |
|||
margin: 0 9px; |
|||
} |
|||
#boxesWorkers > div { |
|||
display: flex; |
|||
} |
|||
#boxesWorkers > 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; |
|||
} |
|||
|
|||
</style> |
|||
|
|||
<div id="topCharts"> |
|||
<div class="chartWrapper"> |
|||
<div class="chartLabel"> |
|||
<!--<div style="float:left; padding-right: 18px;"><i class="fa fa-users"></i><span id="statsWorkers">...</span></div>--> |
|||
<div style="float:left; margin-right: 9px;">{{=String(it.stats.address).split(".")[0]}}</div> |
|||
<div style="float:right; padding-left: 18px;"><small><i class="fa fa-tachometer"></i> <span id="statsHashrateAvg">...</span> (Avg)</small></div> |
|||
<div style="float:right; padding-left: 18px;"><small><i class="fa fa-tachometer"></i> <span id="statsHashrate">...</span> (Now)</small></div> |
|||
<div style="float:right; padding-left: 18px;"><small><i class="fa fa-gavel"></i> Luck <span id="statsLuckDays">...</span> Days</small></div> |
|||
</div> |
|||
<div class="chartHolder"><svg id="workerHashrate" /></div> |
|||
<div> |
|||
<div style="float:right; padding-top: 9px; padding-right: 18px;"><i class="fa fa-cog"></i> Shares: <span id="statsTotalShares">...</span></div> |
|||
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fa fa-money"></i> Immature: <span id="statsTotalImmature">...</span> </div> |
|||
<div style="float:left; padding-top: 9px; padding-left: 18px; padding-right: 18px;"><i class="fa fa-money"></i> Bal: <span id="statsTotalBal">...</span> </div> |
|||
<div style="padding-top: 9px; padding-left: 18px;"><i class="fa fa-money"></i> Paid: <span id="statsTotalPaid">...</span> </div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="boxesWorkers"> </div> |
|||
|
|||
<script> |
|||
var _miner = "{{=String(it.stats.address).split(".")[0]}}"; |
|||
var _workerCount = 0; |
|||
window.statsSource = new EventSource("/api/live_stats"); |
|||
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/miner_stats.js'; |
|||
</script> |
@ -1,25 +0,0 @@ |
|||
<style> |
|||
#miningKeyPage{ |
|||
margin: 15px; |
|||
} |
|||
#keyFrame{ |
|||
padding: 0; |
|||
border: 0; |
|||
width: 100%; |
|||
height: 750px; |
|||
display: block; |
|||
} |
|||
</style> |
|||
|
|||
<div id="miningKeyPage"> |
|||
|
|||
<p> |
|||
This script run client-side (in your browser). For maximum security <a href="/key.html" download="key.html">download</a> the script and run it locally and |
|||
offline in a modern web browser. |
|||
</p> |
|||
|
|||
<iframe id="keyFrame" src="/key.html"> |
|||
|
|||
</iframe> |
|||
|
|||
</div> |
@ -1,94 +0,0 @@ |
|||
<style> |
|||
#bottomNotes { |
|||
display: block; |
|||
padding-left: 18px; |
|||
padding-right: 18px; |
|||
padding-bottom: 18px; |
|||
} |
|||
#topPool { |
|||
padding-top: 18px; |
|||
padding-left: 18px; |
|||
padding-right: 18px; |
|||
} |
|||
#topPool > div > div > svg { |
|||
display: block; |
|||
height: 280px; |
|||
} |
|||
.poolWrapper { |
|||
border: solid 1px #c7c7c7; |
|||
border-radius: 5px; |
|||
padding: 5px; |
|||
margin-bottom: 18px; |
|||
} |
|||
.poolLabel { |
|||
font-size: 1.2em; |
|||
text-align: center; |
|||
padding: 4px; |
|||
} |
|||
.poolMinerTable { |
|||
|
|||
} |
|||
table { |
|||
width: 100%; |
|||
} |
|||
table td { |
|||
padding: 6px 12px; |
|||
} |
|||
</style> |
|||
<script type="text/javascript"> |
|||
$(function () { |
|||
$(document).tooltip({ |
|||
content: function () { |
|||
return $(this).prop('title'); |
|||
}, |
|||
show: null, |
|||
close: function (event, ui) { |
|||
ui.tooltip.hover( |
|||
|
|||
function () { |
|||
$(this).stop(true).fadeTo(400, 1); |
|||
}, |
|||
|
|||
function () { |
|||
$(this).fadeOut("400", function () { |
|||
$(this).remove(); |
|||
}) |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
</script> |
|||
{{ function readableDate(a){ return new Date(parseInt(a)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }} |
|||
{{ for(var pool in it.stats.pools) { }} |
|||
<table class="puretable"> |
|||
<thead> |
|||
<tr> |
|||
<th>Blocks</th> |
|||
<th>Time</th> |
|||
<th>Miners</th> |
|||
<th>Shares</th> |
|||
<th>Amount</th> |
|||
</tr> |
|||
</thead> |
|||
{{ for(var p in it.stats.pools[pool].payments) { }} |
|||
<tr> |
|||
<td style="max-width: 475px; word-wrap: break-word;"> |
|||
{{if (String(it.stats.pools[pool].name) == 'kmd') { }} |
|||
<a href="https://kmdexplorer.io/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name) == 'hush3z') { }} |
|||
<a href="https://hush.explorer.dexstats.info/tx/{{=it.stats.pools[pool].payments[p].txid}}" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name) == 'kmdice') { }} |
|||
<a href="http://kmdice.explorer.dexstats.info/tx/{{=it.stats.pools[pool].payments[p].txid}}" target="_blank" rel="noopener noreferrer">{{=it.stats.pools[pool].payments[p].blocks}}</a> |
|||
{{ } else { }} |
|||
{{=it.stats.pools[pool].payments[p].blocks}} |
|||
{{ } }} |
|||
</td> |
|||
<td>{{=readableDate(it.stats.pools[pool].payments[p].time)}}</td> |
|||
<td>{{=it.stats.pools[pool].payments[p].miners}}</td> |
|||
<td>{{=Math.round(it.stats.pools[pool].payments[p].shares)}}</td> |
|||
<td>{{=it.stats.pools[pool].payments[p].paid}} {{=it.stats.pools[pool].symbol}}</td> |
|||
</tr> |
|||
{{ } }} |
|||
</table> |
|||
</div> |
|||
{{ } }} |
@ -1,234 +0,0 @@ |
|||
<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; |
|||
} |
|||
#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)).toISOString().substring(0, 16).replace('T', ' ') + ' UTC'; } }} |
|||
|
|||
<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">{{=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">{{=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) { }} |
|||
<div class="pure-g-r" id="boxesLower"> |
|||
<div class="pure-u-1-1"> |
|||
<div class="boxStats" id="boxStatsRight"> |
|||
<div class="boxLowerHeader">{{=it.stats.pools[pool].name}} Blocks Found |
|||
<span style="float:right;"><small> |
|||
<i class="fa fa-bars"></i> <span id="statsValidBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.validBlocks}}</span> Blocks |
|||
<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> </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;" title="{{if (it.stats.pools[pool].pending.confirms && it.stats.pools[pool].pending.confirms[block[0]]) { }}{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }}Waiting for dPoW notarization{{} else if (it.stats.pools[pool].pending.confirms[block[0]] < it.poolsConfigs[pool].paymentProcessing.minConf*2) { }}Waiting for min confirmations{{ } else { }}Queued for payment{{ } }}{{ } else { }}Waiting for payment processor to review{{ } }}"> |
|||
<i class="fa fa-bars"></i> |
|||
<small>Block:</small> |
|||
{{if (String(it.stats.pools[pool].name) == "kmd") { }} |
|||
<a href="https://kmdexplorer.io/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name) == "rkt") { }} |
|||
<a href="http://rkt.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name) == "kmdice") { }} |
|||
<a href="https://kmdice.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name) == "hush3z") { }} |
|||
<a href="https://hush.explorer.dexstats.info/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 && it.stats.pools[pool].pending.confirms[block[0]]) { }} |
|||
{{if (it.stats.pools[pool].pending.confirms[block[0]] == 1) { }} |
|||
<span style="float:right; color: red;"><small>Waiting for Notarization</small></span> |
|||
{{ } else { }} |
|||
<span style="float:right; color: red;"><small>{{=it.stats.pools[pool].pending.confirms[block[0]]}} of {{=it.poolsConfigs[pool].paymentProcessing.minConf*2}} Confirmations</small></span> |
|||
{{ } }} |
|||
{{ } else { }} |
|||
<span style="float:right; color: red;"><small>*PENDING*</small></span> |
|||
{{ } }} |
|||
</div> |
|||
{{ } }} |
|||
|
|||
{{ 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) == "kmd") { }} |
|||
<a href="https://kmdexplorer.io/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name).startsWith("rkt")) { }} |
|||
<a href="http://rkt.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name).startsWith("kmdice")) { }} |
|||
<a href="http://kmdice.explorer.dexstats.info/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a> |
|||
{{ } else if (String(it.stats.pools[pool].name) == "hush3z") { }} |
|||
<a href="https://hush.explorer.dexstats.info/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> |
|||
{{ } }} |
|||
<span style="float:right; padding-left: 18px; color: green;"><small>*PAID*</small></span> |
|||
</div> |
|||
{{ } }} |
|||
{{ } }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{{ } }} |
|||
|
|||
<script> |
|||
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js'; |
|||
|
|||
$(function() { |
|||
window.statsSource = new EventSource("/api/live_stats"); |
|||
|
|||
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> |
@ -1,64 +0,0 @@ |
|||
<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 { |
|||
|
|||
} |
|||
|
|||
table { |
|||
width: 100%; |
|||
} |
|||
|
|||
</style> |
|||
|
|||
<table class="pure-table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Pool</th> |
|||
<th>Algo</th> |
|||
<th>Workers</th> |
|||
<th>Valid Shares</th> |
|||
<th>Invalid Shares</th> |
|||
<th>Total Blocks</th> |
|||
<th>Pending</th> |
|||
<th>Confirmed</th> |
|||
<th>Orphaned</th> |
|||
<th>Hashrate</th> |
|||
</tr> |
|||
</thead> |
|||
{{ for(var pool in it.stats.pools) { }} |
|||
<tr class="pure-table-odd"> |
|||
<td>{{=it.stats.pools[pool].name}}</td> |
|||
<td>{{=it.stats.pools[pool].algorithm}}</td> |
|||
<td>{{=Object.keys(it.stats.pools[pool].workers).length}}</td> |
|||
<td>{{=it.stats.pools[pool].poolStats.validShares}}</td> |
|||
<td>{{=it.stats.pools[pool].poolStats.invalidShares}}</td> |
|||
<td>{{=it.stats.pools[pool].poolStats.validBlocks}}</td> |
|||
<td>{{=it.stats.pools[pool].blocks.pending}}</td> |
|||
<td>{{=it.stats.pools[pool].blocks.confirmed}}</td> |
|||
<td>{{=it.stats.pools[pool].blocks.orphaned}}</td> |
|||
<td>{{=it.stats.pools[pool].hashrateString}}</td> |
|||
</tr> |
|||
{{ } }} |
|||
</table> |
@ -1,96 +0,0 @@ |
|||
<style> |
|||
#bottomNotes { |
|||
display: block; |
|||
padding-left: 18px; |
|||
padding-right: 18px; |
|||
padding-bottom: 18px; |
|||
} |
|||
#topPool { |
|||
padding-top: 18px; |
|||
padding-left: 18px; |
|||
padding-right: 18px; |
|||
} |
|||
#topPool > div > div > svg { |
|||
display: block; |
|||
height: 280px; |
|||
} |
|||
.poolWrapper { |
|||
border: solid 1px #c7c7c7; |
|||
border-radius: 5px; |
|||
padding: 5px; |
|||
margin-bottom: 18px; |
|||
} |
|||
.poolLabel { |
|||
font-size: 1.2em; |
|||
text-align: center; |
|||
padding: 4px; |
|||
} |
|||
.poolMinerTable { |
|||
|
|||
} |
|||
table { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
<script type="text/javascript"> |
|||
function searchKeyPress(e) |
|||
{ |
|||
// look for window.event in case event isn't passed in |
|||
e = e || window.event; |
|||
if (e.keyCode == 13) { |
|||
document.getElementById('btnSearch').click(); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
$(document).ready(function(){ |
|||
$('.btn-lg').click(function(){ |
|||
window.location = "workers/" + $('.input-lg').val(); |
|||
}); |
|||
}); |
|||
</script> |
|||
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }} |
|||
{{ var i=0; for(var pool in it.stats.pools) { }} |
|||
<div id="topPool"> |
|||
<div class="poolWrapper"> |
|||
<div class="poolLabel"> |
|||
<span style="float:right; margin-bottom: 8px;"> |
|||
<small> |
|||
Miner Lookup: |
|||
<input type="text" class="form-control input-lg" onkeypress="return searchKeyPress(event);"> |
|||
<span class="input-group-btn"> |
|||
<button class="btn btn-default btn-lg" type="button">Lookup</button> |
|||
</span> |
|||
</small> |
|||
</span> |
|||
{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Top Miners |
|||
<small><i class="fa fa-users"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners |
|||
<i class="fa fa-rocket"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers |
|||
<i class="fa fa-cog"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].shareCount}}</span> Shares </small> |
|||
</div> |
|||
<div class="poolMinerTable"> |
|||
<table class="pure-table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Address</th> |
|||
<th>Shares</th> |
|||
<th>Efficiency</th> |
|||
<th>Hashrate</th> |
|||
</tr> |
|||
</thead> |
|||
{{ var minerindex = 0; }} |
|||
{{ for(var worker in it.stats.pools[pool].miners) { }} |
|||
{{var workerstat = it.stats.pools[pool].miners[worker];}} |
|||
{{ minerindex++; }} |
|||
<tr class="pure-table-odd" id="miner-{{=minerindex}}"> |
|||
<td>Miner #{{=minerindex}}</td> |
|||
<td>{{=Math.round(workerstat.currRoundShares * 100) / 100}}</td> |
|||
<td>{{? workerstat.shares > 0}} {{=Math.floor(10000 * workerstat.shares / (workerstat.shares + workerstat.invalidshares)) / 100}}% {{??}} 0% {{?}}</td> |
|||
<td>{{=workerstat.hashrateString}}</td> |
|||
</tr> |
|||
{{ } }} |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{{ } }} |
@ -1,100 +0,0 @@ |
|||
var docCookies = { |
|||
getItem: function (sKey) { |
|||
return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null; |
|||
}, |
|||
setItem: function (sKey, sValue, vEnd, sPath, sDomain, bSecure) { |
|||
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) { return false; } |
|||
var sExpires = ""; |
|||
if (vEnd) { |
|||
switch (vEnd.constructor) { |
|||
case Number: |
|||
sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd; |
|||
break; |
|||
case String: |
|||
sExpires = "; expires=" + vEnd; |
|||
break; |
|||
case Date: |
|||
sExpires = "; expires=" + vEnd.toUTCString(); |
|||
break; |
|||
} |
|||
} |
|||
document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : ""); |
|||
return true; |
|||
}, |
|||
removeItem: function (sKey, sPath, sDomain) { |
|||
if (!sKey || !this.hasItem(sKey)) { return false; } |
|||
document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + ( sDomain ? "; domain=" + sDomain : "") + ( sPath ? "; path=" + sPath : ""); |
|||
return true; |
|||
}, |
|||
hasItem: function (sKey) { |
|||
return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie); |
|||
} |
|||
}; |
|||
|
|||
var password = docCookies.getItem('password'); |
|||
|
|||
|
|||
function showLogin(){ |
|||
$('#adminCenter').hide(); |
|||
$('#passwordForm').show(); |
|||
} |
|||
|
|||
function showAdminCenter(){ |
|||
$('#passwordForm').hide(); |
|||
$('#adminCenter').show(); |
|||
} |
|||
|
|||
function tryLogin(){ |
|||
apiRequest('pools', {}, function(response){ |
|||
showAdminCenter(); |
|||
displayMenu(response.result) |
|||
}); |
|||
} |
|||
|
|||
function displayMenu(pools){ |
|||
$('#poolList').after(Object.keys(pools).map(function(poolName){ |
|||
return '<li class="poolMenuItem"><a href="#">' + poolName + '</a></li>'; |
|||
}).join('')); |
|||
} |
|||
|
|||
function apiRequest(func, data, callback){ |
|||
var httpRequest = new XMLHttpRequest(); |
|||
httpRequest.onreadystatechange = function(){ |
|||
if (httpRequest.readyState === 4 && httpRequest.responseText){ |
|||
if (httpRequest.status === 401){ |
|||
docCookies.removeItem('password'); |
|||
$('#password').val(''); |
|||
showLogin(); |
|||
alert('Incorrect Password'); |
|||
} |
|||
else{ |
|||
var response = JSON.parse(httpRequest.responseText); |
|||
callback(response); |
|||
} |
|||
} |
|||
}; |
|||
httpRequest.open('POST', '/api/admin/' + func); |
|||
data.password = password; |
|||
httpRequest.setRequestHeader('Content-Type', 'application/json'); |
|||
httpRequest.send(JSON.stringify(data)); |
|||
} |
|||
|
|||
if (password){ |
|||
tryLogin(); |
|||
} |
|||
else{ |
|||
showLogin(); |
|||
} |
|||
|
|||
$('#passwordForm').submit(function(event){ |
|||
event.preventDefault(); |
|||
password = $('#password').val(); |
|||
if (password){ |
|||
if ($('#remember').is(':checked')) |
|||
docCookies.setItem('password', password, Infinity); |
|||
else |
|||
docCookies.setItem('password', password); |
|||
tryLogin(); |
|||
} |
|||
return false; |
|||
}); |
Before Width: | Height: | Size: 413 B |
Before Width: | Height: | Size: 797 B |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 1.2 KiB |
@ -1,30 +0,0 @@ |
|||
$(function(){ |
|||
|
|||
var hotSwap = function(page, pushSate){ |
|||
if (pushSate) history.pushState(null, null, '/' + page); |
|||
$('.pure-menu-selected').removeClass('pure-menu-selected'); |
|||
$('a[href="/' + page + '"]').parent().addClass('pure-menu-selected'); |
|||
$.get("/get_page", {id: page}, function(data){ |
|||
$('main').html(data); |
|||
}, 'html') |
|||
}; |
|||
|
|||
$('.hot-swapper').click(function(event){ |
|||
if (event.which !== 1) return; |
|||
var pageId = $(this).attr('href').slice(1); |
|||
hotSwap(pageId, true); |
|||
event.preventDefault(); |
|||
return false; |
|||
}); |
|||
|
|||
window.addEventListener('load', function() { |
|||
setTimeout(function() { |
|||
window.addEventListener("popstate", function(e) { |
|||
hotSwap(location.pathname.slice(1)); |
|||
}); |
|||
}, 0); |
|||
}); |
|||
|
|||
window.statsSource = new EventSource("/api/live_stats"); |
|||
|
|||
}); |
@ -1,246 +0,0 @@ |
|||
var workerHashrateData; |
|||
var workerHashrateChart; |
|||
var workerHistoryMax = 160; |
|||
|
|||
var statData; |
|||
var totalHash; |
|||
var totalImmature; |
|||
var totalBal; |
|||
var totalPaid; |
|||
var totalShares; |
|||
|
|||
function getReadableHashRateString(hashrate){ |
|||
hashrate = (hashrate * 2); |
|||
if (hashrate < 1000000) { |
|||
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s'; |
|||
} |
|||
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]; |
|||
} |
|||
|
|||
function timeOfDayFormat(timestamp){ |
|||
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp)); |
|||
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1); |
|||
return dStr; |
|||
} |
|||
|
|||
function getWorkerNameFromAddress(w) { |
|||
var worker = w; |
|||
if (w.split(".").length > 1) { |
|||
worker = w.split(".")[1]; |
|||
if (worker == null || worker.length < 1) { |
|||
worker = "noname"; |
|||
} |
|||
} else { |
|||
worker = "noname"; |
|||
} |
|||
return worker; |
|||
} |
|||
|
|||
function buildChartData(){ |
|||
var workers = {}; |
|||
for (var w in statData.history) { |
|||
var worker = getWorkerNameFromAddress(w); |
|||
var a = workers[worker] = (workers[worker] || { |
|||
hashrate: [] |
|||
}); |
|||
for (var wh in statData.history[w]) { |
|||
a.hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); |
|||
} |
|||
if (a.hashrate.length > workerHistoryMax) { |
|||
workerHistoryMax = a.hashrate.length; |
|||
} |
|||
} |
|||
|
|||
var i=0; |
|||
workerHashrateData = []; |
|||
for (var worker in workers){ |
|||
workerHashrateData.push({ |
|||
key: worker, |
|||
disabled: (i > Math.min((_workerCount-1), 3)), |
|||
values: workers[worker].hashrate |
|||
}); |
|||
i++; |
|||
} |
|||
} |
|||
|
|||
function updateChartData(){ |
|||
var workers = {}; |
|||
for (var w in statData.history) { |
|||
var worker = getWorkerNameFromAddress(w); |
|||
// get a reference to lastest workerhistory
|
|||
for (var wh in statData.history[w]) { } |
|||
//var wh = statData.history[w][statData.history[w].length - 1];
|
|||
var foundWorker = false; |
|||
for (var i = 0; i < workerHashrateData.length; i++) { |
|||
if (workerHashrateData[i].key === worker) { |
|||
foundWorker = true; |
|||
if (workerHashrateData[i].values.length >= workerHistoryMax) { |
|||
workerHashrateData[i].values.shift(); |
|||
} |
|||
workerHashrateData[i].values.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); |
|||
break; |
|||
} |
|||
} |
|||
if (!foundWorker) { |
|||
var hashrate = []; |
|||
hashrate.push([statData.history[w][wh].time * 1000, statData.history[w][wh].hashrate]); |
|||
workerHashrateData.push({ |
|||
key: worker, |
|||
values: hashrate |
|||
}); |
|||
rebuildWorkerDisplay(); |
|||
return true; |
|||
} |
|||
} |
|||
triggerChartUpdates(); |
|||
return false; |
|||
} |
|||
|
|||
function calculateAverageHashrate(worker) { |
|||
var count = 0; |
|||
var total = 1; |
|||
var avg = 0; |
|||
for (var i = 0; i < workerHashrateData.length; i++) { |
|||
count = 0; |
|||
for (var ii = 0; ii < workerHashrateData[i].values.length; ii++) { |
|||
if (worker == null || workerHashrateData[i].key === worker) { |
|||
count++; |
|||
avg += parseFloat(workerHashrateData[i].values[ii][1]); |
|||
} |
|||
} |
|||
if (count > total) |
|||
total = count; |
|||
} |
|||
avg = avg / total; |
|||
return avg; |
|||
} |
|||
|
|||
function triggerChartUpdates(){ |
|||
workerHashrateChart.update(); |
|||
} |
|||
|
|||
function displayCharts() { |
|||
nv.addGraph(function() { |
|||
workerHashrateChart = nv.models.lineChart() |
|||
.margin({left: 80, right: 30}) |
|||
.x(function(d){ return d[0] }) |
|||
.y(function(d){ return d[1] }) |
|||
.useInteractiveGuideline(true); |
|||
|
|||
workerHashrateChart.xAxis.tickFormat(timeOfDayFormat); |
|||
|
|||
workerHashrateChart.yAxis.tickFormat(function(d){ |
|||
return getReadableHashRateString(d); |
|||
}); |
|||
d3.select('#workerHashrate').datum(workerHashrateData).call(workerHashrateChart); |
|||
return workerHashrateChart; |
|||
}); |
|||
} |
|||
|
|||
function updateStats() { |
|||
totalHash = statData.totalHash; |
|||
totalPaid = statData.paid; |
|||
totalBal = statData.balance; |
|||
totalImmature = statData.immature; |
|||
totalShares = statData.totalShares; |
|||
// do some calculations
|
|||
var _blocktime = 250; |
|||
var _networkHashRate = parseFloat(statData.networkSols) * 1.2; |
|||
var _myHashRate = (totalHash / 1000000) * 2; |
|||
var luckDays = ((_networkHashRate / _myHashRate * _blocktime) / (24 * 60 * 60)).toFixed(3); |
|||
// update miner stats
|
|||
$("#statsHashrate").text(getReadableHashRateString(totalHash)); |
|||
$("#statsHashrateAvg").text(getReadableHashRateString(calculateAverageHashrate(null))); |
|||
$("#statsLuckDays").text(luckDays); |
|||
$("#statsTotalImmature").text(totalImmature); |
|||
$("#statsTotalBal").text(totalBal); |
|||
$("#statsTotalPaid").text(totalPaid); |
|||
$("#statsTotalShares").text(totalShares.toFixed(2)); |
|||
} |
|||
function updateWorkerStats() { |
|||
// update worker stats
|
|||
var i=0; |
|||
for (var w in statData.workers) { i++; |
|||
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, ''); |
|||
var saneWorkerName = getWorkerNameFromAddress(w); |
|||
$("#statsHashrate"+htmlSafeWorkerName).text(getReadableHashRateString(statData.workers[w].hashrate)); |
|||
$("#statsHashrateAvg"+htmlSafeWorkerName).text(getReadableHashRateString(calculateAverageHashrate(saneWorkerName))); |
|||
$("#statsLuckDays"+htmlSafeWorkerName).text(statData.workers[w].luckDays); |
|||
$("#statsPaid"+htmlSafeWorkerName).text(statData.workers[w].paid); |
|||
$("#statsBalance"+htmlSafeWorkerName).text(statData.workers[w].balance); |
|||
$("#statsShares"+htmlSafeWorkerName).text(Math.round(statData.workers[w].currRoundShares * 100) / 100); |
|||
$("#statsDiff"+htmlSafeWorkerName).text(statData.workers[w].diff); |
|||
} |
|||
} |
|||
function addWorkerToDisplay(name, htmlSafeName, workerObj) { |
|||
var htmlToAdd = ""; |
|||
htmlToAdd = '<div class="boxStats" id="boxStatsLeft" style="float:left; margin: 9px; min-width: 260px;"><div class="boxStatsList">'; |
|||
if (htmlSafeName.indexOf("_") >= 0) { |
|||
htmlToAdd+= '<div class="boxLowerHeader">'+htmlSafeName.substr(htmlSafeName.indexOf("_")+1,htmlSafeName.length)+'</div>'; |
|||
} else { |
|||
htmlToAdd+= '<div class="boxLowerHeader">noname</div>'; |
|||
} |
|||
htmlToAdd+='<div><i class="fa fa-tachometer"></i> <span id="statsHashrate'+htmlSafeName+'">'+getReadableHashRateString(workerObj.hashrate)+'</span> (Now)</div>'; |
|||
htmlToAdd+='<div><i class="fa fa-tachometer"></i> <span id="statsHashrateAvg'+htmlSafeName+'">'+getReadableHashRateString(calculateAverageHashrate(name))+'</span> (Avg)</div>'; |
|||
htmlToAdd+='<div><i class="fa fa-shield"></i> <small>Diff:</small> <span id="statsDiff'+htmlSafeName+'">'+workerObj.diff+'</span></div>'; |
|||
htmlToAdd+='<div><i class="fa fa-cog"></i> <small>Shares:</small> <span id="statsShares'+htmlSafeName+'">'+(Math.round(workerObj.currRoundShares * 100) / 100)+'</span></div>'; |
|||
htmlToAdd+='<div><i class="fa fa-gavel"></i> <small>Luck <span id="statsLuckDays'+htmlSafeName+'">'+workerObj.luckDays+'</span> Days</small></div>'; |
|||
htmlToAdd+='<div><i class="fa fa-money"></i> <small>Bal: <span id="statsBalance'+htmlSafeName+'">'+workerObj.balance+'</span></small></div>'; |
|||
htmlToAdd+='<div><i class="fa fa-money"></i> <small>Paid: <span id="statsPaid'+htmlSafeName+'">'+workerObj.paid+'</span></small></div>'; |
|||
htmlToAdd+='</div></div></div>'; |
|||
$("#boxesWorkers").html($("#boxesWorkers").html()+htmlToAdd); |
|||
} |
|||
|
|||
function rebuildWorkerDisplay() { |
|||
$("#boxesWorkers").html(""); |
|||
var i=0; |
|||
for (var w in statData.workers) { i++; |
|||
var htmlSafeWorkerName = w.split('.').join('_').replace(/[^\w\s]/gi, ''); |
|||
var saneWorkerName = getWorkerNameFromAddress(w); |
|||
addWorkerToDisplay(saneWorkerName, htmlSafeWorkerName, statData.workers[w]); |
|||
} |
|||
} |
|||
|
|||
// resize chart on window resize
|
|||
nv.utils.windowResize(triggerChartUpdates); |
|||
|
|||
// grab initial stats
|
|||
$.getJSON('/api/worker_stats?'+_miner, function(data){ |
|||
statData = data; |
|||
for (var w in statData.workers) { _workerCount++; } |
|||
buildChartData(); |
|||
displayCharts(); |
|||
rebuildWorkerDisplay(); |
|||
updateStats(); |
|||
}); |
|||
|
|||
// live stat updates
|
|||
statsSource.addEventListener('message', function(e){ |
|||
// TODO, create miner_live_stats...
|
|||
// miner_live_stats will return the same josn except without the worker history
|
|||
// FOR NOW, use this to grab updated stats
|
|||
$.getJSON('/api/worker_stats?'+_miner, function(data){ |
|||
statData = data; |
|||
// check for missing workers
|
|||
var wc = 0; |
|||
var rebuilt = false; |
|||
// update worker stats
|
|||
for (var w in statData.workers) { wc++; } |
|||
// TODO, this isn't 100% fool proof!
|
|||
if (_workerCount != wc) { |
|||
if (_workerCount > wc) { |
|||
rebuildWorkerDisplay(); |
|||
rebuilt = true; |
|||
} |
|||
_workerCount = wc; |
|||
} |
|||
rebuilt = (rebuilt || updateChartData()); |
|||
updateStats(); |
|||
if (!rebuilt) { |
|||
updateWorkerStats(); |
|||
} |
|||
}); |
|||
}); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,143 +0,0 @@ |
|||
var poolHashrateData; |
|||
var poolHashrateChart; |
|||
|
|||
var statData; |
|||
var poolKeys; |
|||
|
|||
function buildChartData(){ |
|||
var pools = {}; |
|||
|
|||
poolKeys = []; |
|||
for (var i = 0; i < statData.length; i++){ |
|||
for (var pool in statData[i].pools){ |
|||
if (poolKeys.indexOf(pool) === -1) |
|||
poolKeys.push(pool); |
|||
} |
|||
} |
|||
|
|||
for (var i = 0; i < statData.length; i++) { |
|||
var time = statData[i].time * 1000; |
|||
for (var f = 0; f < poolKeys.length; f++){ |
|||
var pName = poolKeys[f]; |
|||
var a = pools[pName] = (pools[pName] || { |
|||
hashrate: [] |
|||
}); |
|||
if (pName in statData[i].pools){ |
|||
a.hashrate.push([time, statData[i].pools[pName].hashrate]); |
|||
} |
|||
else{ |
|||
a.hashrate.push([time, 0]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
poolHashrateData = []; |
|||
for (var pool in pools){ |
|||
poolHashrateData.push({ |
|||
key: pool, |
|||
values: pools[pool].hashrate |
|||
}); |
|||
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool))); |
|||
} |
|||
} |
|||
|
|||
function calculateAverageHashrate(pool) { |
|||
var count = 0; |
|||
var total = 1; |
|||
var avg = 0; |
|||
for (var i = 0; i < poolHashrateData.length; i++) { |
|||
count = 0; |
|||
for (var ii = 0; ii < poolHashrateData[i].values.length; ii++) { |
|||
if (pool == null || poolHashrateData[i].key === pool) { |
|||
count++; |
|||
avg += parseFloat(poolHashrateData[i].values[ii][1]); |
|||
} |
|||
} |
|||
if (count > total) |
|||
total = count; |
|||
} |
|||
avg = avg / total; |
|||
return avg; |
|||
} |
|||
|
|||
function getReadableHashRateString(hashrate){ |
|||
hashrate = (hashrate * 2); |
|||
if (hashrate < 1000000) { |
|||
return (Math.round(hashrate / 1000) / 1000 ).toFixed(2)+' Sol/s'; |
|||
} |
|||
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]; |
|||
} |
|||
|
|||
function timeOfDayFormat(timestamp){ |
|||
var dStr = d3.time.format('%I:%M %p')(new Date(timestamp)); |
|||
if (dStr.indexOf('0') === 0) dStr = dStr.slice(1); |
|||
return dStr; |
|||
} |
|||
|
|||
function displayCharts(){ |
|||
nv.addGraph(function() { |
|||
poolHashrateChart = nv.models.lineChart() |
|||
.margin({left: 80, right: 30}) |
|||
.x(function(d){ return d[0] }) |
|||
.y(function(d){ return d[1] }) |
|||
.useInteractiveGuideline(true); |
|||
|
|||
poolHashrateChart.xAxis.tickFormat(timeOfDayFormat); |
|||
|
|||
poolHashrateChart.yAxis.tickFormat(function(d){ |
|||
return getReadableHashRateString(d); |
|||
}); |
|||
|
|||
d3.select('#poolHashrate').datum(poolHashrateData).call(poolHashrateChart); |
|||
|
|||
return poolHashrateChart; |
|||
}); |
|||
} |
|||
|
|||
function triggerChartUpdates(){ |
|||
poolHashrateChart.update(); |
|||
} |
|||
|
|||
nv.utils.windowResize(triggerChartUpdates); |
|||
|
|||
$.getJSON('/api/pool_stats', function(data){ |
|||
statData = data; |
|||
buildChartData(); |
|||
displayCharts(); |
|||
}); |
|||
|
|||
statsSource.addEventListener('message', function(e){ |
|||
var stats = JSON.parse(e.data); |
|||
statData.push(stats); |
|||
|
|||
var newPoolAdded = (function(){ |
|||
for (var p in stats.pools){ |
|||
if (poolKeys.indexOf(p) === -1) |
|||
return true; |
|||
} |
|||
return false; |
|||
})(); |
|||
|
|||
if (newPoolAdded || Object.keys(stats.pools).length > poolKeys.length){ |
|||
buildChartData(); |
|||
displayCharts(); |
|||
} |
|||
else { |
|||
var time = stats.time * 1000; |
|||
for (var f = 0; f < poolKeys.length; f++) { |
|||
var pool = poolKeys[f]; |
|||
for (var i = 0; i < poolHashrateData.length; i++) { |
|||
if (poolHashrateData[i].key === pool) { |
|||
poolHashrateData[i].values.shift(); |
|||
poolHashrateData[i].values.push([time, pool in stats.pools ? stats.pools[pool].hashrate : 0]); |
|||
$('#statsHashrateAvg' + pool).text(getReadableHashRateString(calculateAverageHashrate(pool))); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
triggerChartUpdates(); |
|||
} |
|||
}); |
@ -1,68 +0,0 @@ |
|||
html, button, input, select, textarea, .pure-g [class *= "pure-u"], .pure-g-r [class *= "pure-u"]{ |
|||
font-family: 'Open Sans', sans-serif; |
|||
} |
|||
|
|||
html{ |
|||
background: #2d2d2d; |
|||
overflow-y: scroll; |
|||
} |
|||
|
|||
body{ |
|||
display: flex; |
|||
flex-direction: column; |
|||
max-width: 1160px; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
header > .home-menu{ |
|||
background: inherit !important; |
|||
height: 54px; |
|||
display: flex; |
|||
} |
|||
|
|||
header > .home-menu > a.pure-menu-heading, header > .home-menu > ul, header > .home-menu > ul > li{ |
|||
display: flex !important; |
|||
align-items: center; |
|||
justify-content: center; |
|||
line-height: normal !important; |
|||
} |
|||
|
|||
header > .home-menu > a.pure-menu-heading{ |
|||
color: white; |
|||
font-size: 1.5em; |
|||
} |
|||
|
|||
header > .home-menu > ul > li > a{ |
|||
color: #ced4d9; |
|||
} |
|||
|
|||
header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li > a:focus{ |
|||
background: inherit !important; |
|||
} |
|||
|
|||
header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li.pure-menu-selected > a{ |
|||
color: white; |
|||
} |
|||
|
|||
main{ |
|||
background-color: #ebf4fa; |
|||
position: relative; |
|||
} |
|||
|
|||
footer{ |
|||
text-align: center; |
|||
color: #b3b3b3; |
|||
text-decoration: none; |
|||
font-size: 0.8em; |
|||
padding: 15px; |
|||
line-height: 24px; |
|||
} |
|||
|
|||
footer a{ |
|||
color: #fff; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
footer iframe{ |
|||
vertical-align: middle; |
|||
} |
Loading…
Reference in new issue