diff --git a/POOLS.md b/POOLS.md index 42ffd0b4..723c3e53 100644 --- a/POOLS.md +++ b/POOLS.md @@ -111,3 +111,9 @@ Small Time Miners are running various stratum only pools for different coins. | http://ftc.nut2pools.com | Feathercoin | 45-50Mhs | 25 workers | New style, PPLNS | | http://wdc.nut2pools.com | Worldcoin | 3.5 Mhs | 3 workers | New style, PPLNS | | http://pxc.nut2pools.com | Phenixcoin | 0 | 0 | New style | PPLNS | + +### Dids + +| Pool URL | Coin | Avg. Hashrate | Avg. Active Workers | Notes | +| -------- | ---- | ------------: | ------------------: | ----- | +| http://poolmine.it | Litecoin | 0.23 MHash | 5 | PPLNS, Custom Template | diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index 35ce807e..d86245fb 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -41,6 +41,7 @@ require_once(CLASS_DIR . '/invitation.class.php'); require_once(CLASS_DIR . '/share.class.php'); require_once(CLASS_DIR . '/worker.class.php'); require_once(CLASS_DIR . '/statistics.class.php'); +require_once(CLASS_DIR . '/roundstats.class.php'); require_once(CLASS_DIR . '/transaction.class.php'); require_once(CLASS_DIR . '/notification.class.php'); require_once(CLASS_DIR . '/news.class.php'); diff --git a/public/include/classes/block.class.php b/public/include/classes/block.class.php index fb5e8dc4..3f88887d 100644 --- a/public/include/classes/block.class.php +++ b/public/include/classes/block.class.php @@ -133,9 +133,8 @@ class Block { * @param confirmations int Required confirmations to consider block confirmed * @return data array Array with database fields as keys **/ - public function getAllUnconfirmed() { + public function getAllUnconfirmed($confirmations=120) { $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE confirmations < ? AND confirmations > -1"); - empty($this->config['network_confirmations']) ? $confirmations = 120 : $confirmations = $this->config['network_confirmations']; if ($this->checkStmt($stmt) && $stmt->bind_param("i", $confirmations) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return false; diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php index 08f3d3f5..ac61d105 100644 --- a/public/include/classes/notification.class.php +++ b/public/include/classes/notification.class.php @@ -164,9 +164,13 @@ class Notification extends Mail { if ($stmt && $stmt->bind_param('si', $strType, $account_id) && $stmt->execute() && $stmt->bind_result($id) && $stmt->fetch()) { if ($stmt->close() && $this->sendMail('notifications/' . $strType, $aMailData) && $this->addNotification($account_id, $strType, $aMailData)) { return true; + } else { + $this->setErrorMessage('SendMail call failed: ' . $this->mail->getError()); + return false; } } else { $this->setErrorMessage('User disabled ' . $strType . ' notifications'); + return false; } $this->setErrorMessage('Error sending mail notification'); return false; @@ -178,5 +182,5 @@ $notification->setDebug($debug); $notification->setMysql($mysqli); $notification->setSmarty($smarty); $notification->setConfig($config); - +$notification->setSetting($setting); ?> diff --git a/public/include/classes/roundstats.class.php b/public/include/classes/roundstats.class.php new file mode 100644 index 00000000..d93cca43 --- /dev/null +++ b/public/include/classes/roundstats.class.php @@ -0,0 +1,160 @@ +debug = $debug; + $this->mysqli = $mysqli; + $this->config = $config; + $this->debug->append("Instantiated RoundStats class", 2); + } + + // get and set methods + private function setErrorMessage($msg) { + $this->sError = $msg; + } + public function getError() { + return $this->sError; + } + + /** + * Get next block for round stats + **/ + public function getNextBlock($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 prev block for round stats + **/ + public function getPreviousBlock($iHeight=0) { + $stmt = $this->mysqli->prepare(" + SELECT height + FROM $this->tableBlocks + WHERE height < ? + ORDER BY height DESC + 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 details for block height + * @param height int Block Height + * @return data array Block information from DB + **/ + public function getDetailsForBlockHeight($iHeight=0, $isAdmin=0) { + $stmt = $this->mysqli->prepare(" + SELECT + b.id, height, amount, confirmations, difficulty, FROM_UNIXTIME(time) as time, shares, + IF(a.is_anonymous, IF( ? , a.username, 'anonymous'), a.username) AS finder + 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()) + return $result->fetch_assoc(); + return false; + } + + /** + * Get shares statistics for round block height + * @param height int Block Height + * @return data array Block information from DB + **/ + public function getRoundStatsForAccounts($iHeight=0, $isAdmin=0) { + $stmt = $this->mysqli->prepare(" + SELECT + IF(a.is_anonymous, IF( ? , a.username, 'anonymous'), a.username) AS username, + s.valid, + s.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 valid DESC + "); + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $isAdmin, $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + 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) { + $this->debug->append("STA " . __METHOD__, 4); + $stmt = $this->mysqli->prepare(" + SELECT + t.id AS id, + a.username AS username, + 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('i', $iHeight) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + $this->debug->append('Unable to fetch transactions'); + return false; + } + + /** + * Get transactions for round block height user id + * @param height int Block Height + * @param id int user id + * @return data array Block round transactions for user id + **/ + public function getUserRoundTransactions($iHeight=0, $id=0) { + $this->debug->append("STA " . __METHOD__, 4); + $stmt = $this->mysqli->prepare(" + SELECT + t.id AS id, + a.username AS username, + 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 = ? AND a.id = ? + ORDER BY id ASC"); + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $iHeight, $id) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_all(MYSQLI_ASSOC); + $this->debug->append('Unable to fetch transactions'); + return false; + } + + private function checkStmt($bState) { + if ($bState ===! true) { + $this->debug->append("Failed to prepare statement: " . $this->mysqli->error); + $this->setErrorMessage('Internal application Error'); + return false; + } + return true; + } + +} + +$roundstats = new RoundStats($debug, $mysqli, $config); diff --git a/public/include/config/admin_settings.inc.php b/public/include/config/admin_settings.inc.php index f3b68cd8..3342ef49 100644 --- a/public/include/config/admin_settings.inc.php +++ b/public/include/config/admin_settings.inc.php @@ -108,12 +108,19 @@ $aSettings['acl'][] = array( 'tooltip' => 'Make the pool statistics page private (users only) or public.' ); $aSettings['acl'][] = array( - 'display' => 'Blcok Statistics', 'type' => 'select', + 'display' => 'Block Statistics', 'type' => 'select', 'options' => array( 0 => 'Private', 1 => 'Public'), 'default' => 1, 'name' => 'acl_block_statistics', 'value' => $setting->getValue('acl_block_statistics'), 'tooltip' => 'Make the block statistics page private (users only) or public.' ); +$aSettings['acl'][] = array( + 'display' => 'Round Statistics', 'type' => 'select', + 'options' => array( 0 => 'Private', 1 => 'Public'), + 'default' => 1, + 'name' => 'acl_round_statistics', 'value' => $setting->getValue('acl_round_statistics'), + 'tooltip' => 'Make the round statistics page private (users only) or public.' +); $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 82ea1b5a..39335c08 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -11,6 +11,9 @@ define('CLASS_DIR', INCLUDE_DIR . '/classes'); // Our pages directory which takes care of define('PAGES_DIR', INCLUDE_DIR . '/pages'); +// Our theme folder holding all themes +define('THEME_DIR', BASEPATH . 'templates'); + // Set debugging level for our debug class define('DEBUG', 0); diff --git a/public/include/pages/statistics/round.inc.php b/public/include/pages/statistics/round.inc.php new file mode 100644 index 00000000..b6e40a3a --- /dev/null +++ b/public/include/pages/statistics/round.inc.php @@ -0,0 +1,45 @@ +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']; + } + } + echo $iKey; + $aDetailsForBlockHeight = $roundstats->getDetailsForBlockHeight($iKey, $user->isAdmin($_SESSION['USERDATA']['id'])); + $aRoundShareStats = $roundstats->getRoundStatsForAccounts($iKey, $user->isAdmin($_SESSION['USERDATA']['id'])); + + if ($user->isAdmin($_SESSION['USERDATA']['id'])) { + $aUserRoundTransactions = $roundstats->getAllRoundTransactions($iKey); + } else { + $aUserRoundTransactions = $roundstats->getUserRoundTransactions($iKey, $_SESSION['USERDATA']['id']); + } + + // Propagate content our template + $smarty->assign('BLOCKDETAILS', $aDetailsForBlockHeight); + $smarty->assign('ROUNDSHARES', $aRoundShareStats); + $smarty->assign("ROUNDTRANSACTIONS", $aUserRoundTransactions); +} else { + $debug->append('Using cached page', 3); +} + +if ($setting->getValue('acl_round_statistics')) { + $smarty->assign("CONTENT", "default.tpl"); +} else if ($user->isAuthenticated()) { + $smarty->assign("CONTENT", "default.tpl"); +} +?> diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php index 01cc6e5b..f19ff9c7 100644 --- a/public/include/smarty_globals.inc.php +++ b/public/include/smarty_globals.inc.php @@ -74,6 +74,7 @@ $setting->getValue('website_chaininfo_url') ? $aGlobal['website']['chaininfo'][' // ACLs $aGlobal['acl']['pool']['statistics'] = $setting->getValue('acl_pool_statistics'); $aGlobal['acl']['block']['statistics'] = $setting->getValue('acl_block_statistics'); +$aGlobal['acl']['round']['statistics'] = $setting->getValue('acl_round_statistics'); // We support some dynamic reward targets but fall back to our fixed value // Special calculations for PPS Values based on reward_type setting and/or available blocks diff --git a/public/templates/mmcFE/global/navigation.tpl b/public/templates/mmcFE/global/navigation.tpl index 407f24b0..c7f762e9 100644 --- a/public/templates/mmcFE/global/navigation.tpl +++ b/public/templates/mmcFE/global/navigation.tpl @@ -30,6 +30,7 @@
  • Pool Stats
  • Block Stats
  • Hashrate Graphs
  • +
  • Round Stats
  • {else} @@ -40,6 +41,9 @@ {/if} {if $GLOBAL.acl.block.statistics}
  • Block Stats
  • + {/if} + {if $GLOBAL.acl.round.statistics} +
  • Round Stats
  • {/if} {/if} diff --git a/public/templates/mmcFE/statistics/blocks/default.tpl b/public/templates/mmcFE/statistics/blocks/default.tpl index 7ebb4e47..83de463e 100644 --- a/public/templates/mmcFE/statistics/blocks/default.tpl +++ b/public/templates/mmcFE/statistics/blocks/default.tpl @@ -55,11 +55,7 @@ target and network difficulty and assuming a zero variance scenario. {assign var="totalshares" value=$totalshares+$BLOCKSFOUND[block].shares} {assign var="count" value=$count+1} - {if ! $GLOBAL.website.blockexplorer.disabled} - {$BLOCKSFOUND[block].height} - {else} - {$BLOCKSFOUND[block].height} - {/if} + {$BLOCKSFOUND[block].height} {if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations} Confirmed diff --git a/public/templates/mmcFE/statistics/blocks/small_table.tpl b/public/templates/mmcFE/statistics/blocks/small_table.tpl index e826fd3a..0c1760ff 100644 --- a/public/templates/mmcFE/statistics/blocks/small_table.tpl +++ b/public/templates/mmcFE/statistics/blocks/small_table.tpl @@ -13,11 +13,7 @@ {assign var=rank value=1} {section block $BLOCKSFOUND} - {if ! $GLOBAL.website.blockexplorer.disabled} - {$BLOCKSFOUND[block].height} - {else} - {$BLOCKSFOUND[block].height} - {/if} + {$BLOCKSFOUND[block].height} {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].shares|number_format} diff --git a/public/templates/mmcFE/statistics/round/block_stats.tpl b/public/templates/mmcFE/statistics/round/block_stats.tpl new file mode 100644 index 00000000..75b33950 --- /dev/null +++ b/public/templates/mmcFE/statistics/round/block_stats.tpl @@ -0,0 +1,65 @@ +{include file="global/block_header.tpl" ALIGN="left" BLOCK_STYLE="width: 100%" BLOCK_HEADER="Block Stats" STYLE="padding-left:5px;padding-right:5px;"} + + + + + + +
    + + + + + + + + + + + + + + + {if ! $GLOBAL.website.blockexplorer.disabled} + + {else} + + {/if} + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameValue
    ID{$BLOCKDETAILS.id|default:"0"}
    Height{$BLOCKDETAILS.height}{$BLOCKDETAILS.height}
    Amount{$BLOCKDETAILS.amount|default:"0"}
    Confirmations{$BLOCKDETAILS.confirmations|default:"0"}
    Difficulty{$BLOCKDETAILS.difficulty|default:"0"}
    Time{$BLOCKDETAILS.time|default:"0"}
    Shares{$BLOCKDETAILS.shares|default:"0"}
    Finder{$BLOCKDETAILS.finder|default:"0"}
    +
    + + + + +
    + + + +
    +{include file="global/block_footer.tpl"} diff --git a/public/templates/mmcFE/statistics/round/default.tpl b/public/templates/mmcFE/statistics/round/default.tpl new file mode 100644 index 00000000..7098eb06 --- /dev/null +++ b/public/templates/mmcFE/statistics/round/default.tpl @@ -0,0 +1,9 @@ +{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"} + +{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 new file mode 100644 index 00000000..919aed8e --- /dev/null +++ b/public/templates/mmcFE/statistics/round/round_shares.tpl @@ -0,0 +1,28 @@ +{include file="global/block_header.tpl" ALIGN="left" BLOCK_HEADER="Round Shares" } +
    + + + + + + + + + + + +{assign var=rank value=1} +{assign var=listed value=0} +{section contrib $ROUNDSHARES} + + + + + + + +{/section} + +
    RankUser NameValidInvalidInvalid %
    {$rank++}{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"}
    +
    +{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 new file mode 100644 index 00000000..ecb4ea75 --- /dev/null +++ b/public/templates/mmcFE/statistics/round/round_transactions.tpl @@ -0,0 +1,24 @@ +{include file="global/block_header.tpl" ALIGN="right" BLOCK_HEADER="Round Transactions"} +
    + + + + + + + + + + +{section txs $ROUNDTRANSACTIONS} + + + + + + +{/section} + +
    Tx IdUser NameTypeAmount
    {$ROUNDTRANSACTIONS[txs].id|default:"0"}{$ROUNDTRANSACTIONS[txs].username|escape}{$ROUNDTRANSACTIONS[txs].type|default:""}{$ROUNDTRANSACTIONS[txs].amount|default:"0"|number_format:"8"}
    +
    +{include file="global/block_footer.tpl"}