Compare commits

...

157 Commits

Author SHA1 Message Date
sennevb d49e9b4635
Merge pull request #265 from OleksandrBlack/patch-1
Add pool https://lucky-mining.com.ua/ <-- Ukraine
2018-03-31 08:46:41 +02:00
sennevb 0ebab3196c
Merge pull request #314 from crutched/master
PPLNT fix for multiple instances
2018-03-29 21:21:22 +02:00
Konstantin Crutched Anikin ed76b45f4b PPLNT fix for multiple instances. 2018-03-24 10:53:54 +07:00
OleksandrBlack cd9a1a2807
Add pool https://lucky-mining.com.ua/ <-- Ukraine
vot.lucky-mining.com.ua
zcl.lucky-mining.com.ua
zen.lucky-mining.com.ua
hush.lucky-mining.com.ua
btg.lucky-mining.com.ua
2018-01-09 19:33:01 +02:00
sennevb 53e9fdb28a
Merge pull request #259 from kalmare/xss_patch
Fixed Vulnerable of Cross Site Scripting
2018-01-06 22:37:53 +01:00
sennevb 621181ce69
Merge pull request #263 from hellcatz/payment_fix
Update paymentProcessor.js
2018-01-06 22:37:30 +01:00
hellcatz 0dd13bec9d
Update paymentProcessor.js
Fixes Issue
round.confirmations = parseInt((tx.result.confirmations || 0));
^
TypeError: Cannot read property 'confirmations' of null
2018-01-06 13:35:22 -08:00
kalmare 8481e3df5f Fixed Vulnerable of Cross Site Scripting 2017-12-28 18:17:39 +09:00
sennevb e1eba6d88f Merge pull request #197 from madbuda/livestats
Buffer live_stats for compression
2017-10-24 06:12:18 +02:00
sennevb af74e65f05 Merge branch 'master' into livestats 2017-10-24 06:12:07 +02:00
sennevb 1bccbebbf2 Update api.js 2017-10-24 06:06:46 +02:00
sennevb 289600de24 compression 2017-10-22 19:21:41 +02:00
Larry Ludlow cdce1a36a0 Update api.js 2017-09-10 09:02:52 -04:00
Larry Ludlow 677b367004 buffer for compression
allow sending chunks of data prior to end
2017-09-10 08:53:39 -04:00
Larry Ludlow a8cd7ba9e0 Merge pull request #8 from z-classic/master
merge upstream
2017-09-10 08:45:29 -04:00
sennevb ff0e1f6f32 Merge pull request #195 from hellcatz/immature
Immature Balance Tracking
2017-09-05 15:42:23 +02:00
hellcatz 3f30f01a9f Update api.js
From https://github.com/z-classic/z-nomp/pull/174/files
2017-09-04 19:56:01 -07:00
hellcatz f9cdef7a72 Update website.js 2017-09-04 15:30:01 -07:00
hellcatz 9a4497323b Update shareProcessor.js 2017-09-04 15:24:43 -07:00
hellcatz f192dd39c4 Update poolWorker.js 2017-09-04 15:16:44 -07:00
hellcatz 7233c9b726 Update paymentProcessor.js
Include balances owed in total owed checks.
2017-09-03 17:05:48 -07:00
hellcatz 8d463f5c37 Update paymentProcessor.js
Fixes for immature balance tracking.
Treat unpaid blocks as immature, until they are ready for payment.
Moved paymentsUpdate to final redis step in waterfall.
Misc improvements to payments waterfall.
2017-09-03 15:19:20 -07:00
hellcatz 81bba13224 Update api.html 2017-09-03 14:35:52 -07:00
hellcatz c826e4d8f3 Update miner_stats.js 2017-09-02 11:04:20 -07:00
hellcatz 5891af3a2e Update miner_stats.html 2017-09-02 11:02:52 -07:00
hellcatz d8a9ec59a4 Update paymentProcessor.js
Update recommended minimums.
Cache market stats every 5 minutes, do not use payment interval.
Changes to confirmation tracking and payments waterfall.
Add immature balance calculations and tracking.
2017-09-02 10:58:16 -07:00
hellcatz eb5caf93fa Update stats.js 2017-09-01 19:19:13 -07:00
hellcatz 9911037d1b Update api.js
Add blocks api call.
Add immature balance to api.
2017-09-01 19:07:15 -07:00
sennevb 589ec86400 Merge pull request #192 from hellcatz/patch-16
Update api.js
2017-09-01 16:53:49 +02:00
hellcatz e2af3372dd Update api.js
Set `Content-Type: application/json` on api requests. This may help with browser compatibility and also allows browsers to render the json visually when directly browsing the api.
2017-08-30 17:27:15 -07:00
sennevb 5e1301406e Merge pull request #185 from madbuda/madbuda-patch-4
API Compression
2017-08-24 09:25:12 +02:00
sennevb 4a454bbbd9 Merge pull request #179 from hellcatz/patch-15
OPID Monitoring BugFixes
2017-08-24 09:25:00 +02:00
Larry Ludlow f7499029e4 compression on api
Enables compression for api calls
2017-08-23 19:40:06 -04:00
Larry Ludlow 8a852b82ab Merge pull request #7 from z-classic/master
merge upstream
2017-08-23 19:37:04 -04:00
hellcatz dfad325b54 Update paymentProcessor.js
Treat address longer than 40 chars as invalid
Treat address shorter than 30 chars as invalid
2017-08-19 09:11:14 -07:00
hellcatz c0e0cea629 Update zen_example.json 2017-08-19 08:53:47 -07:00
hellcatz 81b7e2e6ee Update paymentProcessor.js
Fix issue when opids may have been cleared from node but not pool.
Do not increase opid count when `executing` as another app may have created an operation.
2017-08-15 09:12:45 -07:00
sennevb cb2951e638 Merge pull request #178 from z-classic/sennevb-patch-2
if invalid adress + workername = 40
2017-08-15 17:36:52 +02:00
sennevb 030ff2931b another 40chars
removed

thanks to hellcatz
2017-08-15 17:33:06 +02:00
sennevb 2c68351b4e if invalid adress + workername = 40
if invalid adress + workername = 40 chars, it doesnt get authenticated..
2017-08-15 09:34:44 +02:00
sennevb e8e52e3eb3 Merge pull request #176 from hellcatz/patch-14
Update paymentProcessor.js
2017-08-12 12:29:07 +02:00
sennevb 0c341dffc9 Merge pull request #172 from hellcatz/hellcatz-patch-13
Update paymentProcessor.js
2017-08-12 12:27:50 +02:00
sennevb 2d7f86fa9f Merge pull request #165 from madbuda/madbuda-patch-1
using existing function for date in payments.html
2017-08-12 12:27:20 +02:00
sennevb 4c982a73ac Merge pull request #159 from madbuda/redispw
adding in redis password auth from UNOMP
2017-08-12 12:26:00 +02:00
hellcatz 129e11e8e3 Update paymentProcessor.js
Only manage opids created by z-nomp. All opids are still monitored.
2017-08-11 19:56:18 -07:00
hellcatz f6fe32b7e5 Update paymentProcessor.js
Oops ...  off by one ...
2017-08-03 14:43:31 -07:00
madbuda 82d765f560 Merge branch 'z-classic-master' 2017-08-03 10:01:16 -04:00
madbuda 86245effe8 Merge branch 'master' of git://github.com/z-classic/z-nomp into z-classic-master 2017-08-03 10:00:43 -04:00
hellcatz f2786e7a5b Update paymentProcessor.js
Sort rounds during payments so blocks are paid in order.
Optimization to max blocks per payment logic.
2017-08-02 19:26:32 -07:00
sennevb 15f4912b4a Merge pull request #170 from hellcatz/zen-updates
Zen Updates
2017-07-21 22:25:54 +02:00
Larry abf70fcfc0 Merge pull request #4 from hellcatz/zen-updates
Zen updates
2017-07-20 17:53:45 -04:00
hellcatz d8dd19ff8b Update paymentProcessor.js
BugFix `result.result[i]` can be undefined in RPC response errors.
2017-07-19 18:41:18 -07:00
hellcatz b16990e18a Update paymentProcessor.js
Trim address of space that somehow get in the beginning or end.
2017-07-18 22:06:47 -07:00
hellcatz 24a84c6380 Update zen_testnet.json 2017-07-18 21:17:16 -07:00
hellcatz 7a3bf72d41 Update zen.json
Support Zen HF at block 139200
2017-07-18 19:30:43 -07:00
Larry 3f2bbe8182 Merge pull request #1 from madbuda/madbuda-patch-1
Madbuda patch 1
2017-07-10 21:23:25 -04:00
Larry 53183e108c removed my css to make generic for use upstream
I left in tooltip, I find it useful
2017-07-10 09:27:55 -04:00
Larry 3c39b549e0 date function was ugly, this is much better 2017-07-10 09:14:20 -04:00
Procrastinator e1675cb5fe Merge pull request #164 from madbuda/madbuda-patch-1
Madbuda patch 1
2017-07-10 01:14:55 -04:00
Procrastinator 6b36c755d4 Merge branch 'master' into madbuda-patch-1 2017-07-07 23:06:47 -04:00
Larry 975e82dedd human readable date in users timezone 2017-07-07 21:20:16 -04:00
Larry 902664c904 allow search by pressing enter or pressing button
really, enter is triggering a function to click the button
2017-07-07 20:52:07 -04:00
Larry 514f2fa869 added hush explorer link to stats page 2017-07-07 20:42:46 -04:00
Larry bc92044354 cleanup 2017-07-03 15:10:50 -04:00
Larry 0403a7d763 payments.html - revamp (#160)
* payments.html - revamp

revamp of payments page css
-Time
+Transaction ID w/link to explorer
now matches worker stats
https://madmining.club/payments

* Update payments.html

taking out link to explorer
TODO add var for block explorer
2017-07-03 01:50:38 -04:00
Larry c74724c19a added redis auth 2017-07-01 20:29:54 -04:00
Larry f6966534ff adding redis auth 2017-07-01 20:27:48 -04:00
Larry bdbe9a7896 adding redis auth password 2017-07-01 20:21:18 -04:00
Larry d96fa1e06b added comments 2017-07-01 20:19:08 -04:00
Larry 6bf70dfb20 adding redis password auth 2017-07-01 20:18:03 -04:00
Larry 1785519db3 adding redis password auth 2017-07-01 20:16:44 -04:00
Larry a30a9d0ba6 add redis password auth 2017-07-01 20:12:56 -04:00
Joshua McKenzie 04ef1a4cc0 Added Headers to Minerpage (#158)
Chrome was wrapping the minerpage html in a <pre> element and not rendering the worker stat page properly. I added ```res.header('Content-Type', 'text/html');``` to the function and now it renders perfectly.
2017-07-01 15:19:27 -04:00
Joshua Yabut 350a6eb44c Adjust difficulty to 2.5 2017-06-12 19:26:17 +00:00
Joshua Yabut 8814ce2b08 ZenCash Mainnet Support 2017-06-12 18:54:53 +00:00
hellcatz f6f6f0c712 Fix zen market stats, Add payment page example (#153)
* Update paymentProcessor.js

Fix market stats for zen

* Update paymentProcessor.js

* Update zcash_testnet.json

Undo ZEN changes to zcash file.

* Update zcash.json

Undo ZEN changes to zcash file.

* Update website.js

Add example payments page.

* Create payments.html

* Update payments.html

* Update payments.html
2017-06-04 01:32:41 -04:00
hellcatz 8fd1d7eceb Fixes & Zen Updates (#149)
* Create zen.json

* Update api.js

Remove unnecessary address.startWith() check in api for improved support of future Zcash forks.

* Update zen.json

* Update paymentProcessor.js

Improved operation id handling during RPC call errors.
Improved error handling and reporting during payment RPC call errors.
Force final rounding of addressAmounts array.
Limit tries when reducing rewards due to insufficient funds.
Do not processPayments at start of z-nomp.

* Update paymentProcessor.js

Improved error handling in cacheNetworkStats()
Updates to error messages

* Update paymentProcessor.js

Remove false positive

* Update paymentProcessor.js

Remove another false positive
2017-05-30 18:15:34 -04:00
Procrastinator 6e638e7bf6 zencash preperations (#143)
* Create zencash_testnet.json

* Update zencash_testnet.json

* Zen testnet parameters

* Core/DAO interval and addresses
2017-05-30 18:14:51 -04:00
hellcatz aa25a81fe1 Improvements to Shielding Process (#147)
* Update paymentProcessor.js

Improved balance rounding and conversions for listUnspent and listUnspentZ

* Update paymentProcessor.js

Extra error detection in RPC callback for listUnspent and listUnspentZ

* Update paymentProcessor.js

logger message fixup

* Update paymentProcessor.js

* Update paymentProcessor.js

Do not process balances equal to fee in sendTToZ and sendZToT

* Update paymentProcessor.js

* Update paymentProcessor.js

* Update paymentProcessor.js

Clear opidCount when daemon reports no operations in progress.

* Update paymentProcessor.js

Default paymentInterval to 3 minutes if missing from pool config.
Warn users on paymentInterval less than 3 minutes.
Force paymentInterval no less than 1 minute to reduce RPC work queue.
Default walletInterval to 1 minute if missing from pool config.
Force walletInterval no less than 1 minute to reduce RPC work queue.
2017-05-25 16:40:53 -04:00
Procrastinator ec70c56327 Fixup Fixup 2017-05-14 02:09:56 -04:00
Procrastinator 5eed7fc001 Merge pull request #142 from z-classic/aayanl-patch-1
Update paymentProcessor.js
2017-05-14 01:57:19 -04:00
Procrastinator 606bc1f0a8 Update paymentProcessor.js 2017-05-14 01:56:39 -04:00
Procrastinator 291c26360d Update paymentProcessor.js 2017-05-14 01:52:26 -04:00
Procrastinator 1988e8186d Fixup 2017-05-14 01:43:52 -04:00
Aayan L be2e0d6bfe Add minconf 2017-05-14 05:42:10 +00:00
Procrastinator f1a9c80feb Merge pull request #141 from hellcatz/patch-8
Resolve Issue #140
2017-05-13 20:22:54 -04:00
hellcatz c5bdda780c Update stats.js
Bugfix to bugfix ;)
2017-05-13 16:13:45 -07:00
hellcatz 9f0a8f5c32 Update stats.js
BugFix for miner balance reporting.
2017-05-13 16:10:55 -07:00
hellcatz ee27470e7a Update stats.js 2017-05-13 15:50:42 -07:00
hellcatz 6edd190842 Update api.js 2017-05-13 15:50:05 -07:00
Procrastinator ec794f34f5 Merge pull request #139 from hellcatz/patch-7
PPLNT Multi-Pool
2017-05-11 21:55:31 -04:00
hellcatz 51d468adb3 Update init.js
Improved multi-pool support for PPLNT time share tracking.
2017-05-11 18:20:15 -07:00
hellcatz fe72b6e533 Merge remote-tracking branch 'upstream/master' 2017-05-11 18:17:53 -07:00
Procrastinator e40f2913b1 Merge pull request #132 from hellcatz/patch-6
Experimental PPLNT support & MORE
2017-05-11 18:46:38 -04:00
hellcatz 9c237291dd Update init.js
Increase share submission window to 15 minutes for PPLNT.
Added worker joined and re-joined logger messages.
2017-05-07 23:18:48 -07:00
hellcatz fe78759bf8 Update stats.js 2017-05-07 22:47:59 -07:00
hellcatz edf10ef2c9 Update stats.js
Add currentRoundTimes to stats.
2017-05-07 14:37:55 -07:00
hellcatz 8c94daec98 Update init.js
Comment out extra logger.debug() used during dev.
2017-05-07 09:58:15 -07:00
hellcatz d233ffcb0d Update paymentProcessor.js
Added work share tracking in payments JSON data.
Remove workers with balanceChange of 0 from payments JSON data.
Commented out console.logs used for dev purposes.
2017-05-07 09:57:19 -07:00
hellcatz d53e6db63a Update website.js
Added support for older node-watch versions, prior to 0.5.0
2017-05-06 17:58:19 -07:00
hellcatz 3062f5ae9e Update shareProcessor.js 2017-05-06 17:46:42 -07:00
hellcatz 6f62e0a7c6 Update poolWorker.js
Added time share tracking messaging to master process for PPLNT.
2017-05-06 17:44:12 -07:00
hellcatz e9d4c0bc92 Update shareProcessor.js
Removed time share tracking from shareProcessor due to threading issues.
2017-05-06 17:43:01 -07:00
hellcatz 7e34563af4 Update init.js
Added PPLNT time share tracking to master process for thread safety.
2017-05-06 17:42:19 -07:00
hellcatz 6ea1df2cd5 Update init.js
Added PPLNT time share tracking to master process for thread safety.
Added redis connection in init.js for PPLNT time share tracking.
2017-05-06 17:41:36 -07:00
hellcatz 7865d6818e Update paymentProcessor.js
Allow minConfShield and minConfPayout to be set via pool_config
Updated stats collection and operation id tracking to use their own fixed timeout intervals.
2017-05-05 22:41:54 -07:00
hellcatz 3bc190ada0 Update shareProcessor.js 2017-05-05 21:19:02 -07:00
hellcatz 8f68e3e36a Update paymentProcessor.js
Added coin market stats caching from https://coinmarketcap.com/api/
2017-05-05 21:00:28 -07:00
hellcatz d5d4f9c67a Update stats.js
Sort pools by name in stats array
Added market stats object
2017-05-05 20:57:47 -07:00
hellcatz 133ce797b7 Update stats.js
BugFix: prevent `confirms` from being null
2017-05-04 18:56:05 -07:00
hellcatz 8d5a13697f Update stats.html
Potential exception fix for issue https://github.com/z-classic/z-nomp/issues/131
2017-05-04 18:30:52 -07:00
hellcatz c0f66c0b29 Update paymentProcessor.js
Updates to comments in code...
2017-05-03 23:41:00 -07:00
hellcatz 241bdea7ee Merge remote-tracking branch 'upstream/master' into patch-6 2017-05-03 22:21:02 -07:00
hellcatz 774e2b0088 Update paymentProcessor.js
Experimental PPLNT support (console.logs need to be removed after experiments)
Major reduction in RPC calls to daemon.
Balance rounding improvements.
Improvements to confirmations tracking.
Improvements to operation id tracking.
Improved error handling.
2017-05-03 22:20:08 -07:00
Aayan L e6c4bf4c10 Fix pie charts to be multipool friendly 2017-05-01 18:25:57 -04:00
Procrastinator d35a770faa Update stats.html 2017-04-30 21:51:14 -04:00
hellcatz aae3018f55 Update komodo_example.json 2017-04-30 17:31:57 -07:00
hellcatz ea82816ce4 Update zcash_example.json 2017-04-30 17:31:38 -07:00
hellcatz 4d2c35312d Update zcash_testnet_example.json 2017-04-30 17:31:22 -07:00
hellcatz cbe82662a8 Update zclassic_example.json 2017-04-30 17:30:51 -07:00
Procrastinator fbc868721c Merge pull request #128 from z-classic/piechart
Add pie chart
2017-04-30 19:59:08 -04:00
Aayan L 5fafea636c Add tooltip 2017-04-30 19:58:02 -04:00
hellcatz 0f6192e3aa Update shareProcessor.js
Track miner times by address not worker name
2017-04-30 13:10:05 -07:00
Aayan L a0548f53eb Add pie chart 2017-04-29 23:52:42 -04:00
hellcatz 4e23d7cace Update shareProcessor.js 2017-04-29 15:16:57 -07:00
hellcatz fb5bcf4af5 Update shareProcessor.js
Improved rounding.
2017-04-29 14:54:26 -07:00
hellcatz 7f66c85362 Update shareProcessor.js 2017-04-29 13:07:09 -07:00
hellcatz 4ac324c796 Update shareProcessor.js
Add time share tracking for PPLNT
2017-04-29 12:44:04 -07:00
hellcatz b224c82971 Update paymentProcessor.js
Track balanceChange in payments.
2017-04-25 22:15:41 -07:00
hellcatz 2d85b9f34a Update stats.js
Force integer sorting of block height.
2017-04-24 10:04:16 -07:00
Procrastinator 28f3c476c2 Update README.md 2017-04-23 17:17:44 -04:00
Procrastinator b8e60519ae Merge pull request #126 from z-classic/hellcatz-patch-5
Update website.js
2017-04-23 14:58:56 -04:00
hellcatz 8f942b7c45 Update website.js
Fix exception when not running TLS website frontend.
2017-04-23 11:40:34 -07:00
Procrastinator cbad5466da Merge pull request #122 from z-classic/aayanl-patch-2
Lockdown package versions #121
2017-04-23 11:07:43 -04:00
Procrastinator 8b33ddd6f1 Merge pull request #123 from aayanl/frontendssl
Add frontend TLS/SSL
2017-04-23 11:07:34 -04:00
Procrastinator 834f453cf0 Update README.md 2017-04-23 11:00:32 -04:00
Aayan L 7839b606a1 Add frontend TLS/SSL 2017-04-23 01:25:58 -04:00
Procrastinator dab2bf427f Lockdown package versions #121 2017-04-22 20:31:19 -04:00
Procrastinator 55aa90ed8b Merge pull request #120 from z-classic/aayanl-patch-1
Update README.md
2017-04-22 19:04:23 -04:00
Procrastinator 354d88257d Update README.md 2017-04-22 18:19:09 -04:00
Procrastinator ed06afc205 Merge pull request #119 from hellcatz/patch-5
compatibility update node-watch 0.5.x
2017-04-22 15:47:13 -04:00
hellcatz 03e141d0b6 Update website.js
Compatibility update for node-watch 0.5
2017-04-21 19:25:10 -07:00
Procrastinator 6937e7b6e2 Merge pull request #116 from hellcatz/patch-4
Solve Issue #86, #113
2017-04-20 16:05:23 -04:00
hellcatz b0cc4cd560 Update paymentProcessor.js 2017-04-20 12:31:13 -07:00
hellcatz ccdbc5c1e5 Update zclassic_example.json 2017-04-19 19:50:15 -07:00
hellcatz efd0a9be09 Update zcash_testnet_example.json 2017-04-19 19:49:57 -07:00
hellcatz 2173628e5e Update zcash_example.json 2017-04-19 19:49:31 -07:00
hellcatz 9b8fbd6885 Update komodo_example.json 2017-04-19 19:49:15 -07:00
hellcatz ca297bc666 Update paymentProcessor.js
Allow pool_config to change maxBlocksPerPayment
2017-04-19 19:48:24 -07:00
hellcatz 8ef812e1ac Update paymentProcessor.js 2017-04-19 19:05:11 -07:00
hellcatz 9d113b9f49 Update paymentProcessor.js
Look for non unique blocks also...
2017-04-19 14:19:44 -07:00
hellcatz a907dfb709 Update paymentProcessor.js 2017-04-18 19:03:36 -07:00
hellcatz fcac8370b3 Update paymentProcessor.js
Begin solution to issue, https://github.com/z-classic/z-nomp/issues/113
Revamped fix for issue, https://github.com/z-classic/z-nomp/issues/86
2017-04-18 18:27:54 -07:00
sennevb 0c4cd514b7 Merge pull request #115 from hellcatz/patch-3
RequireShielding Updates
2017-04-13 20:18:42 +02:00
hellcatz b3c05a9d02 Minor updates. 2017-04-12 18:25:48 -07:00
hellcatz 16aff2d0de Update paymentProcessor.js
Do not validate zAddress when shielding is not required.
2017-04-12 11:47:51 -07:00
Procrastinator 53852d6f0f #105
Fix for older node versions *cough* zdash *cough*
2017-04-10 12:58:04 -04:00
24 changed files with 1816 additions and 646 deletions

View File

@ -17,12 +17,11 @@ Usage of this software requires abilities with sysadmin, database admin, coin da
### Community / Support
IRC
* Support / general discussion join: https://rocketchat.zdeveloper.org
* 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:
https://zpool.minegate.eu/ 1% with the whole fee going to the Zclassic donation fund!
https://pool.cryptobroker.io/zcl Running MPOS and 0.5% of the fee goes to the Zclassic donation fund! 200+ blocks have been found as well!
@ -32,6 +31,12 @@ http://zclmine.com/ Custom frontend
http://zclassic.miningspeed.com Custom frontend and 0% fee
https://zpool.it 0.5% 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
=====

71
coins/zen.json Normal file
View File

@ -0,0 +1,71 @@
{
"name": "zen",
"symbol": "zen",
"algorithm": "equihash",
"requireShielding": true,
"payFoundersReward": true,
"percentFoundersReward": 8.5,
"maxFoundersRewardBlockHeight": 839999,
"foundersRewardAddressChangeInterval": 17500,
"vFoundersRewardAddress": [
"zssEdGnZCQ9G86LZFtbynMn1hYTVhn6eYCL",
"zsrCsXXmUf8k59NLasEKfxA7us3iNvaPATz",
"zsnLPsWMXW2s4w9EmFSwtSLRxL2LhPcfdby",
"zshdovbcPfUAfkPeEE2qLbKnoue9RsbVokU",
"zsqmq97JAKCCBFRGvxgv6FiJgQLCZBDp62S",
"zskyFVFA7VRYX8EGdXmYN75WaBB25FmiL3g",
"zsmncLmwEUdVmAGPUrUnNKmPGXyej7mbmdM",
"zsfa9VVJCEdjfPbku4XrFcRR8kTDm2T64rz",
"zsjdMnfWuFi46VeN2HSXVQWEGsnGHgVxayY",
"zseb8wRQ8rZ722oLX5B8rx7qwZiBRb9mdig",
"zsjxkovhqiMVggoW7jvSRi3NTSD3a6b6qfd",
"zsokCCSU3wvZrS2G6mEDpJ5cH49E7sDyNr1",
"zt12EsFgkABHLMRXA7JNnpMqLrxsgCLnVEV",
"zt39mvuG9gDTHX8A8Qk45rbk3dSdQoJ8ZAv",
"zssTQZs5YxDGijKC86dvcDxzWogWcK7n5AK",
"zsywuMoQK7Bved2nrXs56AEtWBhpb88rMzS",
"zsxVS2w7h1fHFX2nQtGm4372pd4DSHzq9ee",
"zsupGi7ro3uC8CEVwm9r7vrdVUZaXQnHF6T",
"zshVZvW47dA5AB3Sqk1h7ytwWJeUJUJxxaE",
"zsubBCjvDx252MKFsL4Dcf5rJU9Z9Upqr1N",
"zsweaST3NcU4hfgkVULfCsfEq41pjgMDgcW",
"zswz6Rxb1S33fUpftETZwtGiVSeYxNKq2xc",
"zswnpHtiBbrvYDzbhPQshkgvLSfYhDMRJ4S",
"zsjSYAWaEYj35Ht7aXrRJUGY6Dc8qCmgYqu",
"zsvMv8fGroWR8epbSiGDCJHmfe6ec2uFQrt",
"zsujxCT56BExQDAwKwktBjtnopYnw8BiKbg",
"zsxeXc2FTAzmUmeZmqVsKVdwTMSvzyns4rT",
"zsuLqgABNudD8bVPbVGeUjGqapuoXp68i7F",
"zsoc39J1dCFK1U8kckZznvQkv8As7sajYLz",
"zt21NFdu1KRPJ7VRKtrWugM2Jqe5ePNmU4T",
"zsp15qbVcbx9ifcjKe6XZEJTvzsFUZ2BHLT",
"zso2KvqH6yxLQEYggHdmfL3Tcd5V6E9tqhp",
"zsnFG2W5ZHRYh3QucNze4mp31tBkemtfxdj",
"zsex2CGJtxHyHbpLXm7kESBmp3vWRqUkJMy",
"zsvtFv96nrgrXKUbtNe2BpCt8aQEp5oJ7F8",
"zsk5KitThmhK9KBa1KDybPgEmGSFTHzhMVA",
"zsuy4n48c4NsJyaCZEzwdAKULM1FqbB6Y4z",
"zsgtQVMpX2zNMLvHHG2NDwfqKoaebvVectJ",
"zszQqXRSPGdqsWw4iaMTNN6aJz4JjEzSdCF",
"zst6dBLrTtaMQBX7BLMNjKLTGcP11PBmgTV",
"zshD9r6Eb6dZGdzYW2HCb9CzkMokCT1NGJR",
"zswUaj1TboEGmvSfF7fdoxWyH3RMx7MBHHo",
"zsv8s4Poi5GxCsbBrRJ97Vsvazp84nrz5AN",
"zsmmxrKU6dqWFwUKow1iyovg3gxrgXpEivr",
"zskh1221aRC9WEfb5a59WxffeW34McmZZsw",
"zssAhuj57NnVm4yNFT6o8muRctABkUaBu3L",
"zsi5Yr4Z8HwBvdBqQE8gk7ahExDu95J4oqZ",
"zsy6ryEaxfk8emJ8bGVB7tmwRwBL8cfSqBW"
],
"percentTreasuryReward": 12.0,
"treasuryRewardStartBlockHeight": 139200,
"treasuryRewardAddressChangeInterval": 50000,
"vTreasuryRewardAddress": [
"zsyF68hcYYNLPj5i4PfQJ1kUY6nsFnZkc82",
"zsfULrmbX7xbhqhAFRffVqCw9RyGv2hqNNG",
"zsoemTfqjicem2QVU8cgBHquKb1o9JR5p4Z",
"zt339oiGL6tTgc9Q71f5g1sFTZf6QiXrRUr"
],
"peerMagic": "63617368",
"txfee": 0.0004
}

31
coins/zen_testnet.json Normal file
View File

@ -0,0 +1,31 @@
{
"name": "zen_testnet",
"symbol": "znt",
"algorithm": "equihash",
"requireShielding": true,
"payFoundersReward": true,
"percentFoundersReward": 8.5,
"maxFoundersRewardBlockHeight": 839999,
"foundersRewardAddressChangeInterval": 17500,
"vFoundersRewardAddress": [
"zrH8KT8KUcpKKNBu3fjH4hA84jZBCawErqn", "zrGsMC4ou1r5Vxy7Dnxg4PfKpansx83BM8g", "zr6sB2Az36D8CqzeZNavB11WbovsGtJSAZG", "zrBAG3pXCTDq14nivNK9mW8SfwMNcdmMQpb",
"zrRLwpYRYky4wsvwLVrDp8fs89EBTRhNMB1", "zrLozMfptTmE3zLP5SrTLyB8TXqH84Agjrr", "zrMckkaLtVTEUvxj4ouU7BPDGa8xmdTZSVE", "zrFc897wJXmF7BcEdbvi2mS1bLrcuWYK6hm",
"zrHEnni486u9SNcLWacroSgcdyMA33tfM92", "zrJ3ymPV3R8Xk4N3BdNb898xvZvARm5K7mq", "zrDj3P6trx73291krxU51U9QnfkbGxkyJ6E", "zrJs3vMGFJi9pQCireeSLckJonamBnwTSrY",
"zrKFdXQoAkkycy52EFoWARyzZWx6Kat2Som", "zrEXbSe79FXA9KRMnJTZUWZdZhNnjcnAdrq", "zr7iAwfNgJsMpSCmijK3TuVDuNvSmLr1rUz", "zrDEK7K6cftqSjeyVUH1WqJtBUkXN7GidxH",
"zrRennuq75hyBVU4JymtZk8UcQ1vRPKpmpj", "zr9HRTL79pKmn5R8fvkC9kucZ4u1bQruLTD", "zrML8KXpJsa1NVnbJuawX86ZvAn543tWdTT", "zrLBAkQoxpEtnztSUEcdxnEvuwtgxyAMGX7",
"zr6kPnVzFBYmcBDsWoTrPHRuBxLq21o4zvT", "zrMY3vdvqs9KSvx9TawvcyuVurt1Jj6GPVo", "zr9WB1qBpM4nwi1mudUFfjtMNmqzaBQDsXn", "zrAHbtHDPAqmzWJMQqSYzGyFnDWN3oELZRs",
"zrH1f5K3z7EQ6RWWZ7StCDWHTZwFChBVA2W", "zrNTacAid9LS4kAqzM4sw1YcF7gLFrzVM7U", "zrFyZpMVKMeDqbn6A2uUiL9mZmgxuR1pUBg", "zrD1cqGFGzBcPogFHJvnN4XegvvmbTjA43t",
"zr5A1D7czWkB4pAWfGC5Pux5Ek7anYybdPK", "zr8yTAxCy6jAdsc6qPvmVEQHbYo25AJKhy9", "zrFW2YjQw4cABim5kEDwapbSqTz3wW7cWkk", "zr9nJvNbsrvUTZD41fhqAQeUcgMfqZmAweN",
"zrCx4dXZd5b2tD483Ds4diHpo1QxBMJ76Jr", "zr6eVeRwU6Puob3K1RfWtva1R458oj8pzkL", "zr7B92iHtQcobZjGCXo3DAqMQjsn7ka31wE", "zr8bcemLWAjYuphXSVqtqZWEnJipCB9F5oC",
"zrFzsuPXb7HsFd3srBqtVqnC9GQ94DQubV2", "zr4yiBobiHjHnCYi75NmYtyoqCV4A3kpHDL", "zrGVdR4K4F8MfmWxhUiTypK7PTsvHi8uTAh", "zr7WiCDqCMvUdH1xmMu8YrBMFb2x2E6BX3z",
"zrEFrGWLX4hPHuHRUD3TPbMAJyeSpMSctUc", "zr5c3f8PTnW8qBFX1GvK2LhyLBBCb1WDdGG", "zrGkAZkZLqC9QKJR3XomgxNizCpNuAupTeg", "zrM7muDowiun9tCHhu5K9vcDGfUptuYorfZ",
"zrCsWfwKotWnQmFviqAHAPAJ2jXqZYW966P", "zrLLB3JB3jozUoMGFEGhjqyVXTpngVQ8c4T", "zrAEa8YjJ2f3m2VsM1Xa9EwibZxEnRoSLUx", "zrAdJgp7Cx35xTvB7ABWP8YLTNDArMjP1s3"
],
"percentTreasuryReward": 12.0,
"treasuryRewardStartBlockHeight": 85500,
"treasuryRewardAddressChangeInterval": 10000,
"vTreasuryRewardAddress": [
"zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1", "zrRBQ5heytPMN5nY3ssPf3cG4jocXeD8fm1"
],
"txfee": 0.0004
}

View File

@ -25,7 +25,8 @@
},
"redis": {
"host": "127.0.0.1",
"port": 6379
"port": 6379,
"password": ""
}
},
@ -42,6 +43,11 @@
"adminCenter": {
"enabled": false,
"password": "password"
},
"tlsOptions" : {
"enabled": false,
"cert": "",
"key": ""
}
},
@ -91,10 +97,10 @@
"diff": 0.001,
"varDiff": {
"minDiff": 0.001,
"maxDiff": 1,
"targetTime": 15,
"retargetTime": 60,
"variancePercent": 30
"maxDiff": 1,
"targetTime": 15,
"retargetTime": 60,
"variancePercent": 30
}
}
}

88
init.js
View File

@ -6,6 +6,8 @@ var cluster = require('cluster');
var async = require('async');
var extend = require('extend');
var redis = require('redis');
var PoolLogger = require('./libs/logUtil.js');
var CliListener = require('./libs/cliListener.js');
var PoolWorker = require('./libs/poolWorker.js');
@ -31,9 +33,6 @@ var logger = new PoolLogger({
logColors: portalConfig.logColors
});
try {
require('newrelic');
if (cluster.isMaster)
@ -66,7 +65,6 @@ catch(e){
logger.debug('POSIX', 'Connection Limit', '(Safe to ignore) POSIX module not installed and resource (connection) limit was not raised');
}
if (cluster.isWorker){
switch(process.env.workerType){
@ -179,16 +177,36 @@ var buildPoolConfigs = function(){
return configs;
};
function roundTo(n, digits) {
if (digits === undefined) {
digits = 0;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
var test =(Math.round(n) / multiplicator);
return +(test.toFixed(digits));
}
var _lastStartTimes = [];
var _lastShareTimes = [];
var spawnPoolWorkers = function(){
var redisConfig;
var connection;
Object.keys(poolConfigs).forEach(function(coin){
var p = poolConfigs[coin];
if (!Array.isArray(p.daemons) || p.daemons.length < 1){
var pcfg = poolConfigs[coin];
if (!Array.isArray(pcfg.daemons) || pcfg.daemons.length < 1){
logger.error('Master', coin, 'No daemons configured so a pool cannot be started for this coin.');
delete poolConfigs[coin];
} else if (!connection) {
redisConfig = pcfg.redis;
connection = redis.createClient(redisConfig.port, redisConfig.host);
connection.on('ready', function(){
logger.debug('PPLNT', coin, 'TimeShare processing setup with redis (' + redisConfig.host +
':' + redisConfig.port + ')');
});
}
});
@ -236,6 +254,62 @@ var spawnPoolWorkers = function(){
}
});
break;
case 'shareTrack':
// pplnt time share tracking of workers
if (msg.isValidShare && !msg.isValidBlock) {
var now = Date.now();
var lastShareTime = now;
var lastStartTime = now;
var workerAddress = msg.data.worker.split('.')[0];
// if needed, initialize PPLNT objects for coin
if (!_lastShareTimes[msg.coin]) {
_lastShareTimes[msg.coin] = {};
}
if (!_lastStartTimes[msg.coin]) {
_lastStartTimes[msg.coin] = {};
}
// did they just join in this round?
if (!_lastShareTimes[msg.coin][workerAddress] || !_lastStartTimes[msg.coin][workerAddress]) {
_lastShareTimes[msg.coin][workerAddress] = now;
_lastStartTimes[msg.coin][workerAddress] = now;
logger.debug('PPLNT', msg.coin, 'Thread '+msg.thread, workerAddress+' joined.');
}
// grab last times from memory objects
if (_lastShareTimes[msg.coin][workerAddress] != null && _lastShareTimes[msg.coin][workerAddress] > 0) {
lastShareTime = _lastShareTimes[msg.coin][workerAddress];
lastStartTime = _lastStartTimes[msg.coin][workerAddress];
}
var redisCommands = [];
// if its been less than 15 minutes since last share was submitted
var timeChangeSec = roundTo(Math.max(now - lastShareTime, 0) / 1000, 4);
//var timeChangeTotal = roundTo(Math.max(now - lastStartTime, 0) / 1000, 4);
if (timeChangeSec < 900) {
// loyal miner keeps mining :)
redisCommands.push(['hincrbyfloat', msg.coin + ':shares:timesCurrent', workerAddress + "." + poolConfigs[msg.coin].poolId, timeChangeSec]);
//logger.debug('PPLNT', msg.coin, 'Thread '+msg.thread, workerAddress+':{totalTimeSec:'+timeChangeTotal+', timeChangeSec:'+timeChangeSec+'}');
connection.multi(redisCommands).exec(function(err, replies){
if (err)
logger.error('PPLNT', msg.coin, 'Thread '+msg.thread, 'Error with time share processor call to redis ' + JSON.stringify(err));
});
} else {
// they just re-joined the pool
_lastStartTimes[workerAddress] = now;
logger.debug('PPLNT', msg.coin, 'Thread '+msg.thread, workerAddress+' re-joined.');
}
// track last time share
_lastShareTimes[msg.coin][workerAddress] = now;
}
if (msg.isValidBlock) {
// reset pplnt share times for next round
_lastShareTimes[msg.coin] = {};
_lastStartTimes[msg.coin] = {};
}
break;
}
});
};

View File

@ -15,19 +15,30 @@ module.exports = function(logger, portalConfig, poolConfigs){
switch(req.params.method){
case 'stats':
res.header('Content-Type', 'application/json');
res.end(portalStats.statsString);
return;
case 'pool_stats':
res.header('Content-Type', 'application/json');
res.end(JSON.stringify(portalStats.statPoolHistory));
return;
case 'blocks':
case 'getblocksstats':
portalStats.getBlocks(function(data){
res.header('Content-Type', 'application/json');
res.end(JSON.stringify(data));
});
break;
case 'payments':
var poolBlocks = [];
for(var pool in portalStats.stats.pools) {
poolBlocks.push({name: pool, pending: portalStats.stats.pools[pool].pending, payments: portalStats.stats.pools[pool].payments});
}
res.header('Content-Type', 'application/json');
res.end(JSON.stringify(poolBlocks));
return;
case 'worker_stats':
res.header('Content-Type', 'application/json');
if (req.url.indexOf("?")>0) {
var url_parms = req.url.split("?");
if (url_parms.length > 0) {
@ -35,7 +46,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
var workers = {};
var address = url_parms[1] || null;
//res.end(portalStats.getWorkerStats(address));
if (address != null && address.length > 0 && address.startsWith('t'),('R')) {
if (address != null && address.length > 0) {
// make sure it is just the miners address
address = address.split(".")[0];
// get miners balance along with worker balances
@ -43,8 +54,6 @@ module.exports = function(logger, portalConfig, poolConfigs){
// get current round share total
portalStats.getTotalSharesByAddress(address, function(shares) {
var totalHash = parseFloat(0.0);
var totalHeld = parseFloat(0.0);
var totalPaid = parseFloat(0.0);
var totalShares = shares;
var networkSols = 0;
for (var h in portalStats.statHistory) {
@ -69,8 +78,8 @@ module.exports = function(logger, portalConfig, poolConfigs){
workers[w] = portalStats.stats.pools[pool].workers[w];
for (var b in balances.balances) {
if (w == balances.balances[b].worker) {
workers[w].paid = balances.balances[b].paid;
workers[w].balance = balances.balances[b].balance;
workers[w].paid = balances.balances[b].paid;
workers[w].balance = balances.balances[b].balance;
}
}
workers[w].balance = (workers[w].balance || 0);
@ -80,7 +89,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
}
}
res.end(JSON.stringify({miner: address, totalHash: totalHash, totalShares: totalShares, networkSols: networkSols, balance: balances.totalHeld, paid: balances.totalPaid, workers: workers, history: history}));
res.end(JSON.stringify({miner: address, totalHash: totalHash, totalShares: totalShares, networkSols: networkSols, immature: balances.totalImmature, balance: balances.totalHeld, paid: balances.totalPaid, workers: workers, history: history}));
});
});
} else {
@ -102,6 +111,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
res.write('\n');
var uid = Math.random().toString();
_this.liveStatConnections[uid] = res;
res.flush();
req.on("close", function() {
delete _this.liveStatConnections[uid];
});

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,9 @@ module.exports = function(logger){
var proxySwitch = {};
var redisClient = redis.createClient(portalConfig.redis.port, portalConfig.redis.host);
if (portalConfig.redis.password) {
redisClient.auth(portalConfig.redis.password);
}
//Handle messages from master process sent via IPC
process.on('message', function(message) {
switch(message.type){
@ -134,16 +136,6 @@ module.exports = function(logger){
if (poolOptions.validateWorkerUsername !== true)
authCallback(true);
else {
if (workerName.length === 40) {
try {
new Buffer(workerName, 'hex');
authCallback(true);
}
catch (e) {
authCallback(false);
}
}
else {
pool.daemon.cmd('validateaddress', [String(workerName).split(".")[0]], function (results) {
var isValid = results.filter(function (r) {
return r.response.isvalid
@ -151,8 +143,6 @@ module.exports = function(logger){
authCallback(isValid);
});
}
}
};
handlers.share = function(isValidShare, isValidBlock, data){
@ -177,9 +167,9 @@ module.exports = function(logger){
var pool = Stratum.createPool(poolOptions, authorizeFN, logger);
pool.on('share', function(isValidShare, isValidBlock, data){
var shareData = JSON.stringify(data);
if (data.blockHash && !isValidBlock)
logger.debug(logSystem, logComponent, logSubCat, 'We thought a block was found but it was rejected by the daemon, share data: ' + shareData);
@ -187,19 +177,22 @@ module.exports = function(logger){
logger.debug(logSystem, logComponent, logSubCat, 'Block found: ' + data.blockHash + ' by ' + data.worker);
if (isValidShare) {
if(data.shareDiff > 1000000000)
if(data.shareDiff > 1000000000) {
logger.debug(logSystem, logComponent, logSubCat, 'Share was found with diff higher than 1.000.000.000!');
else if(data.shareDiff > 1000000)
} else if(data.shareDiff > 1000000) {
logger.debug(logSystem, logComponent, logSubCat, 'Share was found with diff higher than 1.000.000!');
}
//logger.debug(logSystem, logComponent, logSubCat, 'Share accepted at diff ' + data.difficulty + '/' + data.shareDiff + ' by ' + data.worker + ' [' + data.ip + ']' );
} else if (!isValidShare)
} else if (!isValidShare) {
logger.debug(logSystem, logComponent, logSubCat, 'Share rejected: ' + shareData);
handlers.share(isValidShare, isValidBlock, data)
}
// handle the share
handlers.share(isValidShare, isValidBlock, data);
// send to master for pplnt time tracking
process.send({type: 'shareTrack', thread:(parseInt(forkId)+1), coin:poolOptions.coin.name, isValidShare:isValidShare, isValidBlock:isValidBlock, data:data});
}).on('difficultyUpdate', function(workerName, diff){
logger.debug(logSystem, logComponent, logSubCat, 'Difficulty update to diff ' + diff + ' workerName=' + JSON.stringify(workerName));
handlers.diff(workerName, diff);

View File

@ -25,9 +25,11 @@ module.exports = function(logger, poolConfig){
var logSystem = 'Pool';
var logComponent = coin;
var logSubCat = 'Thread ' + (parseInt(forkId) + 1);
var connection = redis.createClient(redisConfig.port, redisConfig.host);
if (redisConfig.password) {
connection.auth(redisConfig.password);
}
connection.on('ready', function(){
logger.debug(logSystem, logComponent, logSubCat, 'Share processing setup with redis (' + redisConfig.host +
':' + redisConfig.port + ')');
@ -38,7 +40,6 @@ module.exports = function(logger, poolConfig){
connection.on('end', function(){
logger.error(logSystem, logComponent, logSubCat, 'Connection to redis database has been ended');
});
connection.info(function(error, response){
if (error){
logger.error(logSystem, logComponent, logSubCat, 'Redis version check failed');
@ -65,18 +66,17 @@ module.exports = function(logger, poolConfig){
}
});
this.handleShare = function(isValidShare, isValidBlock, shareData){
this.handleShare = function(isValidShare, isValidBlock, shareData) {
var redisCommands = [];
if (isValidShare){
if (isValidShare) {
redisCommands.push(['hincrbyfloat', coin + ':shares:roundCurrent', shareData.worker, shareData.difficulty]);
redisCommands.push(['hincrby', coin + ':stats', 'validShares', 1]);
}
else{
} else {
redisCommands.push(['hincrby', coin + ':stats', 'invalidShares', 1]);
}
/* Stores share diff, worker, and unique value with a score that is the timestamp. Unique value ensures it
doesn't overwrite an existing entry, and timestamp as score lets us query shares from last X minutes to
generate hashrate for each worker and pool. */
@ -86,6 +86,7 @@ module.exports = function(logger, poolConfig){
if (isValidBlock){
redisCommands.push(['rename', coin + ':shares:roundCurrent', coin + ':shares:round' + shareData.height]);
redisCommands.push(['rename', coin + ':shares:timesCurrent', coin + ':shares:times' + shareData.height]);
redisCommands.push(['sadd', coin + ':blocksPending', [shareData.blockHash, shareData.txHash, shareData.height, shareData.worker, dateNow].join(':')]);
redisCommands.push(['hincrby', coin + ':stats', 'validBlocks', 1]);
}
@ -97,8 +98,6 @@ module.exports = function(logger, poolConfig){
if (err)
logger.error(logSystem, logComponent, logSubCat, 'Error with share processor multi ' + JSON.stringify(err));
});
};
};

View File

@ -7,10 +7,16 @@ var os = require('os');
var algos = require('stratum-pool/lib/algoProperties.js');
function balanceRound(number) {
return parseFloat((Math.round(number * 100000000) / 100000000).toFixed(8));
// redis callback Ready check failed bypass trick
function rediscreateClient(port, host, pass) {
var client = redis.createClient(port, host);
if (pass) {
client.auth(pass);
}
return client;
}
/**
* Sort object properties (only own properties will be sorted).
* @param {object} obj object to sort properties
@ -80,17 +86,35 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
redisClients.push({
coins: [coin],
client: redis.createClient(redisConfig.port, redisConfig.host)
client: rediscreateClient(redisConfig.port, redisConfig.host, redisConfig.password)
});
});
function setupStatsRedis(){
redisStats = redis.createClient(portalConfig.redis.port, portalConfig.redis.host);
redisStats.on('error', function(err){
logger.error(logSystem, 'Historics', 'Redis for stats had an error ' + JSON.stringify(err));
redisStats.auth(portalConfig.redis.password);
});
}
this.getBlocks = function (cback) {
var allBlocks = {};
async.each(_this.stats.pools, function(pool, pcb) {
if (_this.stats.pools[pool.name].pending && _this.stats.pools[pool.name].pending.blocks)
for (var i=0; i<_this.stats.pools[pool.name].pending.blocks.length; i++)
allBlocks[pool.name+"-"+_this.stats.pools[pool.name].pending.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].pending.blocks[i];
if (_this.stats.pools[pool.name].confirmed && _this.stats.pools[pool.name].confirmed.blocks)
for (var i=0; i<_this.stats.pools[pool.name].confirmed.blocks.length; i++)
allBlocks[pool.name+"-"+_this.stats.pools[pool.name].confirmed.blocks[i].split(':')[2]] = _this.stats.pools[pool.name].confirmed.blocks[i];
pcb();
}, function(err) {
cback(allBlocks);
});
};
function gatherStatHistory(){
var retentionTime = (((Date.now() / 1000) - portalConfig.website.stats.historicalRetention) | 0).toString();
redisStats.zrangebyscore(['statHistory', retentionTime, '+inf'], function(err, replies){
@ -152,6 +176,45 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
_this.statPoolHistory.push(data);
}
var magnitude = 100000000;
var coinPrecision = magnitude.toString().length - 1;
function roundTo(n, digits) {
if (digits === undefined) {
digits = 0;
}
var multiplicator = Math.pow(10, digits);
n = parseFloat((n * multiplicator).toFixed(11));
var test =(Math.round(n) / multiplicator);
return +(test.toFixed(digits));
}
var satoshisToCoins = function(satoshis){
return roundTo((satoshis / magnitude), coinPrecision);
};
var coinsToSatoshies = function(coins){
return Math.round(coins * magnitude);
};
function coinsRound(number) {
return roundTo(number, coinPrecision);
}
function readableSeconds(t) {
var seconds = Math.round(t);
var minutes = Math.floor(seconds/60);
var hours = Math.floor(minutes/60);
var days = Math.floor(hours/24);
hours = hours-(days*24);
minutes = minutes-(days*24*60)-(hours*60);
seconds = seconds-(days*24*60*60)-(hours*60*60)-(minutes*60);
if (days > 0) { return (days + "d " + hours + "h " + minutes + "m " + seconds + "s"); }
if (hours > 0) { return (hours + "h " + minutes + "m " + seconds + "s"); }
if (minutes > 0) {return (minutes + "m " + seconds + "s"); }
return (seconds + "s");
}
this.getCoins = function(cback){
_this.stats.coins = redisClients[0].coins;
@ -166,7 +229,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
});
}
], function(err, total){
cback(balanceRound(total).toFixed(8));
cback(coinsRound(total).toFixed(8));
});
};
@ -181,7 +244,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
async.each(_this.stats.pools, function(pool, pcb) {
pindex++;
var coin = String(_this.stats.pools[pool.name].name);
client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", function(error, result) {
client.hscan(coin + ':shares:roundCurrent', 0, "match", a+"*", "count", 1000, function(error, result) {
if (error) {
pcb(error);
return;
@ -211,7 +274,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
});
};
this.getBalanceByAddress = function(address, cback){
var a = address.split(".")[0];
@ -222,46 +285,68 @@ module.exports = function(logger, portalConfig, poolConfigs){
var totalHeld = parseFloat(0);
var totalPaid = parseFloat(0);
var totalImmature = parseFloat(0);
async.each(_this.stats.pools, function(pool, pcb) {
var coin = String(_this.stats.pools[pool.name].name);
// get all balances from address
client.hscan(coin + ':balances', 0, "match", a+"*", function(error, bals) {
// get all payouts from address
client.hscan(coin + ':payouts', 0, "match", a+"*", function(error, pays) {
var addressFound = false;
var workerName = "";
var balName = "";
var balAmount = 0;
var paidAmount = 0;
for (var i in pays[1]) {
if (Math.abs(i % 2) != 1) {
workerName = String(pays[1][i]);
} else {
balAmount = 0;
for (var b in bals[1]) {
if (Math.abs(b % 2) != 1) {
balName = String(bals[1][b]);
} else if (balName == workerName) {
balAmount = parseFloat(bals[1][b]);
totalHeld = balanceRound(totalHeld+balAmount);
}
}
paidAmount = parseFloat(pays[1][i]);
totalPaid = balanceRound(totalPaid+paidAmount);
balances.push({
worker:String(workerName),
balance:balanceRound(balAmount),
paid:balanceRound(paidAmount)
});
}
}
pcb();
});
});
// get all immature balances from address
client.hscan(coin + ':immature', 0, "match", a+"*", "count", 10000, function(error, pends) {
// get all balances from address
client.hscan(coin + ':balances', 0, "match", a+"*", "count", 10000, function(error, bals) {
// get all payouts from address
client.hscan(coin + ':payouts', 0, "match", a+"*", "count", 10000, function(error, pays) {
var workerName = "";
var balAmount = 0;
var paidAmount = 0;
var pendingAmount = 0;
var workers = {};
for (var i in pays[1]) {
if (Math.abs(i % 2) != 1) {
workerName = String(pays[1][i]);
workers[workerName] = (workers[workerName] || {});
} else {
paidAmount = parseFloat(pays[1][i]);
workers[workerName].paid = coinsRound(paidAmount);
totalPaid += paidAmount;
}
}
for (var b in bals[1]) {
if (Math.abs(b % 2) != 1) {
workerName = String(bals[1][b]);
workers[workerName] = (workers[workerName] || {});
} else {
balAmount = parseFloat(bals[1][b]);
workers[workerName].balance = coinsRound(balAmount);
totalHeld += balAmount;
}
}
for (var b in pends[1]) {
if (Math.abs(b % 2) != 1) {
workerName = String(pends[1][b]);
workers[workerName] = (workers[workerName] || {});
} else {
pendingAmount = parseFloat(pends[1][b]);
workers[workerName].immature = coinsRound(pendingAmount);
totalImmature += pendingAmount;
}
}
for (var w in workers) {
balances.push({
worker:String(w),
balance:workers[w].balance,
paid:workers[w].paid,
immature:workers[w].immature
});
}
pcb();
});
});
});
}, function(err) {
if (err) {
callback("There was an error getting balances");
@ -270,8 +355,8 @@ module.exports = function(logger, portalConfig, poolConfigs){
_this.stats.balances = balances;
_this.stats.address = address;
cback({totalHeld:totalHeld, totalPaid:totalPaid, balances});
cback({totalHeld:coinsRound(totalHeld), totalPaid:coinsRound(totalPaid), totalImmature:satoshisToCoins(totalImmature), balances});
});
};
@ -296,7 +381,8 @@ module.exports = function(logger, portalConfig, poolConfigs){
['smembers', ':blocksConfirmed'],
['hgetall', ':shares:roundCurrent'],
['hgetall', ':blocksPendingConfirms'],
['zrange', ':payments', -100, -1]
['zrange', ':payments', -100, -1],
['hgetall', ':shares:timesCurrent']
];
var commandsPerCoin = redisCommandTemplates.length;
@ -317,6 +403,12 @@ module.exports = function(logger, portalConfig, poolConfigs){
else{
for(var i = 0; i < replies.length; i += commandsPerCoin){
var coinName = client.coins[i / commandsPerCoin | 0];
var marketStats = {};
if (replies[i + 2]) {
if (replies[i + 2].coinmarketcap) {
marketStats = replies[i + 2] ? (JSON.parse(replies[i + 2].coinmarketcap)[0] || 0) : 0;
}
}
var coinStats = {
name: coinName,
symbol: poolConfigs[coinName].coin.symbol.toUpperCase(),
@ -335,6 +427,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
networkVersion: replies[i + 2] ? (replies[i + 2].networkSubVersion || 0) : 0,
networkProtocolVersion: replies[i + 2] ? (replies[i + 2].networkProtocolVersion || 0) : 0
},
marketStats: marketStats,
/* block stat counts */
blocks: {
pending: replies[i + 3],
@ -344,14 +437,17 @@ module.exports = function(logger, portalConfig, poolConfigs){
/* show all pending blocks */
pending: {
blocks: replies[i + 6].sort(sortBlocks),
confirms: replies[i + 9]
confirms: (replies[i + 9] || {})
},
/* show last 5 found blocks */
/* show last 50 found blocks */
confirmed: {
blocks: replies[i + 7].sort(sortBlocks).slice(0,5)
blocks: replies[i + 7].sort(sortBlocks).slice(0,50)
},
payments: [],
currentRoundShares: replies[i + 8]
currentRoundShares: (replies[i + 8] || {}),
currentRoundTimes: (replies[i + 11] || {}),
maxRoundTime: 0,
shareCount: 0
};
for(var j = replies[i + 10].length; j > 0; j--){
var jsonObj;
@ -364,17 +460,10 @@ module.exports = function(logger, portalConfig, poolConfigs){
coinStats.payments.push(jsonObj);
}
}
/*
for (var b in coinStats.confirmed.blocks) {
var parms = coinStats.confirmed.blocks[b].split(':');
if (parms[4] != null && parms[4] > 0) {
console.log(fancyTimestamp(parseInt(parms[4]), true));
}
break;
}
*/
allCoinStats[coinStats.name] = (coinStats);
}
// sort pools alphabetically
allCoinStats = sortPoolsByName(allCoinStats);
callback();
}
});
@ -419,6 +508,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
shares: workerShares,
invalidshares: 0,
currRoundShares: 0,
currRoundTime: 0,
hashrate: null,
hashrateString: null,
luckDays: null,
@ -436,6 +526,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
shares: workerShares,
invalidshares: 0,
currRoundShares: 0,
currRoundTime: 0,
hashrate: null,
hashrateString: null,
luckDays: null,
@ -455,6 +546,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
shares: 0,
invalidshares: -workerShares,
currRoundShares: 0,
currRoundTime: 0,
hashrate: null,
hashrateString: null,
luckDays: null,
@ -472,6 +564,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
shares: 0,
invalidshares: -workerShares,
currRoundShares: 0,
currRoundTime: 0,
hashrate: null,
hashrateString: null,
luckDays: null,
@ -510,6 +603,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
portalStats.algos[algo].workers += Object.keys(coinStats.workers).length;
var _shareTotal = parseFloat(0);
var _maxTimeShare = parseFloat(0);
for (var worker in coinStats.currentRoundShares) {
var miner = worker.split(".")[0];
if (miner in coinStats.miners) {
@ -520,8 +614,19 @@ module.exports = function(logger, portalConfig, poolConfigs){
}
_shareTotal += parseFloat(coinStats.currentRoundShares[worker]);
}
for (var worker in coinStats.currentRoundTimes) {
var time = parseFloat(coinStats.currentRoundTimes[worker]);
if (_maxTimeShare < time) { _maxTimeShare = time; }
var miner = worker.split(".")[0]; // split poolId from minerAddress
if (miner in coinStats.miners && coinStats.miners[miner].currRoundTime < time) {
coinStats.miners[miner].currRoundTime = time;
}
}
coinStats.shareCount = _shareTotal;
coinStats.maxRoundTime = _maxTimeShare;
coinStats.maxRoundTimeString = readableSeconds(_maxTimeShare);
for (var worker in coinStats.workers) {
var _workerRate = shareMultiplier * coinStats.workers[worker].shares / portalConfig.website.stats.hashrateWindow;
var _wHashRate = (_workerRate / 1000000) * 2;
@ -529,6 +634,10 @@ module.exports = function(logger, portalConfig, poolConfigs){
coinStats.workers[worker].luckHours = ((_networkHashRate / _wHashRate * _blocktime) / (60 * 60)).toFixed(3);
coinStats.workers[worker].hashrate = _workerRate;
coinStats.workers[worker].hashrateString = _this.getReadableHashRateString(_workerRate);
var miner = worker.split('.')[0];
if (miner in coinStats.miners) {
coinStats.workers[worker].currRoundTime = coinStats.miners[miner].currRoundTime;
}
}
for (var miner in coinStats.miners) {
var _workerRate = shareMultiplier * coinStats.miners[miner].shares / portalConfig.website.stats.hashrateWindow;
@ -559,6 +668,7 @@ module.exports = function(logger, portalConfig, poolConfigs){
delete saveStats.pools[pool].pending;
delete saveStats.pools[pool].confirmed;
delete saveStats.pools[pool].currentRoundShares;
delete saveStats.pools[pool].currentRoundTimes;
delete saveStats.pools[pool].payments;
delete saveStats.pools[pool].miners;
});
@ -591,13 +701,24 @@ module.exports = function(logger, portalConfig, poolConfigs){
};
function sortBlocks(a, b) {
var as = a.split(":");
var bs = b.split(":");
if (as[2] > bs[2]) return -1;
if (as[2] < bs[2]) return 1;
return 0;
}
function sortPoolsByName(objects) {
var newObject = {};
var sortedArray = sortProperties(objects, 'name', false, false);
for (var i = 0; i < sortedArray.length; i++) {
var key = sortedArray[i][0];
var value = sortedArray[i][1];
newObject[key] = value;
}
return newObject;
}
function sortBlocks(a, b) {
var as = parseInt(a.split(":")[2]);
var bs = parseInt(b.split(":")[2]);
if (as > bs) return -1;
if (as < bs) return 1;
return 0;
}
function sortWorkersByName(objects) {
var newObject = {};

View File

@ -1,4 +1,4 @@
var https = require('https');
var fs = require('fs');
var path = require('path');
@ -42,7 +42,8 @@ module.exports = function(logger){
'api.html': 'api',
'admin.html': 'admin',
'mining_key.html': 'mining_key',
'miner_stats.html': 'miner_stats'
'miner_stats.html': 'miner_stats',
'payments.html': 'payments'
};
var pageTemplates = {};
@ -53,7 +54,6 @@ module.exports = function(logger){
var keyScriptTemplate = '';
var keyScriptProcessed = '';
var processTemplates = function(){
for (var pageName in pageTemplates){
@ -95,13 +95,19 @@ module.exports = function(logger){
};
//If an html file was changed reload it
watch('website', function(filename){
var basename = path.basename(filename);
// if an html file was changed reload it
/* requires node-watch 0.5.0 or newer */
watch(['./website', './website/pages'], function(evt, filename){
var basename;
// support older versions of node-watch automatically
if (!filename && evt)
basename = path.basename(evt);
else
basename = path.basename(filename);
if (basename in pageFiles){
console.log(filename);
readPageFiles([basename]);
logger.debug(logSystem, 'Server', 'Reloaded file ' + basename);
logger.special(logSystem, 'Server', 'Reloaded file ' + basename);
}
});
@ -128,6 +134,9 @@ module.exports = function(logger){
async.waterfall([
function(callback){
var client = redis.createClient(portalConfig.redis.port, portalConfig.redis.host);
if (portalConfig.redis.password) {
client.auth(portalConfig.redis.password);
}
client.hgetall('coinVersionBytes', function(err, coinBytes){
if (err){
client.quit();
@ -221,6 +230,7 @@ module.exports = function(logger){
address = address.split(".")[0];
portalStats.getBalanceByAddress(address, function(){
processTemplates();
res.header('Content-Type', 'text/html');
res.end(indexesProcessed['miner_stats']);
});
}
@ -259,7 +269,7 @@ module.exports = function(logger){
else
next();
};
var route = function(req, res, next){
var pageId = req.params.page || '';
if (pageId in indexesProcessed){
@ -294,8 +304,8 @@ module.exports = function(logger){
//app.get('/stats/shares/:coin', usershares);
//app.get('/stats/shares', shares);
//app.get('/payout/:address', payout);
app.get('/workers/:address', minerpage);
app.use(compress());
app.get('/workers/:address', minerpage);
app.get('/:page', route);
app.get('/', route);
@ -326,12 +336,24 @@ module.exports = function(logger){
res.send(500, 'Something broke!');
});
try {
app.listen(portalConfig.website.port, portalConfig.website.host, function () {
try {
if (portalConfig.website.tlsOptions && portalConfig.website.tlsOptions.enabled === true) {
var TLSoptions = {
key: fs.readFileSync(portalConfig.website.tlsOptions.key),
cert: fs.readFileSync(portalConfig.website.tlsOptions.cert)
};
https.createServer(TLSoptions, app).listen(portalConfig.website.port, portalConfig.website.host, function() {
logger.debug(logSystem, 'Server', 'TLS Website started on ' + portalConfig.website.host + ':' + portalConfig.website.port);
});
} else {
app.listen(portalConfig.website.port, portalConfig.website.host, function () {
logger.debug(logSystem, 'Server', 'Website started on ' + portalConfig.website.host + ':' + portalConfig.website.port);
});
});
}
}
catch(e){
console.log(e)
logger.error(logSystem, 'Server', 'Could not start website on ' + portalConfig.website.host + ':' + portalConfig.website.port
+ ' - its either in use or you do not have permission');
}

View File

@ -1,7 +1,7 @@
{
"name": "z-nomp",
"version": "0.0.4",
"description": "Zclassic (Equihash) stratum mining pool based on NOMP",
"description": "ZenCash (Equihash) stratum mining pool based on NOMP",
"keywords": [
"stratum",
"mining",
@ -12,9 +12,9 @@
"zcash",
"equihash"
],
"homepage": "https://github.com/z-classic/z-nomp",
"homepage": "https://github.com/zencashio/z-nomp",
"bugs": {
"url": "https://github.com/z-classic/z-nomp/issues"
"url": "https://github.com/zencashio/z-nomp/issues"
},
"license": "MIT",
"author": "Joshua Yabut",
@ -31,31 +31,30 @@
},
"repository": {
"type": "git",
"url": "https://github.com/z-classic/z-nomp.git"
"url": "https://github.com/zencashio/z-nomp.git"
},
"dependencies": {
"stratum-pool": "git+https://github.com/z-classic/node-stratum-pool.git",
"dateformat": "*",
"node-json-minify": "*",
"redis": "*",
"mysql": "*",
"async": "*",
"express": "*",
"body-parser": "*",
"compression": "*",
"dot": "*",
"colors": "*",
"node-watch": "*",
"request": "*",
"nonce": "*",
"bignum": "*",
"extend": "*"
"async": "2.3.0",
"bignum": "0.12.5",
"body-parser": "1.17.1",
"colors": "1.1.2",
"compression": "1.6.2",
"dateformat": "2.0.0",
"dot": "1.1.1",
"express": "4.15.2",
"extend": "3.0.0",
"mysql": "2.13.0",
"node-json-minify": "1.0.0",
"node-watch": "0.5.2",
"nonce": "1.0.4",
"redis": "2.7.1",
"request": "2.81.0",
"stratum-pool": "git+https://github.com/z-classic/node-stratum-pool.git"
},
"engines": {
"node": ">=0.10"
},
"scripts": {
"start": "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/node_modules/stratum-pool/node_modules/equihashverify/build/Release/:$PWD/node_modules/equihashverify/build/Release/ node init.js"
"scripts": {
"start": "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/node_modules/stratum-pool/node_modules/equihashverify/build/Release/:$PWD/node_modules/equihashverify/build/Release/ node init.js"
}
}

View File

@ -26,10 +26,14 @@
},
"paymentProcessing": {
"minConf": 10,
"enabled": true,
"paymentMode": "prop",
"_comment_paymentMode":"prop, pplnt",
"paymentInterval": 57,
"_comment_paymentInterval": "Interval in seconds to check and perform payments.",
"minimumPayment": 0.1,
"maxBlocksPerPayment": 3,
"daemon": {
"host": "127.0.0.1",
"port": 8232,

View File

@ -19,9 +19,13 @@
},
"paymentProcessing": {
"minConf": 10,
"enabled": false,
"paymentMode": "prop",
"_comment_paymentMode":"prop, pplnt",
"paymentInterval": 20,
"minimumPayment": 0.1,
"maxBlocksPerPayment": 3,
"daemon": {
"host": "127.0.0.1",
"port": 19332,

View File

@ -20,9 +20,13 @@
},
"paymentProcessing": {
"minConf": 10,
"enabled": false,
"paymentMode": "prop",
"_comment_paymentMode":"prop, pplnt",
"paymentInterval": 20,
"minimumPayment": 0.1,
"maxBlocksPerPayment": 1,
"daemon": {
"host": "127.0.0.1",
"port": 19332,

View File

@ -24,9 +24,13 @@
},
"paymentProcessing": {
"minConf": 10,
"enabled": true,
"paymentMode": "prop",
"_comment_paymentMode":"prop, pplnt",
"paymentInterval": 20,
"minimumPayment": 0.1,
"maxBlocksPerPayment": 3,
"daemon": {
"host": "127.0.0.1",
"port": 8232,

View File

@ -0,0 +1,88 @@
{
"enabled": false,
"coin": "zen.json",
"address": "znZfjUjJSbUBgMsEqKLXTGxKwUerWh5dDT4",
"_comment_address": "a transparent address to send coinbase rewards to and to transfer to zAddress.",
"zAddress": "zcDVvJbyyFLznbs7jJq974pZaHKsHnk8UXof1ief8HSfQMfG75CucWACCYAZN3vnprhUXCPCUD7vMGTzrFjTjy6nNriiDbe",
"_comment_zAddress": "a private address used to send coins to tAddress.",
"tAddress": "znV763BSvdEySe3SCaTgHNiFrawiYzxRysb",
"_comment_tAddress": "transparent address used to send payments, make this a different address, otherwise payments will not send",
"invalidAddress":"znhGeka9zXmixvw6ufzGpcaSXcSACrjx5WZ",
"_comment_invalidAddress": "Invalid addresses will be converted to the above",
"walletInterval": 2.5,
"rewardRecipients": {
},
"tlsOptions": {
"enabled": false,
"serverKey":"",
"serverCert":"",
"ca":""
},
"paymentProcessing": {
"enabled": false,
"paymentMode": "prop",
"_comment_paymentMode":"prop, pplnt",
"paymentInterval": 20,
"minimumPayment": 0.1,
"maxBlocksPerPayment": 3,
"daemon": {
"host": "127.0.0.1",
"port": 8231,
"user": "rpcuser",
"password": "rpcpassword"
}
},
"ports": {
"3032": {
"tls":false,
"diff": 2.5,
"varDiff": {
"minDiff": 0.04,
"maxDiff": 16,
"targetTime": 15,
"retargetTime": 60,
"variancePercent": 30
}
}
},
"poolId": "main",
"_comment_poolId": "use it for region identification: eu, us, asia or keep default if you have one stratum instance for one coin",
"daemons": [
{
"host": "127.0.0.1",
"port": 8231,
"user": "rpcuser",
"password": "rpcpassword"
}
],
"p2p": {
"enabled": false,
"host": "127.0.0.1",
"port": 19333,
"disableTransactions": true
},
"mposMode": {
"enabled": false,
"host": "127.0.0.1",
"port": 3306,
"user": "me",
"password": "mypass",
"database": "zcl",
"checkPassword": true,
"autoCreateWorker": false
}
}

View File

@ -0,0 +1,82 @@
{
"enabled": false,
"coin": "zen_testnet.json",
"address": "ztXoXdBdoQ4WDxp9mtHNRoqZ9N5pCH2JNWe",
"_comment_address": "a transparent address to send coinbase rewards to and to transfer to zAddress.",
"zAddress": "ztZLon4AswWDcftwdN5Q94ADoZWPcCBBBHaHE84VVDd2bG9o8f6xuMFJgGMdYb35rwLi9LyGLCH3VoDBHKddrNnmEKg5N8c",
"_comment_zAddress": "a private address used to send coins to tAddress.",
"tAddress": "ztj7WuC4ASGVw4r2mCUqgHhyQxzWpxYLbNg",
"_comment_tAddress": "transparent address used to send payments, make this a different address, otherwise payments will not send",
"walletInterval": 2.5,
"rewardRecipients": {
},
"tlsOptions": {
"enabled": false,
"serverKey":"",
"serverCert":"",
"ca":""
},
"paymentProcessing": {
"enabled": false,
"paymentMode": "prop",
"_comment_paymentMode":"prop, pplnt",
"paymentInterval": 20,
"minimumPayment": 0.1,
"maxBlocksPerPayment": 3,
"daemon": {
"host": "127.0.0.1",
"port": 8232,
"user": "testuser",
"password": "testpass"
}
},
"ports": {
"3032": {
"tls":false,
"diff": 2.5,
"varDiff": {
"minDiff": 0.04,
"maxDiff": 16,
"targetTime": 15,
"retargetTime": 60,
"variancePercent": 30
}
}
},
"daemons": [
{
"host": "127.0.0.1",
"port": 18231,
"user": "rpcuser",
"password": "rpcpassword"
}
],
"p2p": {
"enabled": false,
"host": "127.0.0.1",
"port": 19333,
"disableTransactions": true
},
"mposMode": {
"enabled": false,
"host": "127.0.0.1",
"port": 3306,
"user": "me",
"password": "mypass",
"database": "zcl",
"checkPassword": true,
"autoCreateWorker": false
}
}

View File

@ -3,6 +3,7 @@
<ul>
<li><a href="/api/stats">/stats</a> global pool stats</li>
<li><a href="/api/blocks">/stats</a> global block stats</li>
<li><a href="/api/pool_stats">/pool_stats</a> - historical stats</li>
<li><a href="/api/payments">/payments</a> - payment history</li>
<li><a href="/api/worker_stats?taddr">/worker_stats?taddr</a> - historical time per pool json </li>

View File

@ -88,6 +88,7 @@
<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>

View File

@ -0,0 +1,93 @@
<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 () {
$(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)).toString(); } }}
{{ for(var pool in it.stats.pools) { }}
<table>
<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>
{{if (String(it.stats.pools[pool].name).startsWith("zcash")) { }}
<a href="https://explorer.zcha.in/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("zclassic")) { }}
<a href="https://classic.zcha.in/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("hush")) { }}
<a href="https://explorer.myhush.org/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=it.stats.pools[pool].payments[p].blocks}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("zen")) { }}
<a href="http://node1.zenchain.info:8886/tx/{{=it.stats.pools[pool].payments[p].txid}}" title="View transaction" target="_blank">{{=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>
{{ } }}

View File

@ -20,7 +20,7 @@
.chartHolder{
}
#boxesLower {
margin: 0 9px;
}
@ -69,7 +69,24 @@
.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>
@ -109,9 +126,8 @@
</div>
{{ } }}
</div>
{{ for(var pool in it.stats.pools) { }}
{{ var paidJackpots = parseFloat(it.stats.pools[pool].poolStats.validBlocks) * 1.0; }}
{{ var blockscomb = new Array; }}
<div class="pure-g-r" id="boxesLower">
<div class="pure-u-1-1">
<div class="boxStats" id="boxStatsRight">
@ -122,6 +138,7 @@
</div>
<div class="boxStatsList" style="margin-top: 9px;">
<!--<div id="{{=it.stats.pools[pool].name}}NewBlocks"></div>-->
{{ for(var b in it.stats.pools[pool].pending.blocks) { }}
{{ var block = it.stats.pools[pool].pending.blocks[b].split(":"); }}
<div style="margin-bottom: 9px; background-color: #eeeeee; min-width:600px;"><i class="fa fa-bars"></i>
@ -130,19 +147,26 @@
<a href="https://explorer.zcha.in/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("zclassic")) { }}
<a href="https://classic.zcha.in/blocks/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else if (String(it.stats.pools[pool].name).startsWith("hush")) { }}
<a href="https://explorer.myhush.org/block/{{=block[0]}}" target="_blank">{{=block[2]}}</a>
{{ } else { }}
{{=block[2]}}
{{ } }}
{{=block[2]}}
{{ } }}
{{if (block[4] != null) { }}
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
{{if (it.stats.pools[pool].pending.confirms) { }}
{{if (it.stats.pools[pool].pending.confirms[block[0]]) { }}
<span style="float:right; color: red;"><small>{{=it.stats.pools[pool].pending.confirms[block[0]]}} of 100</small></span>
{{ } else { }}
<span style="float:right; color: red;"><small>*PENDING*</small></span>
{{ } }}
{{ } else { }}
<span style="float:right; color: red;"><small>*PENDING*</small></span>
{{ } }}
{{if (it.stats.pools[pool].pending.confirms[block[0]]) { }}
<span style="float:right; color: red;"><small>{{=it.stats.pools[pool].pending.confirms[block[0]]}} of 100</small></span>
{{ } else { }}
<span style="float:right; color: red;"><small>*PENDING*</small></span>
{{ } }}
<div><i class="fa fa-gavel"></i><small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3]}}</a></div>
</div>
{{ blockscomb.push(block);}}
{{ } }}
{{ var i=0; for(var b in it.stats.pools[pool].confirmed.blocks) { }}
{{ if (i < 8) { i++; }}
@ -157,24 +181,142 @@
{{=block[2]}}
{{ } }}
{{if (block[4] != null) { }}
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
<span style="padding-left: 18px;"><small>{{=readableDate(block[4])}}</small></span>
{{ } }}
<span style="float:right; padding-left: 18px; color: green;"><small>*PAID*</small></span>
<div><i class="fa fa-gavel"></i><small>Mined By:</small> <a href="/workers/{{=block[3].split('.')[0]}}">{{=block[3]}}</a></div>
</div>
{{blockscomb.push(block);}}
{{ } }}
{{ } }}
<!--{{=JSON.stringify(blockscomb)}}-->
<script>
var blockscomb = ({{=JSON.stringify(blockscomb)}})
</script>
</div>
</div>
</div>
</div>
</div>
<center><div id="bottomCharts{{=pool}}" style="text-align:center;" align="center">
<div class="chartWrapper" style="text-align:center;">
<div class="chartLabel">Finders of the last {{=blockscomb.length}} blocks</div>
<div class="hidden" id="tooltip{{=pool}}"><p><span id="value{{=pool}}"></span> blocks found by <span id="finderr{{=pool}}"></span></p></div>
<div class="chartHolder" id="pie{{=pool}}"><svg id="blocksPie{{=pool}}" style="display: block; margin: auto; text-align:center;"/></div>
</div>
</div></center>
<script>
var groupedByFinder = {};
var data = [];
for (var i=0; i < blockscomb.length; i++) {
finder=blockscomb[i][3]; // if other doesn 't already have a property for the current letter
// create it and assign it to a new empty array
if (!(finder in groupedByFinder))
groupedByFinder[finder] = [];
groupedByFinder[finder].push(blockscomb[i]);
}
Object.keys(groupedByFinder).forEach(function(i) {
var obj = {};
obj.label = i
obj.value = groupedByFinder[i].length
data.push(obj)
});
console.log(JSON.stringify(data))
var w = 400;
var h = 400;
var r = h/2;
var legendRectSize = 18;
var legendSpacing = 5;
var color = d3.scale.category20c();
var div = d3.select("#pie{{=pool}}").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var vis = d3.select('#blocksPie{{=pool}}')
.data([data])
.attr("width", 1000)
.attr("height", h)
.attr("style", "display: block; margin: auto;")
.attr("preserveAspectRatio", "xMidYMin")
.append("svg:g")
.attr("transform", "translate(" + r + "," + r + ")");
var pie = d3.layout.pie().value(function(d){return d.value;});
// declare an arc generator function
var arc = d3.svg.arc().outerRadius(r);
// select paths, use arc generator to draw
var arcs = vis.selectAll("g.slice{{=pool}}")
.data(pie)
.enter()
.append("svg:g")
.attr("class", "slice{{=pool}}")
.attr("id", "slice")
.on("mouseover", function(d){
d3.select("#tooltip{{=pool}}")
.style("left", d3.event.pageX + "px")
.style("top", d3.event.pageY + "px")
.style("opacity", 1)
.select("#value{{=pool}}")
.text(d.data.value);
d3.select("#tooltip{{=pool}}")
.select("#finderr{{=pool}}")
.text(d.data.label);
});
arcs.append("svg:path")
.attr("fill", function(d, i){
return color(i);
})
.attr("d", function (d) {
return arc(d);
});
var legend = vis.selectAll('.legend')
.data(color.domain())
.enter()
.append('g')
.attr('class', 'legend')
.attr('id', {{=JSON.stringify(pool)}})
.attr('transform', function(d, i) {
var height = legendRectSize + legendSpacing;
var offset = height * color.domain().length / 2;
var horz = 12 * legendRectSize;
var vert = i * height;
return 'translate(' + horz + ',' + vert + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d, i) {
return data[i].label;
});
</script>
{{ } }}
<script>
document.querySelector('main').appendChild(document.createElement('script')).src = '/static/stats.js';
</script>
<script>
window.statsSource = new EventSource("/api/live_stats");
$(function() {
@ -187,7 +329,7 @@
$('#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)+paidJackpots).toFixed(8));
$('#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));
@ -195,7 +337,7 @@
}
});
});
function getReadableNetworkHashRateString(hashrate){
hashrate = (hashrate * 1000000);
if (hashrate < 1000000)

View File

@ -32,7 +32,18 @@
width: 100%;
}
</style>
<script type="text/javascript">
<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();
@ -46,7 +57,7 @@
<div class="poolLabel">
<span style="float:right; margin-bottom: 8px;">
<small>Miner Lookup:
<input type="text" class="form-control input-lg">
<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>

View File

@ -4,6 +4,7 @@ var workerHistoryMax = 160;
var statData;
var totalHash;
var totalImmature;
var totalBal;
var totalPaid;
var totalShares;
@ -143,6 +144,7 @@ function updateStats() {
totalHash = statData.totalHash;
totalPaid = statData.paid;
totalBal = statData.balance;
totalImmature = statData.immature;
totalShares = statData.totalShares;
// do some calculations
var _blocktime = 250;
@ -153,6 +155,7 @@ function updateStats() {
$("#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));
@ -175,7 +178,11 @@ function updateWorkerStats() {
function addWorkerToDisplay(name, htmlSafeName, workerObj) {
var htmlToAdd = "";
htmlToAdd = '<div class="boxStats" id="boxStatsLeft" style="float:left; margin: 9px; min-width: 260px;"><div class="boxStatsList">';
htmlToAdd+='<div class="boxLowerHeader">'+name+'</div><div>';
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>';