From add62039dbaaa0cfadad919c0a6572955e949796 Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Wed, 26 Mar 2014 05:27:28 +0400 Subject: [PATCH 1/7] fix possible typo in paymentProcessor --- libs/paymentProcessor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 3b5c0ac..aa5d0e9 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -365,9 +365,9 @@ function SetupForPool(logger, poolOptions){ var addressAmounts = {}; var totalAmountUnits = 0; for (var address in workerPayments){ - var coiUnits = parseFloat((workerPayments[address] / magnitude).toFixed(coinPrecision));; - addressAmounts[address] = coiUnits; - totalAmountUnits += coiUnits; + var coinUnits = parseFloat((workerPayments[address] / magnitude).toFixed(coinPrecision));; + addressAmounts[address] = coinUnits; + totalAmountUnits += coinUnits; } logger.debug(logSystem, logComponent, 'Payments about to be sent to: ' + JSON.stringify(addressAmounts)); From df68d339834048fde95950b871dc90b374093485 Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Wed, 26 Mar 2014 19:43:52 +0400 Subject: [PATCH 2/7] add fees withdrawal --- libs/paymentProcessor.js | 37 +++++++++++++++------- pool_configs/litecoin_testnet_example.json | 1 + 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index aa5d0e9..9221cb4 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -257,7 +257,7 @@ function SetupForPool(logger, poolOptions){ //number of satoshis in a single coin unit - this can be different for coins so we calculate it :) - daemon.cmd('getbalance', [], function(results){ + daemon.cmd('getbalance', [''], function(results){ var totalBalance = results[0].response * magnitude; var toBePaid = 0; @@ -365,10 +365,11 @@ function SetupForPool(logger, poolOptions){ var addressAmounts = {}; var totalAmountUnits = 0; for (var address in workerPayments){ - var coinUnits = parseFloat((workerPayments[address] / magnitude).toFixed(coinPrecision));; + var coinUnits = parseFloat((workerPayments[address] / magnitude).toFixed(coinPrecision)); addressAmounts[address] = coinUnits; totalAmountUnits += coinUnits; } + var feeAmountUnits = parseFloat((totalAmountUnits / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); logger.debug(logSystem, logComponent, 'Payments about to be sent to: ' + JSON.stringify(addressAmounts)); daemon.cmd('sendmany', ['', addressAmounts], function(results){ @@ -380,9 +381,16 @@ function SetupForPool(logger, poolOptions){ var totalWorkers = Object.keys(workerPayments).length; logger.debug(logSystem, logComponent, 'Payments sent, a total of ' + totalAmountUnits + ' was sent to ' + totalWorkers + ' miners'); + daemon.cmd('move', ['', processingConfig.feeCollectAccount, feeAmountUnits], function(results){ + if (results[0].error){ + callback('Check finished - error with move ' + JSON.stringify(results[0].error)); + return; + } + var totalWorkers = Object.keys(workerPayments).length; + logger.debug(logSystem, logComponent, feeAmountUnits + ' collected as fee'); + }); }); } - } ], function(error, result){ if (error) @@ -400,19 +408,26 @@ function SetupForPool(logger, poolOptions){ if (!processingConfig.feeWithdrawalThreshold) return; - daemon.cmd('getbalance', [], function(results){ + daemon.cmd('getbalance', [processingConfig.feeCollectAccount], function(results){ - var totalBalance = results[0].response; - var withdrawalAmount = totalBalance - processingConfig.minimumReserve; - var leftOverBalance = totalBalance - withdrawalAmount; + var withdrawalAmount = results[0].response; - - if (leftOverBalance < processingConfig.minimumReserve || withdrawalAmount < processingConfig.feeWithdrawalThreshold){ + if (withdrawalAmount < processingConfig.feeWithdrawalThreshold){ logger.debug(logSystem, logComponent, 'Not enough profit to withdrawal yet'); } else{ - //Need to figure out how much of the balance is profit... ??? - logger.debug(logSystem, logComponent, 'Can send profit'); + + var withdrawal = {}; + withdrawal[processingConfig.feeReceiveAddress] = withdrawalAmount; + + daemon.cmd('sendmany', [processingConfig.feeCollectAccount, withdrawal], function(results){ + if (results[0].error){ + logger.debug(logSystem, logComponent, 'Withdrawal profit finished - error with sendmany ' + JSON.stringify(results[0].error)); + return; + } + logger.debug(logSystem, logComponent, 'Profit sent, a total of ' + withdrawalAmount + + ' was sent to ' + processingConfig.feeReceiveAddress); + }); } }); diff --git a/pool_configs/litecoin_testnet_example.json b/pool_configs/litecoin_testnet_example.json index ba66286..6efb22f 100644 --- a/pool_configs/litecoin_testnet_example.json +++ b/pool_configs/litecoin_testnet_example.json @@ -10,6 +10,7 @@ "minimumPayment": 100.001, "minimumReserve": 10, "feePercent": 0.02, + "feeCollectAccount": "feesCollected", "feeReceiveAddress": "LZz44iyF4zLCXJTU8RxztyyJZBntdS6fvv", "feeWithdrawalThreshold": 5, "daemon": { From 0be59cb34ff97c2b7bb79ef26d5973f29dbfd715 Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Wed, 26 Mar 2014 23:59:59 +0400 Subject: [PATCH 3/7] include tx fees and pool fees in minimumReserve check and adjust pool fees accordingly --- libs/paymentProcessor.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 9221cb4..667b1ac 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -27,6 +27,7 @@ function SetupForPool(logger, poolOptions){ var logSystem = 'Payments'; var logComponent = coin; + var paytxfee; var daemon = new Stratum.daemon.interface([processingConfig.daemon]); @@ -38,6 +39,14 @@ function SetupForPool(logger, poolOptions){ logger.error(logSystem, logComponent, 'Daemon does not own pool address - payment processing can not be done with this daemon'); } }); + daemon.cmd('getinfo', [], function(result){ + if (!result[0].response || !result[0].response.paytxfee){ + paytxfee = 0; + logger.error(logSystem, logComponent, 'Daemon does not have paytxfee property on getinfo method results - payment processing could be broken with this daemon'); + return; + } + paytxfee = result[0].response.paytxfee; + }); }).once('connectionFailed', function(error){ logger.error(logSystem, logComponent, 'Failed to connect to daemon for payment processing: ' + JSON.stringify(error)); }).on('error', function(error){ @@ -293,7 +302,9 @@ function SetupForPool(logger, poolOptions){ } - var balanceLeftOver = totalBalance - toBePaid; + var feeAmountToBeCollected = parseFloat((toBePaid / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); + var txFee = Object.keys(workerPayments).length * paytxfee; + var balanceLeftOver = totalBalance - toBePaid - feeAmountToBeCollected - txFee; var minReserveSatoshis = processingConfig.minimumReserve * magnitude; if (balanceLeftOver < minReserveSatoshis){ @@ -369,7 +380,6 @@ function SetupForPool(logger, poolOptions){ addressAmounts[address] = coinUnits; totalAmountUnits += coinUnits; } - var feeAmountUnits = parseFloat((totalAmountUnits / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); logger.debug(logSystem, logComponent, 'Payments about to be sent to: ' + JSON.stringify(addressAmounts)); daemon.cmd('sendmany', ['', addressAmounts], function(results){ @@ -381,12 +391,14 @@ function SetupForPool(logger, poolOptions){ var totalWorkers = Object.keys(workerPayments).length; logger.debug(logSystem, logComponent, 'Payments sent, a total of ' + totalAmountUnits + ' was sent to ' + totalWorkers + ' miners'); - daemon.cmd('move', ['', processingConfig.feeCollectAccount, feeAmountUnits], function(results){ + var feeAmountUnits = parseFloat((totalAmountUnits / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); + var txFee = totalWorkers * paytxfee; + var collectableFee = feeAmountUnits - txFee; + daemon.cmd('move', ['', processingConfig.feeCollectAccount, collectableFee], function(results){ if (results[0].error){ callback('Check finished - error with move ' + JSON.stringify(results[0].error)); return; } - var totalWorkers = Object.keys(workerPayments).length; logger.debug(logSystem, logComponent, feeAmountUnits + ' collected as fee'); }); }); @@ -410,7 +422,7 @@ function SetupForPool(logger, poolOptions){ daemon.cmd('getbalance', [processingConfig.feeCollectAccount], function(results){ - var withdrawalAmount = results[0].response; + var withdrawalAmount = results[0].response - paytxfee; if (withdrawalAmount < processingConfig.feeWithdrawalThreshold){ logger.debug(logSystem, logComponent, 'Not enough profit to withdrawal yet'); From a3b3b17d43bb03e492c76a8b2e6acc1990282152 Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Thu, 27 Mar 2014 03:36:07 +0400 Subject: [PATCH 4/7] fix fee calculations and withdrawals once again --- libs/paymentProcessor.js | 96 +++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 667b1ac..07afffc 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -27,7 +27,6 @@ function SetupForPool(logger, poolOptions){ var logSystem = 'Payments'; var logComponent = coin; - var paytxfee; var daemon = new Stratum.daemon.interface([processingConfig.daemon]); @@ -39,14 +38,6 @@ function SetupForPool(logger, poolOptions){ logger.error(logSystem, logComponent, 'Daemon does not own pool address - payment processing can not be done with this daemon'); } }); - daemon.cmd('getinfo', [], function(result){ - if (!result[0].response || !result[0].response.paytxfee){ - paytxfee = 0; - logger.error(logSystem, logComponent, 'Daemon does not have paytxfee property on getinfo method results - payment processing could be broken with this daemon'); - return; - } - paytxfee = result[0].response.paytxfee; - }); }).once('connectionFailed', function(error){ logger.error(logSystem, logComponent, 'Failed to connect to daemon for payment processing: ' + JSON.stringify(error)); }).on('error', function(error){ @@ -302,13 +293,14 @@ function SetupForPool(logger, poolOptions){ } + // txfee included in feeAmountToBeCollected var feeAmountToBeCollected = parseFloat((toBePaid / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); - var txFee = Object.keys(workerPayments).length * paytxfee; - var balanceLeftOver = totalBalance - toBePaid - feeAmountToBeCollected - txFee; + var balanceLeftOver = totalBalance - toBePaid - feeAmountToBeCollected; var minReserveSatoshis = processingConfig.minimumReserve * magnitude; if (balanceLeftOver < minReserveSatoshis){ callback('Check finished - payments would wipe out minimum reserve, tried to pay out ' + toBePaid + + ' and collect ' + feeAmountToBeCollected + ' as fees' + ' but only have ' + totalBalance + '. Left over balance would be ' + balanceLeftOver + ', needs to be at least ' + minReserveSatoshis); return; @@ -348,13 +340,13 @@ function SetupForPool(logger, poolOptions){ finalRedisCommands.push(['hincrbyfloat', coin + '_stats', 'totalPaid', (toBePaid / magnitude).toFixed(coinPrecision)]); - callback(null, magnitude, workerPayments, finalRedisCommands); + callback(null, magnitude, results[0].response, workerPayments, finalRedisCommands); }); }, - function(magnitude, workerPayments, finalRedisCommands, callback){ + function(magnitude, balanceBefore, workerPayments, finalRedisCommands, callback){ //This does the final all-or-nothing atom transaction if block deamon sent payments var finalizeRedisTx = function(){ @@ -389,18 +381,23 @@ function SetupForPool(logger, poolOptions){ } finalizeRedisTx(); var totalWorkers = Object.keys(workerPayments).length; - logger.debug(logSystem, logComponent, 'Payments sent, a total of ' + totalAmountUnits + + logger.debug(logSystem, logComponent, 'Payments sent, a total of ' + totalAmountUnits + ' ' + poolOptions.coin.symbol + ' was sent to ' + totalWorkers + ' miners'); - var feeAmountUnits = parseFloat((totalAmountUnits / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); - var txFee = totalWorkers * paytxfee; - var collectableFee = feeAmountUnits - txFee; - daemon.cmd('move', ['', processingConfig.feeCollectAccount, collectableFee], function(results){ - if (results[0].error){ - callback('Check finished - error with move ' + JSON.stringify(results[0].error)); - return; - } - logger.debug(logSystem, logComponent, feeAmountUnits + ' collected as fee'); - }); + setTimeout(function() { // not sure if we need some time to let daemon update the wallet balance + daemon.cmd('getbalance', [''], function(results){ + var balanceDiff = balanceBefore - results[0].response; + var txFee = balanceDiff - totalAmountUnits; + var feeAmountUnits = parseFloat((totalAmountUnits / (1 - processingConfig.feePercent) * processingConfig.feePercent).toFixed(coinPrecision)); + var poolFees = feeAmountUnits - txFee; + daemon.cmd('move', ['', processingConfig.feeCollectAccount, poolFees], function(results){ + if (results[0].error){ + callback('Check finished - error with move ' + JSON.stringify(results[0].error)); + return; + } + callback(null, poolFees + ' ' + poolOptions.coin.symbol + ' collected as pool fee'); + }); + }); + }, 1000); }); } } @@ -410,7 +407,8 @@ function SetupForPool(logger, poolOptions){ else{ logger.debug(logSystem, logComponent, result); - withdrawalProfit(); + // not sure if we need some time to let daemon update the wallet balance + setTimeout(withdrawalProfit, 1000); } }); }; @@ -420,27 +418,43 @@ function SetupForPool(logger, poolOptions){ if (!processingConfig.feeWithdrawalThreshold) return; + logger.debug(logSystem, logComponent, 'Trying to withdrawal profit'); daemon.cmd('getbalance', [processingConfig.feeCollectAccount], function(results){ - var withdrawalAmount = results[0].response - paytxfee; + // We have to pay some tx fee here too but maybe we shoudn't really care about it too much as long as fee is less + // then minimumReserve value. Because in this case even if feeCollectAccount account will have negative balance + // total wallet balance will be positive and feeCollectAccount account will be refilled during next payment processing. + // But to be as much accurate as we can we use getinfo command to retrieve minimum tx fee (paytxfee). + daemon.cmd('getinfo', [], function(result){ - if (withdrawalAmount < processingConfig.feeWithdrawalThreshold){ - logger.debug(logSystem, logComponent, 'Not enough profit to withdrawal yet'); - } - else{ + var paytxfee; + if (!result[0].response || !result[0].response.paytxfee){ + logger.error(logSystem, logComponent, 'Daemon does not have paytxfee property on getinfo method results - withdrawal processing could be broken with this daemon'); + paytxfee = 0; + } else { + paytxfee = result[0].response.paytxfee; + } - var withdrawal = {}; - withdrawal[processingConfig.feeReceiveAddress] = withdrawalAmount; + var withdrawalAmount = results[0].response - paytxfee; - daemon.cmd('sendmany', [processingConfig.feeCollectAccount, withdrawal], function(results){ - if (results[0].error){ - logger.debug(logSystem, logComponent, 'Withdrawal profit finished - error with sendmany ' + JSON.stringify(results[0].error)); - return; - } - logger.debug(logSystem, logComponent, 'Profit sent, a total of ' + withdrawalAmount + - ' was sent to ' + processingConfig.feeReceiveAddress); - }); - } + if (withdrawalAmount < processingConfig.feeWithdrawalThreshold){ + logger.debug(logSystem, logComponent, 'Not enough profit to withdrawal yet'); + } + else{ + + var withdrawal = {}; + withdrawal[processingConfig.feeReceiveAddress] = withdrawalAmount; + + daemon.cmd('sendmany', [processingConfig.feeCollectAccount, withdrawal], function(results){ + if (results[0].error){ + logger.debug(logSystem, logComponent, 'Withdrawal profit finished - error with sendmany ' + JSON.stringify(results[0].error)); + return; + } + logger.debug(logSystem, logComponent, 'Profit sent, a total of ' + withdrawalAmount + ' ' + poolOptions.coin.symbol + + ' was sent to ' + processingConfig.feeReceiveAddress); + }); + } + }); }); From 68bea9ea7da901e5f97951ef31236d8117db826b Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Thu, 27 Mar 2014 03:49:08 +0400 Subject: [PATCH 5/7] some syntax cleaning --- libs/paymentProcessor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 07afffc..b33760f 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -418,7 +418,7 @@ function SetupForPool(logger, poolOptions){ if (!processingConfig.feeWithdrawalThreshold) return; - logger.debug(logSystem, logComponent, 'Trying to withdrawal profit'); + logger.debug(logSystem, logComponent, 'Profit withdrawal started'); daemon.cmd('getbalance', [processingConfig.feeCollectAccount], function(results){ // We have to pay some tx fee here too but maybe we shoudn't really care about it too much as long as fee is less @@ -438,7 +438,7 @@ function SetupForPool(logger, poolOptions){ var withdrawalAmount = results[0].response - paytxfee; if (withdrawalAmount < processingConfig.feeWithdrawalThreshold){ - logger.debug(logSystem, logComponent, 'Not enough profit to withdrawal yet'); + logger.debug(logSystem, logComponent, 'Not enough profit to withdraw yet'); } else{ @@ -447,7 +447,7 @@ function SetupForPool(logger, poolOptions){ daemon.cmd('sendmany', [processingConfig.feeCollectAccount, withdrawal], function(results){ if (results[0].error){ - logger.debug(logSystem, logComponent, 'Withdrawal profit finished - error with sendmany ' + JSON.stringify(results[0].error)); + logger.debug(logSystem, logComponent, 'Profit withdrawal finished - error with sendmany ' + JSON.stringify(results[0].error)); return; } logger.debug(logSystem, logComponent, 'Profit sent, a total of ' + withdrawalAmount + ' ' + poolOptions.coin.symbol + From fc5cf3b883bc2fcef0518d4c6012bde7a3efa200 Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Thu, 27 Mar 2014 04:57:29 +0400 Subject: [PATCH 6/7] change success callback in finalizeRedisTx to logger.debug to prevent untimely withdrawalProfit call --- libs/paymentProcessor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index b33760f..4114205 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -355,7 +355,7 @@ function SetupForPool(logger, poolOptions){ callback('Check finished - error with final redis commands for cleaning up ' + JSON.stringify(error)); return; } - callback(null, 'Payments processing performed an interval'); + logger.debug(logSystem, logComponent, 'Payments processing performed an interval'); }); }; From b73b6a828eadba7ed7c920cd2f268c0acce1204f Mon Sep 17 00:00:00 2001 From: "Eugene@ubuntu" Date: Thu, 27 Mar 2014 08:55:58 +0400 Subject: [PATCH 7/7] typo in paymentProcessor --- libs/paymentProcessor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 1e75c35..06104de 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -20,7 +20,7 @@ module.exports = function(logger){ function SetupForPool(logger, poolOptions){ if (!poolOptions.shareProcessing || - poolOptions.shareProcessing.internal || + !poolOptions.shareProcessing.internal || !poolOptions.shareProcessing.internal.enabled) return;