├── .gitignore ├── LICENSE ├── README.md ├── config_example.json ├── init.js ├── lib ├── api.js ├── apiInterfaces.js ├── blockUnlocker.js ├── charts.js ├── chartsDataCollector.js ├── cli.js ├── configReader.js ├── exceptionWriter.js ├── logger.js ├── paymentProcessor.js ├── pool.js └── utils.js ├── package.json ├── redisBlocksUpgrade.js └── website ├── admin.html ├── config.js ├── custom.css ├── custom.js ├── index.html ├── pages ├── admin │ ├── monitoring.html │ ├── statistics.html │ └── userslist.html ├── blockchain_block.html ├── blockchain_blocks.html ├── blockchain_transaction.html ├── getting_started.html ├── home.html ├── network.html ├── payments.html ├── pool_blocks.html └── support.html └── themes ├── deep-gray-dark-theme.css ├── default-theme.css ├── ease-way-light-theme.css ├── img ├── bg.jpg └── bg2.jpg ├── motherboard-dark-theme.css └── nightly-mining-dark-theme.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .idea/ 3 | config.json 4 | logs/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /config_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "coin": "dashcoin", 3 | "symbol": "DSH", 4 | "coinUnits": 1000000000000, 5 | "coinDifficultyTarget": 120, 6 | 7 | "logging": { 8 | "files": { 9 | "level": "info", 10 | "directory": "logs", 11 | "flushInterval": 5 12 | }, 13 | "console": { 14 | "level": "info", 15 | "colors": true 16 | } 17 | }, 18 | 19 | "poolServer": { 20 | "enabled": true, 21 | "clusterForks": "auto", 22 | "poolAddress": "D6WLtrV1SBWV8HWQzQv8uuYuGy3uwZ8ah5iT5HovSqhTKMauquoTsKP8RBJzVqVesX87poYWQgkGWB4NWHJ6Ravv93v4BaE", 23 | "blockRefreshInterval": 1000, 24 | "minerTimeout": 900, 25 | "ports": [ 26 | { 27 | "port": 3333, 28 | "difficulty": 100, 29 | "desc": "Low end hardware" 30 | }, 31 | { 32 | "port": 5555, 33 | "difficulty": 2000, 34 | "desc": "Mid range hardware" 35 | }, 36 | { 37 | "port": 7777, 38 | "difficulty": 10000, 39 | "desc": "High end hardware" 40 | }, 41 | { 42 | "port": 8888, 43 | "difficulty": 10000, 44 | "desc": "Hidden port", 45 | "hidden": true 46 | } 47 | ], 48 | "varDiff": { 49 | "minDiff": 100, 50 | "maxDiff": 200000, 51 | "targetTime": 100, 52 | "retargetTime": 30, 53 | "variancePercent": 30, 54 | "maxJump": 100 55 | }, 56 | "fixedDiff": { 57 | "enabled": true, 58 | "addressSeparator": "." 59 | }, 60 | "shareTrust": { 61 | "enabled": true, 62 | "min": 10, 63 | "stepDown": 3, 64 | "threshold": 10, 65 | "penalty": 30 66 | }, 67 | "banning": { 68 | "enabled": true, 69 | "time": 600, 70 | "invalidPercent": 25, 71 | "checkThreshold": 30 72 | }, 73 | "slushMining": { 74 | "enabled": false, 75 | "weight": 120, 76 | "lastBlockCheckRate": 1 77 | } 78 | }, 79 | 80 | "payments": { 81 | "enabled": true, 82 | "interval": 600, 83 | "maxAddresses": 50, 84 | "mixin": 3, 85 | "transferFee": 50000000, 86 | "minPayment": 1000000000, 87 | "maxTransactionAmount": 0, 88 | "denomination": 1000000000 89 | }, 90 | 91 | "blockUnlocker": { 92 | "enabled": true, 93 | "interval": 30, 94 | "depth": 10, 95 | "poolFee": 2, 96 | "devDonation": 0.1, 97 | "coreDevDonation": 0.1, 98 | "extraFeaturesDevDonation":0.1 99 | }, 100 | 101 | "api": { 102 | "enabled": true, 103 | "hashrateWindow": 600, 104 | "updateInterval": 5, 105 | "port": 8117, 106 | "blocks": 30, 107 | "payments": 30, 108 | "password": "your_password" 109 | }, 110 | 111 | "daemon": { 112 | "host": "127.0.0.1", 113 | "port": 42081, 114 | "legacy": false 115 | }, 116 | 117 | "wallet": { 118 | "host": "127.0.0.1", 119 | "port": 8082 120 | }, 121 | 122 | "redis": { 123 | "host": "127.0.0.1", 124 | "port": 6379 125 | }, 126 | 127 | "monitoring": { 128 | "daemon": { 129 | "checkInterval": 60, 130 | "rpcMethod": "getblockcount" 131 | }, 132 | "wallet": { 133 | "checkInterval": 60, 134 | "rpcMethod": "getbalance" 135 | } 136 | }, 137 | 138 | "charts": { 139 | "pool": { 140 | "hashrate": { 141 | "enabled": true, 142 | "updateInterval": 60, 143 | "stepInterval": 1800, 144 | "maximumPeriod": 86400 145 | }, 146 | "workers": { 147 | "enabled": true, 148 | "updateInterval": 60, 149 | "stepInterval": 1800, 150 | "maximumPeriod": 86400 151 | }, 152 | "difficulty": { 153 | "enabled": true, 154 | "updateInterval": 1800, 155 | "stepInterval": 10800, 156 | "maximumPeriod": 604800 157 | }, 158 | "price": { 159 | "enabled": true, 160 | "updateInterval": 1800, 161 | "stepInterval": 10800, 162 | "maximumPeriod": 604800 163 | }, 164 | "profit": { 165 | "enabled": true, 166 | "updateInterval": 1800, 167 | "stepInterval": 10800, 168 | "maximumPeriod": 604800 169 | } 170 | }, 171 | "user": { 172 | "hashrate": { 173 | "enabled": true, 174 | "updateInterval": 180, 175 | "stepInterval": 1800, 176 | "maximumPeriod": 86400 177 | }, 178 | "payments": { 179 | "enabled": true 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /init.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var cluster = require('cluster'); 3 | var os = require('os'); 4 | 5 | var redis = require('redis'); 6 | 7 | 8 | require('./lib/configReader.js'); 9 | 10 | require('./lib/logger.js'); 11 | 12 | 13 | global.redisClient = redis.createClient(config.redis.port, config.redis.host); 14 | 15 | 16 | if (cluster.isWorker){ 17 | switch(process.env.workerType){ 18 | case 'pool': 19 | require('./lib/pool.js'); 20 | break; 21 | case 'blockUnlocker': 22 | require('./lib/blockUnlocker.js'); 23 | break; 24 | case 'paymentProcessor': 25 | require('./lib/paymentProcessor.js'); 26 | break; 27 | case 'api': 28 | require('./lib/api.js'); 29 | break; 30 | case 'cli': 31 | require('./lib/cli.js'); 32 | break 33 | case 'chartsDataCollector': 34 | require('./lib/chartsDataCollector.js'); 35 | break 36 | 37 | } 38 | return; 39 | } 40 | 41 | var logSystem = 'master'; 42 | require('./lib/exceptionWriter.js')(logSystem); 43 | 44 | 45 | var singleModule = (function(){ 46 | 47 | var validModules = ['pool', 'api', 'unlocker', 'payments', 'chartsDataCollector']; 48 | 49 | for (var i = 0; i < process.argv.length; i++){ 50 | if (process.argv[i].indexOf('-module=') === 0){ 51 | var moduleName = process.argv[i].split('=')[1]; 52 | if (validModules.indexOf(moduleName) > -1) 53 | return moduleName; 54 | 55 | log('error', logSystem, 'Invalid module "%s", valid modules: %s', [moduleName, validModules.join(', ')]); 56 | process.exit(); 57 | } 58 | } 59 | })(); 60 | 61 | 62 | (function init(){ 63 | 64 | checkRedisVersion(function(){ 65 | 66 | if (singleModule){ 67 | log('info', logSystem, 'Running in single module mode: %s', [singleModule]); 68 | 69 | switch(singleModule){ 70 | case 'pool': 71 | spawnPoolWorkers(); 72 | break; 73 | case 'unlocker': 74 | spawnBlockUnlocker(); 75 | break; 76 | case 'payments': 77 | spawnPaymentProcessor(); 78 | break; 79 | case 'api': 80 | spawnApi(); 81 | break; 82 | case 'chartsDataCollector': 83 | spawnChartsDataCollector(); 84 | break; 85 | } 86 | } 87 | else{ 88 | spawnPoolWorkers(); 89 | spawnBlockUnlocker(); 90 | spawnPaymentProcessor(); 91 | spawnApi(); 92 | spawnChartsDataCollector(); 93 | } 94 | 95 | spawnCli(); 96 | 97 | }); 98 | })(); 99 | 100 | 101 | function checkRedisVersion(callback){ 102 | 103 | redisClient.info(function(error, response){ 104 | if (error){ 105 | log('error', logSystem, 'Redis version check failed'); 106 | return; 107 | } 108 | var parts = response.split('\r\n'); 109 | var version; 110 | var versionString; 111 | for (var i = 0; i < parts.length; i++){ 112 | if (parts[i].indexOf(':') !== -1){ 113 | var valParts = parts[i].split(':'); 114 | if (valParts[0] === 'redis_version'){ 115 | versionString = valParts[1]; 116 | version = parseFloat(versionString); 117 | break; 118 | } 119 | } 120 | } 121 | if (!version){ 122 | log('error', logSystem, 'Could not detect redis version - must be super old or broken'); 123 | return; 124 | } 125 | else if (version < 2.6){ 126 | log('error', logSystem, "You're using redis version %s the minimum required version is 2.6. Follow the damn usage instructions...", [versionString]); 127 | return; 128 | } 129 | callback(); 130 | }); 131 | } 132 | 133 | function spawnPoolWorkers(){ 134 | 135 | if (!config.poolServer || !config.poolServer.enabled || !config.poolServer.ports || config.poolServer.ports.length === 0) return; 136 | 137 | if (config.poolServer.ports.length === 0){ 138 | log('error', logSystem, 'Pool server enabled but no ports specified'); 139 | return; 140 | } 141 | 142 | 143 | var numForks = (function(){ 144 | if (!config.poolServer.clusterForks) 145 | return 1; 146 | if (config.poolServer.clusterForks === 'auto') 147 | return os.cpus().length; 148 | if (isNaN(config.poolServer.clusterForks)) 149 | return 1; 150 | return config.poolServer.clusterForks; 151 | })(); 152 | 153 | var poolWorkers = {}; 154 | 155 | var createPoolWorker = function(forkId){ 156 | var worker = cluster.fork({ 157 | workerType: 'pool', 158 | forkId: forkId 159 | }); 160 | worker.forkId = forkId; 161 | worker.type = 'pool'; 162 | poolWorkers[forkId] = worker; 163 | worker.on('exit', function(code, signal){ 164 | log('error', logSystem, 'Pool fork %s died, spawning replacement worker...', [forkId]); 165 | setTimeout(function(){ 166 | createPoolWorker(forkId); 167 | }, 2000); 168 | }).on('message', function(msg){ 169 | switch(msg.type){ 170 | case 'banIP': 171 | Object.keys(cluster.workers).forEach(function(id) { 172 | if (cluster.workers[id].type === 'pool'){ 173 | cluster.workers[id].send({type: 'banIP', ip: msg.ip}); 174 | } 175 | }); 176 | break; 177 | } 178 | }); 179 | }; 180 | 181 | var i = 1; 182 | var spawnInterval = setInterval(function(){ 183 | createPoolWorker(i.toString()); 184 | i++; 185 | if (i - 1 === numForks){ 186 | clearInterval(spawnInterval); 187 | log('info', logSystem, 'Pool spawned on %d thread(s)', [numForks]); 188 | } 189 | }, 10); 190 | } 191 | 192 | function spawnBlockUnlocker(){ 193 | 194 | if (!config.blockUnlocker || !config.blockUnlocker.enabled) return; 195 | 196 | var worker = cluster.fork({ 197 | workerType: 'blockUnlocker' 198 | }); 199 | worker.on('exit', function(code, signal){ 200 | log('error', logSystem, 'Block unlocker died, spawning replacement...'); 201 | setTimeout(function(){ 202 | spawnBlockUnlocker(); 203 | }, 2000); 204 | }); 205 | 206 | } 207 | 208 | function spawnPaymentProcessor(){ 209 | 210 | if (!config.payments || !config.payments.enabled) return; 211 | 212 | var worker = cluster.fork({ 213 | workerType: 'paymentProcessor' 214 | }); 215 | worker.on('exit', function(code, signal){ 216 | log('error', logSystem, 'Payment processor died, spawning replacement...'); 217 | setTimeout(function(){ 218 | spawnPaymentProcessor(); 219 | }, 2000); 220 | }); 221 | } 222 | 223 | function spawnApi(){ 224 | if (!config.api || !config.api.enabled) return; 225 | 226 | var worker = cluster.fork({ 227 | workerType: 'api' 228 | }); 229 | worker.on('exit', function(code, signal){ 230 | log('error', logSystem, 'API died, spawning replacement...'); 231 | setTimeout(function(){ 232 | spawnApi(); 233 | }, 2000); 234 | }); 235 | } 236 | 237 | function spawnCli(){ 238 | 239 | } 240 | 241 | function spawnChartsDataCollector(){ 242 | if (!config.charts) return; 243 | 244 | var worker = cluster.fork({ 245 | workerType: 'chartsDataCollector' 246 | }); 247 | worker.on('exit', function(code, signal){ 248 | log('error', logSystem, 'chartsDataCollector died, spawning replacement...'); 249 | setTimeout(function(){ 250 | spawnChartsDataCollector(); 251 | }, 2000); 252 | }); 253 | } 254 | -------------------------------------------------------------------------------- /lib/apiInterfaces.js: -------------------------------------------------------------------------------- 1 | var http = require('http'); 2 | var https = require('https'); 3 | 4 | function jsonHttpRequest(host, port, data, callback, path){ 5 | path = path || '/json_rpc'; 6 | 7 | var options = { 8 | hostname: host, 9 | port: port, 10 | path: path, 11 | method: data ? 'POST' : 'GET', 12 | headers: { 13 | 'Content-Length': data.length, 14 | 'Content-Type': 'application/json', 15 | 'Accept': 'application/json' 16 | } 17 | }; 18 | 19 | var req = (port == 443 ? https : http).request(options, function(res){ 20 | var replyData = ''; 21 | res.setEncoding('utf8'); 22 | res.on('data', function(chunk){ 23 | replyData += chunk; 24 | }); 25 | res.on('end', function(){ 26 | var replyJson; 27 | try{ 28 | replyJson = JSON.parse(replyData); 29 | } 30 | catch(e){ 31 | callback(e); 32 | return; 33 | } 34 | callback(null, replyJson); 35 | }); 36 | }); 37 | 38 | req.on('error', function(e){ 39 | callback(e); 40 | }); 41 | 42 | req.end(data); 43 | } 44 | 45 | function rpc(host, port, method, params, callback){ 46 | 47 | var data = JSON.stringify({ 48 | id: "0", 49 | jsonrpc: "2.0", 50 | method: method, 51 | params: params 52 | }); 53 | jsonHttpRequest(host, port, data, function(error, replyJson){ 54 | if (error){ 55 | callback(error); 56 | return; 57 | } 58 | callback(replyJson.error, replyJson.result) 59 | }); 60 | } 61 | 62 | function batchRpc(host, port, array, callback){ 63 | var rpcArray = []; 64 | for (var i = 0; i < array.length; i++){ 65 | rpcArray.push({ 66 | id: i.toString(), 67 | jsonrpc: "2.0", 68 | method: array[i][0], 69 | params: array[i][1] 70 | }); 71 | } 72 | var data = JSON.stringify(rpcArray); 73 | jsonHttpRequest(host, port, data, callback); 74 | } 75 | 76 | 77 | module.exports = function(daemonConfig, walletConfig, poolApiConfig){ 78 | return { 79 | batchRpcDaemon: function(batchArray, callback){ 80 | batchRpc(daemonConfig.host, daemonConfig.port, batchArray, callback); 81 | }, 82 | rpcDaemon: function(method, params, callback){ 83 | rpc(daemonConfig.host, daemonConfig.port, method, params, callback); 84 | }, 85 | rpcWallet: function(method, params, callback){ 86 | rpc(walletConfig.host, walletConfig.port, method, params, callback); 87 | }, 88 | pool: function(method, callback){ 89 | jsonHttpRequest('127.0.0.1', poolApiConfig.port, '', callback, method); 90 | }, 91 | jsonHttpRequest: jsonHttpRequest 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /lib/blockUnlocker.js: -------------------------------------------------------------------------------- 1 | var async = require('async'); 2 | 3 | var apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api); 4 | 5 | var logSystem = 'unlocker'; 6 | require('./exceptionWriter.js')(logSystem); 7 | 8 | log('info', logSystem, 'Started'); 9 | 10 | function runInterval(){ 11 | async.waterfall([ 12 | 13 | //Get all block candidates in redis 14 | function(callback){ 15 | redisClient.zrange(config.coin + ':blocks:candidates', 0, -1, 'WITHSCORES', function(error, results){ 16 | if (error){ 17 | log('error', logSystem, 'Error trying to get pending blocks from redis %j', [error]); 18 | callback(true); 19 | return; 20 | } 21 | if (results.length === 0){ 22 | log('info', logSystem, 'No blocks candidates in redis'); 23 | callback(true); 24 | return; 25 | } 26 | 27 | var blocks = []; 28 | 29 | for (var i = 0; i < results.length; i += 2){ 30 | var parts = results[i].split(':'); 31 | blocks.push({ 32 | serialized: results[i], 33 | height: parseInt(results[i + 1]), 34 | hash: parts[0], 35 | time: parts[1], 36 | difficulty: parts[2], 37 | shares: parts[3] 38 | }); 39 | } 40 | 41 | callback(null, blocks); 42 | }); 43 | }, 44 | 45 | //Check if blocks are orphaned 46 | function(blocks, callback){ 47 | async.filter(blocks, function(block, mapCback){ 48 | var block_height = block.height + 1; 49 | if (typeof config.daemon.legacy !== 'undefined' && config.daemon.legacy === true) { 50 | var block_height = block.height 51 | } 52 | apiInterfaces.rpcDaemon('getblockheaderbyheight', {height: block_height}, function(error, result){ 53 | if (error){ 54 | log('error', logSystem, 'Error with getblockheaderbyheight RPC request for block %s - %j', [block.serialized, error]); 55 | block.unlocked = false; 56 | mapCback(); 57 | return; 58 | } 59 | if (!result.block_header){ 60 | log('error', logSystem, 'Error with getblockheaderbyheight, no details returned for %s - %j', [block.serialized, result]); 61 | block.unlocked = false; 62 | mapCback(); 63 | return; 64 | } 65 | var blockHeader = result.block_header; 66 | block.orphaned = blockHeader.hash === block.hash ? 0 : 1; 67 | block.unlocked = blockHeader.depth >= config.blockUnlocker.depth; 68 | block.reward = blockHeader.reward; 69 | mapCback(block.unlocked); 70 | }); 71 | }, function(unlockedBlocks){ 72 | 73 | if (unlockedBlocks.length === 0){ 74 | log('info', logSystem, 'No pending blocks are unlocked yet (%d pending)', [blocks.length]); 75 | callback(true); 76 | return; 77 | } 78 | 79 | callback(null, unlockedBlocks) 80 | }) 81 | }, 82 | 83 | //Get worker shares for each unlocked block 84 | function(blocks, callback){ 85 | 86 | var redisCommands = blocks.map(function(block){ 87 | return ['hgetall', config.coin + ':shares:round' + block.height]; 88 | }); 89 | 90 | 91 | redisClient.multi(redisCommands).exec(function(error, replies){ 92 | if (error){ 93 | log('error', logSystem, 'Error with getting round shares from redis %j', [error]); 94 | callback(true); 95 | return; 96 | } 97 | for (var i = 0; i < replies.length; i++){ 98 | var workerShares = replies[i]; 99 | blocks[i].workerShares = workerShares; 100 | } 101 | callback(null, blocks); 102 | }); 103 | }, 104 | 105 | //Handle orphaned blocks 106 | function(blocks, callback){ 107 | var orphanCommands = []; 108 | 109 | blocks.forEach(function(block){ 110 | if (!block.orphaned) return; 111 | 112 | orphanCommands.push(['del', config.coin + ':shares:round' + block.height]); 113 | 114 | orphanCommands.push(['zrem', config.coin + ':blocks:candidates', block.serialized]); 115 | orphanCommands.push(['zadd', config.coin + ':blocks:matured', block.height, [ 116 | block.hash, 117 | block.time, 118 | block.difficulty, 119 | block.shares, 120 | block.orphaned 121 | ].join(':')]); 122 | 123 | if (block.workerShares) { 124 | var workerShares = block.workerShares; 125 | Object.keys(workerShares).forEach(function (worker) { 126 | orphanCommands.push(['hincrby', config.coin + ':shares:roundCurrent', worker, workerShares[worker]]); 127 | }); 128 | } 129 | }); 130 | 131 | if (orphanCommands.length > 0){ 132 | redisClient.multi(orphanCommands).exec(function(error, replies){ 133 | if (error){ 134 | log('error', logSystem, 'Error with cleaning up data in redis for orphan block(s) %j', [error]); 135 | callback(true); 136 | return; 137 | } 138 | callback(null, blocks); 139 | }); 140 | } 141 | else{ 142 | callback(null, blocks); 143 | } 144 | }, 145 | 146 | //Handle unlocked blocks 147 | function(blocks, callback){ 148 | var unlockedBlocksCommands = []; 149 | var payments = {}; 150 | var totalBlocksUnlocked = 0; 151 | blocks.forEach(function(block){ 152 | if (block.orphaned) return; 153 | totalBlocksUnlocked++; 154 | 155 | unlockedBlocksCommands.push(['del', config.coin + ':shares:round' + block.height]); 156 | unlockedBlocksCommands.push(['zrem', config.coin + ':blocks:candidates', block.serialized]); 157 | unlockedBlocksCommands.push(['zadd', config.coin + ':blocks:matured', block.height, [ 158 | block.hash, 159 | block.time, 160 | block.difficulty, 161 | block.shares, 162 | block.orphaned, 163 | block.reward 164 | ].join(':')]); 165 | 166 | var feePercent = config.blockUnlocker.poolFee / 100; 167 | 168 | if (Object.keys(donations).length) { 169 | for(var wallet in donations) { 170 | var percent = donations[wallet] / 100; 171 | feePercent += percent; 172 | payments[wallet] = Math.round(block.reward * percent); 173 | log('info', logSystem, 'Block %d donation to %s as %d percent of reward: %d', [block.height, wallet, percent, payments[wallet]]); 174 | } 175 | } 176 | 177 | var reward = Math.round(block.reward - (block.reward * feePercent)); 178 | 179 | log('info', logSystem, 'Unlocked %d block with reward %d and donation fee %d. Miners reward: %d', [block.height, block.reward, feePercent, reward]); 180 | 181 | if (block.workerShares) { 182 | var totalShares = parseInt(block.shares); 183 | Object.keys(block.workerShares).forEach(function (worker) { 184 | var percent = block.workerShares[worker] / totalShares; 185 | var workerReward = Math.round(reward * percent); 186 | payments[worker] = (payments[worker] || 0) + workerReward; 187 | log('info', logSystem, 'Block %d payment to %s for %d shares: %d', [block.height, worker, totalShares, payments[worker]]); 188 | }); 189 | } 190 | }); 191 | 192 | for (var worker in payments) { 193 | var amount = parseInt(payments[worker]); 194 | if (amount <= 0){ 195 | delete payments[worker]; 196 | continue; 197 | } 198 | unlockedBlocksCommands.push(['hincrby', config.coin + ':workers:' + worker, 'balance', amount]); 199 | } 200 | 201 | if (unlockedBlocksCommands.length === 0){ 202 | log('info', logSystem, 'No unlocked blocks yet (%d pending)', [blocks.length]); 203 | callback(true); 204 | return; 205 | } 206 | 207 | redisClient.multi(unlockedBlocksCommands).exec(function(error, replies){ 208 | if (error){ 209 | log('error', logSystem, 'Error with unlocking blocks %j', [error]); 210 | callback(true); 211 | return; 212 | } 213 | log('info', logSystem, 'Unlocked %d blocks and update balances for %d workers', [totalBlocksUnlocked, Object.keys(payments).length]); 214 | callback(null); 215 | }); 216 | } 217 | ], function(error, result){ 218 | setTimeout(runInterval, config.blockUnlocker.interval * 1000); 219 | }) 220 | } 221 | 222 | runInterval(); 223 | -------------------------------------------------------------------------------- /lib/charts.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var async = require('async'); 3 | var http = require('http'); 4 | var apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api); 5 | 6 | var logSystem = 'charts'; 7 | require('./exceptionWriter.js')(logSystem); 8 | 9 | log('info', logSystem, 'Started'); 10 | 11 | function startDataCollectors() { 12 | async.each(Object.keys(config.charts.pool), function(chartName) { 13 | var settings = config.charts.pool[chartName]; 14 | if(settings.enabled) { 15 | setInterval(function() { 16 | collectPoolStatWithInterval(chartName, settings); 17 | }, settings.updateInterval * 1000); 18 | } 19 | }); 20 | 21 | var settings = config.charts.user.hashrate; 22 | if(settings.enabled) { 23 | setInterval(function() { 24 | collectUsersHashrate('hashrate', settings); 25 | }, settings.updateInterval * 1000) 26 | } 27 | } 28 | 29 | function getChartDataFromRedis(chartName, callback) { 30 | redisClient.get(getStatsRedisKey(chartName), function(error, data) { 31 | callback(data ? JSON.parse(data) : []); 32 | }); 33 | } 34 | 35 | function getUserHashrateChartData(address, callback) { 36 | getChartDataFromRedis('hashrate:' + address, callback); 37 | } 38 | 39 | function convertPaymentsDataToChart(paymentsData) { 40 | var data = []; 41 | if(paymentsData && paymentsData.length) { 42 | for(var i = 0; paymentsData[i]; i += 2) { 43 | data.unshift([+paymentsData[i + 1], paymentsData[i].split(':')[1]]); 44 | } 45 | } 46 | return data; 47 | } 48 | 49 | function getUserChartsData(address, paymentsData, callback) { 50 | var stats = {}; 51 | var chartsFuncs = { 52 | hashrate: function(callback) { 53 | getUserHashrateChartData(address, function(data) { 54 | callback(null, data); 55 | }); 56 | }, 57 | 58 | payments: function(callback) { 59 | callback(null, convertPaymentsDataToChart(paymentsData)); 60 | } 61 | }; 62 | for(var chartName in chartsFuncs) { 63 | if(!config.charts.user[chartName].enabled) { 64 | delete chartsFuncs[chartName]; 65 | } 66 | } 67 | async.parallel(chartsFuncs, callback); 68 | } 69 | 70 | function getStatsRedisKey(chartName) { 71 | return config.coin + ':charts:' + chartName; 72 | } 73 | 74 | var chartStatFuncs = { 75 | hashrate: getPoolHashrate, 76 | workers: getPoolWorkers, 77 | difficulty: getNetworkDifficulty, 78 | price: getCoinPrice, 79 | profit: getCoinProfit 80 | }; 81 | 82 | var statValueHandler = { 83 | avg: function(set, value) { 84 | set[1] = (set[1] * set[2] + value) / (set[2] + 1); 85 | }, 86 | avgRound: function(set, value) { 87 | statValueHandler.avg(set, value); 88 | set[1] = Math.round(set[1]); 89 | }, 90 | max: function(set, value) { 91 | if(value > set[1]) { 92 | set[1] = value; 93 | } 94 | } 95 | }; 96 | 97 | var preSaveFunctions = { 98 | hashrate: statValueHandler.avgRound, 99 | workers: statValueHandler.max, 100 | difficulty: statValueHandler.avgRound, 101 | price: statValueHandler.avg, 102 | profit: statValueHandler.avg 103 | }; 104 | 105 | function storeCollectedValues(chartName, values, settings) { 106 | for(var i in values) { 107 | storeCollectedValue(chartName + ':' + i, values[i], settings); 108 | } 109 | } 110 | 111 | function storeCollectedValue(chartName, value, settings) { 112 | var now = new Date() / 1000 | 0; 113 | getChartDataFromRedis(chartName, function(sets) { 114 | var lastSet = sets[sets.length - 1]; // [time, avgValue, updatesCount] 115 | if(!lastSet || now - lastSet[0] > settings.stepInterval) { 116 | lastSet = [now, value, 1]; 117 | sets.push(lastSet); 118 | while(now - sets[0][0] > settings.maximumPeriod) { // clear old sets 119 | sets.shift(); 120 | } 121 | } 122 | else { 123 | preSaveFunctions[chartName] 124 | ? preSaveFunctions[chartName](lastSet, value) 125 | : statValueHandler.avgRound(lastSet, value); 126 | lastSet[2]++; 127 | } 128 | redisClient.set(getStatsRedisKey(chartName), JSON.stringify(sets)); 129 | log('info', logSystem, chartName + ' chart collected value ' + value + '. Total sets count ' + sets.length); 130 | }); 131 | } 132 | 133 | function collectPoolStatWithInterval(chartName, settings) { 134 | async.waterfall([ 135 | chartStatFuncs[chartName], 136 | function(value, callback) { 137 | storeCollectedValue(chartName, value, settings, callback); 138 | } 139 | ]); 140 | } 141 | 142 | function getPoolStats(callback) { 143 | apiInterfaces.pool('/stats', callback); 144 | } 145 | 146 | function getPoolHashrate(callback) { 147 | getPoolStats(function(error, stats) { 148 | callback(error, stats.pool ? Math.round(stats.pool.hashrate) : null); 149 | }); 150 | } 151 | 152 | function getPoolWorkers(callback) { 153 | getPoolStats(function(error, stats) { 154 | callback(error, stats.pool ? stats.pool.miners : null); 155 | }); 156 | } 157 | 158 | function getNetworkDifficulty(callback) { 159 | getPoolStats(function(error, stats) { 160 | callback(error, stats.pool ? stats.network.difficulty : null); 161 | }); 162 | } 163 | 164 | function getUsersHashrates(callback) { 165 | apiInterfaces.pool('/miners_hashrate', function(error, data) { 166 | callback(data.minersHashrate); 167 | }); 168 | } 169 | 170 | function collectUsersHashrate(chartName, settings) { 171 | var redisBaseKey = getStatsRedisKey(chartName) + ':'; 172 | redisClient.keys(redisBaseKey + '*', function(keys) { 173 | var hashrates = {}; 174 | for(var i in keys) { 175 | hashrates[keys[i].substr(keys[i].length)] = 0; 176 | } 177 | getUsersHashrates(function(newHashrates) { 178 | for(var address in newHashrates) { 179 | hashrates[address] = newHashrates[address]; 180 | } 181 | storeCollectedValues(chartName, hashrates, settings); 182 | }); 183 | }); 184 | } 185 | 186 | function getCoinPrice(callback) { 187 | apiInterfaces.jsonHttpRequest('api.cryptonator.com', 443, '', function(error, response) { 188 | callback(response.error ? response.error : error, response.success ? +response.ticker.price : null); 189 | }, '/api/ticker/' + config.symbol.toLowerCase() + '-usd'); 190 | } 191 | 192 | function getCoinProfit(callback) { 193 | getCoinPrice(function(error, price) { 194 | if(error) { 195 | callback(error); 196 | return; 197 | } 198 | getPoolStats(function(error, stats) { 199 | if(error) { 200 | callback(error); 201 | return; 202 | } 203 | callback(null, stats.network.reward * price / stats.network.difficulty / config.coinUnits); 204 | }); 205 | }); 206 | } 207 | 208 | function getPoolChartsData(callback) { 209 | var chartsNames = []; 210 | var redisKeys = []; 211 | for(var chartName in config.charts.pool) { 212 | if(config.charts.pool[chartName].enabled) { 213 | chartsNames.push(chartName); 214 | redisKeys.push(getStatsRedisKey(chartName)); 215 | } 216 | } 217 | if(redisKeys.length) { 218 | redisClient.mget(redisKeys, function(error, data) { 219 | var stats = {}; 220 | if(data) { 221 | for(var i in data) { 222 | if(data[i]) { 223 | stats[chartsNames[i]] = JSON.parse(data[i]); 224 | } 225 | } 226 | } 227 | callback(error, stats); 228 | }); 229 | } 230 | else { 231 | callback(null, {}); 232 | } 233 | } 234 | 235 | module.exports = { 236 | startDataCollectors: startDataCollectors, 237 | getUserChartsData: getUserChartsData, 238 | getPoolChartsData: getPoolChartsData 239 | }; 240 | -------------------------------------------------------------------------------- /lib/chartsDataCollector.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var async = require('async'); 3 | var http = require('http'); 4 | var charts = require('./charts.js'); 5 | 6 | var logSystem = 'chartsDataCollector'; 7 | require('./exceptionWriter.js')(logSystem); 8 | 9 | log('info', logSystem, 'Started'); 10 | 11 | charts.startDataCollectors(); 12 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forknote/forknote-pool/7b796fadf0775d74ff420899fa3f1e70f13a9753/lib/cli.js -------------------------------------------------------------------------------- /lib/configReader.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var configFile = (function(){ 4 | for (var i = 0; i < process.argv.length; i++){ 5 | if (process.argv[i].indexOf('-config=') === 0) 6 | return process.argv[i].split('=')[1]; 7 | } 8 | return 'config.json'; 9 | })(); 10 | 11 | 12 | try { 13 | global.config = JSON.parse(fs.readFileSync(configFile)); 14 | } 15 | catch(e){ 16 | console.error('Failed to read config file ' + configFile + '\n\n' + e); 17 | return; 18 | } 19 | 20 | var donationAddresses = { 21 | devDonation: { 22 | XMR: '45Jmf8PnJKziGyrLouJMeBFw2yVyX1QB52sKEQ4S1VSU2NVsaVGPNu4bWKkaHaeZ6tWCepP6iceZk8XhTLzDaEVa72QrtVh' 23 | }, 24 | coreDevDonation: { 25 | BCN: '252m7ru3wT5McAUztrZDExJ9PgnmyJVgk2ayucQLt13dFrf5DE4SrSBVkbtVhvZbRj1Ty4cVWaE6MGDVArZLpuMhCkrvToA', 26 | BBR: '@zoidberg', 27 | XMR: '46BeWrHpwXmHDpDEUmZBWZfoQpdc6HaERCNmx1pEYL2rAcuwufPN9rXHHtyUA4QVy66qeFQkn6sfK8aHYjA3jk3o1Bv16em', 28 | QCN: '1R9wwAH68XNGHZBsSCbyPL5EBepCoqnPPYpUuYx7jyZtc1SqekoM5p4iiB4EnkHBMXUrkwg7vR35vcoC6h48t7AjKXqXWqX', 29 | FCN: '6ntYwFY2syKVha7K1KZrhD8Uyzc2VsCpAjGi8YptCVHmfeqkAyRWQSX8gV23uvnHZY2LssBMoidGfCrVAc9k1RSsN7WKSf2', 30 | AEON: 'WmsG9mv8iSeJ8w2U9J1jRXNbLT7bCUj9VShzGuBctrhEBMHWxLZ2noSYhs8WgM4RDR68mrMW7hm33NRiDV8bNVu52azJb6XoN', 31 | OEC: 'C9ouydpeiyT2gVr5MqPUjHVJ26nJ9b8ZmMtVYRRTpGqHXA973MvzUWiFFhFCapkLmdVivd1c8Fj5wKDNw3oao7K44bUeAqx', 32 | DSH: 'D3z2DDWygoZU4NniCNa4oMjjKi45dC2KHUWUyD1RZ1pfgnRgcHdfLVQgh5gmRv4jwEjCX5LoLERAf5PbjLS43Rkd8vFUM1m', 33 | KRB: 'Kdev1L9V5ow3cdKNqDpLcFFxZCqu5W2GE9xMKewsB2pUXWxcXvJaUWHcSrHuZw91eYfQFzRtGfTemReSSMN4kE445i6Etb3' 34 | }, 35 | extraFeaturesDevDonation: { 36 | XDN: 'dddcPW8VjhJA9U2QDPunnkL8Yky83TdEBGThXsETtmAx8q7jvni7Kt4hn8pqS3ks7GhM2z9BeD22jgKewZ2kQhWK27ZaGfLHQ', 37 | BCN: '23emzdEQqoWAifE1ZQLTrGAmVkdzjami82xgX4zWoX2VbiuGuunMJ1oF14PPa1cVRgGFz8tUWevsSNzMcPqHiQmF7iSzS1g', 38 | BBR: '1Gy4NimzTgyhcZ22432N4ojP9HC6mHpML2g8SsmmjPZS4o8SYNFND99LAihRPHA2ddarf3okkJ3umTC2gLpysKBfLi4hfTF', 39 | XMR: '43JNtJkxnhX789pJnCV6W4DQt8BqAWVoV4pqjGiWZ9845ee3aTBRBibMBzSziQi9BD5aEEpegQjLwguUgsXecB5bCY5wrMe', 40 | QCN: '1MafhBsdrkW3ssQexQzHf8Q2VBEWE3DmrbySKJzXXNJFeHHTWahDkJ3iLkiKnAMMtzHPeLrsYVmkQJJ9DJx3ToodKUapV8p', 41 | FCN: '6iAu6xDGnSFekMxJj7S61aepNVXbyCrV7PgWWKSfsEPyXbUjHAxjgq3KwED3dWrgddCRRtwBrrYgmVLZR7vdBr3KLe9Cowd', 42 | MCN: 'Vdufe8Pjkp2apvJC2N3Q7KdqiDDnLR3cH8hPhB2hjBtdXRxnHmHdgESbCjAD5dv1oiFrA1jKJQqszHWELdNygCGW2Ri6qRH1B', 43 | AEON: 'Wmsfi4rDdUC4xQyMo7f4BkfuPtSooPZ3wfx8e7JFXaKyfFY5buDJF4UakwhLp3FXxKVwB3ZFLQ3bTUBksCoG3tVQ2tzkrCZDm', 44 | OEC: 'C53KdM3sWk2P27yvqihNDEVsCtDQH9koJTdmEX96ftqgTvSsuvg5HMJ2dLnynwcWr5d3oMvwzsQVKdVeYchG5iU6L5rNJjd', 45 | DSH: 'D9t1KjB9w2haRp29ueJ9jHfTyq1FSzpMqavKpfFuwa8yEdHKuryfmh4W6ZzbHC71JFLoRD4ny7HWm15jb52JYcye7bBjD62', 46 | INF8: 'inf8FtwGgmaATeXKvycUT7BfxiawxqhfRXaahPog7s4c7L8qreSvnebNDvwfDBXrip8ptgKgbToV73mS5M1cNviY5sbKhKitCd' 47 | } 48 | }; 49 | 50 | global.donations = {}; 51 | 52 | for(var configOption in donationAddresses) { 53 | var percent = config.blockUnlocker[configOption]; 54 | var wallet = donationAddresses[configOption][config.symbol]; 55 | if(percent && wallet) { 56 | global.donations[wallet] = percent; 57 | } 58 | } 59 | 60 | global.version = "v1.1.4"; 61 | -------------------------------------------------------------------------------- /lib/exceptionWriter.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var cluster = require('cluster'); 3 | 4 | var dateFormat = require('dateformat'); 5 | 6 | 7 | module.exports = function(logSystem){ 8 | 9 | process.on('uncaughtException', function(err) { 10 | console.log('\n' + err.stack + '\n'); 11 | var time = dateFormat(new Date(), 'yyyy-mm-dd HH:MM:ss'); 12 | fs.appendFile(config.logging.files.directory + '/' + logSystem + '_crash.log', time + '\n' + err.stack + '\n\n', function(err){ 13 | if (cluster.isWorker) 14 | process.exit(); 15 | }); 16 | }); 17 | }; -------------------------------------------------------------------------------- /lib/logger.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var util = require('util'); 3 | 4 | var dateFormat = require('dateformat'); 5 | var clc = require('cli-color'); 6 | 7 | var severityMap = { 8 | 'info': clc.blue, 9 | 'warn': clc.yellow, 10 | 'error': clc.red 11 | }; 12 | 13 | var severityLevels = ['info', 'warn', 'error']; 14 | 15 | 16 | var logDir = config.logging.files.directory; 17 | 18 | if (!fs.existsSync(logDir)){ 19 | try { 20 | fs.mkdirSync(logDir); 21 | } 22 | catch(e){ 23 | throw e; 24 | } 25 | } 26 | 27 | var pendingWrites = {}; 28 | 29 | setInterval(function(){ 30 | for (var fileName in pendingWrites){ 31 | var data = pendingWrites[fileName]; 32 | fs.appendFile(fileName, data); 33 | delete pendingWrites[fileName]; 34 | } 35 | }, config.logging.files.flushInterval * 1000); 36 | 37 | global.log = function(severity, system, text, data){ 38 | 39 | var logConsole = severityLevels.indexOf(severity) >= severityLevels.indexOf(config.logging.console.level); 40 | var logFiles = severityLevels.indexOf(severity) >= severityLevels.indexOf(config.logging.files.level); 41 | 42 | if (!logConsole && !logFiles) return; 43 | 44 | var time = dateFormat(new Date(), 'yyyy-mm-dd HH:MM:ss'); 45 | var formattedMessage = text; 46 | 47 | if (data) { 48 | data.unshift(text); 49 | formattedMessage = util.format.apply(null, data); 50 | } 51 | 52 | if (logConsole){ 53 | if (config.logging.console.colors) 54 | console.log(severityMap[severity](time) + clc.white.bold(' [' + system + '] ') + formattedMessage); 55 | else 56 | console.log(time + ' [' + system + '] ' + formattedMessage); 57 | } 58 | 59 | 60 | if (logFiles) { 61 | var fileName = logDir + '/' + system + '_' + severity + '.log'; 62 | var fileLine = time + ' ' + formattedMessage + '\n'; 63 | pendingWrites[fileName] = (pendingWrites[fileName] || '') + fileLine; 64 | } 65 | }; -------------------------------------------------------------------------------- /lib/paymentProcessor.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | 3 | var async = require('async'); 4 | 5 | var apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api); 6 | 7 | 8 | var logSystem = 'payments'; 9 | require('./exceptionWriter.js')(logSystem); 10 | 11 | 12 | log('info', logSystem, 'Started'); 13 | 14 | 15 | function runInterval(){ 16 | async.waterfall([ 17 | 18 | //Get worker keys 19 | function(callback){ 20 | redisClient.keys(config.coin + ':workers:*', function(error, result) { 21 | if (error) { 22 | log('error', logSystem, 'Error trying to get worker balances from redis %j', [error]); 23 | callback(true); 24 | return; 25 | } 26 | callback(null, result); 27 | }); 28 | }, 29 | 30 | //Get worker balances 31 | function(keys, callback){ 32 | var redisCommands = keys.map(function(k){ 33 | return ['hget', k, 'balance']; 34 | }); 35 | redisClient.multi(redisCommands).exec(function(error, replies){ 36 | if (error){ 37 | log('error', logSystem, 'Error with getting balances from redis %j', [error]); 38 | callback(true); 39 | return; 40 | } 41 | var balances = {}; 42 | for (var i = 0; i < replies.length; i++){ 43 | var parts = keys[i].split(':'); 44 | var workerId = parts[parts.length - 1]; 45 | balances[workerId] = parseInt(replies[i]) || 0 46 | 47 | } 48 | callback(null, balances); 49 | }); 50 | }, 51 | 52 | //Filter workers under balance threshold for payment 53 | function(balances, callback){ 54 | 55 | var payments = {}; 56 | 57 | for (var worker in balances){ 58 | var balance = balances[worker]; 59 | if (balance >= config.payments.minPayment){ 60 | var remainder = balance % config.payments.denomination; 61 | var payout = balance - remainder; 62 | if (payout < 0) continue; 63 | payments[worker] = payout; 64 | } 65 | } 66 | 67 | if (Object.keys(payments).length === 0){ 68 | log('info', logSystem, 'No workers\' balances reached the minimum payment threshold'); 69 | callback(true); 70 | return; 71 | } 72 | 73 | var transferCommands = []; 74 | var addresses = 0; 75 | var commandAmount = 0; 76 | var commandIndex = 0; 77 | 78 | for (var worker in payments){ 79 | var amount = parseInt(payments[worker]); 80 | if(config.payments.maxTransactionAmount && amount + commandAmount > config.payments.maxTransactionAmount) { 81 | amount = config.payments.maxTransactionAmount - commandAmount; 82 | } 83 | 84 | if(!transferCommands[commandIndex]) { 85 | transferCommands[commandIndex] = { 86 | redis: [], 87 | amount : 0, 88 | rpc: { 89 | destinations: [], 90 | fee: config.payments.transferFee, 91 | mixin: config.payments.mixin, 92 | unlock_time: 0 93 | } 94 | }; 95 | } 96 | 97 | transferCommands[commandIndex].rpc.destinations.push({amount: amount, address: worker}); 98 | transferCommands[commandIndex].redis.push(['hincrby', config.coin + ':workers:' + worker, 'balance', -amount]); 99 | transferCommands[commandIndex].redis.push(['hincrby', config.coin + ':workers:' + worker, 'paid', amount]); 100 | transferCommands[commandIndex].amount += amount; 101 | 102 | addresses++; 103 | commandAmount += amount; 104 | if (addresses >= config.payments.maxAddresses || ( config.payments.maxTransactionAmount && commandAmount >= config.payments.maxTransactionAmount)) { 105 | commandIndex++; 106 | addresses = 0; 107 | commandAmount = 0; 108 | } 109 | } 110 | 111 | var timeOffset = 0; 112 | 113 | async.filter(transferCommands, function(transferCmd, cback){ 114 | apiInterfaces.rpcWallet('transfer', transferCmd.rpc, function(error, result){ 115 | if (error){ 116 | log('error', logSystem, 'Error with send_transaction RPC request to wallet daemon %j', [error]); 117 | log('error', logSystem, 'Payments failed to send to %j', transferCmd.rpc.destinations); 118 | cback(false); 119 | return; 120 | } 121 | 122 | var now = (timeOffset++) + Date.now() / 1000 | 0; 123 | var txHash = result.tx_hash; 124 | 125 | 126 | transferCmd.redis.push(['zadd', config.coin + ':payments:all', now, [ 127 | txHash, 128 | transferCmd.amount, 129 | transferCmd.rpc.fee, 130 | transferCmd.rpc.mixin, 131 | Object.keys(transferCmd.rpc.destinations).length 132 | ].join(':')]); 133 | 134 | 135 | for (var i = 0; i < transferCmd.rpc.destinations.length; i++){ 136 | var destination = transferCmd.rpc.destinations[i]; 137 | transferCmd.redis.push(['zadd', config.coin + ':payments:' + destination.address, now, [ 138 | txHash, 139 | destination.amount, 140 | transferCmd.rpc.fee, 141 | transferCmd.rpc.mixin 142 | ].join(':')]); 143 | } 144 | 145 | 146 | log('info', logSystem, 'Payments sent via wallet daemon %j', [result]); 147 | redisClient.multi(transferCmd.redis).exec(function(error, replies){ 148 | if (error){ 149 | log('error', logSystem, 'Super critical error! Payments sent yet failing to update balance in redis, double payouts likely to happen %j', [error]); 150 | log('error', logSystem, 'Double payments likely to be sent to %j', transferCmd.rpc.destinations); 151 | cback(false); 152 | return; 153 | } 154 | cback(true); 155 | }); 156 | }); 157 | }, function(succeeded){ 158 | var failedAmount = transferCommands.length - succeeded.length; 159 | log('info', logSystem, 'Payments splintered and %d successfully sent, %d failed', [succeeded.length, failedAmount]); 160 | callback(null); 161 | }); 162 | 163 | } 164 | 165 | ], function(error, result){ 166 | setTimeout(runInterval, config.payments.interval * 1000); 167 | }); 168 | } 169 | 170 | runInterval(); 171 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | var base58 = require('base58-native'); 2 | var cnUtil = require('cryptonote-util'); 3 | 4 | exports.uid = function(){ 5 | var min = 100000000000000; 6 | var max = 999999999999999; 7 | var id = Math.floor(Math.random() * (max - min + 1)) + min; 8 | return id.toString(); 9 | }; 10 | 11 | exports.ringBuffer = function(maxSize){ 12 | var data = []; 13 | var cursor = 0; 14 | var isFull = false; 15 | 16 | return { 17 | append: function(x){ 18 | if (isFull){ 19 | data[cursor] = x; 20 | cursor = (cursor + 1) % maxSize; 21 | } 22 | else{ 23 | data.push(x); 24 | cursor++; 25 | if (data.length === maxSize){ 26 | cursor = 0; 27 | isFull = true; 28 | } 29 | } 30 | }, 31 | avg: function(plusOne){ 32 | var sum = data.reduce(function(a, b){ return a + b }, plusOne || 0); 33 | return sum / ((isFull ? maxSize : cursor) + (plusOne ? 1 : 0)); 34 | }, 35 | size: function(){ 36 | return isFull ? maxSize : cursor; 37 | }, 38 | clear: function(){ 39 | data = []; 40 | cursor = 0; 41 | isFull = false; 42 | } 43 | }; 44 | }; 45 | 46 | exports.varIntEncode = function(n){ 47 | 48 | }; 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forknote-pool", 3 | "version": "0.0.1", 4 | "license": "GPL-2.0", 5 | "authors": "Matthew Little", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/forknote/forknote-pool" 9 | }, 10 | "dependencies": { 11 | "bignum": "*", 12 | "async": "1", 13 | "redis": "*", 14 | "cli-color": "*", 15 | "dateformat": "*", 16 | "base58-native": "*", 17 | "multi-hashing": "git://github.com/fancoder/node-multi-hashing.git", 18 | "cryptonote-util": "git://github.com/forknote/node-cryptonote-util.git" 19 | }, 20 | "engines": { 21 | "node": ">=0.10" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /redisBlocksUpgrade.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | 5 | This script converts the block data in redis from the old format (v0.99.0.6 and earlier) to the new format 6 | used in v0.99.1+ 7 | 8 | */ 9 | 10 | var util = require('util'); 11 | 12 | var async = require('async'); 13 | 14 | var redis = require('redis'); 15 | 16 | require('./lib/configReader.js'); 17 | 18 | var apiInterfaces = require('./lib/apiInterfaces.js')(config.daemon, config.wallet); 19 | 20 | 21 | function log(severity, system, text, data){ 22 | 23 | var formattedMessage = text; 24 | 25 | if (data) { 26 | data.unshift(text); 27 | formattedMessage = util.format.apply(null, data); 28 | } 29 | 30 | console.log(severity + ': ' + formattedMessage); 31 | } 32 | 33 | 34 | var logSystem = 'reward script'; 35 | 36 | var redisClient = redis.createClient(config.redis.port, config.redis.host); 37 | 38 | function getTotalShares(height, callback){ 39 | 40 | redisClient.hgetall(config.coin + ':shares:round' + height, function(err, workerShares){ 41 | 42 | if (err) { 43 | callback(err); 44 | return; 45 | } 46 | 47 | var totalShares = Object.keys(workerShares).reduce(function(p, c){ 48 | return p + parseInt(workerShares[c]) 49 | }, 0); 50 | 51 | callback(null, totalShares); 52 | 53 | }); 54 | } 55 | 56 | 57 | async.series([ 58 | function(callback){ 59 | redisClient.smembers(config.coin + ':blocksUnlocked', function(error, result){ 60 | if (error){ 61 | log('error', logSystem, 'Error trying to get unlocke blocks from redis %j', [error]); 62 | callback(); 63 | return; 64 | } 65 | if (result.length === 0){ 66 | log('info', logSystem, 'No unlocked blocks in redis'); 67 | callback(); 68 | return; 69 | } 70 | 71 | var blocks = result.map(function(item){ 72 | var parts = item.split(':'); 73 | return { 74 | height: parseInt(parts[0]), 75 | difficulty: parts[1], 76 | hash: parts[2], 77 | time: parts[3], 78 | shares: parts[4], 79 | orphaned: 0 80 | }; 81 | }); 82 | 83 | async.map(blocks, function(block, mapCback){ 84 | apiInterfaces.rpcDaemon('getblockheaderbyheight', {height: block.height}, function(error, result){ 85 | if (error){ 86 | log('error', logSystem, 'Error with getblockheaderbyheight RPC request for block %s - %j', [block.serialized, error]); 87 | mapCback(null, block); 88 | return; 89 | } 90 | if (!result.block_header){ 91 | log('error', logSystem, 'Error with getblockheaderbyheight, no details returned for %s - %j', [block.serialized, result]); 92 | mapCback(null, block); 93 | return; 94 | } 95 | var blockHeader = result.block_header; 96 | block.reward = blockHeader.reward; 97 | mapCback(null, block); 98 | }); 99 | }, function(err, blocks){ 100 | 101 | if (blocks.length === 0){ 102 | log('info', logSystem, 'No unlocked blocks'); 103 | callback(); 104 | return; 105 | } 106 | 107 | var zaddCommands = [config.coin + ':blocks:matured']; 108 | 109 | for (var i = 0; i < blocks.length; i++){ 110 | var block = blocks[i]; 111 | zaddCommands.push(block.height); 112 | zaddCommands.push([ 113 | block.hash, 114 | block.time, 115 | block.difficulty, 116 | block.shares, 117 | block.orphaned, 118 | block.reward 119 | ].join(':')); 120 | } 121 | 122 | redisClient.zadd(zaddCommands, function(err, result){ 123 | if (err){ 124 | console.log('failed zadd ' + JSON.stringify(err)); 125 | callback(); 126 | return; 127 | } 128 | console.log('successfully converted unlocked blocks to matured blocks'); 129 | callback(); 130 | }); 131 | 132 | 133 | }); 134 | }); 135 | }, 136 | function(callback){ 137 | redisClient.smembers(config.coin + ':blocksPending', function(error, result) { 138 | if (error) { 139 | log('error', logSystem, 'Error trying to get pending blocks from redis %j', [error]); 140 | callback(); 141 | return; 142 | } 143 | if (result.length === 0) { 144 | log('info', logSystem, 'No pending blocks in redis'); 145 | callback(); 146 | return; 147 | } 148 | 149 | async.map(result, function(item, mapCback){ 150 | var parts = item.split(':'); 151 | var block = { 152 | height: parseInt(parts[0]), 153 | difficulty: parts[1], 154 | hash: parts[2], 155 | time: parts[3], 156 | serialized: item 157 | }; 158 | getTotalShares(block.height, function(err, shares){ 159 | block.shares = shares; 160 | mapCback(null, block); 161 | }); 162 | }, function(err, blocks){ 163 | 164 | var zaddCommands = [config.coin + ':blocks:candidates']; 165 | 166 | for (var i = 0; i < blocks.length; i++){ 167 | var block = blocks[i]; 168 | zaddCommands.push(block.height); 169 | zaddCommands.push([ 170 | block.hash, 171 | block.time, 172 | block.difficulty, 173 | block.shares 174 | ].join(':')); 175 | } 176 | 177 | redisClient.zadd(zaddCommands, function(err, result){ 178 | if (err){ 179 | console.log('failed zadd ' + JSON.stringify(err)); 180 | return; 181 | } 182 | console.log('successfully converted pending blocks to block candidates'); 183 | }); 184 | 185 | }); 186 | 187 | }); 188 | } 189 | ], function(){ 190 | process.exit(); 191 | }); -------------------------------------------------------------------------------- /website/admin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 68 | 69 | 70 | 71 | 222 | 223 | 224 | 225 | 226 | 244 | 245 |
246 |
247 | 252 |
253 |

254 | 255 |
256 |
257 |
258 |
259 | 260 | 261 | 262 | -------------------------------------------------------------------------------- /website/config.js: -------------------------------------------------------------------------------- 1 | var api = "http://poolhost.com:1117"; 2 | 3 | var api_blockexplorer = "http://daemonhost.com:1118"; 4 | 5 | var poolHost = "poolhost.com"; 6 | 7 | var irc = "irc.freenode.net/#poolhost"; 8 | 9 | var email = "support@poolhost.com"; 10 | 11 | var cryptonatorWidget = ["{symbol}-BTC", "{symbol}-USD", "{symbol}-EUR"]; 12 | 13 | var easyminerDownload = "https://github.com/zone117x/cryptonote-easy-miner/releases/"; 14 | 15 | var blockchainExplorer = "http://chainradar.com/{symbol}/block/{id}"; 16 | 17 | var transactionExplorer = "http://chainradar.com/{symbol}/transaction/{id}"; 18 | 19 | var themeCss = "themes/default-theme.css"; 20 | 21 | var networkStat = { 22 | "bcn": [ 23 | ["bcn.mypool.online", "http://bcn.mypool.online:8084"], 24 | ["democats.org", "http://pool.democats.org:7603"] 25 | ], 26 | "bip": [ 27 | ["bip.mypool.online", "http://bip.mypool.online:18874"], 28 | ["democats.org", "http://pool.democats.org:7693"], 29 | ["bip.cryptonotepool.com", "http://5.189.135.137:8121"], 30 | ["bip.ms-pool.net.ua", "http://bip.ms-pool.net.ua:8117"], 31 | ["bip.crypto-coins.club", "http://bip.crypto-coins.club:8118"] 32 | ], 33 | "coal": [ 34 | ["coal.mypool.online", "http://coal.mypool.online:7704"], 35 | ["democats.org", "http://pool.democats.org:7703"], 36 | ["coal.mine2gether.com", "https://coal.mine2gether.com/api"] 37 | ], 38 | "dsh": [ 39 | ["dsh.mypool.online", "http://dsh.mypool.online:29084"], 40 | ["democats.org", "http://pool.democats.org:7613"] 41 | ], 42 | "fcn": [ 43 | ["fcn.mypool.online", "http://fcn.mypool.online:24084"] 44 | ], 45 | "krb": [ 46 | ["krb.mypool.online", "http://api.krb.mypool.online:32351"], 47 | ["democats.org/pool/?name=karbowanec", "http://pool2.democats.org:7673"], 48 | ["pool.karbowanec.com", "http://pool.karbowanec.com:8117"], 49 | ["krb.sberex.com", "http://krb.sberex.com:7006"], 50 | ["krb.crypto-coins.club", "http://krb.crypto-coins.club:8118"], 51 | ["krb.cryptonotepool.com", "http://5.189.135.137:8618"], 52 | ["karbowanec.cryptopool.in", "http://karbowanec.cryptopool.in:8117"], 53 | ["krb.cryptomine.pro", "http://krb.cryptomine.pro:8117"], 54 | ["krb.kopanka.com", "http://krb.kopanka.com:8117"], 55 | ["krb.pool.ualinux.com", "http://krb.pool.ualinux.com:8117"], 56 | ["krb.mininglamp.ml", "http://krb.mininglamp.ml:8117"], 57 | ["krb.multipool.online", "http://krb.multipool.online:8117"], 58 | ["krb.tfoto.com.ua", "http://krb.tfoto.com.ua:8117"], 59 | ["usa.krb.kopanka.com", "http://usa.krb.kopanka.com:8117"], 60 | ["pool.krb-ua.tk", "http://pool.krb-ua.tk:8117"], 61 | ["krb.i-holder.net", "http://krb.i-holder.net:8117"], 62 | ["krbpool.ml", "http://krbpool.ml:8117"], 63 | ["krb.fastpool.io", "http://krb.fastpool.io:8185"], 64 | ["krb.ocukminingpool.com", "http://ocukminingpool.com:8118"], 65 | ["pool2.karbowanec.com", "http://45.77.55.161:8117"], 66 | ["krb.dreampool.info", "https://krb.dreampool.info/api"], 67 | ["krb.miner.rocks", "https://krb.miner.rocks/api"], 68 | ["easyhash.io/start/krb", "https://api-krb.easyhash.io:443"], 69 | ["mine4all.pp.ua", "http://pool2.democats.org:7673"], 70 | ["krb-pool.pp.ua", "http://krb-pool.pp.ua:25417"], 71 | ["krb.mininggood.com", "http://us2.mininggood.com:8137"], 72 | ["krbpool.com", "http://api.krbpool.com:8117"], 73 | ["krb.soyminero.es", "http://krb.soyminero.es:8119"], 74 | ["karbunkul.ga", "http://172.104.225.140:3389"], 75 | ["karbo.coinwire.eu", "http://karbo.coinwire.eu:8118"], 76 | ["krb.miningpool.org.ua", "http://165.227.163.153:7118"], 77 | ["karbowanec.hashparty.io", "http://karbowanec-pool.hashparty.io:8117"], 78 | ["karbo.farm", "http://karbo.farm:8117"], 79 | ["karbo.hashvault.pro", "http://karbo.hashvault.pro:8117"] 80 | ], 81 | "qcn": [ 82 | ["qcn.mypool.online", "http://qcn.mypool.online:23084"] 83 | ], 84 | "xci": [ 85 | ["xci.mypool.online", "http://xci.mypool.online:42004"], 86 | ["xci.cryptonotepool.com", "http://5.189.135.137:8119"] 87 | ] 88 | }; 89 | -------------------------------------------------------------------------------- /website/custom.css: -------------------------------------------------------------------------------- 1 | @import url(//fonts.googleapis.com/css?family=Roboto+Condensed:400,700); 2 | @import url(//fonts.googleapis.com/css?family=Roboto:400,300,500); 3 | /* Insert your pool's unique css here */ 4 | .marketRate { 5 | display: none; 6 | } 7 | a { 8 | color: #03a678; 9 | } 10 | a:hover { 11 | color: #025b42; 12 | } 13 | body { 14 | font-size: 14px; 15 | line-height: 1.428571429; 16 | color: #6f6e6e; 17 | font-family: 'Roboto', Helvetica, Arial, sans-serif; 18 | } 19 | h1, 20 | h2, 21 | h3, 22 | h4, 23 | h5, 24 | h6, 25 | .h1, 26 | .h2, 27 | .h3, 28 | .h4, 29 | .h5, 30 | .h6 { 31 | font-weight: 400; 32 | -webkit-font-smoothing: antialiased; 33 | font-family: 'Roboto Condensed', Arial, sans-serif; 34 | } 35 | h3, 36 | .h3 { 37 | font-size: 32px; 38 | margin-bottom: 14px; 39 | } 40 | .navbar-inverse { 41 | background-color: #2D5768; 42 | border-color: #f9f9f8; 43 | border-width: 0; 44 | } 45 | .navbar-inverse .container { 46 | background-color: rgba(0, 0, 0, 0); 47 | } 48 | .navbar-inverse .navbar-brand { 49 | color: #fff; 50 | } 51 | .navbar-inverse .navbar-brand:hover, 52 | .navbar-inverse .navbar-brand:focus { 53 | color: #fff; 54 | background-color: rgba(255, 255, 255, 0); 55 | } 56 | .navbar-inverse .navbar-text { 57 | color: #CEE3E4; 58 | } 59 | .navbar-inverse .navbar-nav > li > a { 60 | color: #F0F9FA; 61 | } 62 | .navbar-inverse .navbar-nav > li > a:hover, 63 | .navbar-inverse .navbar-nav > li > a:focus { 64 | color: #ffffff; 65 | background-color: transparent; 66 | } 67 | .navbar-inverse .navbar-nav > .active > a, 68 | .navbar-inverse .navbar-nav > .active > a:hover, 69 | .navbar-inverse .navbar-nav > .active > a:focus { 70 | color: #ffffff; 71 | background-color: #03a678; 72 | } 73 | #stats_updated { 74 | color: #F4FC3D; 75 | } 76 | hr { 77 | border-top-color: #BBBBBB; 78 | } 79 | .stats > div:not(#addressError) { 80 | color: #7C7C7C; 81 | padding: 10px 0px; 82 | } 83 | .stats > div:not(#addressError).marketFooter { 84 | padding: 5px 0; 85 | } 86 | .stats > div:not(#addressError) > i.fa { 87 | color: #03a678; 88 | font-size: 21px; 89 | width: 30px; 90 | text-align: center; 91 | } 92 | .stats > div:not(#addressError) > span:not(.input-group-btn):first-of-type { 93 | font-weight: 500; 94 | padding: 0 2px; 95 | color: #336A80; 96 | } 97 | .form-control { 98 | border: 1px solid #03a678; 99 | border-radius: 4px; 100 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 101 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 102 | -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; 103 | -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; 104 | transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; 105 | } 106 | .form-control:focus { 107 | -webkit-box-shadow: none; 108 | box-shadow: none; 109 | border-color: #027454; 110 | } 111 | .input-group-addon { 112 | background-color: #03a678; 113 | color: #fff; 114 | border-color: #03a678; 115 | } 116 | .btn-default { 117 | color: #ffffff; 118 | background-color: #03a678; 119 | border-color: #03a678; 120 | } 121 | .btn-default:hover, 122 | .btn-default:focus, 123 | .btn-default:active, 124 | .btn-default.active, 125 | .open > .dropdown-toggle.btn-default { 126 | color: #ffffff; 127 | background-color: #027454; 128 | border-color: #026a4d; 129 | } 130 | .btn-default:active, 131 | .btn-default.active, 132 | .open > .dropdown-toggle.btn-default { 133 | background-image: none; 134 | } 135 | .btn-default.disabled, 136 | .btn-default[disabled], 137 | fieldset[disabled] .btn-default, 138 | .btn-default.disabled:hover, 139 | .btn-default[disabled]:hover, 140 | fieldset[disabled] .btn-default:hover, 141 | .btn-default.disabled:focus, 142 | .btn-default[disabled]:focus, 143 | fieldset[disabled] .btn-default:focus, 144 | .btn-default.disabled:active, 145 | .btn-default[disabled]:active, 146 | fieldset[disabled] .btn-default:active, 147 | .btn-default.disabled.active, 148 | .btn-default[disabled].active, 149 | fieldset[disabled] .btn-default.active { 150 | background-color: #03a678; 151 | border-color: #03a678; 152 | } 153 | .btn-default .badge { 154 | color: #03a678; 155 | background-color: #ffffff; 156 | } 157 | .table th, 158 | .table .miningAppTitle { 159 | font-weight: 500; 160 | } 161 | code { 162 | padding: 2px 10px; 163 | color: #DB2B24; 164 | background-color: #FDECF1; 165 | border-radius: 0; 166 | } 167 | .container .paymentsStatHolder, 168 | .container .blocksStatHolder { 169 | padding-top: 20px; 170 | } 171 | .container .paymentsStatHolder > span, 172 | .container .blocksStatHolder > span { 173 | border-width: 0; 174 | padding: 6px 13px; 175 | } 176 | .container .paymentsStatHolder > span > span, 177 | .container .blocksStatHolder > span > span { 178 | font-weight: 500; 179 | } 180 | .bg-primary { 181 | background-color: #03a678; 182 | } 183 | .bg-info { 184 | background-color: #336A80; 185 | color: #fff; 186 | } 187 | .table > thead > tr > td.success, 188 | .table > tbody > tr > td.success, 189 | .table > tfoot > tr > td.success, 190 | .table > thead > tr > th.success, 191 | .table > tbody > tr > th.success, 192 | .table > tfoot > tr > th.success, 193 | .table > thead > tr.success > td, 194 | .table > tbody > tr.success > td, 195 | .table > tfoot > tr.success > td, 196 | .table > thead > tr.success > th, 197 | .table > tbody > tr.success > th, 198 | .table > tfoot > tr.success > th { 199 | background-color: #f4f9ff; 200 | } 201 | .table-hover > tbody > tr > td.success:hover, 202 | .table-hover > tbody > tr > th.success:hover, 203 | .table-hover > tbody > tr.success:hover > td, 204 | .table-hover > tbody > tr:hover > .success, 205 | .table-hover > tbody > tr.success:hover > th { 206 | background-color: #dbebff; 207 | } 208 | .table > thead > tr > th { 209 | color: #336A80; 210 | border-bottom-color: #336A80; 211 | } 212 | .table > tbody > tr > td { 213 | border-top-color: #c9e0e9; 214 | } 215 | footer { 216 | background-color: #FDFDFD; 217 | } 218 | /************************************************ 219 | *** charts *** 220 | ************************************************/ 221 | .chartsPoolStat { 222 | padding-top: 30px; 223 | } 224 | 225 | .chartWrap { 226 | display: none; 227 | } 228 | 229 | .userChart .chart, 230 | .chartWrap .chart { 231 | margin-bottom: 10px; 232 | } 233 | .userChart h4, 234 | .chartWrap h4 { 235 | text-align: center; 236 | font-size: 21px; 237 | } 238 | .userChart { 239 | display: none; 240 | } 241 | /************************************************ 242 | *** sparkline override *** 243 | ************************************************/ 244 | .jqstooltip { 245 | border: none !important; 246 | background: rgba(0, 0, 0, 0.8) !important; 247 | border-radius: 2px !important; 248 | margin-top: -20px !important; 249 | /* Override Bootstrap defaults to fix jQuery.Sparkline tooltips appearance */ 250 | -webkit-box-sizing: content-box !important; 251 | -moz-box-sizing: content-box; 252 | box-sizing: content-box !important; 253 | } 254 | .jqstooltip .jqsfield { 255 | color: #ccc; 256 | font-size: 13px !important; 257 | } 258 | .jqstooltip .jqsfield b { 259 | color: #fff; 260 | } 261 | /************************************************ 262 | *** home page fixes *** 263 | ************************************************/ 264 | #yourAddressDisplay { 265 | word-wrap: break-word; 266 | } 267 | /************************************************ 268 | *** 20% width block *** 269 | ************************************************/ 270 | .col-sm-20 { 271 | position: relative; 272 | min-height: 1px; 273 | padding-left: 15px; 274 | padding-right: 15px; 275 | } 276 | @media (min-width: 768px) { 277 | .col-sm-20 { 278 | float: left; 279 | width: 20%; 280 | } 281 | } 282 | /************************************************ 283 | *** admin page *** 284 | ************************************************/ 285 | .btn-primary { 286 | color: #ffffff; 287 | background-color: #03a678; 288 | border-color: #03a678; 289 | } 290 | .btn-primary:hover, 291 | .btn-primary:focus, 292 | .btn-primary:active, 293 | .btn-primary.active, 294 | .open > .dropdown-toggle.btn-primary { 295 | color: #ffffff; 296 | background-color: #027454; 297 | border-color: #026a4d; 298 | } 299 | .btn-primary:active, 300 | .btn-primary.active, 301 | .open > .dropdown-toggle.btn-primary { 302 | background-image: none; 303 | } 304 | .btn-primary.disabled, 305 | .btn-primary[disabled], 306 | fieldset[disabled] .btn-primary, 307 | .btn-primary.disabled:hover, 308 | .btn-primary[disabled]:hover, 309 | fieldset[disabled] .btn-primary:hover, 310 | .btn-primary.disabled:focus, 311 | .btn-primary[disabled]:focus, 312 | fieldset[disabled] .btn-primary:focus, 313 | .btn-primary.disabled:active, 314 | .btn-primary[disabled]:active, 315 | fieldset[disabled] .btn-primary:active, 316 | .btn-primary.disabled.active, 317 | .btn-primary[disabled].active, 318 | fieldset[disabled] .btn-primary.active { 319 | background-color: #03a678; 320 | border-color: #03a678; 321 | } 322 | .btn-primary .badge { 323 | color: #03a678; 324 | background-color: #ffffff; 325 | } 326 | a.list-group-item { 327 | font-size: 1.1em; 328 | } 329 | a.list-group-item.active, 330 | a.list-group-item.active:hover, 331 | a.list-group-item.active:focus { 332 | color: #ffffff; 333 | background-color: #03a678; 334 | border-color: #03a678; 335 | } 336 | a.list-group-item:first-child { 337 | border-top-right-radius: 0; 338 | border-top-left-radius: 0; 339 | } 340 | a.list-group-item:last-child { 341 | border-bottom-right-radius: 0; 342 | border-bottom-left-radius: 0; 343 | } 344 | .adminStats > div { 345 | min-height: 127px; 346 | color: #2E3D31; 347 | position: relative; 348 | -webkit-box-shadow: inset 0px 0px 0 1px #ffffff; 349 | box-shadow: inset 0px 0px 0 1px #ffffff; 350 | background-color: #EBEBEB; 351 | } 352 | .adminStats .statValue { 353 | position: absolute; 354 | display: block; 355 | padding: 0 10px; 356 | height: 100%; 357 | width: 100%; 358 | top: 0; 359 | left: 0; 360 | line-height: 100px; 361 | text-align: center; 362 | word-wrap: break-word; 363 | font-size: 17px; 364 | } 365 | .adminStats .statValue.lead { 366 | font-size: 21px; 367 | font-weight: 600; 368 | } 369 | .adminStats h4 { 370 | text-align: right; 371 | font-size: 18px; 372 | position: absolute; 373 | bottom: 10px; 374 | right: 15px; 375 | margin: 0; 376 | color: #26839B; 377 | } 378 | .adminStats .statsTitle h3 { 379 | line-height: 127px; 380 | margin: 0; 381 | color: #00C1FF; 382 | text-align: center; 383 | } 384 | .usersList { 385 | table-layout: fixed; 386 | word-wrap: break-word; 387 | } 388 | .usersList .tooltip-inner { 389 | max-width: 100%; 390 | } 391 | .usersList .sort { 392 | cursor: pointer; 393 | } 394 | .usersList tr > th:first-child { 395 | width: 40%; 396 | } 397 | strong, 398 | b { 399 | font-weight: 500; 400 | } 401 | .nav-pills > li > a { 402 | border-radius: 0; 403 | background-color: #F3F3F3; 404 | } 405 | .nav-pills > li.active > a, 406 | .nav-pills > li.active > a:hover, 407 | .nav-pills > li.active > a:focus { 408 | color: #fff; 409 | background-color: #03a678; 410 | } 411 | .adminMonitor code { 412 | white-space: normal; 413 | } 414 | .adminMonitor .tab-pane li { 415 | margin-bottom: 10px; 416 | } 417 | 418 | -------------------------------------------------------------------------------- /website/custom.js: -------------------------------------------------------------------------------- 1 | /* Insert your pool's unique Javascript here */ -------------------------------------------------------------------------------- /website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Mining Pool 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 81 | 82 | 83 | 84 | 85 | 86 | 347 | 348 | 406 | 407 |
408 | 409 |
410 | 411 |

412 | 413 |
414 | 415 | 422 | 423 | 424 | 425 | 426 | -------------------------------------------------------------------------------- /website/pages/admin/monitoring.html: -------------------------------------------------------------------------------- 1 | 2 | 64 | 65 | 66 | 124 | 125 |
126 | 127 |
128 |
129 |
130 |
131 | -------------------------------------------------------------------------------- /website/pages/admin/statistics.html: -------------------------------------------------------------------------------- 1 | 54 |
55 |
56 |

Total Owed

57 | ... 58 |
59 |
60 |

Total Paid

61 | ... 62 |
63 |
64 |

Total Mined

65 | ... 66 |
67 |
68 |

Profit (before tx fees)

69 | ... 70 |
71 |
72 |

Average Luck (shares/diff)

73 | ... 74 |
75 |
76 |

Orphan Percent

77 | ... 78 |
79 |
80 |

Registered Addresses

81 | ... 82 |
83 |
84 | -------------------------------------------------------------------------------- /website/pages/admin/userslist.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
WalletHashrate Hashes Pending Paid Last share
80 |
81 | -------------------------------------------------------------------------------- /website/pages/blockchain_block.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 |
7 | 8 |
9 | 10 |
11 |

Block

12 |
13 |
Height:
14 |
Timestamp:
15 |
Difficulty:
16 |
Orphan:
17 |
Transactions:
18 |
Total coins in the network:
19 |
Total transactions in the network:
20 |
21 | 22 |
23 |
Total transactions size, bytes:
24 |
Total block size, bytes:
25 |
Current txs median, bytes:
26 |
Effective txs median, bytes:
27 |
Reward penalty:
28 |
Base Reward:
29 |
Transactions fee:
30 |
Reward:
31 |
32 |
33 | 34 |

Тransactions

35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Hash Fee Total Amount Size
49 |
50 | 51 | 147 | -------------------------------------------------------------------------------- /website/pages/blockchain_blocks.html: -------------------------------------------------------------------------------- 1 | 25 | 26 |
27 | 28 | 31 |
32 | 33 | 110 | 111 |
112 | Total Blocks: 113 | Hash Rate: 114 | Difficulty: 115 |
116 | 117 |
118 | 119 |
120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 |
Height Size Block Hash Time Found Transactions
134 |
135 | 136 |

137 | 138 |

139 | 140 | 297 | -------------------------------------------------------------------------------- /website/pages/blockchain_transaction.html: -------------------------------------------------------------------------------- 1 | 80 | 81 | 82 |
83 | 84 |
85 | 86 | 87 |
88 |

Transaction

89 |
90 |
Hash:
91 |
Fee:
92 |
Sum of outputs:
93 |
Size:
94 |
Payment ID:
95 |
Mixin count:
96 |
97 |
98 | 99 | 100 |
101 |

From block

102 |
103 |
Hash:
104 |
Height:
105 |
Timestamp:
106 |
107 |
108 | 109 |

Inputs

110 |
111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Amount Image
122 |
123 | 124 | 125 |

Outputs

126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 |
Amount Key
138 |
139 | 140 | -------------------------------------------------------------------------------- /website/pages/getting_started.html: -------------------------------------------------------------------------------- 1 | 49 | 50 | 51 |

Connection Details

52 |
53 |
Mining Pool Address:
54 |
55 | 56 |

Mining Ports

57 |
58 |
59 |
Port:
60 |
Starting Difficulty:
61 |
Description:
62 |
63 |
64 | 65 |
66 | 67 |

For Windows users new to mining

68 |

69 | You can Download 70 | and run cryptonote-easy-miner 71 | which will automatically generate your wallet address and run CPUMiner with the proper parameters. 72 |

73 | 74 |
75 | 76 |

Mining Apps

77 |
78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 194 | 195 | 196 |
App Name Architecture Downloads Discussion Source Code
XMR-Stak-CPU (by fireice_uk)CPUGithubRedditGithub
98 | Example: 99 | xmr-stak-cpu 100 | Please edit config.txt file to suit your needs. 101 |
XMR-Stak-AMD (by fireice_uk)OpenCL (AMD)GithubRedditGithub
112 | Example: 113 | xmr-stak-amd 114 | Please edit config.txt file to suit your needs. 115 |
CPUMiner (forked by LucasJones & Wolf)CPUGithubBitcoinTalkGithub
126 | Example: 127 | minerd -a cryptonight -o stratum+tcp://: -u YOUR_WALLET_ADDRESS -p x 128 |
YAM Miner (by yvg1900)CPUMEGATwitterProprietary
139 | Example: 140 | yam -c x -M stratum+tcp://YOUR_WALLET_ADDRESS:x@:/xmr 141 |
Claymore CPU MinerCPUMEGABitcoinTalkProprietary
152 | Example: 153 | NsCpuCNMiner64 -o stratum+tcp://: -u YOUR_WALLET_ADDRESS -p x 154 |
Claymore GPU MinerOpenCL (AMD)MEGADiscussionProprietary
165 | Example: 166 | NsGpuCNMiner -o stratum+tcp://: -u YOUR_WALLET_ADDRESS -p x 167 |
ccminer (forked by tsiv)CUDA (Nvidia)GithubBitcoinTalkGithub
178 | Example: 179 | ccminer -o stratum+tcp://: -u YOUR_WALLET_ADDRESS -p x 180 |
xmrMinerCUDA (Nvidia)GithubForumGithub
191 | Example: 192 | xmrMiner_0.2.0.exe --url=stratum+tcp://: -u YOUR_WALLET_ADDRESS -p x --bfactor=8 --bsleep=100 193 |
197 |
198 | 199 | 200 | -------------------------------------------------------------------------------- /website/pages/network.html: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
Pools Height Hashrate Miners Total Fee Last Block Found
24 |
25 | 26 | 73 | -------------------------------------------------------------------------------- /website/pages/payments.html: -------------------------------------------------------------------------------- 1 | 19 | 20 |
21 | Total Payments: 22 | Total Miners Paid: 23 | Minimum Payment Threshold: 24 | Denomination Unit: 25 |
26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
Time Sent Transaction Hash Amount Fee Mixin Payees
45 |
46 | 47 |

48 | 49 |

50 | 51 | 52 | -------------------------------------------------------------------------------- /website/pages/pool_blocks.html: -------------------------------------------------------------------------------- 1 | 25 | 26 |
27 | Total Blocks Mined: 28 | Maturity Depth Requirement: 29 |
30 | 31 |
32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Height Maturity Difficulty Block Hash Time Found Shares/Diff
49 |
50 | 51 |

52 | 53 |

54 | 55 | 218 | -------------------------------------------------------------------------------- /website/pages/support.html: -------------------------------------------------------------------------------- 1 |

Contact

2 |

Email pool support at

3 | 4 |

Chat Room

5 | 6 | 7 | -------------------------------------------------------------------------------- /website/themes/deep-gray-dark-theme.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #3AB34D; 3 | } 4 | a:hover { 5 | color: #34a045; 6 | } 7 | body { 8 | color: #ffffff; 9 | background-color: #000000; 10 | background-image: url(http://subtlepatterns.com/patterns/outlets.png); 11 | } 12 | .form-control { 13 | background-color: rgba(0, 0, 0, 0.7); 14 | color: #fff; 15 | } 16 | .navbar-inverse { 17 | background-color: #464646; 18 | border-color: #000000; 19 | border-bottom: 1px solid #6d6d6d; 20 | } 21 | .navbar-inverse .container { 22 | background-color: rgba(0, 0, 0, 0); 23 | } 24 | .navbar-inverse .navbar-brand { 25 | color: #fff; 26 | } 27 | .navbar-inverse .navbar-brand:hover, 28 | .navbar-inverse .navbar-brand:focus { 29 | color: #fff; 30 | background-color: rgba(255, 255, 255, 0); 31 | } 32 | .navbar-inverse .navbar-text { 33 | color: #CEE3E4; 34 | } 35 | .navbar-inverse .navbar-nav > li > a { 36 | color: #F0F9FA; 37 | } 38 | .navbar-inverse .navbar-nav > li > a:hover, 39 | .navbar-inverse .navbar-nav > li > a:focus { 40 | color: #ffffff; 41 | background-color: transparent; 42 | } 43 | .navbar-inverse .navbar-nav > .active > a, 44 | .navbar-inverse .navbar-nav > .active > a:hover, 45 | .navbar-inverse .navbar-nav > .active > a:focus { 46 | color: #ffffff; 47 | background-color: #6d6d6d; 48 | } 49 | #stats_updated { 50 | /*color: #F4FC3D;*/ 51 | } 52 | hr { 53 | border-top-color: #818181 !important; 54 | } 55 | .stats > div:not(#addressError) { 56 | color: #E2E2E2; 57 | } 58 | .stats > div:not(#addressError) > i.fa { 59 | color: #A5A5A5; 60 | } 61 | .stats > div:not(#addressError) > span:not(.input-group-btn):first-of-type { 62 | color: #755900; 63 | } 64 | .form-control { 65 | border: 1px solid #6d6d6d; 66 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 67 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 68 | } 69 | .form-control:focus { 70 | border-color: #535353; 71 | } 72 | .input-group-addon { 73 | background-color: #6d6d6d; 74 | color: #fff; 75 | border-color: #6d6d6d; 76 | } 77 | .btn-default { 78 | color: #ffffff; 79 | background-color: #6d6d6d; 80 | border-color: #6d6d6d; 81 | } 82 | .btn-default:hover, 83 | .btn-default:focus, 84 | .btn-default:active, 85 | .btn-default.active, 86 | .open > .dropdown-toggle.btn-default { 87 | color: #ffffff; 88 | background-color: #535353; 89 | border-color: #4e4e4e; 90 | } 91 | .btn-default:active, 92 | .btn-default.active, 93 | .open > .dropdown-toggle.btn-default { 94 | background-image: none; 95 | } 96 | .btn-default.disabled, 97 | .btn-default[disabled], 98 | fieldset[disabled] .btn-default, 99 | .btn-default.disabled:hover, 100 | .btn-default[disabled]:hover, 101 | fieldset[disabled] .btn-default:hover, 102 | .btn-default.disabled:focus, 103 | .btn-default[disabled]:focus, 104 | fieldset[disabled] .btn-default:focus, 105 | .btn-default.disabled:active, 106 | .btn-default[disabled]:active, 107 | fieldset[disabled] .btn-default:active, 108 | .btn-default.disabled.active, 109 | .btn-default[disabled].active, 110 | fieldset[disabled] .btn-default.active { 111 | background-color: #6d6d6d; 112 | border-color: #6d6d6d; 113 | } 114 | .btn-default .badge { 115 | color: #6d6d6d; 116 | background-color: #ffffff; 117 | } 118 | code { 119 | color: #FFF500; 120 | background-color: #3D3D3D; 121 | } 122 | .bg-primary { 123 | background-color: #6d6d6d; 124 | } 125 | .bg-info { 126 | background-color: #A3A3A3; 127 | color: #fff; 128 | } 129 | .table > thead > tr > td.success, 130 | .table > tbody > tr > td.success, 131 | .table > tfoot > tr > td.success, 132 | .table > thead > tr > th.success, 133 | .table > tbody > tr > th.success, 134 | .table > tfoot > tr > th.success, 135 | .table > thead > tr.success > td, 136 | .table > tbody > tr.success > td, 137 | .table > tfoot > tr.success > td, 138 | .table > thead > tr.success > th, 139 | .table > tbody > tr.success > th, 140 | .table > tfoot > tr.success > th { 141 | background-color: #000000; 142 | } 143 | .table-hover > tbody > tr > td.success:hover, 144 | .table-hover > tbody > tr > th.success:hover, 145 | .table-hover > tbody > tr.success:hover > td, 146 | .table-hover > tbody > tr:hover > .success, 147 | .table-hover > tbody > tr.success:hover > th { 148 | background-color: #000000; 149 | } 150 | .table > thead > tr > th { 151 | color: #C2C2C2; 152 | border-bottom-color: #C2C2C2; 153 | } 154 | .table-striped > tbody > tr:nth-child(odd) > td, 155 | .table-striped > tbody > tr:nth-child(odd) > th { 156 | background-color: #2E2E2E; 157 | } 158 | .table > tbody > tr:hover td, 159 | .table > tbody > tr:hover th { 160 | background-color: #353535; 161 | } 162 | .table > tbody > tr > td { 163 | border-top-color: #c9e0e9; 164 | } 165 | .table > tbody > tr > td .luckGood { 166 | color: #5eff5e; 167 | } 168 | .table > tbody > tr > td .luckBad { 169 | color: red; 170 | } 171 | footer { 172 | background-color: #464646 !important; 173 | } 174 | footer .text-muted { 175 | color: #fff; 176 | } 177 | .chartWrap p span { 178 | color: #755900; 179 | } 180 | .btn-primary { 181 | color: #ffffff; 182 | background-color: #6d6d6d; 183 | border-color: #6d6d6d; 184 | } 185 | .btn-primary:hover, 186 | .btn-primary:focus, 187 | .btn-primary:active, 188 | .btn-primary.active, 189 | .open > .dropdown-toggle.btn-primary { 190 | color: #ffffff; 191 | background-color: #535353; 192 | border-color: #4e4e4e; 193 | } 194 | .btn-primary:active, 195 | .btn-primary.active, 196 | .open > .dropdown-toggle.btn-primary { 197 | background-image: none; 198 | } 199 | .btn-primary.disabled, 200 | .btn-primary[disabled], 201 | fieldset[disabled] .btn-primary, 202 | .btn-primary.disabled:hover, 203 | .btn-primary[disabled]:hover, 204 | fieldset[disabled] .btn-primary:hover, 205 | .btn-primary.disabled:focus, 206 | .btn-primary[disabled]:focus, 207 | fieldset[disabled] .btn-primary:focus, 208 | .btn-primary.disabled:active, 209 | .btn-primary[disabled]:active, 210 | fieldset[disabled] .btn-primary:active, 211 | .btn-primary.disabled.active, 212 | .btn-primary[disabled].active, 213 | fieldset[disabled] .btn-primary.active { 214 | background-color: #6d6d6d; 215 | border-color: #6d6d6d; 216 | } 217 | .btn-primary .badge { 218 | color: #6d6d6d; 219 | background-color: #ffffff; 220 | } 221 | a.list-group-item.active, 222 | a.list-group-item.active:hover, 223 | a.list-group-item.active:focus { 224 | color: #ffffff; 225 | background-color: #6d6d6d; 226 | border-color: #6d6d6d; 227 | } 228 | .adminStats > div { 229 | color: #2E3D31; 230 | -webkit-box-shadow: inset 0px 0px 0 1px #ffffff; 231 | box-shadow: inset 0px 0px 0 1px #ffffff; 232 | background-color: #EBEBEB; 233 | } 234 | .adminStats h4 { 235 | color: #26839B; 236 | } 237 | .adminStats .statsTitle h3 { 238 | color: #00C1FF; 239 | } 240 | .nav-pills > li > a { 241 | background-color: #F3F3F3; 242 | } 243 | .nav-pills > li.active > a, 244 | .nav-pills > li.active > a:hover, 245 | .nav-pills > li.active > a:focus { 246 | background-color: #6d6d6d; 247 | } 248 | -------------------------------------------------------------------------------- /website/themes/default-theme.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #03a678; 3 | } 4 | a:hover { 5 | color: #025b42; 6 | } 7 | body { 8 | line-height: 1.428571429; 9 | color: #6f6e6e; 10 | } 11 | .navbar-inverse { 12 | background-color: #2D5768; 13 | border-color: #f9f9f8; 14 | } 15 | .navbar-inverse .container { 16 | background-color: rgba(0, 0, 0, 0); 17 | } 18 | .navbar-inverse .navbar-brand { 19 | color: #fff; 20 | } 21 | .navbar-inverse .navbar-brand:hover, 22 | .navbar-inverse .navbar-brand:focus { 23 | color: #fff; 24 | background-color: rgba(255, 255, 255, 0); 25 | } 26 | .navbar-inverse .navbar-text { 27 | color: #CEE3E4; 28 | } 29 | .navbar-inverse .navbar-nav > li > a { 30 | color: #F0F9FA; 31 | } 32 | .navbar-inverse .navbar-nav > li > a:hover, 33 | .navbar-inverse .navbar-nav > li > a:focus { 34 | color: #ffffff; 35 | background-color: transparent; 36 | } 37 | .navbar-inverse .navbar-nav > .active > a, 38 | .navbar-inverse .navbar-nav > .active > a:hover, 39 | .navbar-inverse .navbar-nav > .active > a:focus { 40 | color: #ffffff; 41 | background-color: #03a678; 42 | } 43 | #stats_updated { 44 | color: #F4FC3D; 45 | } 46 | hr { 47 | border-top-color: #BBBBBB; 48 | } 49 | .stats > div:not(#addressError) { 50 | color: #7C7C7C; 51 | } 52 | .stats > div:not(#addressError) > i.fa { 53 | color: #03a678; 54 | } 55 | .stats > div:not(#addressError) > span:not(.input-group-btn):first-of-type { 56 | color: #336A80; 57 | } 58 | .form-control { 59 | border: 1px solid #03a678; 60 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 61 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 62 | } 63 | .form-control:focus { 64 | border-color: #027454; 65 | } 66 | .input-group-addon { 67 | background-color: #03a678; 68 | color: #fff; 69 | border-color: #03a678; 70 | } 71 | .btn-default { 72 | color: #ffffff; 73 | background-color: #03a678; 74 | border-color: #03a678; 75 | } 76 | .btn-default:hover, 77 | .btn-default:focus, 78 | .btn-default:active, 79 | .btn-default.active, 80 | .open > .dropdown-toggle.btn-default { 81 | color: #ffffff; 82 | background-color: #027454; 83 | border-color: #026a4d; 84 | } 85 | .btn-default:active, 86 | .btn-default.active, 87 | .open > .dropdown-toggle.btn-default { 88 | background-image: none; 89 | } 90 | .btn-default.disabled, 91 | .btn-default[disabled], 92 | fieldset[disabled] .btn-default, 93 | .btn-default.disabled:hover, 94 | .btn-default[disabled]:hover, 95 | fieldset[disabled] .btn-default:hover, 96 | .btn-default.disabled:focus, 97 | .btn-default[disabled]:focus, 98 | fieldset[disabled] .btn-default:focus, 99 | .btn-default.disabled:active, 100 | .btn-default[disabled]:active, 101 | fieldset[disabled] .btn-default:active, 102 | .btn-default.disabled.active, 103 | .btn-default[disabled].active, 104 | fieldset[disabled] .btn-default.active { 105 | background-color: #03a678; 106 | border-color: #03a678; 107 | } 108 | .btn-default .badge { 109 | color: #03a678; 110 | background-color: #ffffff; 111 | } 112 | code { 113 | color: #DB2B24; 114 | background-color: #FDECF1; 115 | } 116 | .bg-primary { 117 | background-color: #03a678; 118 | } 119 | .bg-info { 120 | background-color: #336A80; 121 | color: #fff; 122 | } 123 | .table > thead > tr > td.success, 124 | .table > tbody > tr > td.success, 125 | .table > tfoot > tr > td.success, 126 | .table > thead > tr > th.success, 127 | .table > tbody > tr > th.success, 128 | .table > tfoot > tr > th.success, 129 | .table > thead > tr.success > td, 130 | .table > tbody > tr.success > td, 131 | .table > tfoot > tr.success > td, 132 | .table > thead > tr.success > th, 133 | .table > tbody > tr.success > th, 134 | .table > tfoot > tr.success > th { 135 | background-color: #f4f9ff; 136 | } 137 | .table-hover > tbody > tr > td.success:hover, 138 | .table-hover > tbody > tr > th.success:hover, 139 | .table-hover > tbody > tr.success:hover > td, 140 | .table-hover > tbody > tr:hover > .success, 141 | .table-hover > tbody > tr.success:hover > th { 142 | background-color: #dbebff; 143 | } 144 | .table > thead > tr > th { 145 | color: #336A80; 146 | border-bottom-color: #336A80; 147 | } 148 | .table > tbody > tr > td { 149 | border-top-color: #c9e0e9; 150 | } 151 | footer { 152 | background-color: #FDFDFD; 153 | } 154 | .btn-primary { 155 | color: #ffffff; 156 | background-color: #03a678; 157 | border-color: #03a678; 158 | } 159 | .btn-primary:hover, 160 | .btn-primary:focus, 161 | .btn-primary:active, 162 | .btn-primary.active, 163 | .open > .dropdown-toggle.btn-primary { 164 | color: #ffffff; 165 | background-color: #027454; 166 | border-color: #026a4d; 167 | } 168 | .btn-primary:active, 169 | .btn-primary.active, 170 | .open > .dropdown-toggle.btn-primary { 171 | background-image: none; 172 | } 173 | .btn-primary.disabled, 174 | .btn-primary[disabled], 175 | fieldset[disabled] .btn-primary, 176 | .btn-primary.disabled:hover, 177 | .btn-primary[disabled]:hover, 178 | fieldset[disabled] .btn-primary:hover, 179 | .btn-primary.disabled:focus, 180 | .btn-primary[disabled]:focus, 181 | fieldset[disabled] .btn-primary:focus, 182 | .btn-primary.disabled:active, 183 | .btn-primary[disabled]:active, 184 | fieldset[disabled] .btn-primary:active, 185 | .btn-primary.disabled.active, 186 | .btn-primary[disabled].active, 187 | fieldset[disabled] .btn-primary.active { 188 | background-color: #03a678; 189 | border-color: #03a678; 190 | } 191 | .btn-primary .badge { 192 | color: #03a678; 193 | background-color: #ffffff; 194 | } 195 | a.list-group-item.active, 196 | a.list-group-item.active:hover, 197 | a.list-group-item.active:focus { 198 | color: #ffffff; 199 | background-color: #03a678; 200 | border-color: #03a678; 201 | } 202 | .adminStats > div { 203 | color: #2E3D31; 204 | -webkit-box-shadow: inset 0px 0px 0 1px #ffffff; 205 | box-shadow: inset 0px 0px 0 1px #ffffff; 206 | background-color: #EBEBEB; 207 | } 208 | .adminStats h4 { 209 | color: #26839B; 210 | } 211 | .adminStats .statsTitle h3 { 212 | color: #00C1FF; 213 | } 214 | .nav-pills > li > a { 215 | background-color: #F3F3F3; 216 | } 217 | .nav-pills > li.active > a, 218 | .nav-pills > li.active > a:hover, 219 | .nav-pills > li.active > a:focus { 220 | color: #fff; 221 | background-color: #03a678; 222 | } 223 | 224 | -------------------------------------------------------------------------------- /website/themes/ease-way-light-theme.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #0088aa; 3 | } 4 | a:hover { 5 | color: #007491; 6 | } 7 | body { 8 | color: #8a8a8a; 9 | background-color: #ffffff; 10 | background-image: url(img/bg2.jpg); 11 | background-repeat: no-repeat; 12 | background-position: center center; 13 | background-attachment: fixed; 14 | } 15 | .navbar-inverse { 16 | background-color: #2B2B2B; 17 | border-color: #ffffff; 18 | border-bottom: 1px solid #0088aa; 19 | } 20 | .navbar-inverse .container { 21 | background-color: rgba(0, 0, 0, 0); 22 | } 23 | .navbar-inverse .navbar-brand { 24 | color: #fff; 25 | } 26 | .navbar-inverse .navbar-brand:hover, 27 | .navbar-inverse .navbar-brand:focus { 28 | color: #fff; 29 | background-color: rgba(255, 255, 255, 0); 30 | } 31 | .navbar-inverse .navbar-text { 32 | color: #CEE3E4; 33 | } 34 | .navbar-inverse .navbar-nav > li > a { 35 | color: #F0F9FA; 36 | } 37 | .navbar-inverse .navbar-nav > li > a:hover, 38 | .navbar-inverse .navbar-nav > li > a:focus { 39 | color: #ffffff; 40 | background-color: transparent; 41 | } 42 | .navbar-inverse .navbar-nav > .active > a, 43 | .navbar-inverse .navbar-nav > .active > a:hover, 44 | .navbar-inverse .navbar-nav > .active > a:focus { 45 | color: #ffffff; 46 | background-color: #0088aa; 47 | } 48 | #stats_updated { 49 | /*color: #F4FC3D;*/ 50 | } 51 | hr { 52 | border-top-color: #818181 !important; 53 | } 54 | .stats > div:not(#addressError) { 55 | color: #8A8A8A; 56 | } 57 | .stats > div:not(#addressError) > i.fa { 58 | color: #727272; 59 | } 60 | .stats > div:not(#addressError) > span:not(.input-group-btn):first-of-type { 61 | color: #464646; 62 | } 63 | .form-control { 64 | border: 1px solid #0088aa; 65 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 66 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 67 | } 68 | .form-control:focus { 69 | border-color: #005f77; 70 | } 71 | .input-group-addon { 72 | background-color: #0088aa; 73 | color: #fff; 74 | border-color: #0088aa; 75 | } 76 | .btn-default { 77 | color: #ffffff; 78 | background-color: #0088aa; 79 | border-color: #0088aa; 80 | } 81 | .btn-default:hover, 82 | .btn-default:focus, 83 | .btn-default:active, 84 | .btn-default.active, 85 | .open > .dropdown-toggle.btn-default { 86 | color: #ffffff; 87 | background-color: #005f77; 88 | border-color: #00576d; 89 | } 90 | .btn-default:active, 91 | .btn-default.active, 92 | .open > .dropdown-toggle.btn-default { 93 | background-image: none; 94 | } 95 | .btn-default.disabled, 96 | .btn-default[disabled], 97 | fieldset[disabled] .btn-default, 98 | .btn-default.disabled:hover, 99 | .btn-default[disabled]:hover, 100 | fieldset[disabled] .btn-default:hover, 101 | .btn-default.disabled:focus, 102 | .btn-default[disabled]:focus, 103 | fieldset[disabled] .btn-default:focus, 104 | .btn-default.disabled:active, 105 | .btn-default[disabled]:active, 106 | fieldset[disabled] .btn-default:active, 107 | .btn-default.disabled.active, 108 | .btn-default[disabled].active, 109 | fieldset[disabled] .btn-default.active { 110 | background-color: #0088aa; 111 | border-color: #0088aa; 112 | } 113 | .btn-default .badge { 114 | color: #0088aa; 115 | background-color: #ffffff; 116 | } 117 | code { 118 | color: #4F5A51; 119 | background-color: #C9C9C9; 120 | } 121 | .bg-primary { 122 | background-color: #0088aa; 123 | } 124 | .bg-info { 125 | background-color: #A3A3A3; 126 | color: #fff; 127 | } 128 | .table > thead > tr > td.success, 129 | .table > tbody > tr > td.success, 130 | .table > tfoot > tr > td.success, 131 | .table > thead > tr > th.success, 132 | .table > tbody > tr > th.success, 133 | .table > tfoot > tr > th.success, 134 | .table > thead > tr.success > td, 135 | .table > tbody > tr.success > td, 136 | .table > tfoot > tr.success > td, 137 | .table > thead > tr.success > th, 138 | .table > tbody > tr.success > th, 139 | .table > tfoot > tr.success > th { 140 | background-color: #fafafa; 141 | } 142 | .table-hover > tbody > tr > td.success:hover, 143 | .table-hover > tbody > tr > th.success:hover, 144 | .table-hover > tbody > tr.success:hover > td, 145 | .table-hover > tbody > tr:hover > .success, 146 | .table-hover > tbody > tr.success:hover > th { 147 | background-color: #ededed; 148 | } 149 | .table > thead > tr > th { 150 | color: #0088aa; 151 | border-bottom-color: #0088aa; 152 | } 153 | .table-striped > tbody > tr:nth-child(odd) > td, 154 | .table-striped > tbody > tr:nth-child(odd) > th { 155 | background-color: #E7E7E7; 156 | } 157 | .table > tbody > tr:hover td, 158 | .table > tbody > tr:hover th { 159 | background-color: #E7E7E7; 160 | } 161 | .table > tbody > tr > td { 162 | border-top-color: #c9e0e9; 163 | } 164 | .table > tbody > tr > td .luckGood { 165 | color: #008500; 166 | } 167 | .table > tbody > tr > td .luckBad { 168 | color: red; 169 | } 170 | footer { 171 | background-color: #2B2B2B !important; 172 | } 173 | footer .text-muted { 174 | color: #fff; 175 | } 176 | .chartWrap p span { 177 | color: #464646; 178 | } 179 | .btn-primary { 180 | color: #ffffff; 181 | background-color: #0088aa; 182 | border-color: #0088aa; 183 | } 184 | .btn-primary:hover, 185 | .btn-primary:focus, 186 | .btn-primary:active, 187 | .btn-primary.active, 188 | .open > .dropdown-toggle.btn-primary { 189 | color: #ffffff; 190 | background-color: #005f77; 191 | border-color: #00576d; 192 | } 193 | .btn-primary:active, 194 | .btn-primary.active, 195 | .open > .dropdown-toggle.btn-primary { 196 | background-image: none; 197 | } 198 | .btn-primary.disabled, 199 | .btn-primary[disabled], 200 | fieldset[disabled] .btn-primary, 201 | .btn-primary.disabled:hover, 202 | .btn-primary[disabled]:hover, 203 | fieldset[disabled] .btn-primary:hover, 204 | .btn-primary.disabled:focus, 205 | .btn-primary[disabled]:focus, 206 | fieldset[disabled] .btn-primary:focus, 207 | .btn-primary.disabled:active, 208 | .btn-primary[disabled]:active, 209 | fieldset[disabled] .btn-primary:active, 210 | .btn-primary.disabled.active, 211 | .btn-primary[disabled].active, 212 | fieldset[disabled] .btn-primary.active { 213 | background-color: #0088aa; 214 | border-color: #0088aa; 215 | } 216 | .btn-primary .badge { 217 | color: #0088aa; 218 | background-color: #ffffff; 219 | } 220 | a.list-group-item.active, 221 | a.list-group-item.active:hover, 222 | a.list-group-item.active:focus { 223 | color: #ffffff; 224 | background-color: #0088aa; 225 | border-color: #0088aa; 226 | } 227 | .adminStats > div { 228 | color: #2E3D31; 229 | -webkit-box-shadow: inset 0px 0px 0 1px #ffffff; 230 | box-shadow: inset 0px 0px 0 1px #ffffff; 231 | background-color: #EBEBEB; 232 | } 233 | .adminStats h4 { 234 | color: #26839B; 235 | } 236 | .adminStats .statsTitle h3 { 237 | color: #00C1FF; 238 | } 239 | .nav-pills > li > a { 240 | background-color: #F3F3F3; 241 | } 242 | .nav-pills > li.active > a, 243 | .nav-pills > li.active > a:hover, 244 | .nav-pills > li.active > a:focus { 245 | color: #fff; 246 | background-color: #0088aa; 247 | } 248 | 249 | -------------------------------------------------------------------------------- /website/themes/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forknote/forknote-pool/7b796fadf0775d74ff420899fa3f1e70f13a9753/website/themes/img/bg.jpg -------------------------------------------------------------------------------- /website/themes/img/bg2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/forknote/forknote-pool/7b796fadf0775d74ff420899fa3f1e70f13a9753/website/themes/img/bg2.jpg -------------------------------------------------------------------------------- /website/themes/motherboard-dark-theme.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #00863b; 3 | } 4 | a:hover { 5 | color: #006d30; 6 | } 7 | body { 8 | color: #ffffff; 9 | background-color: #000000; 10 | background-image: url(img/bg.jpg); 11 | } 12 | .form-control { 13 | background-color: rgba(0, 0, 0, 0.7); 14 | color: #00863b; 15 | } 16 | .navbar-inverse { 17 | background-color: #1E4B44; 18 | border-color: #000000; 19 | border-bottom: 1px solid #00863b; 20 | } 21 | .navbar-inverse .container { 22 | background-color: rgba(0, 0, 0, 0); 23 | } 24 | .navbar-inverse .navbar-brand { 25 | color: #fff; 26 | } 27 | .navbar-inverse .navbar-brand:hover, 28 | .navbar-inverse .navbar-brand:focus { 29 | color: #fff; 30 | background-color: rgba(255, 255, 255, 0); 31 | } 32 | .navbar-inverse .navbar-text { 33 | color: #CEE3E4; 34 | } 35 | .navbar-inverse .navbar-nav > li > a { 36 | color: #F0F9FA; 37 | } 38 | .navbar-inverse .navbar-nav > li > a:hover, 39 | .navbar-inverse .navbar-nav > li > a:focus { 40 | color: #ffffff; 41 | background-color: transparent; 42 | } 43 | .navbar-inverse .navbar-nav > .active > a, 44 | .navbar-inverse .navbar-nav > .active > a:hover, 45 | .navbar-inverse .navbar-nav > .active > a:focus { 46 | color: #ffffff; 47 | background-color: #00863b; 48 | } 49 | #stats_updated { 50 | /*color: #F4FC3D;*/ 51 | } 52 | hr { 53 | border-top-color: #BBBBBB; 54 | } 55 | .stats > div:not(#addressError) { 56 | color: #76A500; 57 | } 58 | .stats > div:not(#addressError) > i.fa { 59 | color: #888888; 60 | } 61 | .stats > div:not(#addressError) > span:not(.input-group-btn):first-of-type { 62 | color: #E3FF9D; 63 | } 64 | .form-control { 65 | border: 1px solid #00863b; 66 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 67 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 68 | } 69 | .form-control:focus { 70 | border-color: #005325; 71 | } 72 | .input-group-addon { 73 | background-color: #00863b; 74 | color: #fff; 75 | border-color: #00863b; 76 | } 77 | .btn-default { 78 | color: #ffffff; 79 | background-color: #00863b; 80 | border-color: #00863b; 81 | } 82 | .btn-default:hover, 83 | .btn-default:focus, 84 | .btn-default:active, 85 | .btn-default.active, 86 | .open > .dropdown-toggle.btn-default { 87 | color: #ffffff; 88 | background-color: #005325; 89 | border-color: #004920; 90 | } 91 | .btn-default:active, 92 | .btn-default.active, 93 | .open > .dropdown-toggle.btn-default { 94 | background-image: none; 95 | } 96 | .btn-default.disabled, 97 | .btn-default[disabled], 98 | fieldset[disabled] .btn-default, 99 | .btn-default.disabled:hover, 100 | .btn-default[disabled]:hover, 101 | fieldset[disabled] .btn-default:hover, 102 | .btn-default.disabled:focus, 103 | .btn-default[disabled]:focus, 104 | fieldset[disabled] .btn-default:focus, 105 | .btn-default.disabled:active, 106 | .btn-default[disabled]:active, 107 | fieldset[disabled] .btn-default:active, 108 | .btn-default.disabled.active, 109 | .btn-default[disabled].active, 110 | fieldset[disabled] .btn-default.active { 111 | background-color: #00863b; 112 | border-color: #00863b; 113 | } 114 | .btn-default .badge { 115 | color: #00863b; 116 | background-color: #ffffff; 117 | } 118 | code { 119 | color: #FFF500; 120 | background-color: #3D3D3D; 121 | } 122 | .bg-primary { 123 | background-color: #00863b; 124 | } 125 | .bg-info { 126 | background-color: #3A6C94; 127 | color: #fff; 128 | } 129 | .table > thead > tr > td.success, 130 | .table > tbody > tr > td.success, 131 | .table > tfoot > tr > td.success, 132 | .table > thead > tr > th.success, 133 | .table > tbody > tr > th.success, 134 | .table > tfoot > tr > th.success, 135 | .table > thead > tr.success > td, 136 | .table > tbody > tr.success > td, 137 | .table > tfoot > tr.success > td, 138 | .table > thead > tr.success > th, 139 | .table > tbody > tr.success > th, 140 | .table > tfoot > tr.success > th { 141 | background-color: #000000; 142 | } 143 | .table-hover > tbody > tr > td.success:hover, 144 | .table-hover > tbody > tr > th.success:hover, 145 | .table-hover > tbody > tr.success:hover > td, 146 | .table-hover > tbody > tr:hover > .success, 147 | .table-hover > tbody > tr.success:hover > th { 148 | background-color: #000000; 149 | } 150 | .table > thead > tr > th { 151 | color: #fff; 152 | border-bottom-color: #fff; 153 | } 154 | .table-striped > tbody > tr:nth-child(odd) > td, 155 | .table-striped > tbody > tr:nth-child(odd) > th { 156 | background-color: #202020; 157 | } 158 | .table > tbody > tr:hover td, 159 | .table > tbody > tr:hover th { 160 | background-color: #353535; 161 | } 162 | .table > tbody > tr > td { 163 | border-top-color: #c9e0e9; 164 | } 165 | .table > tbody > tr > td .luckGood { 166 | color: #5eff5e; 167 | } 168 | .table > tbody > tr > td .luckBad { 169 | color: red; 170 | } 171 | footer { 172 | background-color: #1E4B44 !important; 173 | } 174 | footer .text-muted { 175 | color: #fff; 176 | } 177 | .chartWrap p span { 178 | color: #E3FF9D; 179 | } 180 | .btn-primary { 181 | color: #ffffff; 182 | background-color: #00863b; 183 | border-color: #00863b; 184 | } 185 | .btn-primary:hover, 186 | .btn-primary:focus, 187 | .btn-primary:active, 188 | .btn-primary.active, 189 | .open > .dropdown-toggle.btn-primary { 190 | color: #ffffff; 191 | background-color: #005325; 192 | border-color: #004920; 193 | } 194 | .btn-primary:active, 195 | .btn-primary.active, 196 | .open > .dropdown-toggle.btn-primary { 197 | background-image: none; 198 | } 199 | .btn-primary.disabled, 200 | .btn-primary[disabled], 201 | fieldset[disabled] .btn-primary, 202 | .btn-primary.disabled:hover, 203 | .btn-primary[disabled]:hover, 204 | fieldset[disabled] .btn-primary:hover, 205 | .btn-primary.disabled:focus, 206 | .btn-primary[disabled]:focus, 207 | fieldset[disabled] .btn-primary:focus, 208 | .btn-primary.disabled:active, 209 | .btn-primary[disabled]:active, 210 | fieldset[disabled] .btn-primary:active, 211 | .btn-primary.disabled.active, 212 | .btn-primary[disabled].active, 213 | fieldset[disabled] .btn-primary.active { 214 | background-color: #00863b; 215 | border-color: #00863b; 216 | } 217 | .btn-primary .badge { 218 | color: #00863b; 219 | background-color: #ffffff; 220 | } 221 | a.list-group-item.active, 222 | a.list-group-item.active:hover, 223 | a.list-group-item.active:focus { 224 | color: #ffffff; 225 | background-color: #00863b; 226 | border-color: #00863b; 227 | } 228 | .adminStats > div { 229 | color: #2E3D31; 230 | -webkit-box-shadow: inset 0px 0px 0 1px #ffffff; 231 | box-shadow: inset 0px 0px 0 1px #ffffff; 232 | background-color: #EBEBEB; 233 | } 234 | .adminStats h4 { 235 | color: #26839B; 236 | } 237 | .adminStats .statsTitle h3 { 238 | color: #00C1FF; 239 | } 240 | .nav-pills > li > a { 241 | background-color: #F3F3F3; 242 | } 243 | .nav-pills > li.active > a, 244 | .nav-pills > li.active > a:hover, 245 | .nav-pills > li.active > a:focus { 246 | color: #fff; 247 | background-color: #00863b; 248 | } 249 | -------------------------------------------------------------------------------- /website/themes/nightly-mining-dark-theme.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #6ED5EE; 3 | } 4 | a:hover { 5 | color: #57ceeb; 6 | } 7 | body { 8 | color: #ffffff; 9 | background-color: #333333; 10 | background-image: url(http://subtlepatterns.com/patterns/subtle_carbon.png); 11 | } 12 | .form-control { 13 | background-color: #131313; 14 | color: #00FF33; 15 | } 16 | .navbar-inverse { 17 | background-color: #213442; 18 | border-color: #333333; 19 | border-width: 0; 20 | border-bottom: 1px solid #1f94b1; 21 | } 22 | .navbar-inverse .container { 23 | background-color: rgba(0, 0, 0, 0); 24 | } 25 | .navbar-inverse .navbar-brand { 26 | color: #fff; 27 | } 28 | .navbar-inverse .navbar-brand:hover, 29 | .navbar-inverse .navbar-brand:focus { 30 | color: #fff; 31 | background-color: rgba(255, 255, 255, 0); 32 | } 33 | .navbar-inverse .navbar-text { 34 | color: #CEE3E4; 35 | } 36 | .navbar-inverse .navbar-nav > li > a { 37 | color: #F0F9FA; 38 | } 39 | .navbar-inverse .navbar-nav > li > a:hover, 40 | .navbar-inverse .navbar-nav > li > a:focus { 41 | color: #ffffff; 42 | background-color: transparent; 43 | } 44 | .navbar-inverse .navbar-nav > .active > a, 45 | .navbar-inverse .navbar-nav > .active > a:hover, 46 | .navbar-inverse .navbar-nav > .active > a:focus { 47 | color: #ffffff; 48 | background-color: #1f94b1; 49 | } 50 | #stats_updated { 51 | /*color: #F4FC3D;*/ 52 | } 53 | hr { 54 | border-top-color: #BBBBBB; 55 | } 56 | .stats > div:not(#addressError) { 57 | color: #E6E6E6; 58 | } 59 | .stats > div:not(#addressError) > i.fa { 60 | color: #1f94b1; 61 | } 62 | .stats > div:not(#addressError) > span:not(.input-group-btn):first-of-type { 63 | color: #01C2AB; 64 | } 65 | .form-control { 66 | border: 1px solid #1f94b1; 67 | -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 68 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 69 | } 70 | .form-control:focus { 71 | border-color: #177086; 72 | } 73 | .input-group-addon { 74 | background-color: #1f94b1; 75 | color: #fff; 76 | border-color: #1f94b1; 77 | } 78 | .btn-default { 79 | color: #ffffff; 80 | background-color: #1f94b1; 81 | border-color: #1f94b1; 82 | } 83 | .btn-default:hover, 84 | .btn-default:focus, 85 | .btn-default:active, 86 | .btn-default.active, 87 | .open > .dropdown-toggle.btn-default { 88 | color: #ffffff; 89 | background-color: #177086; 90 | border-color: #16687d; 91 | } 92 | .btn-default.disabled, 93 | .btn-default[disabled], 94 | fieldset[disabled] .btn-default, 95 | .btn-default.disabled:hover, 96 | .btn-default[disabled]:hover, 97 | fieldset[disabled] .btn-default:hover, 98 | .btn-default.disabled:focus, 99 | .btn-default[disabled]:focus, 100 | fieldset[disabled] .btn-default:focus, 101 | .btn-default.disabled:active, 102 | .btn-default[disabled]:active, 103 | fieldset[disabled] .btn-default:active, 104 | .btn-default.disabled.active, 105 | .btn-default[disabled].active, 106 | fieldset[disabled] .btn-default.active { 107 | background-color: #1f94b1; 108 | border-color: #1f94b1; 109 | } 110 | .btn-default .badge { 111 | color: #1f94b1; 112 | background-color: #ffffff; 113 | } 114 | code { 115 | color: #ECA4A2; 116 | background-color: #3C3C3C; 117 | } 118 | .bg-primary { 119 | background-color: #1f94b1; 120 | } 121 | .bg-info { 122 | background-color: #336A80; 123 | color: #fff; 124 | } 125 | .table > thead > tr > td.success, 126 | .table > tbody > tr > td.success, 127 | .table > tfoot > tr > td.success, 128 | .table > thead > tr > th.success, 129 | .table > tbody > tr > th.success, 130 | .table > tfoot > tr > th.success, 131 | .table > thead > tr.success > td, 132 | .table > tbody > tr.success > td, 133 | .table > tfoot > tr.success > td, 134 | .table > thead > tr.success > th, 135 | .table > tbody > tr.success > th, 136 | .table > tfoot > tr.success > th { 137 | background-color: #000000; 138 | } 139 | .table-hover > tbody > tr > td.success:hover, 140 | .table-hover > tbody > tr > th.success:hover, 141 | .table-hover > tbody > tr.success:hover > td, 142 | .table-hover > tbody > tr:hover > .success, 143 | .table-hover > tbody > tr.success:hover > th { 144 | background-color: #000000; 145 | } 146 | .table > thead > tr > th { 147 | color: #20BFFF; 148 | border-bottom-color: #20BFFF; 149 | } 150 | .table-striped > tbody > tr:nth-child(odd) > td, 151 | .table-striped > tbody > tr:nth-child(odd) > th { 152 | background-color: #202020; 153 | } 154 | .table > tbody > tr:hover td, 155 | .table > tbody > tr:hover th { 156 | background-color: #353535; 157 | } 158 | .table > tbody > tr > td { 159 | border-top-color: #c9e0e9; 160 | } 161 | .table > tbody > tr > td .luckGood { 162 | color: #5eff5e; 163 | } 164 | .table > tbody > tr > td .luckBad { 165 | color: red; 166 | } 167 | footer { 168 | background-color: #213442 !important; 169 | } 170 | footer .text-muted { 171 | color: #fff; 172 | } 173 | /************************************************ 174 | *** admin page *** 175 | ************************************************/ 176 | .btn-primary { 177 | color: #ffffff; 178 | background-color: #1f94b1; 179 | border-color: #1f94b1; 180 | } 181 | .btn-primary:hover, 182 | .btn-primary:focus, 183 | .btn-primary:active, 184 | .btn-primary.active, 185 | .open > .dropdown-toggle.btn-primary { 186 | color: #ffffff; 187 | background-color: #177086; 188 | border-color: #16687d; 189 | } 190 | .btn-primary:active, 191 | .btn-primary.active, 192 | .open > .dropdown-toggle.btn-primary { 193 | background-image: none; 194 | } 195 | .btn-primary.disabled, 196 | .btn-primary[disabled], 197 | fieldset[disabled] .btn-primary, 198 | .btn-primary.disabled:hover, 199 | .btn-primary[disabled]:hover, 200 | fieldset[disabled] .btn-primary:hover, 201 | .btn-primary.disabled:focus, 202 | .btn-primary[disabled]:focus, 203 | fieldset[disabled] .btn-primary:focus, 204 | .btn-primary.disabled:active, 205 | .btn-primary[disabled]:active, 206 | fieldset[disabled] .btn-primary:active, 207 | .btn-primary.disabled.active, 208 | .btn-primary[disabled].active, 209 | fieldset[disabled] .btn-primary.active { 210 | background-color: #1f94b1; 211 | border-color: #1f94b1; 212 | } 213 | .btn-primary .badge { 214 | color: #1f94b1; 215 | background-color: #ffffff; 216 | } 217 | a.list-group-item { 218 | font-size: 1.1em; 219 | } 220 | a.list-group-item.active, 221 | a.list-group-item.active:hover, 222 | a.list-group-item.active:focus { 223 | color: #ffffff; 224 | background-color: #1f94b1; 225 | border-color: #1f94b1; 226 | } 227 | .adminStats > div { 228 | color: #2E3D31; 229 | -webkit-box-shadow: inset 0px 0px 0 1px #ffffff; 230 | box-shadow: inset 0px 0px 0 1px #ffffff; 231 | background-color: #EBEBEB; 232 | } 233 | .adminStats h4 { 234 | color: #26839B; 235 | } 236 | .adminStats .statsTitle h3 { 237 | color: #00C1FF; 238 | } 239 | .nav-pills > li > a { 240 | background-color: #F3F3F3; 241 | } 242 | .nav-pills > li.active > a, 243 | .nav-pills > li.active > a:hover, 244 | .nav-pills > li.active > a:focus { 245 | color: #fff; 246 | background-color: #1f94b1; 247 | } 248 | --------------------------------------------------------------------------------