Compare commits

...

28 Commits

Author SHA1 Message Date
fekt 27231cf425 Rename to zaddr 2 months ago
fekt 3bd9f86878 Fixing broken JS 2 months ago
fekt aea5609ec1 Updating to our own node-stratum-pool 5 months ago
fekt ce4c39cc5f Removing ac_founders 5 months ago
fekt 769f075961 Update 'README.md' 5 months ago
fekt 917a5921bd Bump bignum version 5 months ago
Duke Leto 323dd92254 Update 'README.md' 2 years ago
Duke Leto 4e5efd1a48 Merge pull request 'hushpool.is changes and JS updates' (#4) from fekt/hnomp:master into master 2 years ago
fekt 6006ac6abf hushpool.is changes and JS updates 2 years ago
Duke Leto 522fdcaa01 Merge pull request 'dev-fekt' (#3) from fekt/hnomp:dev-fekt into master 2 years ago
fekt 6669c653af Sample configs and other stuff from hushpool.is 2 years ago
fekt 30752ce857 Merge branch 'master' of https://git.hush.is/fekt/hnomp 2 years ago
fekt 717fcf0008 Updated paymentProcessor.js 2 years ago
fekt d4e2647219 Update 'website/hush/pages/stats.html' 2 years ago
fekt 6715b7db04 website and some cleanup 2 years ago
fekt 0fd9a3f070 Update 'README.md' 2 years ago
fekt 25c4620972 invalidAddress should be z-addr 2 years ago
fekt e256f2b8ce added invalidAddress back 2 years ago
fekt df18d715c9 Add 'pool_configs/hush.json' 2 years ago
fekt 60f5f4240d Update 'coins/hush.json' 2 years ago
jahway603 4aa0e40ee4 Merge pull request 'more hush love' (#2) from dev into master 3 years ago
jahway603 badaf05704 Merge branch 'master' into dev 3 years ago
jahway603 b920d04d31 minor README update 3 years ago
jahway603 25e648201e some updates 3 years ago
jahway603 27626e1b01 Merge pull request 'updated for Hush' (#1) from dev into master 3 years ago
jahway603 90f12e3dbe changed hushsolo to default disabled 3 years ago
jahway603 0a02d54d85 bringing the hush puppy in 3 years ago
Duke Leto 6129d88531 Update 'README.md' 3 years ago
  1. 9
      .gitignore
  2. 20
      .vscode/launch.json
  3. 34
      CONFIGURE.md
  4. 19
      Dockerfile
  5. 11
      Old/CHANGELOG.md
  6. 7
      Old/LICENSE
  7. 164
      Old/README.md
  8. 88
      README.md
  9. 8
      coins/hush.json
  10. 2
      config_example.json
  11. 14
      docker-compose.yml
  12. 16
      gencfg.sh
  13. 2
      libs/api.js
  14. 8
      libs/paymentProcessor.js
  15. 4
      libs/stats.js
  16. 2
      libs/website.js
  17. 7
      package.json
  18. 74
      pool_configs/hush.json
  19. 36
      pool_configs/hushsolo.json
  20. 6
      website/default/index.html
  21. 8
      website/default/pages/home.html
  22. BIN
      website/default/static/hush-logo-horizontal-01.png
  23. BIN
      website/default/static/hushfavicon.ico
  24. 39
      website/hush/index.html
  25. 2
      website/hush/key.html
  26. 0
      website/hush/pages/admin.html
  27. 11
      website/hush/pages/api.html
  28. 48
      website/hush/pages/getting_started.html
  29. 154
      website/hush/pages/home.html
  30. 54
      website/hush/pages/miner_stats.html
  31. 0
      website/hush/pages/mining_key.html
  32. 48
      website/hush/pages/payments.html
  33. 174
      website/hush/pages/stats.html
  34. 36
      website/hush/pages/tbs.html
  35. 54
      website/hush/pages/workers.html
  36. BIN
      website/hush/static/UbuntuMono.ttf
  37. 0
      website/hush/static/admin.js
  38. 0
      website/hush/static/favicon.png
  39. BIN
      website/hush/static/hush-logo-horizontal-01.png
  40. BIN
      website/hush/static/hushfavicon.ico
  41. 0
      website/hush/static/kmdfavicon.svg
  42. 0
      website/hush/static/komodo-logo-horizontal-01.png
  43. 0
      website/hush/static/logo.svg
  44. 0
      website/hush/static/main.js
  45. 250
      website/hush/static/miner_stats.js
  46. 461
      website/hush/static/nvd3.css
  47. 8
      website/hush/static/nvd3.js
  48. 6
      website/hush/static/stats.js
  49. 1
      website/hush/static/style.css
  50. 11
      website/minerpond/pages/api.html
  51. 325
      website/minerpond/pages/getting_started.html
  52. 134
      website/minerpond/pages/home.html
  53. 105
      website/minerpond/pages/miner_stats.html
  54. 94
      website/minerpond/pages/payments.html
  55. 234
      website/minerpond/pages/stats.html
  56. 96
      website/minerpond/pages/workers.html
  57. 246
      website/minerpond/static/miner_stats.js
  58. 1
      website/minerpond/static/nvd3.css
  59. 6
      website/minerpond/static/nvd3.js
  60. 68
      website/minerpond/static/style.css

9
.gitignore

@ -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

20
.vscode/launch.json

@ -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
}
]
}

34
CONFIGURE.md

@ -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

19
Dockerfile

@ -1,5 +1,8 @@
FROM ubuntu:18.04
LABEL maintainer="webworker01"
LABEL maintainer="jahway603"
# added this to fix strange error about /tmp
RUN chmod 1777 /tmp
RUN apt-get update -y && \
apt-get install -y gcc g++ make libboost-dev libboost-system-dev libsodium-dev sudo curl git iputils-ping
@ -7,17 +10,17 @@ RUN apt-get update -y && \
RUN curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - && \
apt-get install -y nodejs
RUN useradd knomp
COPY . /home/knomp/knomp
RUN useradd hnomp
COPY . /home/hnomp/hnomp
RUN echo "knomp ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \
RUN echo "hnomp ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \
chmod 0440 /etc/sudoers.d/user && \
chown -R knomp:knomp /home/knomp
chown -R hnomp:hnomp /home/hnomp
RUN cd /home/knomp/knomp && npm install
RUN cd /home/hnomp/hnomp && npm install
USER knomp
WORKDIR /home/knomp/knomp
USER hnomp
WORKDIR /home/hnomp/hnomp
EXPOSE 8080

11
Old/CHANGELOG.md

@ -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

7
Old/LICENSE

@ -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.

164
Old/README.md

@ -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.

88
README.md

@ -1,35 +1,40 @@
# Mining stratum for Hush and Hush assetchains.
# Mining stratum for Hush and Hush Smart Chains
## Table of Contents
* [Differences between this and Z-NOMP](#differences-between-this-and-z-nomp)
* [Using Docker (easy)](#using-docker-easy)
* [Bare metal installation](#bare-metal-installation)
* [Continued Installation on either setup](#continued-installation-on-either-setup)
* [More Config Information](#more-config-information)
* [More Resources](#more-resources)
* [License](#license)
## Differences between this and Z-NOMP
* This is meant for Hush mining
* Founders, Treasury, and other ZEC/ZEN specific stuff is removed
* This is meant for Hush and Hush smartchain mining
* ZEC/ZEN specific stuff is removed
## Using Docker (easy)
This method sets up 2 docker containers, one with knomp and one with redis.
This method sets up 2 docker containers, one with hnomp and one with redis.
It will directly use your host system's network so you can connect to the coin daemon without opening up RPC beyond 127.0.0.1.
The ports it listens on must not be in use, this includes 8080 for the website, 6379 for redis and any ports you open for stratums (default is 3333).
It is currently untested, but config.json has the ports as line items, so perhaps they can be changed in that file.
### Requirements
[Install Docker](https://docs.docker.com/engine/install/) and [docker-compose](https://docs.docker.com/compose/install/)
### Docker Install
```
git clone https://git.hush.is/jahway603/knomp.git
cd ./knomp
git clone https://git.hush.is/hush/hnomp.git
cd ./hnomp
cp config_example.json config.json
```
Setup your [config.json](./config_example.json), `./coins/` and `./pool_configs/` in here, then:
* **Next follow this [new config document](CONFIGURE.md) and then come back to this one & start to get Docker up and running.**
Then run the following command in the hnomp directory.
```
docker-compose up &
```
@ -39,7 +44,7 @@ docker-compose up &
docker-compose down
```
### Docker rebuild and update
### To rebuild and update Docker version
```
docker-compose down
docker rmi knomp_knomp
@ -55,62 +60,60 @@ docker-compose up &
* Redis (see https://redis.io/topics/quickstart for details)
### Upgrade
Please be sure to backup your `./coins` and `./pool_configs` directory before upgrading
**Please be sure to backup your `./coins` and `./pool_configs` directory before upgrading**
Kill your running pool (CTRL-C)
```shell
cd knomp
cd hnomp
git pull
npm install
npm start
```
## Continued Installation on either setup
**Note: This setup from here-on applies to both Docker and bare-metal installations.**
### Install Daemon
Some initial setup
```shell
# The following packages are needed to build both Hush and this stratum:
sudo apt-get update
sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib autoconf libtool ncurses-dev unzip git python python-zmq zlib1g-dev wget libcurl4-openssl-dev bsdmainutils automake curl libboost-dev libboost-system-dev libsodium-dev jq redis-server nano -y
```
Now, let's build Hush
```shell
git clone https://git.hush.is/hush/hush3
cd hush3
./build.sh -j$(nproc)
```
Now, let's build the Hush daemon. In order to not duplicate documentation, please follow the instructions in the [hush3 repository here](https://git.hush.is/hush/hush3/src/branch/master/INSTALL.md) before proceeding.
Now, let's run the assets. This will start ALL of the assets might take a day or so to sync, depending on system speed/network connection.
Now, start up the Hush deamon which should start downloading its blockchain. This might take a couple of hours to a day to sync, depending on system speed/network connection.
_If you are setting up a single chain to mine and/or don't know what pubkey is, skip this step and use the startup params for the hushd daemon as provided by the individual coin's team._
```shell
cd ~/hush3/src
./assetchains
./smartchains
```
### Install Pool
Once all the chains you want on your pool have synced up we can configure the stratum.
Once all the blockchains you want on your pool have synced up we can configure the stratum.
We need node and npm installed
We need node and npm installed to start and recommend you install them via your Linux OS's package manager.
```shell
cd ~
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
```
Now, let's build our stratum and run it. This will install the pool and configure it for all the assetchains on your system automatically. It must be run from the same user as the coin deamons were launched, as it pulls the rpcuser/pass from the conf file in the home directory.
Now, let's build our stratum and run it. This will install the pool and configure it for all the smartchains on your system automatically. It must be run from the same user as the coin deamons were launched, as it pulls the rpcuser/pass from the conf file in the home directory.
```shell
git clone https://git.hush.is/jahway603/knomp.git
cd ./knomp
git clone https://git.hush.is/hush/hnomp.git
cd ./hnomp
npm install
cp config_example.json config.json (and configure it)
nano gencfg.sh
```
Edit line 3 in so that it has your own HUSH based address, CTRL-X then Y to save and exit
Edit line 7 to your own HUSH based address...
We need to generate the coins files (coin daemon must be running!): `gencfg.sh <coin name>`
You can run just gencfg.sh with no coin name to use the assetchains.json in hush3/src directory for all coins. Make sure you edit the template with the correct values you want before running the config generator.
You can run just gencfg.sh with no coin name to use the smartchains.json in hush3/src directory for all coins. Make sure you edit the template with the correct values you want before running the config generator.
Finally we are ready to start the pool software
@ -120,9 +123,27 @@ npm start
If all went well the program should start without error and you should be able to browse to your pool website on your server via port 8080.
### Dependencies/Install Issues
**Note:** This was last tested and successfully runs with node 10.24.1 and npm 6.14.12. If you have issues with install, try these specific versions. It is recommended to use NVM to easily install and change versions.
#### Installing NVM on Ubuntu
```
sudo apt install curl
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
```
#### Install and use node 10.24.1 (should install npm 6.14.12 by default)
```
nvm install 10.24.1
```
#### Clearing cache and deleting node_modules for rebuilding
```
sudo npm cache clean --force
sudo rm -r node_modules
```
## More Config Information
### Disable Coinbase Mode
This mode uses -pubkey to tell the daemon where the coinbase should be sent, and uses the daemons coinbase transaction rather then having the pool create the coinabse transaction. This enables special coinbase transactions, such as ac_founders and ac_script or new modes with CC vouts in the coinbase not yet created, it will work with all coins, except Full Z support described below.
This mode uses -pubkey to tell the daemon where the coinbase should be sent, and uses the daemons coinbase transaction rather then having the pool create the coinbase transaction. This enables special coinbase transactions, such as ac_founders and ac_script or new modes with CC vouts in the coinbase not yet created, it will work with all coins, except Full Z support described below.
To enable it, change the value in the `./coins/*.json` to `"disablecb" : true`
@ -174,13 +195,20 @@ In pool_config:
"maxBlocksPerPayment": 20,
```
### More Resources
[Further info on config](https://github.com/zone117x/node-open-mining-portal#2-configuration) and some [sample configs](https://github.com/z-classic/z-nomp)
## More Resources
1. [This resource has further info on configs](https://github.com/zone117x/node-open-mining-portal) and was a great help.
1. [This repository has sample configs](https://github.com/z-classic/z-nomp/tree/master/pool_configs) is an old Z-NOMP with pool configurations, so these were helpful to see other options.
1. Reference [the hush.json here](coins/hush.json) to configure your coin file, but [refer to this repo](https://github.com/zone117x/node-stratum-pool#module-usage) to help learn more about coin files in general.
## License
Forked from ComputerGenie repo (deleted)
Released under the GNU General Public License v2
http://www.gnu.org/licenses/gpl-2.0.html
_Forked from [z-classic/z-nomp](https://github.com/z-classic/z-nomp) which is incorrectly licensed under MIT License - see [zone117x/node-open-mining-portal](https://github.com/zone117x/node-open-mining-portal)_
## Copyright
2016-2022 The Hush Developers

8
coins/hush.json

@ -5,6 +5,8 @@
"peerMagic": "f9eee48d",
"txfee": 0.0001,
"privateChain": true,
"burnFees": true,
"sapling": true
}
"sapling": true,
"overwintered": true,
"requireShielding": true,
"disablecb": true
}

2
config_example.json

@ -37,7 +37,7 @@
"enabled": true,
"host": "0.0.0.0",
"port": 8080,
"stratumHost": "stratum.piratepool.io",
"stratumHost": "stratum.hushpool.io",
"template": "default",
"stats": {
"updateInterval": 30,

14
docker-compose.yml

@ -1,18 +1,18 @@
version: '3'
services:
knomp:
container_name: knomp
hnomp:
container_name: hnomp
network_mode: host
build:
context: .
dockerfile: Dockerfile
volumes:
- ./config.json:/home/knomp/knomp/config.json
- ./coins:/home/knomp/knomp/coins
- ./libs:/home/knomp/knomp/libs
- ./pool_configs:/home/knomp/knomp/pool_configs
- ./website:/home/knomp/knomp/website
- ./config.json:/home/hnomp/hnomp/config.json
- ./coins:/home/hnomp/hnomp/coins
- ./libs:/home/hnomp/hnomp/libs
- ./pool_configs:/home/hnomp/hnomp/pool_configs
- ./website:/home/hnomp/hnomp/website
# ports:
# - 8080:8080
# - 3333:3333

16
gencfg.sh

@ -1,17 +1,21 @@
#!/bin/bash
# Copyright (c) 2021 The Hush Developers
# Distributed under the GPLv2 software license, see the accompanying
# file LICENSE or https://www.gnu.org/licenses/gpl-3.0.en.html
#
# Put the address to mine to here
walletaddress=
#Change to path of komodo-cli here
komodoexec=~/komodo/src/komodo-cli
# Change to path of hush-cli here
hushexec=/usr/bin/hush-cli
# Any coins you would like to skip go here
declare -a skip=("BEER" "PIZZA")
declare -a skip=("BEER" "PIZZA" "DANK")
# Stratum port to start with
stratumport=3030
cli="komodo-cli"
cli="hush-cli"
coinsdir=./coins
poolconfigdir=./pool_configs
coinstpl=coins.template
@ -41,7 +45,7 @@ fi
listassetchains () {
if [[ $specificchain = "0" ]]; then
~/komodo/src/listassetchains
~/hush3/src/listassetchains
else
echo $specificchain
fi
@ -65,7 +69,7 @@ listassetchains | while read chain; do
magicrev=$(echo ${magic:6:2}${magic:4:2}${magic:2:2}${magic:0:2})
p2pport=$(echo $getinfo | jq '.p2pport')
thisconf=$(<~/.komodo/$chain/$chain.conf)
thisconf=$(<~/.hush/$chain/$chain.conf)
rpcuser=$(echo $thisconf | grep -Po "rpcuser=(\S*)" | sed 's/rpcuser=//')
rpcpass=$(echo $thisconf | grep -Po "rpcpassword=(\S*)" | sed 's/rpcpassword=//')

2
libs/api.js

@ -151,4 +151,4 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
};
*/
};
};

8
libs/paymentProcessor.js

@ -290,8 +290,8 @@ function SetupForPool(logger, poolOptions, setupFinished) {
}
var amount = satoshisToCoins(tBalance - sendingTXFeeSats);
var params = [poolOptions.address, [{'address': poolOptions.zAddress, 'amount': amount}]];
daemon.cmd('z_sendmany', params,
var params = [poolOptions.address, poolOptions.zAddress, 0.00001, 0];
daemon.cmd('z_shieldcoinbase', params,
function (result) {
//Check if payments failed because wallet doesn't have enough coins to pay for tx fees
if (!result || result.error || result[0].error || !result[0].response) {
@ -300,7 +300,7 @@ function SetupForPool(logger, poolOptions, setupFinished) {
callback(true);
}
else {
var opid = (result.response || result[0].response);
var opid = result[4];
opidCount++;
opids.push(opid);
logger.special(logSystem, logComponent, 'Shield balance ' + amount + ' ' + opid);
@ -969,7 +969,7 @@ function SetupForPool(logger, poolOptions, setupFinished) {
logger.error(logSystem, logComponent, 'Error checking pool balance before processing payments.');
return callback(true);
} else if (tBalance < totalOwed) {
logger.error(logSystem, logComponent, 'Insufficient [' + listunspenttype + '] funds ('+satoshisToCoins(tBalance) + ') to process payments (' + satoshisToCoins(totalOwed)+'); possibly waiting for txs.');
logger.error(logSystem, logComponent, 'Insufficient [' + listunspenttype + '] funds ('+satoshisToCoins(tBalance) + ') in ('+ poolOptions.zAddress + ') to process payments (' + satoshisToCoins(totalOwed)+'); possibly waiting for txs.');
performPayment = false;
} else if (tBalance > totalOwed) {
performPayment = true;

4
libs/stats.js

@ -344,7 +344,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
balances.push({
worker:String(w),
balance:workers[w].balance,
paid:workers[w].paid,
//paid:workers[w].paid,
immature:workers[w].immature
});
}
@ -425,7 +425,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
validShares: replies[i + 2] ? (replies[i + 2].validShares || 0) : 0,
validBlocks: replies[i + 2] ? (replies[i + 2].validBlocks || 0) : 0,
invalidShares: replies[i + 2] ? (replies[i + 2].invalidShares || 0) : 0,
totalPaid: replies[i + 2] ? (replies[i + 2].totalPaid || 0) : 0,
//totalPaid: replies[i + 2] ? (replies[i + 2].totalPaid || 0) : 0,
networkBlocks: replies[i + 2] ? (replies[i + 2].networkBlocks || 0) : 0,
networkSols: replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0,
networkSolsString: getReadableNetworkHashRateString(replies[i + 2] ? (replies[i + 2].networkSols || 0) : 0),

2
libs/website.js

@ -38,7 +38,7 @@ module.exports = function(logger){
'home.html': '',
'getting_started.html': 'getting_started',
'stats.html': 'stats',
'tbs.html': 'tbs',
// 'tbs.html': 'tbs',
'workers.html': 'workers',
'api.html': 'api',
// 'admin.html': 'admin',

7
package.json

@ -18,7 +18,8 @@
"contributors": [
"z-classic",
"ComputerGenie",
"webworker01"
"webworker01",
"fekt"
],
"main": "init.js",
"bin": {
@ -30,7 +31,7 @@
},
"dependencies": {
"async": "^2.6.3",
"bignum": "0.13.0",
"bignum": "0.13.1",
"body-parser": "1.18.3",
"colors": "1.3.2",
"compression": "^1.7.4",
@ -45,7 +46,7 @@
"nonce": "1.0.4",
"redis": "2.8.0",
"request": "^2.88.0",
"stratum-pool": "git+https://github.com/webworker01/node-stratum-pool.git"
"stratum-pool": "git+https://git.hush.is/fekt/node-stratum-pool.git"
},
"engines": {
"node": ">=8.11"

74
pool_configs/hush.json

@ -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
}
}

36
pool_configs/hushsolo.json

@ -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 }
}

6
website/default/index.html

@ -4,7 +4,7 @@
<head>
<meta charset="utf-8">
<link rel="shortcut icon" type="image/png" href="/static/kmdfavicon.svg"/>
<link rel="shortcut icon" type="image/png" href="/static/hushfavicon.ico"/>
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
@ -21,7 +21,7 @@
<script src="/static/main.js"></script>
<link rel="stylesheet" href="/static/style.css">
<title>knomp</title>
<title>hnomp</title>
</head>
@ -79,7 +79,7 @@
<footer>
&lt;3 🐸 &middot; <a href="https://github.com/webworker01/knomp" target="_blank">knomp on Github</a>
&lt;3 🐸 &middot; <a href="https://git.hush.is/hush/hnomp" target="_blank">hnomp on our own Gitea</a>
</footer>
</body>

8
website/default/pages/home.html

@ -74,11 +74,11 @@
</style>
<div class="pure-g-r" id="boxWelcome">
<img src="/static/komodo-logo-horizontal-01.png" style="margin: 0 auto; height:150px;">
<img src="/static/hush-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;">KNOMP</div>
<div style="text-align:center; margin-bottom:10px;"">Low 0.5% fee! Min payouts of 1!</div>
<div style="font-size: 2em; text-align:center; margin-bottom:10px;">HNOMP</div>
<div style="text-align:center; margin-bottom:10px;"">Low 1.5% fee! Min payouts of 1!</div>
</div>
</div>
@ -129,4 +129,4 @@
}
});
});
</script>
</script>

BIN
website/default/static/hush-logo-horizontal-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
website/default/static/hushfavicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

39
website/minerpond/index.html → website/hush/index.html

@ -4,24 +4,21 @@
<head>
<meta charset="utf-8">
<link rel="shortcut icon" type="image/png" href="/static/kmdfavicon.svg"/>
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
<link rel="shortcut icon" type="image/png" href="/static/hushfavicon.ico"/>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.0.3/css/font-awesome.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/3.0.1/normalize.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/pure/0.4.2/pure-min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.5/d3.min.js"></script>
<script src="/static/nvd3.js"></script>
<link rel="stylesheet" href="/static/nvd3.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.6/nv.d3.min.js"></script>
<script src="/static/main.js"></script>
<link rel="stylesheet" href="/static/style.css">
<title>minerpond - komodo assetchains mining pool</title>
<title>hushpool.is - Mining Pool For Hush - Speak & Transact Freely</title>
</head>
@ -42,13 +39,7 @@
<li class="{{? it.selected === 'stats' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/stats">
<i class="fa fa-bar-chart-o"></i>&nbsp;
Graph Stats
</a>
</li>
<li class="{{? it.selected === 'tbs' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/tbs">
<i class="fa fa-table"></i>&nbsp;
Tab Stats
Pool Stats
</a>
</li>
<li class="{{? it.selected === 'workers' }}pure-menu-selected{{?}}">
@ -63,12 +54,6 @@
Payments
</a>
</li>
<li class="{{? it.selected === 'api' }}pure-menu-selected{{?}}">
<a class="hot-swapper" href="/api">
<i class="fa fa-code"></i>&nbsp;
API
</a>
</li>
</ul>
</div>
</header>
@ -79,7 +64,13 @@
<footer>
&lt;3 <a href="https://webworker.sh" target="_blank">🐸</a> &middot; <a href="https://github.com/webworker01/knomp" target="_blank">knomp on Github</a> &middot; <a href="https://discord.gg/QaPwxKB" target="_blank" rel="nofollow noreferrer noopener">Discord Chat</a>
<div class="links">
<a href="https://hush.is/matrix"><span style="color: #262626">[</span> matrix <span style="color: #262626">]</span></a>
<a href="https://hush.is/mastodon"><span style="color: #262626">[</span> mastodon <span style="color: #262626">]</span></a>
<a href="https://videos.hush.is"><span style="color: #262626">[</span> peertube <span style="color: #262626">]</span></a>
<a href="https://t.me/hush_main"><span style="color: #262626">[</span> telegram <span style="color: #262626">]</span></a>
</div>
&lt;3&#128056; &middot; <a href="https://git.hush.is/hush/hnomp" target="_blank">hnomp on our own Gitea</a>
</footer>
</body>

2
website/minerpond/key.html → website/hush/key.html

@ -104,7 +104,7 @@
<button id="returnKeyStart">Go back to <i>Key input or generation</i></button>
<div class="roundedWrapper">
<div class="heading warning">NO NOT LOSE THIS PRIVATE KEY. Any coins mined using this public key can
<div class="heading warning">DO NOT LOSE THIS PRIVATE KEY. Any coins mined using this public key can
only be controlled with this private key.</div>
<div class="heading">Private key: <br><input type="text" width="550px" readonly id="privateKeyHex"></div>

0
website/minerpond/pages/admin.html → website/hush/pages/admin.html

11
website/hush/pages/api.html

@ -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>

48
website/hush/pages/getting_started.html

@ -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>

154
website/hush/pages/home.html

@ -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> &amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp; &amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp; &amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp; &amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;&amp;&amp; &amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;&amp;&amp;
&amp;&amp;&amp;&amp;
<!-- 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>

54
website/hush/pages/miner_stats.html

@ -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
website/minerpond/pages/mining_key.html → website/hush/pages/mining_key.html

48
website/hush/pages/payments.html

@ -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>
{{ } }}

174
website/hush/pages/stats.html

@ -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 &nbsp;&nbsp;
</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>

36
website/minerpond/pages/tbs.html → website/hush/pages/tbs.html

@ -1,37 +1,3 @@
<style>
#topCharts {
padding: 18px;
}
#topCharts > div > div > svg {
display: block;
height: 280px;
}
.chartWrapper {
border: solid 1px #c7c7c7;
border-radius: 5px;
padding: 5px;
margin-bottom: 18px;
}
.chartLabel {
font-size: 1.2em;
text-align: center;
padding: 4px;
}
.chartHolder {
}
table {
width: 100%;
}
</style>
<table class="pure-table">
<thead>
<tr>
@ -48,7 +14,7 @@
</tr>
</thead>
{{ for(var pool in it.stats.pools) { }}
<tr class="pure-table-odd">
<tr>
<td>{{=it.stats.pools[pool].name}}</td>
<td>{{=it.stats.pools[pool].algorithm}}</td>
<td>{{=Object.keys(it.stats.pools[pool].workers).length}}</td>

54
website/hush/pages/workers.html

@ -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 &nbsp;&nbsp;
<i class="fa fa-rocket"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers &nbsp;&nbsp;
<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>
{{ } }}

BIN
website/hush/static/UbuntuMono.ttf

Binary file not shown.

0
website/minerpond/static/admin.js → website/hush/static/admin.js

0
website/minerpond/static/favicon.png → website/hush/static/favicon.png

Before

Width:  |  Height:  |  Size: 413 B

After

Width:  |  Height:  |  Size: 413 B

BIN
website/hush/static/hush-logo-horizontal-01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
website/hush/static/hushfavicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

0
website/minerpond/static/kmdfavicon.svg → website/hush/static/kmdfavicon.svg

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 797 B

0
website/minerpond/static/komodo-logo-horizontal-01.png → website/hush/static/komodo-logo-horizontal-01.png

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

0
website/minerpond/static/logo.svg → website/hush/static/logo.svg

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

0
website/minerpond/static/main.js → website/hush/static/main.js

250
website/hush/static/miner_stats.js

@ -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();
}
});
});

461
website/hush/static/nvd3.css

@ -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 {
}

8
website/hush/static/nvd3.js

File diff suppressed because one or more lines are too long

6
website/minerpond/static/stats.js → website/hush/static/stats.js

@ -4,6 +4,8 @@ var poolHashrateChart;
var statData;
var poolKeys;
nv.utils.windowResize(triggerChartUpdates);
function buildChartData(){
var pools = {};
@ -81,6 +83,7 @@ function displayCharts(){
nv.addGraph(function() {
poolHashrateChart = nv.models.lineChart()
.margin({left: 80, right: 30})
.showLegend(false)
.x(function(d){ return d[0] })
.y(function(d){ return d[1] })
.useInteractiveGuideline(true);
@ -101,7 +104,6 @@ function triggerChartUpdates(){
poolHashrateChart.update();
}
nv.utils.windowResize(triggerChartUpdates);
$.getJSON('/api/pool_stats', function(data){
statData = data;
@ -140,4 +142,4 @@ statsSource.addEventListener('message', function(e){
}
triggerChartUpdates();
}
});
});

1
website/hush/static/style.css

@ -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;}

11
website/minerpond/pages/api.html

@ -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>

325
website/minerpond/pages/getting_started.html

@ -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, '&quot;');
}}
<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, '&quot;');
}}
<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>

134
website/minerpond/pages/home.html

@ -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>

105
website/minerpond/pages/miner_stats.html

@ -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>

94
website/minerpond/pages/payments.html

@ -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>
{{ } }}

234
website/minerpond/pages/stats.html

@ -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 &nbsp;&nbsp;
<span style="float:right;"><small>
<i class="fa fa-bars"></i> <span id="statsValidBlocks{{=pool}}">{{=it.stats.pools[pool].poolStats.validBlocks}}</span> Blocks &nbsp;&nbsp;
<i class="fa fa-money"></i> Paid: <span id="statsTotalPaid{{=pool}}">{{=(parseFloat(it.stats.pools[pool].poolStats.totalPaid)).toFixed(8)}}</span> {{=it.stats.pools[pool].symbol}}</small>&nbsp;&nbsp;</span>
</div>
<div class="boxStatsList" style="margin-top: 9px;">
<!--<div id="{{=it.stats.pools[pool].name}}NewBlocks"></div>-->
{{ for(var b in it.stats.pools[pool].pending.blocks) { }}
{{ var block = it.stats.pools[pool].pending.blocks[b].split(":"); }}
<div style="margin-bottom: 9px; background-color: #eeeeee; min-width:600px;" 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>

96
website/minerpond/pages/workers.html

@ -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 &nbsp;&nbsp;
<small><i class="fa fa-users"></i> <span id="statsMiners{{=pool}}">{{=it.stats.pools[pool].minerCount}}</span> Miners &nbsp;&nbsp;
<i class="fa fa-rocket"></i> <span id="statsWorkers{{=pool}}">{{=it.stats.pools[pool].workerCount}}</span> Workers &nbsp;&nbsp;
<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>
{{ } }}

246
website/minerpond/static/miner_stats.js

@ -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
website/minerpond/static/nvd3.css

File diff suppressed because one or more lines are too long

6
website/minerpond/static/nvd3.js

File diff suppressed because one or more lines are too long

68
website/minerpond/static/style.css

@ -1,68 +0,0 @@
html, button, input, select, textarea, .pure-g [class *= "pure-u"], .pure-g-r [class *= "pure-u"]{
font-family: 'Open Sans', sans-serif;
}
html{
background: #2d2d2d;
overflow-y: scroll;
}
body{
display: flex;
flex-direction: column;
max-width: 1160px;
margin: 0 auto;
}
header > .home-menu{
background: inherit !important;
height: 54px;
display: flex;
}
header > .home-menu > a.pure-menu-heading, header > .home-menu > ul, header > .home-menu > ul > li{
display: flex !important;
align-items: center;
justify-content: center;
line-height: normal !important;
}
header > .home-menu > a.pure-menu-heading{
color: white;
font-size: 1.5em;
}
header > .home-menu > ul > li > a{
color: #ced4d9;
}
header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li > a:focus{
background: inherit !important;
}
header > .home-menu > ul > li > a:hover, header > .home-menu > ul > li.pure-menu-selected > a{
color: white;
}
main{
background-color: #ebf4fa;
position: relative;
}
footer{
text-align: center;
color: #b3b3b3;
text-decoration: none;
font-size: 0.8em;
padding: 15px;
line-height: 24px;
}
footer a{
color: #fff;
text-decoration: none;
}
footer iframe{
vertical-align: middle;
}
Loading…
Cancel
Save