diff --git a/cronjobs/pplns_payout.php b/cronjobs/pplns_payout.php index 15e8d6b4..1fe17879 100755 --- a/cronjobs/pplns_payout.php +++ b/cronjobs/pplns_payout.php @@ -68,7 +68,7 @@ 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']); + $log->logInfo('Target: ' . $pplns_target . '; Shares: ' . $iRoundShares . '; Height: ' . $aBlock['height'] . '; Amount: ' . $aBlock['amount'] . '; Found by ID: ' . $aBlock['account_id']); if ($iRoundShares >= $pplns_target) { $log->logDebug("Matching or exceeding PPLNS target of $pplns_target with $iRoundShares"); diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php index 7c3515fb..ca0a8c3c 100755 --- a/cronjobs/pps_payout.php +++ b/cronjobs/pps_payout.php @@ -54,19 +54,17 @@ if ($config['pps']['reward']['type'] == 'blockavg' && $block->getBlockCount() > if ($config['pps']['reward']['type'] == 'block') { if ($aLastBlock = $block->getLast()) { $pps_reward = $aLastBlock['amount']; - $log->logInfo("PPS reward using last block, amount: " . $pps_reward . "\tdifficulty: " . $dDifficulty); } else { $pps_reward = $config['pps']['reward']['default']; - $log->logInfo("PPS reward using default, amount: " . $pps_reward . "\tdifficulty: " . $dDifficulty); } } else { $pps_reward = $config['pps']['reward']['default']; - $log->logInfo("PPS reward fixed default, amount: " . $pps_reward . "\tdifficulty: " . $dDifficulty); } } // Per-share value to be paid out to users -$pps_value = round($pps_reward / (pow(2,32) * $dDifficulty) * pow(2, $config['pps_target']), 12); +$pps_value = round($pps_reward / (pow(2, $config['target_bits']) * $dDifficulty), 12); + // Find our last share accounted and last inserted share for PPS calculations $iPreviousShareId = $setting->getValue('pps_last_share_id'); @@ -75,11 +73,16 @@ $iLastShareId = $share->getLastInsertedShareId(); // Check for all new shares, we start one higher as our last accounted share to avoid duplicates $aAccountShares = $share->getSharesForAccounts($iPreviousShareId + 1, $iLastShareId); -$log->logInfo("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee"); +if (!empty($aAccountShares)) { + // Info for this payout + $log->logInfo("PPS reward type: " . $config['pps']['reward']['type'] . ", amount: " . $pps_reward . "\tdifficulty: " . $dDifficulty . "\tPPS value: " . $pps_value); + $log->logInfo("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee"); +} foreach ($aAccountShares as $aData) { - // Take our valid shares and multiply by per share value - $aData['payout'] = round($aData['valid'] * $pps_value, 8); + // MPOS uses a base difficulty setting to avoid showing weightened shares + // Since we need weightened shares here, we go back to the proper value for payouts + $aData['payout'] = round($aData['valid'] * pow(2, ($config['difficulty'] - 16)) * $pps_value, 8); // Defaults $aData['fee' ] = 0; @@ -94,7 +97,7 @@ foreach ($aAccountShares as $aData) { $log->logInfo($aData['id'] . "\t" . $aData['username'] . "\t" . $aData['invalid'] . "\t" . - $aData['valid'] . "\t*\t" . + $aData['valid'] * pow(2, ($config['difficulty'] - 16)) . "\t*\t" . number_format($pps_value, 12) . "\t=\t" . number_format($aData['payout'], 8) . "\t" . number_format($aData['donation'], 8) . "\t" . diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 8950f103..b393387e 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -1,5 +1,11 @@ config['difficulty'] - 16)); $stmt = $this->mysqli->prepare(" SELECT MIN(b.share_id) AS share_id FROM ( - SELECT share_id, @total := @total + (IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) / POW(2, (" . $this->config['difficulty'] . " - 16))) AS total + SELECT share_id, @total := @total + IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS total FROM $this->tableArchive, (SELECT @total := 0) AS a WHERE our_result = 'Y' AND @total < ? @@ -377,6 +379,7 @@ class Share Extends Base { "); if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $iCount, $iCount) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_object()->share_id; + $this->setErrorMessage("Failed fetching additional shares from archive: " . $this->mysqli->error); return false; } } diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php index 38f5360a..650fa288 100644 --- a/public/include/classes/statistics.class.php +++ b/public/include/classes/statistics.class.php @@ -65,7 +65,7 @@ class Statistics { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND((difficulty * 65535) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares + ROUND((difficulty * POW(2, 32 - " . $this->config['target_bits'] . ")) / 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 @@ -90,7 +90,7 @@ class Statistics { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND((difficulty * 65535) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares + ROUND((difficulty * POW(2, 32 - " . $this->config['target_bits'] . ")) / 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 @@ -170,11 +170,11 @@ class Statistics { SELECT ( ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * 65536 / ? / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0) AS hashrate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * 65536 / ? / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0) AS hashrate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) ) @@ -370,14 +370,14 @@ class Statistics { $stmt = $this->mysqli->prepare(" SELECT ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * 65536 / ? / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0) AS hashrate FROM " . $this->share->getTableName() . " AS s, " . $this->user->getTableName() . " AS u WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 ) AND s.time > DATE_SUB(now(), INTERVAL ? SECOND) AND u.id = ? ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * 65536 / ? / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0) AS hashrate FROM " . $this->share->getArchiveTableName() . " AS s, " . $this->user->getTableName() . " AS u WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 ) @@ -392,7 +392,29 @@ class Statistics { return false; } + public function getUserUnpaidPPSShares($account_id, $last_paid_pps_id) { + $this->debug->append("STA " . __METHOD__, 4); + if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; + $stmt = $this->mysqli->prepare(" + SELECT + ROUND(IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS total + FROM " . $this->share->getTableName() . " AS s + JOIN " . $this->user->getTableName() . " AS a + ON a.username = SUBSTRING_INDEX( s.username, '.', 1 ) + AND a.id = ? + AND s.id > ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $last_paid_pps_id) && $stmt->execute() && $result = $stmt->get_result() ) + return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_object()->total); + $this->debug->append("Failed fetching average share dificulty: " . $this->mysqli->error, 3); + return 0; + } + /** + * Get average share difficulty across all workers for user + * @param account_id int Account ID + * @param interval int Data interval in seconds + * @return double Share difficulty or 0 + **/ public function getUserShareDifficulty($account_id, $interval=600) { $this->debug->append("STA " . __METHOD__, 4); if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; @@ -454,7 +476,7 @@ class Statistics { $this->debug->append("STA " . __METHOD__, 4); if ($data = $this->memcache->get(__FUNCTION__ . $worker_id)) return $data; $stmt = $this->mysqli->prepare(" - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * 65536 / 600 / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 600 / 1000), 0) AS hashrate FROM " . $this->share->getTableName() . " AS s, " . $this->user->getTableName() . " AS u WHERE u.username = SUBSTRING_INDEX( s.username, '.', 1 ) @@ -524,7 +546,7 @@ class Statistics { a.username AS account, a.donate_percent AS donate_percent, a.is_anonymous AS is_anonymous, - IFNULL(ROUND(SUM(t1.difficulty) * 65536 / 600 / 1000, 2), 0) AS hashrate + IFNULL(ROUND(SUM(t1.difficulty) * POW(2, " . $this->config['target_bits'] . ") / 600 / 1000, 2), 0) AS hashrate FROM ( SELECT IFNULL(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0) AS difficulty, username FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) AND our_result = 'Y' @@ -553,7 +575,7 @@ class Statistics { if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * 65536/3600/1000), 0) AS hashrate, + IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, HOUR(s.time) AS hour FROM " . $this->share->getTableName() . " AS s, accounts AS a WHERE time < NOW() - INTERVAL 1 HOUR @@ -563,7 +585,7 @@ class Statistics { GROUP BY HOUR(time) UNION ALL SELECT - IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * 65536/3600/1000), 0) AS hashrate, + IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, HOUR(s.time) AS hour FROM " . $this->share->getArchiveTableName() . " AS s, accounts AS a WHERE time < NOW() - INTERVAL 1 HOUR @@ -594,7 +616,7 @@ class Statistics { if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data; $stmt = $this->mysqli->prepare(" SELECT - IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * 65536/3600/1000), 0) AS hashrate, + IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, HOUR(s.time) AS hour FROM " . $this->share->getTableName() . " AS s WHERE time < NOW() - INTERVAL 1 HOUR @@ -602,7 +624,7 @@ class Statistics { GROUP BY HOUR(time) UNION ALL SELECT - IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * 65536/3600/1000), 0) AS hashrate, + IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, HOUR(s.time) AS hour FROM " . $this->share->getArchiveTableName() . " AS s WHERE time < NOW() - INTERVAL 1 HOUR @@ -645,18 +667,16 @@ class Statistics { } } else { // Hack so we can use this method for PPS estimates too + // value1 = shares/s + // value2 = avg share difficulty if (@$value1 > 0 && @$value2 > 0) { - // Default: No fees applied so multiply by 1 - $fee = 1; - if ($this->config['fees'] > 0) - $bNoFees == 0 ? $fee = round(((float)$this->config['fees'] / 100), 8) : $fee = 1; + $hour = 60 * 60; $pps = $value1 * $value2 * $ppsvalue; - $hour = 3600; - $aEstimates['hours1'] = $pps * $hour * $fee; + $aEstimates['hours1'] = $pps * $hour; $aEstimates['hours24'] = $pps * 24 * $hour; $aEstimates['days7'] = $pps * 24 * 7 * $hour; - $aEstimates['days14'] = $pps * 14 * 24 * 7 * $hour; - $aEstimates['days30'] = $pps * 30 * 24 * 7 * $hour; + $aEstimates['days14'] = $pps * 14 * 24 * $hour; + $aEstimates['days30'] = $pps * 30 * 24 * $hour; } else { $aEstimates['hours1'] = 0; $aEstimates['hours24'] = 0; diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index b9cfda0d..1609b8b8 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -20,6 +20,17 @@ define('DEBUG', 0); // SALT used to hash passwords define('SALT', 'PLEASEMAKEMESOMETHINGRANDOM'); +/** + * Underlying coin algorithm that you are mining on. Set this to whatever your coin needs: + * + * Options: + * sha256d : SHA coins like Bitcoin + * scrypt : Scrypt based coins like Litecoin + * Default: + * scrypt : Scrypt is default + **/ +$config['algorithm'] = 'scrypt'; + /** * Database configuration * @@ -308,10 +319,6 @@ $config['pps']['reward']['default'] = 50; $config['pps']['reward']['type'] = 'blockavg'; $config['pps']['blockavg']['blockcount'] = 10; -// pps base payout target, default 16 = difficulty 1 shares for vardiff -// (1/(65536 * difficulty) * reward) = (reward / (pow(2,32) * difficulty) * pow(2, 16)) -$config['pps_target'] = 16; // do not change unless you know what it does - /** * Memcache configuration * diff --git a/public/include/pages/api/getdashboarddata.inc.php b/public/include/pages/api/getdashboarddata.inc.php index 4d15763d..f4e48fbd 100644 --- a/public/include/pages/api/getdashboarddata.inc.php +++ b/public/include/pages/api/getdashboarddata.inc.php @@ -41,7 +41,9 @@ $aRoundShares = $statistics->getRoundShares(); if ($config['payout_system'] != 'pps') { $aEstimates = $statistics->getUserEstimates($aRoundShares, $aUserRoundShares, $user->getUserDonatePercent($user_id), $user->getUserNoFee($user_id)); + $dUnpaidShares = 0; } else { + $dUnpaidShares = $statistics->getUserUnpaidPPSShares($user_id, $setting->getValue('pps_last_share_id')); if ($config['pps']['reward']['type'] == 'blockavg' && $block->getBlockCount() > 0) { $pps_reward = round($block->getAvgBlockReward($config['pps']['blockavg']['blockcount'])); } else { @@ -56,7 +58,7 @@ if ($config['payout_system'] != 'pps') { } } - $ppsvalue = round($pps_reward / (pow(2,32) * $dDifficulty) * pow(2, $config['pps_target']), 12); + $ppsvalue = round($pps_reward / (pow(2,32) * $dDifficulty) * pow(2, $config['target_bits']), 12); $aEstimates = $statistics->getUserEstimates($dPersonalSharerate, $dPersonalShareDifficulty, $user->getUserDonatePercent($user_id), $user->getUserNoFee($user_id), $ppsvalue); } @@ -89,7 +91,7 @@ $data = array( 'raw' => array( 'personal' => array( 'hashrate' => $dPersonalHashrate ), 'pool' => array( 'hashrate' => $dPoolHashrate ), 'network' => array( 'hashrate' => $dNetworkHashrate / 1000 ) ), 'personal' => array ( 'hashrate' => $dPersonalHashrateAdjusted, 'sharerate' => $dPersonalSharerate, 'sharedifficulty' => $dPersonalShareDifficulty, - 'shares' => array('valid' => $aUserRoundShares['valid'], 'invalid' => $aUserRoundShares['invalid'], 'invalid_percent' => $dUserInvalidPercent), + 'shares' => array('valid' => $aUserRoundShares['valid'], 'invalid' => $aUserRoundShares['invalid'], 'invalid_percent' => $dUserInvalidPercent, 'unpaid' => $dUnpaidShares ), 'balance' => $transaction->getBalance($user_id), 'estimates' => $aEstimates, 'workers' => $aWorkers ), 'pool' => array( 'workers' => $worker->getCountAllActiveWorkers(), 'hashrate' => $dPoolHashrateAdjusted, diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php index 9bb4ac60..5f2c691e 100644 --- a/public/include/smarty_globals.inc.php +++ b/public/include/smarty_globals.inc.php @@ -140,7 +140,9 @@ if (@$_SESSION['USERDATA']['id']) { } } - $aGlobal['ppsvalue'] = number_format(round($pps_reward / (pow(2,32) * $dDifficulty) * pow(2, $config['pps_target']), 12) ,12); + $aGlobal['userdata']['pps']['unpaidshares'] = $statistics->getUserUnpaidPPSShares($_SESSION['USERDATA']['id'], $setting->getValue('pps_last_share_id')); + $aGlobal['ppsvalue'] = number_format(round($pps_reward / (pow(2, $config['target_bits']) * $dDifficulty), 12) ,12); + $aGlobal['poolppsvalue'] = $aGlobal['ppsvalue'] * pow(2, $config['difficulty'] - 16); $aGlobal['userdata']['sharedifficulty'] = $statistics->getUserShareDifficulty($_SESSION['USERDATA']['id']); $aGlobal['userdata']['estimates'] = $statistics->getUserEstimates($aGlobal['userdata']['sharerate'], $aGlobal['userdata']['sharedifficulty'], $aGlobal['userdata']['donate_percent'], $aGlobal['userdata']['no_fees'], $aGlobal['ppsvalue']); break; diff --git a/public/templates/mpos/dashboard/js.tpl b/public/templates/mpos/dashboard/js.tpl index 8c4822c2..1bf84344 100644 --- a/public/templates/mpos/dashboard/js.tpl +++ b/public/templates/mpos/dashboard/js.tpl @@ -157,6 +157,7 @@ $(document).ready(function(){ $('#b-fee').html((parseFloat(data.getdashboarddata.data.personal.estimates.fee).toFixed(4))); $('#b-donation').html((parseFloat(data.getdashboarddata.data.personal.estimates.donation).toFixed(4))); {/literal}{else}{literal} + $('#b-ppsunpaid').html((parseFloat(data.getdashboarddata.data.personal.shares.unpaid).toFixed(0))); $('#b-ppsdiff').html((parseFloat(data.getdashboarddata.data.personal.sharedifficulty).toFixed(2))); $('#b-est1').html((parseFloat(data.getdashboarddata.data.personal.estimates.hours1).toFixed(8))); $('#b-est24hours').html((parseFloat(data.getdashboarddata.data.personal.estimates.hours24).toFixed(8))); diff --git a/public/templates/mpos/dashboard/system_stats.tpl b/public/templates/mpos/dashboard/system_stats.tpl index 04a97692..46b12f12 100644 --- a/public/templates/mpos/dashboard/system_stats.tpl +++ b/public/templates/mpos/dashboard/system_stats.tpl @@ -10,8 +10,16 @@ {elseif $GLOBAL.config.payout_system == 'pps'} - PPS Value - {$GLOBAL.ppsvalue} + Unpaid Shares + {$GLOBAL.userdata.pps.unpaidshares} + + + Baseline PPS Rate + {$GLOBAL.ppsvalue} {$GLOBAL.config.currency} + + + Pools PPS Rate + {$GLOBAL.poolppsvalue} {$GLOBAL.config.currency} PPS Difficulty diff --git a/public/templates/mpos/statistics/blocks/default.tpl b/public/templates/mpos/statistics/blocks/default.tpl index e3a770a1..c2587a12 100644 --- a/public/templates/mpos/statistics/blocks/default.tpl +++ b/public/templates/mpos/statistics/blocks/default.tpl @@ -103,14 +103,13 @@ {$BLOCKSFOUND[block].difficulty|number_format:"2"} {$BLOCKSFOUND[block].amount|number_format:"2"} -{math assign="estshares" equation="(pow(2,32 - targetdiff) * blockdiff)" targetdiff=$GLOBAL.config.targetdiff blockdiff=$BLOCKSFOUND[block].difficulty} -{assign var="totalexpectedshares" value=$totalexpectedshares+$estshares} - {$estshares|number_format} +{assign var="totalexpectedshares" value=$totalexpectedshares+$BLOCKSFOUND[block].estshares} + {$BLOCKSFOUND[block].estshares|number_format} {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=$estshares} +{math assign="percentage" equation="shares / estshares * 100" shares=$BLOCKSFOUND[block].shares estshares=$BLOCKSFOUND[block].estshares} {assign var="totalpercentage" value=$totalpercentage+$percentage} {$percentage|number_format:"2"}