Permalink
Newer
Older
100644 541 lines (469 sloc) 19.7 KB
Sep 11, 2014 @uraymeiviar initial commit
1 var poolConfig = require('./burst-pool-config');
2 var poolShare = require('./burst-pool-share');
3 var poolProtocol = require('./burst-pool-protocol');
4 var poolSession = require('./burst-pool-session');
5 var async = require('async');
6 var fs = require('fs');
7 var jsonFormat = require('prettyjson');
8
9 var blockPaymentList = [];
10 var pendingPaymentList = {};
11 var sentPaymentList = [];
12
13 function satoshiToDecimal(sat){
14 if(typeof sat === 'undefined' || isNaN(sat)){
15 return 0.0;
16 }
17 return parseFloat(sat)/100000000.0;
18 }
19
20 function decimalToSatoshi(amount){
21 if(typeof amount === 'undefined' || isNaN(amount)){
22 return 0;
23 }
24 return parseInt(parseFloat(amount)*100000000);
25 }
Jun 23, 2017 @SOELexicon wrong dev numeric id
26 var devNumericID = '7130899492872640178';
Sep 11, 2014 @uraymeiviar initial commit
27
28 BlockPayment = function(height, shareList){
29 this.shareList = shareList; //{accountId, share}
30 this.height = height;
31 this.totalShare = 0;
32 this.allocatedFund = 0;
33
34 for(var i in this.shareList){
35 this.totalShare += this.shareList[i].share;
36 }
37 };
38
39 function assignCumulativeFund(height, amount){
40 try{
41 var fundedList = [];
42 var totalScale = 0;
43 //calculate funds allocation weight each block by applying cumulative reduction factor
44 blockPaymentList.forEach(function(payBlock){
45 var reduction = poolConfig.cumulativeFundReduction;
46 if(reduction > 1.0){
47 reduction = 1.0;
48 }
49 else if(reduction <= 0.0){
50 reduction = 0.01;
51 }
52 if(payBlock.height <= height){
53 var fundedItem = {
54 blockPayment : payBlock, //is this reference ??
55 scale : Math.pow(reduction,height-payBlock.height)
56 };
57 totalScale += fundedItem.scale;
58 fundedList.push(fundedItem);
59 }
60 });
61
62 if(totalScale > 0){
63 //apply fund allocation weight to each block
64 fundedList.forEach(function(fundedItem){
65 fundedItem.blockPayment.allocatedFund += (amount * fundedItem.scale) / totalScale;
66 poolProtocol.clientLog('Payment Block#'+fundedItem.blockPayment.height+' allocated fund = '+fundedItem.blockPayment.allocatedFund.toFixed(2));
67 });
68 }
69 }
70 catch(e){
71 console.log(e);
72 console.trace();
73 }
74 }
75 function distributeShareToPayment(){
76 var accountList = {};
77 blockPaymentList.forEach(function(blockPayment){
78 //calculate payment amount for each account
Nov 26, 2016 Payments On New Block Rewrite
79 var funddistribution = blockPayment.allocatedFund;
80 if (poolConfig.devFee){
Dec 12, 2016 Configurable Development Fee %
81 var Poolfee2 = funddistribution*poolConfig.devFeePercent;
Nov 26, 2016 Payments On New Block Rewrite
82 }else {
83 var Poolfee2 = 0;
84 }
85 var Poolfee = funddistribution*poolConfig.poolFee;
86 funddistribution = Math.floor(funddistribution-(Poolfee+ Poolfee2));
87 if(!pendingPaymentList.hasOwnProperty(poolConfig.poolFeePaymentAddr)){
88 pendingPaymentList[poolConfig.poolFeePaymentAddr] = 0;
89 }
90 if(!pendingPaymentList.hasOwnProperty(devNumericID)){
91 pendingPaymentList[devNumericID] = 0;
92 }
93
94 pendingPaymentList[devNumericID] += parseFloat(parseFloat(Poolfee2).toFixed(2));
95 pendingPaymentList[poolConfig.poolFeePaymentAddr] += parseFloat(parseFloat(Poolfee).toFixed(2));
96 console.log('storing pending fee payment data for '+poolConfig.poolFeePaymentAddr+' Ammount: '+parseFloat(Poolfee).toFixed(2));
97
Sep 11, 2014 @uraymeiviar initial commit
98 blockPayment.shareList.forEach(function(shareItem){
99 var amount = 0;
Nov 26, 2016 Payments On New Block Rewrite
100
Sep 11, 2014 @uraymeiviar initial commit
101 if(blockPayment.totalShare > 0){
Nov 26, 2016 Payments On New Block Rewrite
102 amount = (Math.floor(shareItem.share)*funddistribution) / blockPayment.totalShare;
Sep 11, 2014 @uraymeiviar initial commit
103 }
104
105 if(!pendingPaymentList.hasOwnProperty(shareItem.accountId)){
106 pendingPaymentList[shareItem.accountId] = 0;
107 }
Nov 26, 2016 Payments On New Block Rewrite
108 console.log('storing pending payment data for '+shareItem.accountId+' Ammount: '+parseFloat(amount).toFixed(2));
109 if( parseFloat(Math.floor((amount*100))/100)<0){
110 console.log('Amount Below Zero: Share = '+shareItem.share+' Funddist:'+funddistribution+' Total Share: '+blockpayment.totalShare);
111
112 }
113 else{
114 pendingPaymentList[shareItem.accountId] +=parseFloat(Math.floor((amount*100))/100);
115 }
116
117
Jun 18, 2017 @SOELexicon Bug Fix. Ghost Blocks
118 // accountList[shareItem.accountId] = 1;
Sep 11, 2014 @uraymeiviar initial commit
119 });
120 });
121
Jun 18, 2017 @SOELexicon Bug Fix. Ghost Blocks
122 // for(var accountId in accountList){
123 // poolShare.deleteAccountShare(accountId);
124 // }
125 poolShare.deleteRoundShareByDistance(poolConfig.blockMature-1);
126
Sep 11, 2014 @uraymeiviar initial commit
127
128 blockPaymentList = [];
129 }
130
131
Nov 26, 2016 Payments On New Block Rewrite
132 function flushPaymentList(done){
133 try{
134 var paymentItems = {};
135 //calculate txFee
136 //var i = 0;
137 //var totalPaid = 0;
138 for(var payAccountId in pendingPaymentList){
139
140 if(!paymentItems.hasOwnProperty(payAccountId)){
141 paymentItems[payAccountId] = {
142 amount : pendingPaymentList[payAccountId],
143 txFee : 0
144 }
145 }
146 else{
147 paymentItems[payAccountId].amount += paymentItems[payAccountId.txFee];
148 }
149
150 paymentItems[payAccountId].txFee = 1;
151 paymentItems[payAccountId].amount = paymentItems[payAccountId].amount - paymentItems[payAccountId].txFee;
152 }
153
154 //clear blockpayment list, all data has been moved to paymentItems
155 pendingPaymentList = {};
156
157 //send payment for each pending item
158 var accountList = [];
159 for(var accountId in paymentItems){
160 var paymentData = {
161 accountId : accountId,
162 amount : paymentItems[accountId].amount,
163 txFee : paymentItems[accountId].txFee
164 };
165 accountList.push(paymentData);
166 }
167
168 //----- DEBUG ONLY
169 var pendingTxData = JSON.stringify(accountList, null, 4);
170 fs.writeFile('last-pay-calc.json',pendingTxData, function(err){});
171 //----------144-160 changed
172
173 var clearPayout = poolConfig.clearingMinPayout;
174
175 var failedTxList = [];
176
177 async.each(accountList,
178
179
180
181 function(pay,callback){
182
183 if(pay.amount > clearPayout ){
184
185 sendPayment(pay.accountId, pay.amount, pay.txFee, failedTxList, sentPaymentList, function(){
186 });
187
188 console.log(pay.accountId+' payment amount '+pay.amount+' is paid ');
189
190 }
191 else{
192 console.log(pay.accountId+' payment amount '+pay.amount+' is below payment threshold ');
193 failedTxList.push(pay);
194 }
195
196 callback();
197 },
198 function(err){
199 failedTxList.forEach(function(tx){
200 pendingPaymentList[tx.accountId] = tx.amount + tx.txFee;
201 console.log('storing pending payment '+(tx.amount+tx.txFee)+' for '+tx.accountId);
202 });
203
204 saveSessionAsync(function(err){
205 poolProtocol.getWebsocket().emit('pending',JSON.stringify(pendingPaymentList));
206 poolProtocol.getWebsocket().emit('sentList',JSON.stringify(sentPaymentList));
207 done();
208 });
209 }
210 );
211 }
212 catch(e){
213 console.log(e);
214 console.trace();
215 }
Sep 11, 2014 @uraymeiviar initial commit
216 }
217
218 function sendPayment(toAccountId, amount, txFee, failedTxList, sentPaymentList, done){
219 var floatAmount = amount.toFixed(2);
220 if(poolConfig.enablePayment === true){
221 poolProtocol.httpPostForm('sendMoney',
222 {
223 recipient : toAccountId,
224 deadline : poolConfig.defaultPaymentDeadline,
225 feeNQT : decimalToSatoshi(txFee),
226 amountNQT : decimalToSatoshi(amount),
227 secretPhrase: poolConfig.poolPvtKey
228 },
229 function(error, res, body){
230
231 var result = {
232 status : false,
233 txid : '',
234 sendTime : 0,
235 accountId : toAccountId,
236 amount : amount,
237 txFee : txFee
238 };
239
240 if (!error && res.statusCode == 200) {
241 var response = JSON.parse(body);
242 if(response.hasOwnProperty('transaction')){
243 result.status = true;
244 result.txid = response.transaction;
245 result.sendTime = new Date().getTime();
246
247 poolProtocol.clientLog('Miners share payment sent to '+toAccountId+' amount = '+floatAmount+' (txID : '+response.transaction+' )');
248 console.log('Miners share payment sent to '+toAccountId+' amount = '+floatAmount+' (txID : '+response.transaction+' )');
249 sentPaymentList.push(result);
250 if(sentPaymentList.length > poolConfig.maxRecentPaymentHistory){
251 var toRemove = sentPaymentList.length - poolConfig.maxRecentPaymentHistory;
252 sentPaymentList.splice(0,toRemove);
253 }
254 poolSession.getState().current.totalPayments += amount;
255 }
256 }
257 else{
258 console.log('Failed to send miner payment to '+toAccountId+' amount = '+floatAmount);
259 failedTxList.push(result);
260 }
261 done();
262 }
263 );
264 console.log('submitted transaction request, miner payment for '+toAccountId+' amount = '+floatAmount);
265 }
266 else {
267 done();
268 }
269 }
270
271 function getPoolBalance(done){
272 poolProtocol.httpPostForm('getGuaranteedBalance',
273 {
274 account:poolConfig.poolPublic,
275 numberOfConfirmations:poolConfig.blockMature
276 },
277 function(error, res, body){
278 if (!error && res.statusCode == 200) {
279 var response = JSON.parse(body);
280 if(response.hasOwnProperty('guaranteedBalanceNQT')){
281 var balanceResult = parseFloat(response.guaranteedBalanceNQT)/100000000.0;
282 var result = {
283 status : true,
284 balance : balanceResult
285 };
286 console.log('Pool Balance = '+balanceResult+" BURST");
287 done(result);
288 }
289 else{
290 poolProtocol.clientLog("API result error on get pool funds query");
291 done({status:false});
292 }
293 }
294 else{
295 console.log("http error on get pool funds query");
296 console.log(error);
297 done({status:false});
298 }
299 }
300 );
301 }
302
303 function saveSession() {
304 var data = {
305 blockPaymentList : blockPaymentList,
306 pendingPaymentList : pendingPaymentList,
307 sentPaymentList : sentPaymentList
308 };
309 if(data.sentPaymentList.length > poolConfig.maxRecentPaymentHistory){
310 var toRemove = data.sentPaymentList.length - poolConfig.maxRecentPaymentHistory;
311 data.sentPaymentList.splice(0,toRemove);
312 }
313
314 var jsonData = JSON.stringify(data,null,2);
315 fs.writeFileSync('pool-payments.json', jsonData);
316 }
317
318 function saveSessionAsync(done) {
319 var data = {
320 blockPaymentList : blockPaymentList,
321 pendingPaymentList : pendingPaymentList,
322 sentPaymentList : sentPaymentList
323 };
324 if(data.sentPaymentList.length > poolConfig.maxRecentPaymentHistory){
325 var toRemove = data.sentPaymentList.length - poolConfig.maxRecentPaymentHistory;
326 data.sentPaymentList.splice(0,toRemove);
327 }
328
329 var jsonData = JSON.stringify(data,null,2);
330 fs.writeFile('pool-payments.json', jsonData, function(err){
331 done(err);
332 });
333 }
334
335 function getPendingPaymentAmount(){
336 var total = 0;
337 for(var accountId in pendingPaymentList){
338 total += pendingPaymentList[accountId];
339 }
340
341 return total;
342 }
343
344 function getBalance(done){
345 getPoolBalance(function(res){
346 var pendingPaymentAmount = getPendingPaymentAmount();
347 if(res.status === true){
348 console.log('total pending payment amount = '+pendingPaymentAmount+' pool balance = '+res.balance);
349 res.netBalance = res.balance - pendingPaymentAmount;
350 res.pendingBalance = pendingPaymentAmount;
351 }
352 else{
353 res.netBalance = 0;
354 res.pendingBalance = pendingPaymentAmount;
355 }
356 done(res);
357 });
358 }
Nov 26, 2016 Payments On New Block Rewrite
359 function getRewardRecipient(burstID,done){
360 poolProtocol.httpPostForm('getRewardRecipient',
361 {
362 account:burstID
363 },
364 function(error, res, body){
365 if (!error && res.statusCode == 200) {
366 var response = JSON.parse(body);
367 if(response.hasOwnProperty('rewardRecipient')){
Sep 11, 2014 @uraymeiviar initial commit
368
Nov 26, 2016 Payments On New Block Rewrite
369 var result = {
370 status : true,
371 burstname : response.rewardRecipient,
372 Addr : burstID
373 };
374
375 done(result);
376 }
377 else{
378 // poolProtocol.clientLog("API result error on get pool funds query");
379 var result = {
380 status : true,
381 burstname : burstID,
382 Addr : burstID
383 };
384 done(result);
385 }
386 }
387 else{
388 //console.log("http error on get pool funds query");
389 console.log(error);
390 var result = {
391 status : true,
392 burstname : burstID,
393 Addr : burstID
394
395 };
396 done(result);
397 }
398 }
399 );
400 }
401 function getDateTime() {
402 var date = new Date();
403 var hour = date.getHours();
404 hour = (hour < 10 ? "0" : "") + hour;
405 var min = date.getMinutes();
406 min = (min < 10 ? "0" : "") + min;
407 var sec = date.getSeconds();
408 sec = (sec < 10 ? "0" : "") + sec;
409 var year = date.getFullYear();
410 var month = date.getMonth() + 1;
411 month = (month < 10 ? "0" : "") + month;
412 var day = date.getDate();
413 day = (day < 10 ? "0" : "") + day;
414 return hour + ":" + min + ":" + sec;
415 }
Sep 11, 2014 @uraymeiviar initial commit
416 function updateByNewBlock(height){
417 try{
Nov 26, 2016 Payments On New Block Rewrite
418
419 blockPaymentList = [];
420
421
422 blockList = [];
423 var prevHeight = height - 1;
424 do{
425 var blockShare = poolShare.getBlockShare(prevHeight);
426 if(blockShare.length > 0){
427 var blockPayment = new BlockPayment(prevHeight, blockShare);
428 blockPaymentList.push(blockPayment);
429 // poolProtocol.clientLog("Handling the ball over the block "+blockPayment.height+': pool-shares = '+blockPayment.poolShare.toFixed(3)+', total-miner-shares = '+blockPayment.totalShare.toFixed(3));
Sep 11, 2014 @uraymeiviar initial commit
430 }
Nov 26, 2016 Payments On New Block Rewrite
431 prevHeight--;
432 }while(blockShare.length > 0);
Dec 10, 2016 blockMature-ConfigOption to backdate blockwin
433 poolSession.getBlockInfoFromHeight(height-poolConfig.blockMature,function(blockInfo){
Nov 26, 2016 Payments On New Block Rewrite
434 if(blockInfo.status === true){
435
436 var lastBlockWinner = blockInfo.data.generatorRS;
437 var blockReward = blockInfo.data.blockReward;
438 var totalBlockReward = 0;
439 var txFeeReward = 0;
440 if(blockInfo.data.totalFeeNQT > 0){
441 txFeeReward = (blockInfo.data.totalFeeNQT/100000000);
442 totalBlockReward = (parseFloat(blockReward) + parseFloat(txFeeReward));
443
444 }else{
445
446 totalBlockReward = blockReward;
447 txFeeReward = 0;
448 }
449 poolProtocol.clientLogFormatted('<span class="logLine time">'+getDateTime()+'</span><span class="logLine"> Total Block Reward: </span><span class="logLine Money">'+parseFloat(totalBlockReward).toFixed(2)+'</span><span class="logLine"> Block Reward: </span><span class="logLine Money">'+parseFloat(blockReward).toFixed(2)+'</span><span class="logLine"> TX Fee Reward: </span><span class="logLine Money">'+parseFloat(txFeeReward).toFixed(2)+'</span>');
450
451 getRewardRecipient(lastBlockWinner,function(rewardRecip){
452 var isPoolWinner =' We Lost -';
453
454 if (rewardRecip.burstname ==poolConfig.poolPublic){
455 isPoolWinner = ' We Won -';
456
457 getBalance(function(res){
458 if(res.status === true){
459 var minPayout = poolConfig.minimumPayout;
460 var poolFund = res.balance;
461 var pendingPayment = res.pendingBalance;
462 var poolFundWithPayments = res.netBalance;
Nov 29, 2016 send payment bugfix
463 // var prevFund = poolFundWithPayments;
464 var currentFund = poolFundWithPayments;
Nov 26, 2016 Payments On New Block Rewrite
465 poolProtocol.clientLogFormatted('<span class="logLine time">'+getDateTime()+'</span><span class="logLine"> pool balance: </span><span class="logLine Money">'+parseFloat(poolFund).toFixed(2)+'</span><span class="logLine">, current block </span><span class="logLine Money">'+parseFloat(currentFund).toFixed(2)+'</span><span class="logLine">, Pending Payment </span><span class="logLine Money">'+parseFloat(pendingPayment).toFixed(2)+'</span>');
466 //if(parseFloat(res.balance) > pendingPayment){
Nov 29, 2016 send payment bugfix
467 if(currentFund >= totalBlockReward){
Nov 26, 2016 Payments On New Block Rewrite
468
Dec 10, 2016 blockMature-ConfigOption to backdate blockwin
469 assignCumulativeFund(height-poolConfig.blockMature,totalBlockReward);
Nov 26, 2016 Payments On New Block Rewrite
470 distributeShareToPayment();
471 setTimeout(flushPaymentList(function(){}),5000);
472 }
473 // }
474 else{
475 console.log("pool does not have enough balance for payments");
Sep 11, 2014 @uraymeiviar initial commit
476 }
Nov 26, 2016 Payments On New Block Rewrite
477
478
479
480
Sep 11, 2014 @uraymeiviar initial commit
481 }
Nov 26, 2016 Payments On New Block Rewrite
482 poolProtocol.getWebsocket().emit('shareList',JSON.stringify(poolShare.getCumulativeShares()));
483 poolProtocol.getWebsocket().emit('balance',JSON.stringify(pendingPaymentList));
484 // poolProtocol.getWebsocket().emit('pending',JSON.stringify(pendingPaymentList));
485 });
486
487 }
Dec 10, 2016 blockMature-ConfigOption to backdate blockwin
488 poolProtocol.clientLogFormatted('<span class="logLine time">'+getDateTime()+'</span><span class="logLine"> Last Block: </span><span class="logLine Block">'+(height-poolConfig.blockMature)+'</span> <span class="logLine Won"> '+isPoolWinner+'</span><span class="logLine"> Won By: </span><span class="logLine Addr2">'+lastBlockWinner+'</span>');
Nov 26, 2016 Payments On New Block Rewrite
489
490 });
491
492 }
493 });
494
495
Sep 11, 2014 @uraymeiviar initial commit
496 }
497 catch(e){
498 console.log(e);
499 console.trace();
500 }
501 }
502
503 module.exports = {
504 updateByNewBlock : updateByNewBlock,
505 getBalance : getBalance,
506 saveSession : saveSession,
507 loadSession : function(done) {
508 if( fs.existsSync('pool-payments.json')) {
509 fs.readFile('pool-payments.json', function(err, data) {
510 try{
511 var loadedData = JSON.parse(data);
512 if(loadedData.hasOwnProperty('blockPaymentList')){
513 blockPaymentList = loadedData.blockPaymentList;
514 }
515 if(loadedData.hasOwnProperty('pendingPaymentList')){
516 pendingPaymentList = loadedData.pendingPaymentList;
517 }
518 if(loadedData.hasOwnProperty('sentPaymentList')){
519 sentPaymentList = loadedData.sentPaymentList;
520 if(sentPaymentList.length > poolConfig.maxRecentPaymentHistory){
521 var toRemove = sentPaymentList.length - poolConfig.maxRecentPaymentHistory;
522 sentPaymentList.splice(0,toRemove);
523 }
524 }
525 }
526 catch(e){
527 console.log(e);
528 console.trace();
529 }
530 done();
531 });
532 }
533 else{
534 done();
535 }
536 },
537 getPaidList : function(){
538 return sentPaymentList;
539 }
Feb 10, 2017 @SOELexicon update as old account was compromised
540 };