Compare commits
28 Commits
Author | SHA1 | Date |
---|---|---|
fekt | 27231cf425 | 2 months ago |
fekt | 3bd9f86878 | 2 months ago |
fekt | aea5609ec1 | 5 months ago |
fekt | ce4c39cc5f | 5 months ago |
fekt | 769f075961 | 5 months ago |
fekt | 917a5921bd | 5 months ago |
Duke Leto | 323dd92254 | 2 years ago |
Duke Leto | 4e5efd1a48 | 2 years ago |
fekt | 6006ac6abf | 2 years ago |
Duke Leto | 522fdcaa01 | 2 years ago |
fekt | 6669c653af | 2 years ago |
fekt | 30752ce857 | 2 years ago |
fekt | 717fcf0008 | 2 years ago |
fekt | d4e2647219 | 2 years ago |
fekt | 6715b7db04 | 2 years ago |
fekt | 0fd9a3f070 | 2 years ago |
fekt | 25c4620972 | 2 years ago |
fekt | e256f2b8ce | 2 years ago |
fekt | df18d715c9 | 2 years ago |
fekt | 60f5f4240d | 2 years ago |
jahway603 | 4aa0e40ee4 | 3 years ago |
jahway603 | badaf05704 | 3 years ago |
jahway603 | b920d04d31 | 3 years ago |
jahway603 | 25e648201e | 3 years ago |
jahway603 | 27626e1b01 | 3 years ago |
jahway603 | 90f12e3dbe | 3 years ago |
jahway603 | 0a02d54d85 | 3 years ago |
Duke Leto | 6129d88531 | 3 years ago |
@ -1,8 +1,11 @@ |
|||
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/ |
|||
website/hush/static/nvd3-old.js |
|||
libs/paymentProcessor-orig.js |
|||
|
@ -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 |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,34 @@ |
|||
# Configuration notes |
|||
|
|||
## Table of Contents |
|||
* [Setup Config](#setup-config) |
|||
* [Setup your coin file](#setup-your-coin-file) |
|||
* [Setup your pool config](#setup-your-pool-config) |
|||
* [Notes](#notes) |
|||
* [License](#license) |
|||
|
|||
## Setup Config |
|||
|
|||
1. Open your new [config.json](config_example.json) and edit the following: |
|||
1. Change `"forks": 1` to `"forks: auto`. |
|||
1. Change `"stratumHost": "stratum.hushpool.io"` to your server. |
|||
|
|||
## Setup your coin file |
|||
|
|||
1. Change directory to coins. |
|||
1. You will see [HUSH](coins/hush.json) there as an example. |
|||
1. I then recommend you change the "hush.json example by |
|||
[reading and learning from this repo](https://github.com/zone117x/node-stratum-pool#module-usage) to configure your own coin's file. |
|||
|
|||
## Next, setup your pool |
|||
|
|||
1. Change directory to the pool_configs directory. |
|||
1. You will see the [hushsolo example](pool_configs/hushsolo.json) there, which you can use to start from. |
|||
1. If you want to setup more than a solo pool, then I suggest learning what each |
|||
option does [from this link](https://github.com/zone117x/node-open-mining-portal) |
|||
as well as [checking these config out](https://github.com/z-classic/z-nomp/tree/master/pool_configs) to do so. |
|||
|
|||
## License |
|||
|
|||
Released under the GNU General Public License v2 |
|||
http://www.gnu.org/licenses/gpl-2.0.html |
@ -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,74 @@ |
|||
{ |
|||
"enabled":false, |
|||
"coin":"hush.json", |
|||
"address":"t-address-#1", |
|||
"zAddress":"pool-z-address", |
|||
"tAddress":"same-as-t-address-#1", |
|||
"invalidAddress":"z-address-ValidAddressOfYourChoosingThatsNotThePoolZAddress", |
|||
"pubkey":"pubkey-of-t-address-#1 (./hush-cli validateaddress t-address-#1)", |
|||
"walletInterval":1, |
|||
"rewardRecipients":{ |
|||
"pool-operators-z-address-with-1.5-percent":1.5, |
|||
"2nd-pool-operators-z-address-with-0.5-percent":0.5, |
|||
"can-remove-these-if-only-solo-mining":0.1 |
|||
}, |
|||
"tlsOptions":{ |
|||
"enabled":false, |
|||
"serverKey":"", |
|||
"serverCert":"", |
|||
"ca":"" |
|||
}, |
|||
"paymentProcessing":{ |
|||
"enabled":false, |
|||
"minConf":10, |
|||
"paymentMode":"prop", |
|||
"_comment_paymentMode":"prop, pplnt", |
|||
"paymentInterval":3600, |
|||
"_comment_paymentInterval":"Interval in seconds to check and perform payments.", |
|||
"minimumPayment":1, |
|||
"maxBlocksPerPayment":3, |
|||
"daemon":{ |
|||
"host":"127.0.0.1", |
|||
"port":18031, |
|||
"user":"username-set-in-HUSH3.conf", |
|||
"password":"password-set-in-HUSH3.conf" |
|||
} |
|||
}, |
|||
"ports":{ |
|||
"3333":{ |
|||
"tls":false, |
|||
"diff":0.5, |
|||
"varDiff":{ |
|||
"minDiff":0.04, |
|||
"maxDiff":272, |
|||
"targetTime":15, |
|||
"retargetTime":60, |
|||
"variancePercent":30 |
|||
} |
|||
} |
|||
}, |
|||
"daemons":[ |
|||
{ |
|||
"host":"127.0.0.1", |
|||
"port":18031, |
|||
"user":"username-set-in-HUSH3.conf", |
|||
"password":"password-set-in-HUSH3.conf" |
|||
} |
|||
], |
|||
"p2p":{ |
|||
"enabled":false, |
|||
"host":"127.0.0.1", |
|||
"port":18030, |
|||
"disableTransactions":true |
|||
}, |
|||
"mposMode":{ |
|||
"enabled":false, |
|||
"host":"127.0.0.1", |
|||
"port":3306, |
|||
"user":"me", |
|||
"password":"mypass", |
|||
"database":"hush", |
|||
"checkPassword":true, |
|||
"autoCreateWorker":false |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
{ |
|||
"enabled": false, |
|||
"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 |
@ -0,0 +1,11 @@ |
|||
<div style="margin: 18px;" align="left"> |
|||
<p style="color:white" align="center">API - The API is work in progress and is subject to change during development.</p> |
|||
<div> |
|||
<a href="/api/stats" class="mainlink">/api/stats</a> - global pool stats<br/> |
|||
<a href="/api/blocks" class="mainlink">/api/blocks</a> - global block stats<br/> |
|||
<a href="/api/pool_stats" class="mainlink">/api/pool_stats</a> - historical stats<br/> |
|||
<a href="/api/payments" class="mainlink">/api/payments</a> - payment history<br/> |
|||
<a href="/api/worker_stats?zaddr" class="mainlink">/api/worker_stats?zaddr</a> - historical time per pool json <br/> |
|||
<a href="/api/live_stats" class="mainlink">/api/live_stats</a> - live stats (websocket)<br/> |
|||
</div> |
|||
</div> |
@ -0,0 +1,48 @@ |
|||
<div style="text-align:center"> |
|||
<h2 style="color:#FFFFFF">ASIC Miner configuration</h2> |
|||
</div> |
|||
<div id="holder"> |
|||
<div id="coinInfoRows"> |
|||
<div id="coinInfoRowKeys" style="text-align:right"> |
|||
<div>Username:</div> |
|||
<div>Password:</div> |
|||
<div>GPU/Medium Diff Port <small style="color:#999999">(var diff 0.5-68)</small>:</div> |
|||
<div>ASIC/Hi Diff Port <small style="color:#999999">(var diff 68-272)</small>:</div> |
|||
<div>Extra Hi Diff Port <small style="color:#999999">(var diff 272+)</small>:</div> |
|||
</div> |
|||
<div id="coinInfoRowValues"> |
|||
<div>your hush wallet z-address</div> |
|||
<div>anything</div> |
|||
<div>stratum+tcp://{{=it.portalConfig.website.stratumHost}}:3332</div> |
|||
<div>stratum+tcp://{{=it.portalConfig.website.stratumHost}}:3333</div> |
|||
<div>stratum+tcp://{{=it.portalConfig.website.stratumHost}}:3334</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<font color="white">Choose the appropriate difficulty port based on your rigs.<br/>Port 3333 is recommended for most hobbyists mining with ASICs.<br/>Other ports are for low/medium difficulty mining or extra high difficulty.<br/><br/> |
|||
<strong>Do not mine to an exchange address!</strong><br/><br/> |
|||
Download a Hush wallet and create a z-address to mine to. Hush wallet addresses start with a <strong>zs1</strong> |
|||
Mining to any other addresses and invalid addresses will result in wasting electricity and no funds received for your work. |
|||
</font> |
|||
<table> |
|||
<tbody |
|||
<tr> |
|||
<td colspan="2" width="50%"><a href="https://git.hush.is/hush/SilentDragonLite/releases" target="_blank">Lite Wallet</a></td> |
|||
<td colspan="2" width="50%"><a href="https://git.hush.is/hush/SilentDragon/releases" target="_blank">Full Node Wallet</a></td> |
|||
</tr> |
|||
</tbody></table><br/> |
|||
|
|||
<div id="coinInfoRows"> |
|||
<div id="coinInfoRowKeys"> |
|||
<div>Minimum Payout:</div> |
|||
<div>Payout Frequency:</div> |
|||
<div>Pool Fee:</div> |
|||
</div> |
|||
<div id="coinInfoRowValues"> |
|||
<div>30 HUSH</div> |
|||
<div>Every 4 Hours</div> |
|||
<div>0.5%</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
@ -0,0 +1,154 @@ |
|||
<style> |
|||
body{ |
|||
color:#B3B3B3; |
|||
} |
|||
#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; |
|||
} |
|||
|
|||
</style> |
|||
|
|||
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }} |
|||
<div style="text-align:center"> |
|||
<h1 style="color:#FFFFFF">hushpool.is - Mining Pool For Hush</h1> |
|||
<h2>Hush - Speak and Transact Freely</h2> |
|||
<h3>Private Cryptocurrency and Messenger using Zero Knowledge Mathematics</h3> |
|||
<pre> &&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&& &&&&&& &&&& &&&&&& &&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& &&&&& |
|||
&&&&& &&&& && &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&& |
|||
&&&&& &&&& &&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&&& &&&&& |
|||
&&&&& &&&&&& &&&&&& &&&&& |
|||
&&& &&&&&& && && &&&&&& &&& |
|||
&&&&&& &&&&&& &&&&&& |
|||
&&&& &&&&&& &&&& |
|||
&&&&&& |
|||
&&&& |
|||
<!-- thanks onryō --> |
|||
</pre> |
|||
</div> |
|||
<table> |
|||
<tbody><tr> |
|||
<td><a href="https://hush.land">Why Hush</a></td> |
|||
<td><a href="https://hush.land/hushchat.html">HushChat</a></td> |
|||
<td><a href="https://hushpool.is">HushPool</a></td> |
|||
<td><a href="https://git.hush.is/onryo/hush-box">HushBox</a></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://explorer.hush.land">Explorer</a></td> |
|||
<td><a href="https://git.hush.is/hush">Gitea</a></td> |
|||
<td><a href="https://hush.land/faq.html">F.A.Q</a></td> |
|||
<td><a href="https://hush.land/team.html">Team</a></td> |
|||
</tr> |
|||
</tbody></table> |
|||
<br/> |
|||
|
|||
|
|||
<div id="coinInfoRows"> |
|||
<div id="coinInfoRowKeys"> |
|||
<div>Minimum Payout:</div> |
|||
<div>Payout Frequency:</div> |
|||
<div>Pool Fee:</div> |
|||
</div> |
|||
<div id="coinInfoRowValues"> |
|||
<div>30 HUSH</div> |
|||
<div>Every 4 Hours</div> |
|||
<div>0.5%</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
<div class="pure-g-r" id="boxesLower"> |
|||
{{ for(var pool in it.stats.pools) { }} |
|||
<div class="pure-u-1-2"> |
|||
<div class="boxStats" id="boxStatsLeft"> |
|||
<div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Pool Stats</div> |
|||
<div class="boxStatsList"> |
|||
<div> |
|||
<div><i class="fa fa-users"></i><span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</div> |
|||
<div><i class="fa fa-rocket"></i><span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</div> |
|||
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</div> |
|||
<div><i class="fa fa-tachometer"></i><span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</div> |
|||
<div><i class="fa fa-gavel"></i>Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="pure-u-1-2"> |
|||
<div class="boxStats" id="boxStatsRight"> |
|||
<div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Network Stats</div> |
|||
<div class="boxStatsList"> |
|||
<div> |
|||
<div><i class="fa fa-bars" aria-hidden="true"></i><small>Block Height:</small> <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></div> |
|||
<div><i class="fa fa-tachometer"></i><small>Network Hash/s:</small> <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></div> |
|||
<div><i class="fa fa-unlock-alt" aria-hidden="true"></i><small>Difficulty:</small> <span id="statsNetworkDiff{{=pool}}">{{=it.stats.pools[pool].poolStats.networkDiff}}</span></div> |
|||
<div><i class="fa fa-users"></i><small>Node Connections:</small> <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{{ } }} |
|||
</div> |
|||
|
|||
|
|||
|
|||
<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> |
|||
|
@ -0,0 +1,54 @@ |
|||
<style> |
|||
#topCharts{ |
|||
padding-left: 18px; |
|||
padding-right: 18px; |
|||
padding-top: 18px; |
|||
padding-bottom: 0px; |
|||
} |
|||
#topCharts > div > div > svg{ |
|||
display: block; |
|||
height: 280px; |
|||
} |
|||
.chartWrapper{ |
|||
padding: 10px; |
|||
margin: 18px; |
|||
} |
|||
.chartLabel{ |
|||
font-size: 1.2em; |
|||
text-align: center; |
|||
padding: 4px; |
|||
} |
|||
.chartHolder{ |
|||
padding:10px; |
|||
height:300px; |
|||
} |
|||
td{border:0px !important} |
|||
|
|||
</style> |
|||
<div style="padding-top:18px"> |
|||
<div class="chartWrapper"> |
|||
<div style="margin-right: 9px; color:white">{{=String(it.stats.address).split(".")[0]}}</div> |
|||
<div align="center"> |
|||
<small><i class="fa fa-tachometer"></i> <span id="statsHashrateAvg">...</span> (Avg)</small> |
|||
<small><i class="fa fa-tachometer"></i> <span id="statsHashrate">...</span> (Now)</small> |
|||
<small><i class="fa fa-gavel"></i> Luck <span id="statsLuckDays">...</span> Days</small> |
|||
</div> |
|||
|
|||
<div class="chartHolder"><svg id="workerHashrate" style="padding:10px"/></div> |
|||
<div style="color:white"> |
|||
<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> |
@ -0,0 +1,48 @@ |
|||
<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" style="padding-top:18px"> |
|||
<thead> |
|||
<tr style="color:white"> |
|||
<th>Transaction</th> |
|||
<th>Time</th> |
|||
</tr> |
|||
</thead> |
|||
{{ for(var p in it.stats.pools[pool].payments) { }} |
|||
<tr> |
|||
<td style="max-width: 315px; word-wrap: break-word;"> |
|||
{{if (String(it.stats.pools[pool].name) == 'hush') { }} |
|||
<a href="https://explorer.hush.is/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank" rel="noopener noreferrer" class="mainlink">{{=it.stats.pools[pool].payments[p].txid}}</a> |
|||
{{ } else { }} |
|||
{{=it.stats.pools[pool].payments[p].blocks}} |
|||
{{ } }} |
|||
</td> |
|||
<td>{{=readableDate(it.stats.pools[pool].payments[p].time)}}</td> |
|||
</tr> |
|||
{{ } }} |
|||
</table> |
|||
</div> |
|||
{{ } }} |
@ -0,0 +1,174 @@ |
|||
<style> |
|||
#topCharts{ |
|||
padding: 18px; |
|||
} |
|||
#topCharts > div > div > svg{ |
|||
display: block; |
|||
height: 280px; |
|||
} |
|||
.chartWrapper{ |
|||
background-color: #0d0d0d; |
|||
border: 1px solid #1a1a1a; |
|||
padding: 15px; |
|||
color: #999999; |
|||
} |
|||
.chartLabel{ |
|||
font-size: 1.2em; |
|||
text-align: center; |
|||
padding: 4px; |
|||
color:#FFF; |
|||
} |
|||
#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; |
|||
} |
|||
.nvtooltip table td.legend-color-guide div { |
|||
background-color:#FF0000 !important; |
|||
} |
|||
|
|||
td{border:0px !important} |
|||
|
|||
</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">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Pool Stats</div> |
|||
<div class="boxStatsList"> |
|||
<div> |
|||
<div><i class="fa fa-users"></i><span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners</div> |
|||
<div><i class="fa fa-rocket"></i><span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers</div> |
|||
<div><i class="fa fa-tachometer"></i><span id="statsHashrate{{=pool}}">{{=it.stats.pools[pool].hashrateString}}</span> (Now)</div> |
|||
<div><i class="fa fa-tachometer"></i><span id="statsHashrateAvg{{=pool}}">...</span> (Avg)</div> |
|||
<div><i class="fa fa-gavel"></i>Luck <span id="statsLuckDays{{=pool}}">{{=it.stats.pools[pool].luckDays}}</span> Days</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="pure-u-1-2"> |
|||
<div class="boxStats" id="boxStatsRight"> |
|||
<div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Network Stats</div> |
|||
<div class="boxStatsList"> |
|||
<div> |
|||
<div><i class="fa fa-bars" aria-hidden="true"></i><small>Block Height:</small> <span id="statsNetworkBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.networkBlocks}}</span></div> |
|||
<div><i class="fa fa-tachometer"></i><small>Network Hash/s:</small> <span id="statsNetworkSols{{=pool}}">{{=it.stats.pools[pool].poolStats.networkSolsString}}</span></div> |
|||
<div><i class="fa fa-unlock-alt" aria-hidden="true"></i><small>Difficulty:</small> <span id="statsNetworkDiff{{=pool}}">{{=it.stats.pools[pool].poolStats.networkDiff}}</span></div> |
|||
<div><i class="fa fa-users"></i><small>Node Connections:</small> <span id="statsNetworkConnections{{=pool}}">{{=it.stats.pools[pool].poolStats.networkConnections}}</span></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
{{ } }} |
|||
</div> |
|||
|
|||
{{ for(var pool in it.stats.pools) { }} |
|||
<div class="pure-g-r" id="boxesLower"> |
|||
<div class="pure-u-1-1"> |
|||
<div class="boxStats" id="boxStatsRight"> |
|||
<div class="boxLowerHeader">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Blocks Found |
|||
</div> |
|||
|
|||
<div class="boxStatsList" style="margin-top: 9px;"> |
|||
{{ 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: #000000; 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 for payment processor to review {{} 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{{ } }}"> |
|||
<div style="float:left"> |
|||
<i class="fa fa-bars"></i> |
|||
<small>Block:</small> |
|||
<a href="https://explorer.hush.is/block/{{=block[2]}}" target="_blank" class="mainlink">{{=block[2]}}</a> |
|||
|
|||
{{if (block[4] != null) { }} |
|||
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span></div> |
|||
{{ } }} |
|||
{{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: white;"><small>*NEW*</small></span> |
|||
{{ } else { }} |
|||
<span style="float:right; color: red;"><small>*IMMATURE*</small></span> |
|||
{{ } }} |
|||
{{ } else { }} |
|||
<span style="float:right; color: white;"><small>*NEW*</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: #000000; min-width:600px;"> |
|||
<div style="float:left"><i class="fa fa-bars"></i> |
|||
<small>Block:</small> |
|||
<a href="https://explorer.hush.is/block/{{=block[2]}}" target="_blank" class="mainlink">{{=block[2]}}</a> |
|||
|
|||
{{if (block[4] != null) { }} |
|||
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span></div> |
|||
{{ } }} |
|||
<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> |
@ -0,0 +1,54 @@ |
|||
<script type="text/javascript"> |
|||
$(document).ready(function(){ |
|||
$("#btnSearch").click(function(){ |
|||
window.location = "https://hushpool.is/workers/" + $('#zaddr').val(); |
|||
}); |
|||
}); |
|||
</script> |
|||
{{ function capitalizeFirstLetter(t){return t.charAt(0).toUpperCase()+t.slice(1)} }} |
|||
{{ var i=0; for(var pool in it.stats.pools) { }} |
|||
<div style="padding-top:18px"> |
|||
<div> |
|||
<div> |
|||
<span style="float:right; margin-bottom: 8px;"> |
|||
<small><span style="color:white">Miner Lookup:</span> |
|||
<input type="text" id="zaddr" class="form-control input-lg" style="width:200px" placeholder="z-address"> |
|||
<span class="input-group-btn"> |
|||
<button id="btnSearch" class="btn btn-default btn-lg" type="button">Search</button> |
|||
</span> |
|||
</small> |
|||
</span> |
|||
<span style="color:white">{{=capitalizeFirstLetter(it.stats.pools[pool].name)}} Miners</span> |
|||
<div> |
|||
<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> |
|||
<div style="color:white; padding:25px"><strong>Miner addresses are hidden for extreme privacy.</strong><br/><strong>Miner stats:</strong> https://hushpool.is/workers/z-address</div> |
|||
<div> |
|||
<table> |
|||
<thead> |
|||
<tr style="color:white"> |
|||
<th>Miner</th> |
|||
<th>Shares</th> |
|||
<th>Efficiency</th> |
|||
<th>Hashrate</th> |
|||
</tr> |
|||
</thead> |
|||
{{ var minerindex = 0; }} |
|||
{{ for(var worker in it.stats.pools[pool].miners) { }} |
|||
{{ minerindex++; }} |
|||
{{var workerstat = it.stats.pools[pool].miners[worker];}} |
|||
<tr> |
|||
<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> |
|||
{{ } }} |
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 413 B |
After Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 797 B After Width: | Height: | Size: 797 B |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,250 @@ |
|||
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, bottom:30, top:30}) |
|||
.height(300) |
|||
.showLegend(false) |
|||
.x(function(d){ return d[0] }) |
|||
.y(function(d){ return d[1] }) |
|||
.useInteractiveGuideline(true) |
|||
.color(["red","tomato", "Aquamarine", "greenyellow", "cyan", "darkseagreen", "deeppink", "fuchsia", "orange", "wheat", "hotpink", "indianred", "lightcoral", "lightpink", "lightsalmon", "lime"]); |
|||
|
|||
workerHashrateChart.xAxis.tickFormat(timeOfDayFormat); |
|||
|
|||
workerHashrateChart.yAxis.tickFormat(function(d){ |
|||
return getReadableHashRateString(d); |
|||
}); |
|||
d3.select('#workerHashrate').datum(workerHashrateData).call(workerHashrateChart); |
|||
return workerHashrateChart; |
|||
}); |
|||
} |
|||
|
|||
function updateStats() { |
|||
|
|||
console.log(JSON.stringify(statData)); |
|||
|
|||
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></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(); |
|||
} |
|||
}); |
|||
}); |
@ -0,0 +1,461 @@ |
|||
.chartWrap { |
|||
margin: 0; |
|||
padding: 0; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.nvtooltip { |
|||
position: absolute; |
|||
z-index: 10000; |
|||
background-color: #000; |
|||
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 { |
|||
} |
|||
.nvtooltip h3 { |
|||
margin: 0; |
|||
padding: 4px 14px; |
|||
line-height: 18px; |
|||
font-weight: 400; |
|||
background-color: rgba(247, 247, 247, 0.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 { |
|||
|
|||
} |
|||
.nvtooltip table td.legend-color-guide div { |
|||
width: 8px; |
|||
height: 8px; |
|||
vertical-align: middle; |
|||
background-color:#FF0000; |
|||
color:#FF0000; |
|||
} |
|||
.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: 0.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: 0.75; |
|||
shape-rendering: crispEdges; |
|||
} |
|||
.nvd3 .nv-axis path.domain { |
|||
stroke-opacity: 0.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: 0.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: 0.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: 0.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: 0.5 !important; |
|||
stroke-opacity: 0.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: 0.95 !important; |
|||
stroke-opacity: 0.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: 0.5; |
|||
} |
|||
.nvd3 .nv-scatter .nv-point.hover { |
|||
fill-opacity: 1; |
|||
} |
|||
.nvd3.nv-stackedarea path.nv-area { |
|||
fill-opacity: 0.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: 0.9; |
|||
} |
|||
.nvd3.nv-stackedarea .nv-groups .nv-point { |
|||
stroke-opacity: 0; |
|||
fill-opacity: 0; |
|||
} |
|||
.nvd3.nv-linePlusBar .nv-bar rect { |
|||
fill-opacity: 0.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: 0.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: 0.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: 0.4; |
|||
} |
|||
.nvd3.nv-bullet .nv-range:hover { |
|||
fill-opacity: 0.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: 0.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: 0.4; |
|||
fill: #fff; |
|||
fill-opacity: 0.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: 0.4; |
|||
shape-rendering: crispEdges; |
|||
} |
|||
.nvd3 .foreground path { |
|||
fill: none; |
|||
stroke: #4682b4; |
|||
stroke-opacity: 0.7; |
|||
} |
|||
.nvd3 .brush .extent { |
|||
fill-opacity: 0.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 { |
|||
|
|||
} |
@ -0,0 +1 @@ |
|||
html{background:#101010;overflow-y:scroll}body{display:flex;flex-direction:column;max-width:1160px;margin:0 auto;color:#fff}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:#fff;font-size:1.5em}header>.home-menu>ul>li>a{color:#ced4d9}header>.home-menu>ul>li>a:focus,header>.home-menu>ul>li>a:hover{background:inherit!important}header>.home-menu>ul>li.pure-menu-selected>a,header>.home-menu>ul>li>a:hover{color:#fff}main{background-color:#101010;position:relative}footer{text-align:center;color:#b3b3b3;text-decoration:none;font-size:.8em;padding:15px;line-height:24px}footer a{color:#fff;text-decoration:none}footer iframe{vertical-align:middle}body{background-color:#101010;max-width:820px;margin:auto;color:grey;text-align:center}table{width:100%;border-collapse:collapse;margin-top:15px}td{border:1px solid #1a1a1a;font-size:16px;padding:.5em}td:hover{background-color:#1a1a1a}pre{background-color:#0d0d0d;border:1px solid #1a1a1a;font-size:6px;padding:15px;color:#e6e6e6}details{cursor:pointer;background-color:#0d0d0d;text-align:left;margin-top:15px;padding:.5em;border:1px solid #1a1a1a;font-size:13px;word-wrap:break-word}summary{outline:0;padding:.4em}.blockt{border:1px solid #1a1a1a;padding:.15em;background-color:#0d0d0d;margin-top:15px;text-align:left;font-size:13px;word-wrap:break-word}.blockt p{padding-left:.7em;padding-right:.7em}.button:link{float:right;font-size:10px}.mainlink:link{text-decoration:dotted underline;text-underline-position:under}.mainlink:hover{text-decoration:none;color:#595959}.links{margin:15px;font-size:13px}a:link{color:#b3b3b3;text-decoration:none}a:visited{color:#b3b3b3}a:hover{color:#b3b3b3}*{scrollbar-width:thin;scrollbar-color:#333333 #101010}::-webkit-scrollbar{width:6px}::-webkit-scrollbar-thumb{background:#333}@font-face{font-family:'Ubuntu Mono';src:url('UbuntuMono.ttf') format('truetype')}.pure-g-r [class*=pure-u]{font-family:'Ubuntu Mono'}button,html,input,select,svg text,textarea{font-family:'Ubuntu Mono'}text{fill:#B3B3B3}#boxStatsLeft{background-color:#0d0d0d;border:1px solid #1a1a1a;padding:15px;color:#999}#boxStatsRight{background-color:#0d0d0d;border:1px solid #1a1a1a;padding:15px;color:#999}.boxStatsList{display:flex;flex-flow:row wrap;justify-content:space-around;opacity:.77;margin-bottom:5px;flex:1 1 auto}.boxStatsList i.fa{height:15px;width:33px;text-align:center}.boxStatsList>div{padding:5px 20px}.boxStatsList>div>div{padding:3px}.nv-group.nv-series-0,.nv-series:first-of-type .nv-legend-symbol{stroke-opacity:1;fill-opacity:0.5;fill:#FF0000!important;stroke:#FF0000!important}#coinInfo{display:flex;flex-direction:column;color:#fff;width:750px;min-height:400px;top:50px;left:50%;margin-left:-375px;position:absolute}#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:20px;background-color:#0d0d0d;border:1px solid #1a1a1a;padding:15px;color:#999}#coinInfoRows>div{display:flex;flex-direction:column;justify-content:center}#coinInfoRows>div>div{padding:3px}#coinInfoRowKeys{font-weight:700;padding-right:30px;color:#fff}#coinInfoRowKeys .coinInfoSubtle{font-weight:400}#coinInfoClose{position:absolute;font-size:3em;top:0;right:0;width:60px;height:60px;text-align:center;color:#fff;text-decoration:none}#coinInfoClose:hover{color:#50f0e3}.standardBox{background-color:#0d0d0d;border:1px solid #1a1a1a;padding:15px;color:#999}.boxLowerHeader{color:#fff}#boxesLower>div{display:flex}#boxesLower>div>div{flex:1 1 auto;display:flex;flex-direction:column}.boxLowerHeader{font-size:1.3em;margin:0 0 5px 10px}.mainlink:link { text-decoration: dotted underline; text-underline-position: under }.nvtooltip{color: #FFF;background-color: #000;} |
@ -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,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,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,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(); |
|||
} |
|||
}); |
|||
}); |
@ -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; |
|||
} |