First working version of PPLNS payouts
* Based PPLNS on Prop Payout script * Using defaults from prop payout, no class adjustments * Added more methods required for PPLNS * Added block methods for dynamic payout calculations * Added PPLNS Sidebar that also displays the PPLNS Target * Shares beyond this target will not be included in payouts * Shares missing to this target will be added from archives * Enabled archiving by default for PPLNS * Added configuration options for PPLNS * Documented the usage for PPLNS, defaults are sane * Added pplns_payout to run-crons Addresses #143 and if accepted will fix it
This commit is contained in:
parent
dc51d874a7
commit
2f2acdad6d
@ -68,11 +68,11 @@ Features
|
|||||||
|
|
||||||
The following feature have been implemented so far:
|
The following feature have been implemented so far:
|
||||||
|
|
||||||
* Mobile WebUI **NEW**
|
* Mobile WebUI
|
||||||
* Reward Systems
|
* Reward Systems
|
||||||
* Propotional
|
* Propotional
|
||||||
* PPS
|
* PPS
|
||||||
* (Planned) PPLNS
|
* PPLNS **NEW**
|
||||||
* Use of memcache for statistics instead of a cronjob
|
* Use of memcache for statistics instead of a cronjob
|
||||||
* Web User accounts
|
* Web User accounts
|
||||||
* Re-Captcha protected registration form
|
* Re-Captcha protected registration form
|
||||||
|
|||||||
142
cronjobs/pplns_payout.php
Executable file
142
cronjobs/pplns_payout.php
Executable file
@ -0,0 +1,142 @@
|
|||||||
|
#!/usr/bin/php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright:: 2013, Sebastian Grewe
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Include all settings and classes
|
||||||
|
require_once('shared.inc.php');
|
||||||
|
|
||||||
|
// Check if we are set as the payout system
|
||||||
|
if ($config['payout_system'] != 'pplns') {
|
||||||
|
verbose("Please activate this cron in configuration via payout_system = pplns\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch all unaccounted blocks
|
||||||
|
$aAllBlocks = $block->getAllUnaccounted('ASC');
|
||||||
|
if (empty($aAllBlocks)) {
|
||||||
|
verbose("No new unaccounted blocks found\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We support some dynamic share targets but fall back to our fixed value
|
||||||
|
if ($config['pplns']['shares']['type'] == 'blockavg' && $block->getBlockCount() > 0) {
|
||||||
|
$pplns_target = round($block->getAvgBlockShares($config['pplns']['type']['blockavg']['blockcount']));
|
||||||
|
} else {
|
||||||
|
$pplns_target = $config['pplns']['shares']['default'] ;
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
foreach ($aAllBlocks as $iIndex => $aBlock) {
|
||||||
|
if (!$aBlock['accounted']) {
|
||||||
|
$iPreviousShareId = @$aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
|
||||||
|
$iCurrentUpstreamId = $aBlock['share_id'];
|
||||||
|
$iRoundShares = $share->getRoundShares($iPreviousShareId, $aBlock['share_id']);
|
||||||
|
$config['reward_type'] == 'block' ? $dReward = $aBlock['amount'] : $dReward = $config['reward'];
|
||||||
|
$aRoundAccountShares = $share->getSharesForAccounts($iPreviousShareId, $aBlock['share_id']);
|
||||||
|
|
||||||
|
if ($iRoundShares >= $pplns_target) {
|
||||||
|
verbose("Matching or exceeding PPLNS target of $pplns_target\n");
|
||||||
|
$aAccountShares = $share->getSharesForAccounts($aBlock['share_id'] - $pplns_target + 1, $aBlock['share_id']);
|
||||||
|
} else {
|
||||||
|
verbose("Not able to match PPLNS target of $pplns_target\n");
|
||||||
|
// We need to fill up with archived shares
|
||||||
|
// Grab the full current round shares since we didn't match target
|
||||||
|
$aAccountShares = $aRoundAccountShares;
|
||||||
|
// Grab only the most recent shares from Archive that fill the missing shares
|
||||||
|
$aArchiveShares = $share->getArchiveShares($share->getMaxArchiveShareId() - ($pplns_target- $iRoundShares) + 1, $share->getMaxArchiveShareId());
|
||||||
|
// Add archived shares to users current shares, if we have any in archive
|
||||||
|
if (is_array($aArchiveShares)) {
|
||||||
|
foreach($aAccountShares as $key => $aData) {
|
||||||
|
if (array_key_exists($aData['username'], $aArchiveShares)) {
|
||||||
|
$aAccountShares[$key]['valid'] += $aArchiveShares[$aData['username']]['valid'];
|
||||||
|
$aAccountShares[$key]['invalid'] += $aArchiveShares[$aData['username']]['invalid'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty($aAccountShares)) {
|
||||||
|
verbose("\nNo shares found for this block\n\n");
|
||||||
|
sleep(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table header for account shares
|
||||||
|
verbose("ID\tUsername\tValid\tInvalid\tPercentage\tPayout\t\tDonation\tFee\t\tStatus\n");
|
||||||
|
|
||||||
|
// Loop through all accounts that have found shares for this round
|
||||||
|
foreach ($aAccountShares as $key => $aData) {
|
||||||
|
// Payout based on PPLNS target shares, proportional payout for all users
|
||||||
|
$aData['percentage'] = number_format(round(( 100 / $pplns_target) * $aData['valid'], 8), 8);
|
||||||
|
$aData['payout'] = number_format(round(( $aData['percentage'] / 100 ) * $dReward, 8), 8);
|
||||||
|
// Defaults
|
||||||
|
$aData['fee' ] = 0;
|
||||||
|
$aData['donation'] = 0;
|
||||||
|
|
||||||
|
if ($config['fees'] > 0)
|
||||||
|
$aData['fee'] = number_format(round($config['fees'] / 100 * $aData['payout'], 8), 8);
|
||||||
|
// Calculate donation amount, fees not included
|
||||||
|
$aData['donation'] = number_format(round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8), 8);
|
||||||
|
|
||||||
|
// Verbose output of this users calculations
|
||||||
|
verbose($aData['id'] . "\t" .
|
||||||
|
$aData['username'] . "\t" .
|
||||||
|
$aData['valid'] . "\t" .
|
||||||
|
$aData['invalid'] . "\t" .
|
||||||
|
$aData['percentage'] . "\t" .
|
||||||
|
$aData['payout'] . "\t" .
|
||||||
|
$aData['donation'] . "\t" .
|
||||||
|
$aData['fee'] . "\t");
|
||||||
|
|
||||||
|
$strStatus = "OK";
|
||||||
|
// Add full round share statistics, not just PPLNS
|
||||||
|
foreach ($aRoundAccountShares as $key => $aRoundData) {
|
||||||
|
if ($aRoundData['username'] == $aData['username'])
|
||||||
|
if (!$statistics->updateShareStatistics($aRoundData, $aBlock['id']))
|
||||||
|
$strStatus = "Stats Failed";
|
||||||
|
}
|
||||||
|
// Add new credit transaction
|
||||||
|
if (!$transaction->addTransaction($aData['id'], $aData['payout'], 'Credit', $aBlock['id']))
|
||||||
|
$strStatus = "Transaction Failed";
|
||||||
|
// Add new fee debit for this block
|
||||||
|
if ($aData['fee'] > 0 && $config['fees'] > 0)
|
||||||
|
if (!$transaction->addTransaction($aData['id'], $aData['fee'], 'Fee', $aBlock['id']))
|
||||||
|
$strStatus = "Fee Failed";
|
||||||
|
// Add new donation debit
|
||||||
|
if ($aData['donation'] > 0)
|
||||||
|
if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation', $aBlock['id']))
|
||||||
|
$strStatus = "Donation Failed";
|
||||||
|
verbose("\t$strStatus\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move counted shares to archive before this blockhash upstream share
|
||||||
|
$share->moveArchive($iCurrentUpstreamId, $aBlock['id'], $iPreviousShareId);
|
||||||
|
// Delete all accounted shares
|
||||||
|
if (!$share->deleteAccountedShares($iCurrentUpstreamId, $iPreviousShareId)) {
|
||||||
|
verbose("\nERROR : Failed to delete accounted shares from $iPreviousShareId to $iCurrentUpstreamId, aborting!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
// Mark this block as accounted for
|
||||||
|
if (!$block->setAccounted($aBlock['id'])) {
|
||||||
|
verbose("\nERROR : Failed to mark block as accounted! Aborting!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
verbose("------------------------------------------------------------------------\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@ PIDFILE='/tmp/mmcfe-ng-cron.pid'
|
|||||||
CRONHOME='.'
|
CRONHOME='.'
|
||||||
|
|
||||||
# List of cruns to execute
|
# List of cruns to execute
|
||||||
CRONS="findblock.php proportional_payout.php pps_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php statistics.php"
|
CRONS="findblock.php proportional_payout.php pplns_payout.php pps_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php statistics.php"
|
||||||
|
|
||||||
# Additional arguments to pass to cronjobs
|
# Additional arguments to pass to cronjobs
|
||||||
CRONARGS="-v"
|
CRONARGS="-v"
|
||||||
|
|||||||
@ -79,6 +79,30 @@ class Block {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get total amount of blocks in our table
|
||||||
|
* @param noone
|
||||||
|
* @return data int Count of rows
|
||||||
|
**/
|
||||||
|
public function getBlockCount() {
|
||||||
|
$stmt = $this->mysqli->prepare("SELECT COUNT(id) AS blocks FROM $this->table");
|
||||||
|
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
|
||||||
|
return (int)$result->fetch_object()->blocks;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch our average share count for the past N blocks
|
||||||
|
* @param limit int Maximum blocks to check
|
||||||
|
* @return data float Float value of average shares
|
||||||
|
**/
|
||||||
|
public function getAvgBlockShares($limit=10) {
|
||||||
|
$stmt = $this->mysqli->prepare("SELECT AVG(shares) AS average FROM $this->table LIMIT ?");
|
||||||
|
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result())
|
||||||
|
return (float)$result->fetch_object()->average;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch all unconfirmed blocks from table
|
* Fetch all unconfirmed blocks from table
|
||||||
* @param confirmations int Required confirmations to consider block confirmed
|
* @param confirmations int Required confirmations to consider block confirmed
|
||||||
|
|||||||
@ -13,9 +13,10 @@ class Share {
|
|||||||
// This defines each share
|
// This defines each share
|
||||||
public $rem_host, $username, $our_result, $upstream_result, $reason, $solution, $time;
|
public $rem_host, $username, $our_result, $upstream_result, $reason, $solution, $time;
|
||||||
|
|
||||||
public function __construct($debug, $mysqli, $salt) {
|
public function __construct($debug, $mysqli, $user) {
|
||||||
$this->debug = $debug;
|
$this->debug = $debug;
|
||||||
$this->mysqli = $mysqli;
|
$this->mysqli = $mysqli;
|
||||||
|
$this->user = $user;
|
||||||
$this->debug->append("Instantiated Share class", 2);
|
$this->debug->append("Instantiated Share class", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,47 +87,67 @@ class Share {
|
|||||||
* Fetch all shares grouped by accounts to count share per account
|
* Fetch all shares grouped by accounts to count share per account
|
||||||
* @param previous_upstream int Previous found share accepted by upstream to limit results
|
* @param previous_upstream int Previous found share accepted by upstream to limit results
|
||||||
* @param current_upstream int Current upstream accepted share
|
* @param current_upstream int Current upstream accepted share
|
||||||
|
* @param limit int Limit to this amount of shares for PPLNS
|
||||||
* @return data array username, valid and invalid shares from account
|
* @return data array username, valid and invalid shares from account
|
||||||
**/
|
**/
|
||||||
public function getSharesForAccounts($previous_upstream=0, $current_upstream) {
|
public function getSharesForAccounts($previous_upstream=0, $current_upstream) {
|
||||||
$stmt = $this->mysqli->prepare("SELECT
|
$stmt = $this->mysqli->prepare("
|
||||||
a.id,
|
SELECT
|
||||||
validT.account AS username,
|
a.id,
|
||||||
sum(validT.valid) as valid,
|
SUBSTRING_INDEX( s.username , '.', 1 ) as username,
|
||||||
IFNULL(sum(invalidT.invalid),0) as invalid
|
SUM(IF(our_result='Y', 1, 0)) AS valid,
|
||||||
FROM
|
SUM(IF(our_result='N', 1, 0)) AS invalid
|
||||||
(
|
FROM $this->table AS s
|
||||||
SELECT DISTINCT
|
LEFT JOIN " . $this->user->getTableName() . " AS a
|
||||||
SUBSTRING_INDEX( `username` , '.', 1 ) as account,
|
ON a.username = SUBSTRING_INDEX( s.username , '.', 1 )
|
||||||
COUNT(id) AS valid
|
WHERE s.id BETWEEN ? AND ?
|
||||||
FROM $this->table
|
GROUP BY username DESC
|
||||||
WHERE id BETWEEN ? AND ?
|
");
|
||||||
AND our_result = 'Y'
|
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $previous_upstream, $current_upstream) && $stmt->execute() && $result = $stmt->get_result())
|
||||||
GROUP BY account
|
|
||||||
) validT
|
|
||||||
LEFT JOIN
|
|
||||||
(
|
|
||||||
SELECT DISTINCT
|
|
||||||
SUBSTRING_INDEX( `username` , '.', 1 ) as account,
|
|
||||||
COUNT(id) AS invalid
|
|
||||||
FROM $this->table
|
|
||||||
WHERE id BETWEEN ? AND ?
|
|
||||||
AND our_result = 'N'
|
|
||||||
GROUP BY account
|
|
||||||
) invalidT
|
|
||||||
ON validT.account = invalidT.account
|
|
||||||
INNER JOIN accounts a ON a.username = validT.account
|
|
||||||
GROUP BY a.username DESC");
|
|
||||||
if ($this->checkStmt($stmt)) {
|
|
||||||
$stmt->bind_param('iiii', $previous_upstream, $current_upstream, $previous_upstream, $current_upstream);
|
|
||||||
$stmt->execute();
|
|
||||||
$result = $stmt->get_result();
|
|
||||||
$stmt->close();
|
|
||||||
return $result->fetch_all(MYSQLI_ASSOC);
|
return $result->fetch_all(MYSQLI_ASSOC);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the highest available share ID from archive
|
||||||
|
**/
|
||||||
|
function getMaxArchiveShareId() {
|
||||||
|
$stmt = $this->mysqli->prepare("
|
||||||
|
SELECT MAX(share_id) AS share_id FROM $this->tableArchive
|
||||||
|
");
|
||||||
|
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
|
||||||
|
return $result->fetch_object()->share_id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need a certain amount of valid archived shares
|
||||||
|
* param left int Left/lowest share ID
|
||||||
|
* param right int Right/highest share ID
|
||||||
|
* return array data Returns an array with usernames as keys for easy access
|
||||||
|
**/
|
||||||
|
function getArchiveShares($left, $right) {
|
||||||
|
$stmt = $this->mysqli->prepare("
|
||||||
|
SELECT
|
||||||
|
a.id,
|
||||||
|
SUBSTRING_INDEX( s.username , '.', 1 ) as username,
|
||||||
|
SUM(IF(our_result='Y', 1, 0)) AS valid,
|
||||||
|
SUM(IF(our_result='N', 1, 0)) AS invalid
|
||||||
|
FROM $this->tableArchive AS s
|
||||||
|
LEFT JOIN " . $this->user->getTableName() . " AS a
|
||||||
|
ON a.username = SUBSTRING_INDEX( s.username , '.', 1 )
|
||||||
|
WHERE s.id BETWEEN ? AND ?
|
||||||
|
GROUP BY username DESC
|
||||||
|
");
|
||||||
|
if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $left, $right) && $stmt->execute() && $result = $stmt->get_result()) {
|
||||||
|
$aData = NULL;
|
||||||
|
while ($row = $result->fetch_assoc()) {
|
||||||
|
$aData[$row['username']] = $row;
|
||||||
|
}
|
||||||
|
if (is_array($aData)) return $aData;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Move accounted shares to archive table, this step is optional
|
* Move accounted shares to archive table, this step is optional
|
||||||
* @param previous_upstream int Previous found share accepted by upstream to limit results
|
* @param previous_upstream int Previous found share accepted by upstream to limit results
|
||||||
@ -135,10 +156,11 @@ class Share {
|
|||||||
* @return bool
|
* @return bool
|
||||||
**/
|
**/
|
||||||
public function moveArchive($current_upstream, $block_id, $previous_upstream=0) {
|
public function moveArchive($current_upstream, $block_id, $previous_upstream=0) {
|
||||||
$archive_stmt = $this->mysqli->prepare("INSERT INTO $this->tableArchive (share_id, username, our_result, upstream_result, block_id, time)
|
$archive_stmt = $this->mysqli->prepare("
|
||||||
SELECT id, username, our_result, upstream_result, ?, time
|
INSERT INTO $this->tableArchive (share_id, username, our_result, upstream_result, block_id, time)
|
||||||
FROM $this->table
|
SELECT id, username, our_result, upstream_result, ?, time
|
||||||
WHERE id BETWEEN ? AND ?");
|
FROM $this->table
|
||||||
|
WHERE id BETWEEN ? AND ?");
|
||||||
if ($this->checkStmt($archive_stmt) && $archive_stmt->bind_param('iii', $block_id, $previous_upstream, $current_upstream) && $archive_stmt->execute()) {
|
if ($this->checkStmt($archive_stmt) && $archive_stmt->bind_param('iii', $block_id, $previous_upstream, $current_upstream) && $archive_stmt->execute()) {
|
||||||
$archive_stmt->close();
|
$archive_stmt->close();
|
||||||
return true;
|
return true;
|
||||||
@ -267,4 +289,4 @@ class Share {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$share = new Share($debug, $mysqli, SALT);
|
$share = new Share($debug, $mysqli, $user);
|
||||||
|
|||||||
@ -183,6 +183,30 @@ $config['chaininfo'] = 'http://allchains.info';
|
|||||||
// Pool fees applied to users in percent, default: 0 (disabled)
|
// Pool fees applied to users in percent, default: 0 (disabled)
|
||||||
$config['fees'] = 0;
|
$config['fees'] = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PPLNS requires some settings to run properly. First we need to define
|
||||||
|
* a default shares count that is applied if we don't have a proper type set.
|
||||||
|
* Different dynamic types can be applied, or you can run a fixed scheme.
|
||||||
|
*
|
||||||
|
* Explanation
|
||||||
|
* default : Default target shares for PPLNS
|
||||||
|
* type : Payout type used in PPLNS
|
||||||
|
* blockcount : Amount of blocks to check for avg shares
|
||||||
|
*
|
||||||
|
* Available Options:
|
||||||
|
* default : amount of shares, integeger
|
||||||
|
* type : blockavg or fixed
|
||||||
|
* blockcount : amount of blocks, any integer
|
||||||
|
*
|
||||||
|
* Defaults:
|
||||||
|
* default = 4000000
|
||||||
|
* type = `blockavg`
|
||||||
|
* blockcount = 10
|
||||||
|
**/
|
||||||
|
$config['pplns']['shares']['default'] = 4000000;
|
||||||
|
$config['pplns']['shares']['type'] = 'blockavg';
|
||||||
|
$config['pplns']['blockavg']['blockcount'] = 10;
|
||||||
|
|
||||||
// Pool target difficulty as set in pushpoold configuration file
|
// Pool target difficulty as set in pushpoold configuration file
|
||||||
// Please also read this for stratum: https://github.com/TheSerapher/php-mmcfe-ng/wiki/FAQ
|
// Please also read this for stratum: https://github.com/TheSerapher/php-mmcfe-ng/wiki/FAQ
|
||||||
$config['difficulty'] = 20;
|
$config['difficulty'] = 20;
|
||||||
|
|||||||
@ -83,6 +83,13 @@ if (@$_SESSION['USERDATA']['id']) {
|
|||||||
$aGlobal['userdata']['sharerate'] = $statistics->getUserSharerate($_SESSION['USERDATA']['id']);
|
$aGlobal['userdata']['sharerate'] = $statistics->getUserSharerate($_SESSION['USERDATA']['id']);
|
||||||
|
|
||||||
switch ($config['payout_system']) {
|
switch ($config['payout_system']) {
|
||||||
|
case 'pplns':
|
||||||
|
if ($iAvgBlockShares = round($block->getAvgBlockShares($config['pplns']['type']['blockavg']['blockcount']))) {
|
||||||
|
$aGlobal['pplns']['target'] = $iAvgBlockShares;
|
||||||
|
} else {
|
||||||
|
$aGlobal['pplns']['target'] = $config['pplns']['shares']['default'];
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'pps':
|
case 'pps':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
74
public/templates/mmcFE/global/sidebar_pplns.tpl
Normal file
74
public/templates/mmcFE/global/sidebar_pplns.tpl
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<div class="block" style="clear:none; margin-top:15px; margin-left:13px;">
|
||||||
|
<div class="block_head">
|
||||||
|
<div class="bheadl"></div>
|
||||||
|
<div class="bheadr"></div>
|
||||||
|
<h1>Dashboard</h1>
|
||||||
|
</div>
|
||||||
|
<div class="block_content" style="padding-top:10px;">
|
||||||
|
<table class="sidebar" style="width: 196px">
|
||||||
|
<tr>
|
||||||
|
<td><b>PPLNS Target</b></td>
|
||||||
|
<td class="right">{$GLOBAL.pplns.target|number_format}</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2"> </td></tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>Your Stats</u></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Hashrate</b></td>
|
||||||
|
<td class="right">{$GLOBAL.userdata.hashrate|number_format} KH/s</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>Unpaid Shares</u></b> <span id='tt'><img src='{$PATH}/images/questionmark.png' height='15px' width='15px' title='Submitted shares between the last 120 confirms block until now.'></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Your Valid<b></td>
|
||||||
|
<td class="right"><i>{$GLOBAL.userdata.shares.valid|number_format}</i><font size='1px'></font></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Pool Valid</td>
|
||||||
|
<td class="right"><i>{$GLOBAL.roundshares.valid|number_format}</i> <font size='1px'></font></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>Round Shares</u></b> <span id='tt'><img src='{$PATH}/images/questionmark.png' height='15px' width='15px' title='Submitted shares since last found block (ie. round shares)'></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Pool Valid</b></td>
|
||||||
|
<td class="right"><i>{$GLOBAL.roundshares.valid|number_format}</i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Pool Invalid</b></td>
|
||||||
|
<td class="right"><i>{$GLOBAL.roundshares.invalid|number_format}</i>{if $GLOBAL.roundshares.valid > 0}<font size='1px'> ({(100 / $GLOBAL.roundshares.valid * $GLOBAL.roundshares.invalid)|number_format:"2"}%)</font>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Your Invalid</b></td>
|
||||||
|
<td class="right"><i>{$GLOBAL.userdata.shares.invalid|number_format}</i>{if $GLOBAL.roundshares.valid > 0}<font size='1px'> ({(100 / $GLOBAL.roundshares.valid * $GLOBAL.userdata.shares.invalid)|number_format:"2"}%)</font>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>{$GLOBAL.config.currency} Round Estimate</u></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Block</b></td>
|
||||||
|
<td class="right">{$GLOBAL.userdata.est_block|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Fees</b></td>
|
||||||
|
<td class="right">{$GLOBAL.userdata.est_fee|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Donation</b></td>
|
||||||
|
<td class="right">{$GLOBAL.userdata.est_donation|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Payout</b></td>
|
||||||
|
<td class="right">{$GLOBAL.userdata.est_payout|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2"> </td></tr>
|
||||||
|
<tr><td colspan="2"><b><u>{$GLOBAL.config.currency} Account Balance</u></b></td></tr>
|
||||||
|
<tr><td>Confirmed</td><td class="right"><b>{$GLOBAL.userdata.balance.confirmed|default:"0"}</td></tr>
|
||||||
|
<tr><td>Unconfirmed</td><td class="right"><b>{$GLOBAL.userdata.balance.unconfirmed|default:"0"}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="bendl"></div>
|
||||||
|
<div class="bendr"></div>
|
||||||
|
</div>
|
||||||
63
public/templates/mobile/global/sidebar_pplns.tpl
Normal file
63
public/templates/mobile/global/sidebar_pplns.tpl
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><b>PPLNS Target</b></td>
|
||||||
|
<td align="right">{$GLOBAL.pplns.target|number_format}</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2"> </td></tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>Your Stats</u></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Hashrate</b></td>
|
||||||
|
<td align="right">{$GLOBAL.userdata.hashrate|number_format} KH/s</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>Unpaid Shares</u></b> <span id='tt'><img src='{$PATH}/images/questionmark.png' height='15px' width='15px' title='Submitted shares between the last 120 confirms block until now.'></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Your Valid<b></td>
|
||||||
|
<td align="right"><i>{$GLOBAL.userdata.shares.valid|number_format}</i><font size='1px'></font></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Pool Valid</td>
|
||||||
|
<td align="right"><i>{$GLOBAL.roundshares.valid|number_format}</i> <font size='1px'></font></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>Round Shares</u></b> <span id='tt'><img src='{$PATH}/images/questionmark.png' height='15px' width='15px' title='Submitted shares since last found block (ie. round shares)'></span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Pool Valid</b></td>
|
||||||
|
<td align="right"><i>{$GLOBAL.roundshares.valid|number_format}</i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Pool Invalid</b></td>
|
||||||
|
<td align="right"><i>{$GLOBAL.roundshares.invalid|number_format}</i>{if $GLOBAL.roundshares.valid > 0}<font size='1px'> ({(100 / $GLOBAL.roundshares.valid * $GLOBAL.roundshares.invalid)|number_format:"2"}%)</font>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Your Invalid</b></td>
|
||||||
|
<td align="right"><i>{$GLOBAL.userdata.shares.invalid|number_format}</i>{if $GLOBAL.roundshares.valid > 0}<font size='1px'> ({(100 / $GLOBAL.roundshares.valid * $GLOBAL.userdata.shares.invalid)|number_format:"2"}%)</font>{/if}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="2"><b><u>{$GLOBAL.config.currency} Round Estimate</u></b></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Block</b></td>
|
||||||
|
<td align="right">{$GLOBAL.userdata.est_block|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Fees</b></td>
|
||||||
|
<td align="right">{$GLOBAL.userdata.est_fee|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Donation</b></td>
|
||||||
|
<td align="right">{$GLOBAL.userdata.est_donation|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Payout</b></td>
|
||||||
|
<td align="right">{$GLOBAL.userdata.est_payout|number_format:"3"}</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td colspan="2"> </td></tr>
|
||||||
|
<tr><td colspan="2"><b><u>{$GLOBAL.config.currency} Account Balance</u></b></td></tr>
|
||||||
|
<tr><td>Confirmed</td><td align="right"><b>{$GLOBAL.userdata.balance.confirmed|default:"0"}</td></tr>
|
||||||
|
<tr><td>Unconfirmed</td><td align="right"><b>{$GLOBAL.userdata.balance.unconfirmed|default:"0"}</td></tr>
|
||||||
|
</table>
|
||||||
Loading…
Reference in New Issue
Block a user