More development for payment processing. so close...

This commit is contained in:
Matt 2014-03-12 18:09:12 -06:00
parent 191d81bd18
commit 5acaaa5686
3 changed files with 65 additions and 54 deletions

View File

@ -128,15 +128,16 @@ Description of options:
payments less frequently (they dislike). Opposite for a lower minimum payment. */ payments less frequently (they dislike). Opposite for a lower minimum payment. */
"minimumPayment": 0.001, "minimumPayment": 0.001,
/* Minimum number of coins to keep in pool wallet. It is recommended to deposit at
at least this many coins into the pool wallet when first starting the pool. */
"minimumReserve": 10,
/* (2% default) What percent fee your pool takes from the block reward. */ /* (2% default) What percent fee your pool takes from the block reward. */
"feePercent": 0.02, "feePercent": 0.02,
/* Your address that receives pool revenue from fees */ /* Your address that receives pool revenue from fees */
"feeReceiveAddress": "LZz44iyF4zLCXJTU8RxztyyJZBntdS6fvv", "feeReceiveAddress": "LZz44iyF4zLCXJTU8RxztyyJZBntdS6fvv",
/* Minimum number of coins to keep in pool wallet */
"minimumReserve": 10,
/* How many coins from fee revenue must accumulate on top of the minimum reserve amount /* How many coins from fee revenue must accumulate on top of the minimum reserve amount
in order to trigger withdrawal to fee address. The higher this threshold, the less of in order to trigger withdrawal to fee address. The higher this threshold, the less of
your profit goes to transactions fees. */ your profit goes to transactions fees. */

View File

@ -100,11 +100,11 @@ function SetupForPool(logger, poolOptions){
return; return;
} }
var rounds = []; var rounds = results.map(function(r){
results.forEach(function(item){ var details = r.split(':');
var details = item.split(':'); return {txHash: details[0], height: details[1], reward: details[2]};
rounds.push({txHash: details[0], height: details[1], reward: details[2]});
}); });
callback(null, rounds); callback(null, rounds);
}); });
}, },
@ -114,11 +114,10 @@ function SetupForPool(logger, poolOptions){
It also adds the block reward amount to the round object - which the daemon gives also gives us. */ It also adds the block reward amount to the round object - which the daemon gives also gives us. */
function(rounds, callback){ function(rounds, callback){
var batchRPCcommand = []; var batchRPCcommand = rounds.map(function(r){
return ['gettransaction', [r.txHash]];
});
for (var i = 0; i < rounds.length; i++){
batchRPCcommand.push(['gettransaction', [rounds[i].txHash]]);
}
daemon.batchCmd(batchRPCcommand, function(error, txDetails){ daemon.batchCmd(batchRPCcommand, function(error, txDetails){
if (error || !txDetails){ if (error || !txDetails){
@ -128,18 +127,14 @@ function SetupForPool(logger, poolOptions){
//Rounds that are not confirmed yet are removed from the round array //Rounds that are not confirmed yet are removed from the round array
//We also get reward amount for each block from daemon reply //We also get reward amount for each block from daemon reply
txDetails.forEach(function(tx){ rounds = rounds.filter(function(r){
var txResult = tx.result; var tx = txDetails.filter(function(t){ return t.result.txid === r.txHash; })[0];
var txDetails = tx.result.details[0]; if (tx.result.details[0].category !== 'generate') return false;
for (var i = 0; i < rounds.length; i++){ r.amount = tx.result.amount;
if (rounds[i].txHash === txResult.txid){ r.magnitude = r.reward / r.amount;
rounds[i].amount = txResult.amount; return true;
rounds[i].magnitude = rounds[i].reward / txResult.amount;
if (txDetails.category !== 'generate')
rounds.splice(i, 1);
}
}
}); });
if (rounds.length === 0){ if (rounds.length === 0){
callback('done - no confirmed transactions yet'); callback('done - no confirmed transactions yet');
return; return;
@ -154,14 +149,12 @@ function SetupForPool(logger, poolOptions){
amount owned to each miner for each round. */ amount owned to each miner for each round. */
function(rounds, callback){ function(rounds, callback){
var shareLooksup = [];
for (var i = 0; i < rounds.length; i++){
shareLooksup.push(['hgetall', coin + '_shares:round' + rounds[i].height]);
}
var shareLookups = rounds.map(function(r){
return ['hgetall', coin + '_shares:round' + r.height]
});
redisClient.multi(shareLookups).exec(function(error, allWorkerShares){
redisClient.multi(shareLooksup).exec(function(error, allWorkerShares){
if (error){ if (error){
callback('done - redis error with multi get rounds share') callback('done - redis error with multi get rounds share')
return; return;
@ -169,58 +162,68 @@ function SetupForPool(logger, poolOptions){
var workerRewards = {}; var workerRewards = {};
for (var i = 0; i < rounds.length; i++){ for (var i = 0; i < rounds.length; i++){
var round = rounds[i]; var round = rounds[i];
var workerShares = allWorkerShares[i]; var workerShares = allWorkerShares[i];
var reward = round.reward * (1 - processingConfig.feePercent); var reward = round.reward * (1 - processingConfig.feePercent);
var totalShares = 0; var totalShares = Object.keys(workerShares).reduce(function(p, c){
for (var worker in workerShares){ return p + parseInt(workerShares[c])
totalShares += parseInt(workerShares[worker]); }, 0);
}
for (var worker in workerShares){ for (var worker in workerShares){
var singleWorkerShares = parseInt(workerShares[worker]); var percent = parseInt(workerShares[worker]) / totalShares;
var percent = singleWorkerShares / totalShares; var workerRewardTotal = Math.floor(reward * percent);
var workerRewardTotal = (reward * percent) / round.magnitude; if (!(worker in workerRewards)) workerRewards[worker] = 0;
workerRewardTotal = Math.floor(workerRewardTotal * round.magnitude) / round.magnitude; workerRewards[worker] += workerRewardTotal;
if (worker in workerRewards)
workerRewards[worker] += workerRewardTotal;
else
workerRewards[worker] = workerRewardTotal;
} }
} }
//this calculates profit if you wanna see it
/*
var workerTotalRewards = Object.keys(workerRewards).reduce(function(p, c){
return p + workerRewards[c];
}, 0);
console.dir(workerRewards); var poolTotalRewards = rounds.reduce(function(p, c){
return p + c.amount;
}, 0);
callback(null, rounds); console.log(workerRewards);
console.log('pool profit percent' + ((poolTotalRewards - workerTotalRewards) / poolTotalRewards));
*/
callback(null, rounds, workerRewards);
}); });
}, },
/* Does a batch call to redis to get worker existing balances from coin_balances*/ /* Does a batch call to redis to get worker existing balances from coin_balances*/
function(rounds, callback){ function(rounds, workerRewards, callback){
/*
var workerAddress = Object.keys(balancesForRounds);
redisClient.hmget([coin + '_balances'].concat(workerAddress), function(error, results){ var workers = Object.keys(workerRewards);
redisClient.hmget([coin + '_balances'].concat(workers), function(error, results){
if (error){ if (error){
callback('done - redis error with multi get rounds share') callback('done - redis error with multi get rounds share')
return; return;
} }
console.dir(workerRewards);
for (var i = 0; i < results.length; i++){ var workerBalances = {};
var shareInt = parseInt(results[i]);
if (shareInt)
balancesForRounds[workerAddress[i]] += shareInt;
for (var i = 0; i < workers.length; i++){
workerBalances[workers[i]] = parseInt(results[i]) || 0;
} }
callback(null, rounds, balancesForRounds) console.dir(workerBalances);
callback(null, rounds, workerRewards, workerBalances)
}); });
*/
}, },
@ -230,13 +233,20 @@ function SetupForPool(logger, poolOptions){
when deciding the sent balance, it the difference should be -1*amount they had in db, when deciding the sent balance, it the difference should be -1*amount they had in db,
if not sending the balance, the differnce should be +(the amount they earned this round) if not sending the balance, the differnce should be +(the amount they earned this round)
*/ */
function(fullBalance, rounds, callback){ function(rounds, workerRewards, workerBalances, callback){
/* if payments dont succeed (likely because daemon isnt responding to rpc), then cancel here /* if payments dont succeed (likely because daemon isnt responding to rpc), then cancel here
so that all of this can be tried again when the daemon is working. otherwise we will consider so that all of this can be tried again when the daemon is working. otherwise we will consider
payment sent after we cleaned up the db. payment sent after we cleaned up the db.
*/ */
/* In here do daemon.getbalance, figure out how many payments should be sent, see if the
remaining balance after payments-to-be sent is greater than the min reserver, otherwise
put everything in worker balances to be paid next time.
*/
}, },

View File

@ -8,9 +8,9 @@
"validateWorkerAddress": true, "validateWorkerAddress": true,
"paymentInterval": 10, "paymentInterval": 10,
"minimumPayment": 0.001, "minimumPayment": 0.001,
"minimumReserve": 10,
"feePercent": 0.02, "feePercent": 0.02,
"feeReceiveAddress": "LZz44iyF4zLCXJTU8RxztyyJZBntdS6fvv", "feeReceiveAddress": "LZz44iyF4zLCXJTU8RxztyyJZBntdS6fvv",
"minimumReserve": 10,
"feeWithdrawalThreshold": 5, "feeWithdrawalThreshold": 5,
"daemon": { "daemon": {
"host": "localhost", "host": "localhost",