diff --git a/cronjobs/pplns_payout.php b/cronjobs/pplns_payout.php index 39ea294a..15e8d6b4 100755 --- a/cronjobs/pplns_payout.php +++ b/cronjobs/pplns_payout.php @@ -46,7 +46,9 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { // We support some dynamic share targets but fall back to our fixed value // Re-calculate after each run due to re-targets in this loop if ($config['pplns']['shares']['type'] == 'blockavg' && $block->getBlockCount() > 0) { - $pplns_target = round($block->getAvgBlockShares($aBlock['height'], $config['pplns']['blockavg']['blockcount'])); + $pplns_target = round($block->getAvgBlockShares($aBlock['height'], $config['pplns']['blockavg']['blockcount'])); + } else if ($config['pplns']['shares']['type'] == 'dynamic' && $block->getBlockCount() > 0) { + $pplns_target = round($block->getAvgBlockShares($aBlock['height'], $config['pplns']['blockavg']['blockcount']) * (100 - $config['pplns']['dynamic']['percent'])/100 + $aBlock['shares'] * $config['pplns']['dynamic']['percent']/100); } else { $pplns_target = $config['pplns']['shares']['default']; } @@ -66,6 +68,8 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { $config['reward_type'] == 'block' ? $dReward = $aBlock['amount'] : $dReward = $config['reward']; $aRoundAccountShares = $share->getSharesForAccounts($iPreviousShareId, $aBlock['share_id']); + $log->logInfo('Shares: ' . $iRoundShares . "\t" . 'Height: ' . $aBlock['height'] . ' Amount: ' . $aBlock['amount'] . "\t" . 'Found by ID: ' . $aBlock['account_id']); + if ($iRoundShares >= $pplns_target) { $log->logDebug("Matching or exceeding PPLNS target of $pplns_target with $iRoundShares"); $iMinimumShareId = $share->getMinimumShareId($pplns_target, $aBlock['share_id']); @@ -81,7 +85,7 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { foreach($aAccountShares as $key => $aData) { $iNewRoundShares += $aData['valid']; } - $log->logInfo('Adjusting round target to PPLNS target ' . $iNewRoundShares); + $log->logInfo('Adjusting round to PPLNS target of ' . $pplns_target . ' shares used ' . $iNewRoundShares); $iRoundShares = $iNewRoundShares; } else { $log->logDebug("Not able to match PPLNS target of $pplns_target with $iRoundShares"); @@ -114,6 +118,24 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { $aAccountShares[$key]['invalid'] += $aArchiveShares[$aData['username']]['invalid']; } } + // reverse payout + if ($config['pplns']['reverse_payout']) { + $aSharesData = NULL; + foreach($aAccountShares as $key => $aData) { + $aSharesData[$aData['username']] = $aData; + } + // Add users from archive not in current round + foreach($aArchiveShares as $key => $aArchData) { + if (!array_key_exists($aArchData['account'], $aSharesData)) { + $log->logDebug('Adding user ' . $aArchData['account'] . ' to round shares'); + $log->logDebug(' valid : ' . $aArchData['valid']); + $log->logDebug(' invalid : ' . $aArchData['invalid']); + $aArchData['username'] = $aArchData['account']; + $aSharesData[$aArchData['account']] = $aArchData; + } + } + $aAccountShares = $aSharesData; + } } // We tried to fill up to PPLNS target, now we need to check the actual shares to properly payout users foreach($aAccountShares as $key => $aData) { @@ -162,6 +184,19 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { $log->logError('Failed to update share statistics for ' . $aData['username']); } + // Add PPLNS share statistics + foreach ($aAccountShares as $key => $aRoundData) { + if ($aRoundData['username'] == $aData['username']){ + if (@$statistics->getIdShareStatistics($aRoundData, $aBlock['id'])){ + if (!$statistics->updatePPLNSShareStatistics($aRoundData, $aBlock['id'])) + $log->logError('Failed to update pplns statistics for ' . $aData['username']); + } else { + if (!$statistics->insertPPLNSShareStatistics($aRoundData, $aBlock['id'])) + $log->logError('Failed to insert pplns statistics for ' . $aData['username']); + } + } + } + // Add new credit transaction if (!$transaction->addTransaction($aData['id'], $aData['payout'], 'Credit', $aBlock['id'])) $log->logFatal('Failed to insert new Credit transaction to database for ' . $aData['username']); diff --git a/public/include/classes/roundstats.class.php b/public/include/classes/roundstats.class.php index 6b187973..1f5ab765 100644 --- a/public/include/classes/roundstats.class.php +++ b/public/include/classes/roundstats.class.php @@ -56,20 +56,51 @@ class RoundStats { return false; } + /** + * search for block height + **/ + public function searchForBlockHeight($iHeight=0) { + $stmt = $this->mysqli->prepare(" + SELECT height + FROM $this->tableBlocks + WHERE height >= ? + ORDER BY height ASC + LIMIT 1"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_object()->height; + return false; + } + + /** + * get next block for stats paging + **/ + public function getNextBlockForStats($iHeight=0, $limit=10) { + $stmt = $this->mysqli->prepare(" + SELECT MAX(x.height) AS height + FROM (SELECT height FROM $this->tableBlocks + WHERE height >= ? + ORDER BY height ASC LIMIT ?) AS x"); + if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $iHeight, $limit) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_object()->height; + return false; + } + /** * Get details for block height * @param height int Block Height * @return data array Block information from DB **/ - public function getDetailsForBlockHeight($iHeight=0, $isAdmin=0) { + public function getDetailsForBlockHeight($iHeight=0) { $stmt = $this->mysqli->prepare(" SELECT b.id, height, blockhash, amount, confirmations, difficulty, FROM_UNIXTIME(time) as time, shares, - IF(a.is_anonymous, IF( ? , a.username, 'anonymous'), a.username) AS finder + IF(a.is_anonymous, 'anonymous', a.username) AS finder, + ROUND((difficulty * 65535) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares, + (time - (SELECT time FROM $this->tableBlocks WHERE height < ? ORDER BY height DESC LIMIT 1)) AS round_time FROM $this->tableBlocks as b LEFT JOIN $this->tableUsers AS a ON b.account_id = a.id WHERE b.height = ? LIMIT 1"); - if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $isAdmin, $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $iHeight, $iHeight) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_assoc(); return false; } @@ -79,10 +110,11 @@ class RoundStats { * @param height int Block Height * @return data array Block information from DB **/ - public function getRoundStatsForAccounts($iHeight=0, $isAdmin=0) { + public function getRoundStatsForAccounts($iHeight=0) { $stmt = $this->mysqli->prepare(" SELECT - IF(a.is_anonymous, IF( ? , a.username, 'anonymous'), a.username) AS username, + a.username, + a.is_anonymous, s.valid, s.invalid FROM $this->tableStats AS s @@ -92,30 +124,71 @@ class RoundStats { GROUP BY username ASC ORDER BY valid DESC "); - if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $isAdmin, $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('i',$iHeight) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return false; } + /** + * Get pplns statistics for round block height + * @param height int Block Height + * @return data array Block information from DB + **/ + public function getPPLNSRoundStatsForAccounts($iHeight=0) { + $stmt = $this->mysqli->prepare(" + SELECT + a.username, + a.is_anonymous, + s.pplns_valid, + s.pplns_invalid + FROM $this->tableStats AS s + LEFT JOIN $this->tableBlocks AS b ON s.block_id = b.id + LEFT JOIN $this->tableUsers AS a ON a.id = s.account_id + WHERE b.height = ? + GROUP BY username ASC + ORDER BY pplns_valid DESC + "); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + return false; + } + + /** + * Get total valid pplns shares for block height + **/ + public function getPPLNSRoundShares($iHeight=0) { + $stmt = $this->mysqli->prepare(" + SELECT + SUM(s.pplns_valid) AS pplns_valid + FROM $this->tableStats AS s + LEFT JOIN $this->tableBlocks AS b ON s.block_id = b.id + WHERE b.height = ? + "); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_object()->pplns_valid; + return false; + } + /** * Get all transactions for round block height for admin * @param height int Block Height * @return data array Block round transactions **/ - public function getAllRoundTransactions($iHeight=0, $admin) { + public function getAllRoundTransactions($iHeight=0) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT t.id AS id, - IF(a.is_anonymous, IF( ? , a.username, 'anonymous'), a.username) AS username, + a.username AS username, + a.is_anonymous, t.type AS type, t.amount AS amount FROM $this->tableTrans AS t LEFT JOIN $this->tableBlocks AS b ON t.block_id = b.id LEFT JOIN $this->tableUsers AS a ON t.account_id = a.id - WHERE b.height = ? - ORDER BY id ASC"); - if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $admin, $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + WHERE b.height = ? AND t.type = 'Credit' + ORDER BY amount DESC"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $iHeight) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); $this->debug->append('Unable to fetch transactions'); return false; diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php index 8fd80aa9..3f608701 100644 --- a/public/include/classes/statistics.class.php +++ b/public/include/classes/statistics.class.php @@ -77,6 +77,32 @@ class Statistics { return false; } + /** + * Get our last $limit blocks found by height + * @param limit int Last limit blocks + * @return array + **/ + public function getBlocksFoundHeight($iHeight=0, $limit=10) { + $this->debug->append("STA " . __METHOD__, 4); + if ($data = $this->memcache->get(__FUNCTION__ . $iHeight . $limit)) return $data; + $stmt = $this->mysqli->prepare(" + SELECT + b.*, + a.username AS finder, + a.is_anonymous AS is_anonymous, + ROUND((difficulty * 65535) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares + FROM " . $this->block->getTableName() . " AS b + LEFT JOIN " . $this->user->getTableName() . " AS a + ON b.account_id = a.id + WHERE b.height <= ? + ORDER BY height DESC LIMIT ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $iHeight, $limit) && $stmt->execute() && $result = $stmt->get_result()) + return $this->memcache->setCache(__FUNCTION__ . $iHeight . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); + // Catchall + $this->debug->append("Failed to find blocks:" . $this->mysqli->error); + return false; + } + /** * Currently the only function writing to the database * Stored per block user statistics of valid and invalid shares @@ -93,6 +119,44 @@ class Statistics { return false; } + /** + * update user statistics of valid and invalid pplns shares + **/ + public function updatePPLNSShareStatistics($aStats, $iBlockId) { + $this->debug->append("STA " . __METHOD__, 4); + $stmt = $this->mysqli->prepare(" + UPDATE $this->table SET pplns_valid = ?, pplns_invalid = ? WHERE account_id = ? AND block_id = ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('iiii', $aStats['valid'], $aStats['invalid'], $aStats['id'], $iBlockId) && $stmt->execute()) return true; + // Catchall + $this->debug->append("Failed to update pplns share stats: " . $this->mysqli->error); + return false; + } + + /** + * insert user statistics of valid and invalid pplns shares "rbpplns" + **/ + public function insertPPLNSShareStatistics($aStats, $iBlockId) { + $this->debug->append("STA " . __METHOD__, 4); + $stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, valid, invalid, pplns_valid, pplns_invalid, block_id) VALUES (?, 0, 0, ?, ?, ?)"); + if ($this->checkStmt($stmt) && $stmt->bind_param('iiii', $aStats['id'], $aStats['valid'], $aStats['invalid'], $iBlockId) && $stmt->execute()) return true; + // Catchall + $this->debug->append("Failed to insert pplns share stats: " . $this->mysqli->error); + return false; + } + + /** + * Fetch the share ID from stats for rbpplns + **/ + function getIdShareStatistics($aStats, $iBlockId) { + $stmt = $this->mysqli->prepare(" + SELECT id AS id FROM $this->table + WHERE account_id = ? AND block_id = ? + "); + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $aStats['id'], $iBlockId) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_object()->id; + return false; + } + /** * Get our current pool hashrate for the past 10 minutes across both * shares and shares_archive table @@ -196,7 +260,6 @@ class Statistics { $data['share_id'] = 0; $data['data'] = array(); } - $data['last_update'] = time(); $stmt = $this->mysqli->prepare(" SELECT ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS valid, @@ -246,12 +309,14 @@ class Statistics { if ($data = $this->memcache->get(STATISTICS_ALL_USER_SHARES)) { if (array_key_exists($account_id, $data['data'])) return $data['data'][$account_id]; + // We have no cached value, we return defaults + return array('valid' => 0, 'invalid' => 0, 'donate_percent' => 0, 'is_anonymous' => 0); } - // if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; + if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0), 0) AS invalid + ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS valid, + ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS invalid FROM " . $this->share->getTableName() . " AS s, " . $this->user->getTableName() . " AS u WHERE diff --git a/public/include/config/admin_settings.inc.php b/public/include/config/admin_settings.inc.php index e85b9480..c56bf623 100644 --- a/public/include/config/admin_settings.inc.php +++ b/public/include/config/admin_settings.inc.php @@ -123,6 +123,13 @@ $aSettings['statistics'][] = array( 'name' => 'statistics_block_count', 'value' => $setting->getValue('statistics_block_count'), 'tooltip' => 'Blocks to fetch for the block statistics page.' ); +$aSettings['statistics'][] = array( + 'display' => 'Show block average', 'type' => 'select', + 'options' => array( 0 => 'No', 1 => 'Yes' ), + 'default' => 0, + 'name' => 'show_block_average', 'value' => $setting->getValue('show_block_average'), + 'tooltip' => 'Show block average in block statistics page.' +); $aSettings['statistics'][] = array( 'display' => 'Pool Hashrate Modifier', 'type' => 'select', 'options' => array( '1' => 'KH/s', '0.001' => 'MH/s', '0.000001' => 'GH/s' ), @@ -165,13 +172,6 @@ $aSettings['acl'][] = array( 'name' => 'acl_round_statistics', 'value' => $setting->getValue('acl_round_statistics'), 'tooltip' => 'Make the round statistics page private (users only) or public.' ); -$aSettings['acl'][] = array( - 'display' => 'Round Transactions', 'type' => 'select', - 'options' => array( 0 => 'Admins', 1 => 'Public'), - 'default' => 0, - 'name' => 'acl_round_transactions', 'value' => $setting->getValue('acl_round_transactions'), - 'tooltip' => 'Display all transactions regardless of admin status.' -); $aSettings['system'][] = array( 'display' => 'Disable e-mail confirmations', 'type' => 'select', 'options' => array( 0 => 'No', 1 => 'Yes' ), diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 941f57b0..b9cfda0d 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -231,9 +231,20 @@ $config['fees'] = 0; * type = `blockavg` * blockcount = 10 **/ +/** + * $config['pplns']['shares']['type'] = 'dynamic'; + * Dynamic target adjustment allows the blockavg target to adjust faster to share counts + * while still tracking round share averages by using a percentage of the current round shares + * to alter the pplns blockavg target this is useful with the nature of many alt coins low and fast + * adjusting difficulties and quick round times + * reverse_payout is useful to even out payouts for fast round times when even steady miners + * are missing share submissions for the current round +**/ $config['pplns']['shares']['default'] = 4000000; $config['pplns']['shares']['type'] = 'blockavg'; $config['pplns']['blockavg']['blockcount'] = 10; +$config['pplns']['reverse_payout'] = false; // add user shares from archive even if user not in current round +$config['pplns']['dynamic']['percent'] = 30; // percentage of round shares factored into block average when using dynamic type // Pool target difficulty as set in pushpoold configuration file // Please also read this for stratum: https://github.com/TheSerapher/php-mpos/wiki/FAQ diff --git a/public/include/pages/statistics/blocks.inc.php b/public/include/pages/statistics/blocks.inc.php index 116d999d..ce3667cb 100644 --- a/public/include/pages/statistics/blocks.inc.php +++ b/public/include/pages/statistics/blocks.inc.php @@ -8,11 +8,71 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); // Grab the last blocks found $setting->getValue('statistics_block_count') ? $iLimit = $setting->getValue('statistics_block_count') : $iLimit = 20; - $aBlocksFoundData = $statistics->getBlocksFound($iLimit); + if (@$_REQUEST['limit'] && !empty($_REQUEST['limit']) && is_numeric($_REQUEST['limit'])) { + $iLimit = $_REQUEST['limit']; + if ( $iLimit > 40 ) + $iLimit = 40; + } + + $iHeight = 0; + if (@$_REQUEST['next'] && !empty($_REQUEST['height']) && is_numeric($_REQUEST['height'])) { + $iHeight = @$roundstats->getNextBlockForStats($_REQUEST['height'], $iLimit); + if (!$iHeight) { + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; + } + } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height']) && is_numeric($_REQUEST['height'])) { + $iHeight = $_REQUEST['height']; + } else if (empty($_REQUEST['height'])) { + $aBlock = $block->getLast(); + $iHeight = $aBlock['height']; + } + + $test = false; + if (@$_REQUEST['test'] && $user->isAdmin($_SESSION['USERDATA']['id'])) { + $test = true; + $count = 10; + $percent = 30; + if (@$_REQUEST['count'] && is_numeric($_REQUEST['count'])) + $count = $_REQUEST['count']; + if (@$_REQUEST['percent'] && is_numeric($_REQUEST['percent'])) + $percent = $_REQUEST['percent']; + } + + $aBlocksFoundData = $statistics->getBlocksFoundHeight($iHeight, $iLimit); + $use_average = false; + if ($config['payout_system'] == 'pplns') { + foreach($aBlocksFoundData as $key => $aData) { + $aBlocksFoundData[$key]['pplns_shares'] = $roundstats->getPPLNSRoundShares($aData['height']); + if ($setting->getValue('show_block_average') && !$test) { + $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $config['pplns']['blockavg']['blockcount'])); + $use_average = true; + } + } + } else if ($config['payout_system'] == 'prop' || $config['payout_system'] == 'pps') { + if ($setting->getValue('show_block_average') && !$test) { + foreach($aBlocksFoundData as $key => $aData) { + $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $config['pplns']['blockavg']['blockcount'])); + $use_average = true; + } + } + } + // show test data in graph + if ($test) { + $use_average = true; + foreach($aBlocksFoundData as $key => $aData) { + if ($_REQUEST['test'] == 1) { + $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $count)); + } else if ($_REQUEST['test'] == 2) { + $aBlocksFoundData[$key]['block_avg'] = round($block->getAvgBlockShares($aData['height'], $count) * (100 - $percent) / 100 + $aData['shares'] * $percent / 100); + } + } + } // Propagate content our template $smarty->assign("BLOCKSFOUND", $aBlocksFoundData); $smarty->assign("BLOCKLIMIT", $iLimit); + $smarty->assign("USEBLOCKAVERAGE", $use_average); } else { $debug->append('Using cached page', 3); } diff --git a/public/include/pages/statistics/round.inc.php b/public/include/pages/statistics/round.inc.php index 4c37f749..bcc53ebe 100644 --- a/public/include/pages/statistics/round.inc.php +++ b/public/include/pages/statistics/round.inc.php @@ -6,32 +6,57 @@ if (!defined('SECURITY')) die('Hacking attempt'); if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); - if (@$_REQUEST['next'] && !empty($_REQUEST['height'])) { - $iKey = $roundstats->getNextBlock($_REQUEST['height']); - } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height'])) { - $iKey = $roundstats->getPreviousBlock($_REQUEST['height']); - } else { - - if (empty($_REQUEST['height'])) { - $iBlock = $block->getLast(); - $iKey = $iBlock['height']; - } else { - $iKey = $_REQUEST['height']; - } + if (@$_REQUEST['search']) { + $_REQUEST['height'] = $roundstats->searchForBlockHeight($_REQUEST['search']); } - $aDetailsForBlockHeight = $roundstats->getDetailsForBlockHeight($iKey, $user->isAdmin(@$_SESSION['USERDATA']['id'])); - $aRoundShareStats = $roundstats->getRoundStatsForAccounts($iKey, $user->isAdmin(@$_SESSION['USERDATA']['id'])); - - if ($user->isAdmin(@$_SESSION['USERDATA']['id']) || $setting->getValue('acl_round_transactions')) { - $aUserRoundTransactions = $roundstats->getAllRoundTransactions($iKey, @$_SESSION['USERDATA']['id']); + if (@$_REQUEST['next'] && !empty($_REQUEST['height'])) { + $iHeight = @$roundstats->getNextBlock($_REQUEST['height']); + if (!$iHeight) { + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; + } + } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height'])) { + $iHeight = $roundstats->getPreviousBlock($_REQUEST['height']); + } else if (empty($_REQUEST['height'])) { + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; } else { - $aUserRoundTransactions = $roundstats->getUserRoundTransactions($iKey, @$_SESSION['USERDATA']['id']); + $iHeight = $_REQUEST['height']; + } + $_REQUEST['height'] = $iHeight; + + $iPPLNSShares = 0; + $aDetailsForBlockHeight = $roundstats->getDetailsForBlockHeight($iHeight); + $aRoundShareStats = $roundstats->getRoundStatsForAccounts($iHeight); + + if ($config['payout_system'] == 'pplns') { + $aUserRoundTransactions = $roundstats->getAllRoundTransactions($iHeight); + foreach($aRoundShareStats as $key => $aData) { + $aSharesData[$aData['username']] = $aData; + } + $aPPLNSRoundShares = $roundstats->getPPLNSRoundStatsForAccounts($iHeight); + foreach($aPPLNSRoundShares as $key => $aData) { + $iPPLNSShares += $aData['pplns_valid']; + } + $block_avg = $block->getAvgBlockShares($iHeight, $config['pplns']['blockavg']['blockcount']); + } else if ($config['payout_system'] == 'prop') { + $aUserRoundTransactions = $roundstats->getAllRoundTransactions($iHeight); } // Propagate content our template $smarty->assign('BLOCKDETAILS', $aDetailsForBlockHeight); $smarty->assign('ROUNDSHARES', $aRoundShareStats); - $smarty->assign("ROUNDTRANSACTIONS", $aUserRoundTransactions); + + if ($config['payout_system'] == 'pplns') { + $smarty->assign('SHARESDATA', $aSharesData); + $smarty->assign('PPLNSROUNDSHARES', $aPPLNSRoundShares); + $smarty->assign("PPLNSSHARES", $iPPLNSShares); + $smarty->assign("BLOCKAVGCOUNT", $config['pplns']['blockavg']['blockcount']); + $smarty->assign("BLOCKAVERAGE", $block_avg ); + $smarty->assign("ROUNDTRANSACTIONS", $aUserRoundTransactions); + } else if ($config['payout_system'] == 'prop') { + $smarty->assign("ROUNDTRANSACTIONS", $aUserRoundTransactions); + } } else { $debug->append('Using cached page', 3); } diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl index 5929524d..1ab96c10 100644 --- a/public/templates/mmcFE/statistics/blocks/default.tpl +++ b/public/templates/mmcFE/statistics/blocks/default.tpl @@ -21,13 +21,38 @@ {$BLOCKSFOUND[block].shares} {/section} + {if $GLOBAL.config.payout_system == 'pplns'} + PPLNS +{section block $BLOCKSFOUND step=-1} + {$BLOCKSFOUND[block].pplns_shares} +{/section} + {/if} + {if $USEBLOCKAVERAGE} + Average +{section block $BLOCKSFOUND step=-1} + {$BLOCKSFOUND[block].block_avg} +{/section} + {/if}

The graph above illustrates N shares to find a block vs. E Shares expected to find a block based on target and network difficulty and assuming a zero variance scenario. -

+

+ + + + + + + +
+ + + +
+ {include file="global/block_footer.tpl"} {include file="global/block_header.tpl" BLOCK_HEADER="Last $BLOCKLIMIT Blocks Found" BLOCK_STYLE="clear:none;"} @@ -42,6 +67,7 @@ target and network difficulty and assuming a zero variance scenario. Difficulty Amount Expected Shares + {if $GLOBAL.config.payout_system == 'pplns'}PPLNS Shares{/if} Actual Shares Percentage @@ -51,9 +77,11 @@ target and network difficulty and assuming a zero variance scenario. {assign var=totalexpectedshares value=0} {assign var=totalshares value=0} {assign var=totalpercentage value=0} +{assign var=pplnsshares value=0} {section block $BLOCKSFOUND} {assign var="totalshares" value=$totalshares+$BLOCKSFOUND[block].shares} {assign var="count" value=$count+1} + {if $GLOBAL.config.payout_system == 'pplns'}{assign var="pplnsshares" value=$pplnsshares+$BLOCKSFOUND[block].pplns_shares}{/if} {$BLOCKSFOUND[block].height} @@ -62,7 +90,7 @@ target and network difficulty and assuming a zero variance scenario. {else if $BLOCKSFOUND[block].confirmations == -1} Orphan {else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if} - {if $BLOCKSFOUND[block].is_anonymous|default:"0" == 1 && $GLOBAL.userdata.is_admin|default:"0" == 0}anonymous{else}{$BLOCKSFOUND[block].finder|default:"unknown"|escape}{/if} + {if $BLOCKSFOUND[block].is_anonymous|default:"0" == 1}anonymous{else}{$BLOCKSFOUND[block].finder|default:"unknown"|escape}{/if} {$BLOCKSFOUND[block].time|date_format:"%d/%m %H:%M:%S"} {$BLOCKSFOUND[block].difficulty|number_format:"8"} {$BLOCKSFOUND[block].amount|number_format:"2"} @@ -70,6 +98,7 @@ target and network difficulty and assuming a zero variance scenario. {$BLOCKSFOUND[block].estshares|number_format} {assign var="totalexpectedshares" value=$totalexpectedshares+$BLOCKSFOUND[block].estshares} + {if $GLOBAL.config.payout_system == 'pplns'}{$BLOCKSFOUND[block].pplns_shares|number_format}{/if} {$BLOCKSFOUND[block].shares|number_format} {math assign="percentage" equation="shares / estshares * 100" shares=$BLOCKSFOUND[block].shares estshares=$BLOCKSFOUND[block].estshares} @@ -82,6 +111,7 @@ target and network difficulty and assuming a zero variance scenario. Totals {$totalexpectedshares|number_format} + {if $GLOBAL.config.payout_system == 'pplns'}{$pplnsshares|number_format}{/if} {$totalshares|number_format} {($totalpercentage / $count)|number_format:"2"} diff --git a/public/templates/mmcFE/statistics/round/block_stats.tpl b/public/templates/mmcFE/statistics/round/block_stats.tpl index 75b33950..dbd37bae 100644 --- a/public/templates/mmcFE/statistics/round/block_stats.tpl +++ b/public/templates/mmcFE/statistics/round/block_stats.tpl @@ -1,16 +1,24 @@ {include file="global/block_header.tpl" ALIGN="left" BLOCK_STYLE="width: 100%" BLOCK_HEADER="Block Stats" STYLE="padding-left:5px;padding-right:5px;"} - {assign var=rank value=1} -{assign var=listed value=0} {section contrib $ROUNDSHARES} - + - + - + {/section}
+ + + + + + - - - -
+ + + +
- - + - + @@ -26,7 +34,12 @@ - + @@ -38,7 +51,7 @@ - + @@ -47,19 +60,12 @@
NameValueBlock Round Statistics
ID{$BLOCKDETAILS.id|default:"0"}{$BLOCKDETAILS.id|number_format:"0"|default:"0"}
Height
Confirmations{$BLOCKDETAILS.confirmations|default:"0"}{if $BLOCKDETAILS.confirmations >= $GLOBAL.confirmations} + Confirmed + {else if $BLOCKDETAILS.confirmations == -1} + Orphan + {else if $BLOCKDETAILS.confirmations == 0}0 + {else}{($GLOBAL.confirmations - $BLOCKDETAILS.confirmations)|default:"0"} left{/if}
Difficulty
Shares{$BLOCKDETAILS.shares|default:"0"}{$BLOCKDETAILS.shares|number_format:"0"|default:"0"}
Finder
-
+ - +
- - - -
{include file="global/block_footer.tpl"} + diff --git a/public/templates/mmcFE/statistics/round/default.tpl b/public/templates/mmcFE/statistics/round/default.tpl index 7098eb06..c233a827 100644 --- a/public/templates/mmcFE/statistics/round/default.tpl +++ b/public/templates/mmcFE/statistics/round/default.tpl @@ -1,9 +1,14 @@ {include file="global/block_header.tpl" BLOCK_HEADER="Round Statistics" BLOCK_STYLE="clear:none;"} -{include file="statistics/round/block_stats.tpl"} - -{include file="statistics/round/round_transactions.tpl"} - -{include file="statistics/round/round_shares.tpl"} +{if $GLOBAL.config.payout_system == 'pplns'} + {include file="statistics/round/pplns_block_stats.tpl"} + {include file="statistics/round/round_shares.tpl"} + {include file="statistics/round/pplns_round_shares.tpl"} + {include file="statistics/round/pplns_transactions.tpl"} +{else} + {include file="statistics/round/block_stats.tpl"} + {include file="statistics/round/round_shares.tpl"} + {include file="statistics/round/round_transactions.tpl"} +{/if} {include file="global/block_footer.tpl"} diff --git a/public/templates/mmcFE/statistics/round/pplns_block_stats.tpl b/public/templates/mmcFE/statistics/round/pplns_block_stats.tpl new file mode 100644 index 00000000..f23facb3 --- /dev/null +++ b/public/templates/mmcFE/statistics/round/pplns_block_stats.tpl @@ -0,0 +1,118 @@ +{include file="global/block_header.tpl" ALIGN="left" BLOCK_STYLE="width: 100%" BLOCK_HEADER="Block Stats" STYLE="padding-left:5px;padding-right:5px;"} +
+
+ +
+ + + + + + +{assign var=percentage value=0} +{assign var=percentage1 value=0} +{assign var=percentage2 value=0} + +
+ + + +
+ + + + + + + + + + + + + + {if ! $GLOBAL.website.blockexplorer.disabled} + + {else} + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Block Round Statistics
ID{$BLOCKDETAILS.id|number_format:"0"|default:"0"}
Height{$BLOCKDETAILS.height}{$BLOCKDETAILS.height}
Amount{$BLOCKDETAILS.amount|default:"0"}
Confirmations{if $BLOCKDETAILS.confirmations >= $GLOBAL.confirmations} + Confirmed + {else if $BLOCKDETAILS.confirmations == -1} + Orphan + {else if $BLOCKDETAILS.confirmations == 0}0 + {else}{($GLOBAL.confirmations - $BLOCKDETAILS.confirmations)|default:"0"} left{/if}
Difficulty{$BLOCKDETAILS.difficulty|default:"0"}
Time{$BLOCKDETAILS.time|default:"0"}
Shares{$BLOCKDETAILS.shares|number_format:"0"|default:"0"}
Finder{$BLOCKDETAILS.finder|default:"0"}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PPLNS Round Statistics
PPLNS Shares{$PPLNSSHARES|number_format:"0"|default:"0"}
Estimated Shares{$BLOCKDETAILS.estshares|number_format|default:"0"}
Target Variance{if $PPLNSSHARES > 0}{math assign="percentage" equation=(($BLOCKDETAILS.estshares / $PPLNSSHARES) * 100)}{/if}{$percentage|number_format:"2"} %
Block Average{$BLOCKAVERAGE|number_format:"0"|default:"0"}
Average Efficiency{if $BLOCKAVERAGE > 0 && $BLOCKDETAILS.estshares > 0}{math assign="percentage2" equation=(($BLOCKDETAILS.estshares / $BLOCKAVERAGE) * 100)}{/if}{$percentage2|number_format:"2"} %
Target Rounds{$BLOCKAVGCOUNT|number_format:"0"|default:"0"}
Seconds This Round{$BLOCKDETAILS.round_time|number_format:"0"|default:"0"}
Round Variance{if $PPLNSSHARES > 0}{math assign="percentage1" equation=(($BLOCKDETAILS.shares / $PPLNSSHARES) * 100)}{/if}{$percentage1|number_format:"2"} %
+{include file="global/block_footer.tpl"} + diff --git a/public/templates/mmcFE/statistics/round/pplns_round_shares.tpl b/public/templates/mmcFE/statistics/round/pplns_round_shares.tpl new file mode 100644 index 00000000..52c47f9c --- /dev/null +++ b/public/templates/mmcFE/statistics/round/pplns_round_shares.tpl @@ -0,0 +1,29 @@ +{include file="global/block_header.tpl" ALIGN="right" BLOCK_HEADER="PPLNS Round Shares" } +
+ + + + + + + + + + + +{assign var=rank value=1} +{assign var=listed value=0} +{section contrib $PPLNSROUNDSHARES} + + + + + + + +{/section} + +
RankUser NameValidInvalidInvalid %
{$rank++}{if $PPLNSROUNDSHARES[contrib].is_anonymous|default:"0" == 1}anonymous{else}{$PPLNSROUNDSHARES[contrib].username|escape}{/if}{$PPLNSROUNDSHARES[contrib].pplns_valid|number_format}{$PPLNSROUNDSHARES[contrib].pplns_invalid|number_format}{if $PPLNSROUNDSHARES[contrib].pplns_invalid > 0 && $PPLNSROUNDSHARES[contrib].pplns_valid > 0}{($PPLNSROUNDSHARES[contrib].pplns_invalid / $PPLNSROUNDSHARES[contrib].pplns_valid * 100)|number_format:"2"|default:"0"}{else}0.00{/if}
+
+{include file="global/block_footer.tpl"} + diff --git a/public/templates/mmcFE/statistics/round/pplns_transactions.tpl b/public/templates/mmcFE/statistics/round/pplns_transactions.tpl new file mode 100644 index 00000000..4052a24b --- /dev/null +++ b/public/templates/mmcFE/statistics/round/pplns_transactions.tpl @@ -0,0 +1,34 @@ +{include file="global/block_header.tpl" ALIGN="left" BLOCK_STYLE="width: 100%" BLOCK_HEADER="Round Transactions"} +
+ + + + + + + + + + + + + +{assign var=percentage1 value=0} +{section txs $ROUNDTRANSACTIONS} + + + + + + + + + {assign var=percentage1 value=0} + +{/section} + +
User NameRound SharesRound %PPLNS SharesPPLNS Round %VarianceAmount
{if $ROUNDTRANSACTIONS[txs].is_anonymous|default:"0" == 1}anonymous{else}{$ROUNDTRANSACTIONS[txs].username|escape}{/if}{$SHARESDATA[$ROUNDTRANSACTIONS[txs].username].valid|number_format}{if $SHARESDATA[$ROUNDTRANSACTIONS[txs].username].valid > 0 }{(( 100 / $BLOCKDETAILS.shares) * $SHARESDATA[$ROUNDTRANSACTIONS[txs].username].valid)|number_format:"2"}{else}0.00{/if}{$PPLNSROUNDSHARES[txs].pplns_valid|number_format|default:"0"}{if $PPLNSROUNDSHARES[txs].pplns_valid > 0 }{(( 100 / $PPLNSSHARES) * $PPLNSROUNDSHARES[txs].pplns_valid)|number_format:"2"|default:"0"}{else}0{/if}{if $SHARESDATA[$ROUNDTRANSACTIONS[txs].username].valid > 0 && $PPLNSROUNDSHARES[txs].pplns_valid > 0}{math assign="percentage1" equation=(100 / ((( 100 / $BLOCKDETAILS.shares) * $SHARESDATA[$ROUNDTRANSACTIONS[txs].username].valid) / (( 100 / $PPLNSSHARES) * $PPLNSROUNDSHARES[txs].pplns_valid)))}{else if $PPLNSROUNDSHARES[txs].pplns_valid == 0}{assign var=percentage1 value=0}{else}{assign var=percentage1 value=100}{/if} + {$percentage1|number_format:"2"}{$ROUNDTRANSACTIONS[txs].amount|default:"0"|number_format:"8"}
+
+{include file="global/block_footer.tpl"} + diff --git a/public/templates/mmcFE/statistics/round/round_shares.tpl b/public/templates/mmcFE/statistics/round/round_shares.tpl index fa09ca0a..63a03a89 100644 --- a/public/templates/mmcFE/statistics/round/round_shares.tpl +++ b/public/templates/mmcFE/statistics/round/round_shares.tpl @@ -12,17 +12,17 @@
{$rank++}{if $ROUNDSHARES[contrib].is_anonymous|default:"0" == 1 && $GLOBAL.userdata.is_admin|default:"0" == 0}anonymous{else}{$ROUNDSHARES[contrib].username|escape}{/if}{if $ROUNDSHARES[contrib].is_anonymous|default:"0" == 1}anonymous{else}{$ROUNDSHARES[contrib].username|escape}{/if} {$ROUNDSHARES[contrib].valid|number_format} {$ROUNDSHARES[contrib].invalid|number_format}{($ROUNDSHARES[contrib].invalid / $ROUNDSHARES[contrib].valid * 100)|number_format:"2"}{if $ROUNDSHARES[contrib].invalid > 0 }{($ROUNDSHARES[contrib].invalid / $ROUNDSHARES[contrib].valid * 100)|number_format:"2"|default:"0"}{else}0.00{/if}
{include file="global/block_footer.tpl"} + diff --git a/public/templates/mmcFE/statistics/round/round_transactions.tpl b/public/templates/mmcFE/statistics/round/round_transactions.tpl index ecb4ea75..39f47697 100644 --- a/public/templates/mmcFE/statistics/round/round_transactions.tpl +++ b/public/templates/mmcFE/statistics/round/round_transactions.tpl @@ -3,18 +3,18 @@ - + {section txs $ROUNDTRANSACTIONS} - - - + + + {/section} @@ -22,3 +22,4 @@
Tx Id User Name TypeRound % Amount
{$ROUNDTRANSACTIONS[txs].id|default:"0"}{$ROUNDTRANSACTIONS[txs].username|escape}{if $ROUNDTRANSACTIONS[txs].is_anonymous|default:"0" == 1}anonymous{else}{$ROUNDTRANSACTIONS[txs].username|escape}{/if} {$ROUNDTRANSACTIONS[txs].type|default:""}{(( 100 / $BLOCKDETAILS.shares) * $ROUNDSHARES[txs].valid)|number_format:"2"} {$ROUNDTRANSACTIONS[txs].amount|default:"0"|number_format:"8"}
{include file="global/block_footer.tpl"} + diff --git a/public/templates/mpos/statistics/blocks/default.tpl b/public/templates/mpos/statistics/blocks/default.tpl index 02bcaf21..eb87227b 100644 --- a/public/templates/mpos/statistics/blocks/default.tpl +++ b/public/templates/mpos/statistics/blocks/default.tpl @@ -22,6 +22,30 @@ {$BLOCKSFOUND[block].shares} {/section} + {if $GLOBAL.config.payout_system == 'pplns'} + PPLNS +{section block $BLOCKSFOUND step=-1} + {$BLOCKSFOUND[block].pplns_shares} +{/section} + {/if} + {if $USEBLOCKAVERAGE} + Average +{section block $BLOCKSFOUND step=-1} + {$BLOCKSFOUND[block].block_avg} +{/section} + {/if} + + + + + + + +
+ + + +