Merge pull request #851 from iAmShorty/blockfinder

Blockfinder Stats
This commit is contained in:
Sebastian Grewe 2013-11-18 05:01:12 -08:00
commit f910398f33
29 changed files with 260 additions and 31 deletions

7
cronjobs/findblock.php Executable file → Normal file
View File

@ -75,13 +75,12 @@ if (empty($aAllBlocks)) {
$log->logDebug('No new blocks without share_id found in database');
} else {
// Loop through our unaccounted blocks
$log->logInfo("Block ID\tHeight\t\tAmount\tShare ID\tShares\tFinder\t\tType");
$log->logInfo("Block ID\tHeight\t\tAmount\tShare ID\tShares\tFinder\tWorker\t\tType");
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (empty($aBlock['share_id'])) {
// Fetch share information
if ( !$iPreviousShareId = $block->getLastShareId())
$iPreviousShareId = 0;
// Fetch this blocks upstream ID
$aBlockRPCInfo = $bitcoin->query('getblock', $aBlock['blockhash']);
if ($share->findUpstreamShare($aBlockRPCInfo, $iPreviousShareId)) {
@ -117,6 +116,7 @@ if (empty($aAllBlocks)) {
} else {
$iRoundShares = $share->getRoundShares($iPreviousShareId, $iCurrentUpstreamId);
$iAccountId = $user->getUserId($share->getUpstreamFinder());
$iWorker = $share->getUpstreamWorker();
}
} else {
$log->logFatal('E0005: Unable to fetch blocks upstream share, aborted:' . $share->getCronError());
@ -130,6 +130,7 @@ if (empty($aAllBlocks)) {
. $iCurrentUpstreamId . "\t\t"
. $iRoundShares . "\t"
. "[$iAccountId] " . $user->getUserName($iAccountId) . "\t"
. $iWorker . "\t"
. $share->share_type
);
@ -138,6 +139,8 @@ if (empty($aAllBlocks)) {
$log->logError('Failed to update share ID in database for block ' . $aBlock['height'] . ': ' . $block->getCronError());
if (!$block->setFinder($aBlock['id'], $iAccountId))
$log->logError('Failed to update finder account ID in database for block ' . $aBlock['height'] . ': ' . $block->getCronError());
if (!$block->setFindingWorker($aBlock['id'], $iWorker))
$log->logError('Failed to update worker ID in database for block ' . $aBlock['height'] . ': ' . $block->getCronError());
if (!$block->setShares($aBlock['id'], $iRoundShares))
$log->logError('Failed to update share count in database for block ' . $aBlock['height'] . ': ' . $block->getCronError());
if ($config['block_bonus'] > 0 && !$transaction->addTransaction($iAccountId, $config['block_bonus'], 'Bonus', $aBlock['id'])) {

View File

@ -197,6 +197,17 @@ class Block extends Base {
$field = array( 'name' => 'account_id', 'value' => $account_id, 'type' => 'i' );
return $this->updateSingle($block_id, $field);
}
/**
* Set finding worker of a block
* @param block_id int Block ID
* @param worker_id int Worker ID of finder
* @return bool
**/
public function setFindingWorker($block_id, $worker=NULL) {
$field = array( 'name' => 'worker_name', 'value' => $worker, 'type' => 's' );
return $this->updateSingle($block_id, $field);
}
/**
* Set finding share for a block

View File

@ -231,6 +231,9 @@ class Share Extends Base {
public function getUpstreamFinder() {
return @$this->oUpstream->account;
}
public function getUpstreamWorker() {
return @$this->oUpstream->worker;
}
public function getUpstreamShareId() {
return @$this->oUpstream->id;
}
@ -254,39 +257,39 @@ class Share Extends Base {
$header_hex = implode(unpack("H*", $header_bin));
// Stratum supported blockhash solution entry
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution = ? LIMIT 1");
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM $this->table WHERE solution = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $aBlock['hash']) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
$this->share_type = 'stratum_blockhash';
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id))
return true;
}
// Stratum scrypt hash check
$scrypt_hash = swapEndian(bin2hex(Scrypt::calc($header_bin, $header_bin, 1024, 1, 1, 32)));
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution = ? LIMIT 1");
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM $this->table WHERE solution = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $scrypt_hash) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
$this->share_type = 'stratum_solution';
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id))
return true;
}
// Failed to fetch via startum solution, try pushpoold
// Fallback to pushpoold solution type
$ppheader = sprintf('%08d', $aBlock['version']) . word_reverse($aBlock['previousblockhash']) . word_reverse($aBlock['merkleroot']) . dechex($aBlock['time']) . $aBlock['bits'] . dechex($aBlock['nonce']);
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id FROM $this->table WHERE solution LIKE CONCAT(?, '%') LIMIT 1");
$stmt = $this->mysqli->prepare("SELECT SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id FROM $this->table WHERE solution LIKE CONCAT(?, '%') LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $ppheader) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
$this->share_type = 'pp_solution';
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id))
return true;
}
// Still no match, try upstream result with timerange
$stmt = $this->mysqli->prepare("
SELECT
SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id
SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id
FROM $this->table
WHERE upstream_result = 'Y'
AND id > ?
@ -296,14 +299,14 @@ class Share Extends Base {
if ($this->checkStmt($stmt) && $stmt->bind_param('iii', $last, $aBlock['time'], $aBlock['time']) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
$this->share_type = 'upstream_share';
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id))
return true;
}
// We failed again, now we take ANY result matching the timestamp
$stmt = $this->mysqli->prepare("
SELECT
SUBSTRING_INDEX( `username` , '.', 1 ) AS account, id
SUBSTRING_INDEX( `username` , '.', 1 ) AS account, username as worker, id
FROM $this->table
WHERE our_result = 'Y'
AND id > ?
@ -312,7 +315,7 @@ class Share Extends Base {
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $last, $aBlock['time']) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
$this->share_type = 'any_share';
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
if (!empty($this->oUpstream->account) && !empty($this->oUpstream->worker) && is_int($this->oUpstream->id))
return true;
}
$this->setErrorMessage($this->getErrorMsg('E0052', $aBlock['height']));

View File

@ -122,7 +122,7 @@ class Statistics extends Base {
**/
public function getBlocksFoundHeight($iHeight=0, $limit=10) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $iHeight . $limit)) return $data;
if ($data = $this->memcache->get(__FUNCTION__ . $iHeight . $limit)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
b.*,
@ -139,6 +139,54 @@ class Statistics extends Base {
return $this->sqlError();
}
/**
* Get SUM of blocks found and generated Coins for each Account
* @param limit int Last limit blocks
* @return array
**/
public function getBlocksSolvedbyAccount($limit=25) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $limit)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
b.*,
a.username AS finder,
a.is_anonymous AS is_anonymous,
COUNT(b.id) AS solvedblocks,
SUM(b.amount) AS generatedcoins
FROM " . $this->block->getTableName() . " AS b
LEFT JOIN " . $this->user->getTableName() . " AS a
ON b.account_id = a.id
WHERE confirmations > 0
GROUP BY finder
ORDER BY solvedblocks DESC LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
return $this->sqlError();
}
/**
* Get SUM of blocks found and generated Coins for each worker
* @param limit int Last limit blocks
* @return array
**/
public function getBlocksSolvedbyWorker($account_id, $limit=25) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $account_id . $limit)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
worker_name AS finder,
COUNT(id) AS solvedblocks,
SUM(amount) AS generatedcoins
FROM " . $this->block->getTableName() . "
WHERE account_id = ? AND worker_name != 'unknown'
GROUP BY finder
ORDER BY solvedblocks DESC LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $limit) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5);
return $this->sqlError();
}
/**
* Currently the only function writing to the database
* Stored per block user statistics of valid and invalid shares

View File

@ -187,6 +187,13 @@ $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' => 'Block Finder Statistics', 'type' => 'select',
'options' => array( 0 => 'Private', 1 => 'Public'),
'default' => 1,
'name' => 'acl_blockfinder_statistics', 'value' => $setting->getValue('acl_blockfinder_statistics'),
'tooltip' => 'Make the Block Finder Statistics page private (users only) or public.'
);
$aSettings['acl'][] = array(
'display' => 'Uptime Statistics', 'type' => 'select',
'options' => array( 0 => 'Private', 1 => 'Public'),

View File

@ -0,0 +1,26 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
// Grab Block Finder
if (!$smarty->isCached('master.tpl', $smarty_cache_key)) {
$debug->append('No cached version available, fetching from backend', 3);
$getBlocksSolvedbyAccount = $statistics->getBlocksSolvedbyAccount();
$smarty->assign("BLOCKSSOLVEDBYACCOUNT", $getBlocksSolvedbyAccount);
} else {
$debug->append('Using cached page', 3);
}
if ($setting->getValue('acl_blockfinder_statistics')) {
$smarty->assign("CONTENT", "finder.tpl");
} else if ($user->isAuthenticated()) {
$getBlocksSolvedbyWorker = $statistics->getBlocksSolvedbyWorker($_SESSION['USERDATA']['id']);
$smarty->assign("BLOCKSSOLVEDBYWORKER", $getBlocksSolvedbyWorker);
$smarty->assign("CONTENT", "finder.tpl");
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Block Finders are currently disabled. Please try again later.', 'TYPE' => 'errormsg');
$smarty->assign("CONTENT", "default.tpl");
}
?>

View File

@ -104,6 +104,7 @@ $aGlobal['statistics']['analytics']['code'] = $setting->getValue('statistics_ana
$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');
$aGlobal['acl']['blockfinder']['statistics'] = $setting->getValue('acl_blockfinder_statistics');
$aGlobal['acl']['uptime']['statistics'] = $setting->getValue('acl_uptime_statistics');
// We don't want these session infos cached

View File

@ -1,6 +1,7 @@
.icon-dollar:before { content: '\e818'; } /* '' */
.icon-doc:before { content: '\e81b'; } /* '' */
.icon-login:before { content: '\e81c'; } /* '' */
.icon-exchange:before { content: '\e81a'; } /* '' */
.icon-money:before { content: '\e819'; } /* '' */
.icon-mail:before { content: '\e814'; } /* '' */
@ -18,7 +19,7 @@
.icon-bell:before { content: '\e817'; } /* '' */
.icon-trash:before { content: '\e812'; } /* '' */
.icon-cog:before { content: '\e810'; } /* '' */
.icon-login:before { content: '\e81c'; } /* '' */
.icon-search:before { content: '\e827'; } /* '' */
.icon-resize-full-alt:before { content: '\e824'; } /* '' */
.icon-down-open:before { content: '\e825'; } /* '' */
.icon-left-open:before { content: '\e801'; } /* '' */

View File

@ -12,6 +12,12 @@
"code": 59416,
"src": "fontawesome"
},
{
"uid": "7222571caa5c15f83dcfd447c58d68d9",
"css": "search",
"code": 59431,
"src": "entypo"
},
{
"uid": "a204f0fa972408eaae5a363c444991b2",
"css": "login",

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,7 @@
.icon-dollar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe818;&nbsp;'); }
.icon-doc { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81b;&nbsp;'); }
.icon-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81c;&nbsp;'); }
.icon-exchange { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81a;&nbsp;'); }
.icon-money { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe819;&nbsp;'); }
.icon-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe814;&nbsp;'); }
@ -18,7 +19,7 @@
.icon-bell { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe817;&nbsp;'); }
.icon-trash { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe812;&nbsp;'); }
.icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe810;&nbsp;'); }
.icon-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81c;&nbsp;'); }
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe827;&nbsp;'); }
.icon-resize-full-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe824;&nbsp;'); }
.icon-down-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe825;&nbsp;'); }
.icon-left-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }

View File

@ -12,6 +12,7 @@
.icon-dollar { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe818;&nbsp;'); }
.icon-doc { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81b;&nbsp;'); }
.icon-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81c;&nbsp;'); }
.icon-exchange { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81a;&nbsp;'); }
.icon-money { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe819;&nbsp;'); }
.icon-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe814;&nbsp;'); }
@ -29,7 +30,7 @@
.icon-bell { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe817;&nbsp;'); }
.icon-trash { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe812;&nbsp;'); }
.icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe810;&nbsp;'); }
.icon-login { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe81c;&nbsp;'); }
.icon-search { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe827;&nbsp;'); }
.icon-resize-full-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe824;&nbsp;'); }
.icon-down-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe825;&nbsp;'); }
.icon-left-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }

View File

@ -1,10 +1,10 @@
@font-face {
font-family: 'fontello';
src: url('../font/fontello.eot?25380644');
src: url('../font/fontello.eot?25380644#iefix') format('embedded-opentype'),
url('../font/fontello.woff?25380644') format('woff'),
url('../font/fontello.ttf?25380644') format('truetype'),
url('../font/fontello.svg?25380644#fontello') format('svg');
src: url('../font/fontello.eot?43056661');
src: url('../font/fontello.eot?43056661#iefix') format('embedded-opentype'),
url('../font/fontello.woff?43056661') format('woff'),
url('../font/fontello.ttf?43056661') format('truetype'),
url('../font/fontello.svg?43056661#fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@ -14,7 +14,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'fontello';
src: url('../font/fontello.svg?25380644#fontello') format('svg');
src: url('../font/fontello.svg?43056661#fontello') format('svg');
}
}
*/
@ -52,6 +52,7 @@
.icon-dollar:before { content: '\e818'; } /* '' */
.icon-doc:before { content: '\e81b'; } /* '' */
.icon-login:before { content: '\e81c'; } /* '' */
.icon-exchange:before { content: '\e81a'; } /* '' */
.icon-money:before { content: '\e819'; } /* '' */
.icon-mail:before { content: '\e814'; } /* '' */
@ -69,7 +70,7 @@
.icon-bell:before { content: '\e817'; } /* '' */
.icon-trash:before { content: '\e812'; } /* '' */
.icon-cog:before { content: '\e810'; } /* '' */
.icon-login:before { content: '\e81c'; } /* '' */
.icon-search:before { content: '\e827'; } /* '' */
.icon-resize-full-alt:before { content: '\e824'; } /* '' */
.icon-down-open:before { content: '\e825'; } /* '' */
.icon-left-open:before { content: '\e801'; } /* '' */

View File

@ -8,6 +8,7 @@
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="dollar" unicode="&#xe818;" d="m546 189q0-86-56-147t-144-77v-97q0-8-5-13t-13-5h-75q-7 0-13 5t-5 13v97q-37 5-71 18t-57 25t-41 26t-26 21t-10 10q-9 12-1 23l58 76q3 5 12 6q9 1 14-5l1-1q63-55 135-70q21-4 42-4q45 0 79 24t35 68q0 16-9 30t-18 23t-33 21t-37 18t-45 18q-21 9-34 14t-34 15t-35 17t-32 20t-29 24t-25 27t-20 32t-11 37t-5 44q0 77 55 135t142 75v100q0 7 5 13t13 5h75q8 0 13-5t5-13v-98q32-4 62-13t48-19t36-21t21-16t9-8q9-10 3-21l-46-81q-4-9-12-9q-8-2-16 4q-1 1-8 6t-21 15t-33 18t-42 15t-47 6q-53 0-87-24t-33-62q0-14 4-27t17-23t22-18t31-18t34-15t39-15q30-11 45-18t43-19t42-24t34-28t30-35t18-43t7-52z" horiz-adv-x="571.4" />
<glyph glyph-name="doc" unicode="&#xe81b;" d="m0-25l0 625q0 39 27 66t67 28l31 0l0 62q0 39 27 67t67 27l687 0q39 0 67-27t27-67l0-781q0-53-36-89t-89-36l-750 0q-53 0-89 36t-36 89z m63 0q0-25 18-44t44-19l750 0q25 0 44 19t18 44l0 781q0 14-8 23t-23 8l-687 0q-14 0-23-8t-8-23l0-750q0-13-9-22t-23-9t-22 9t-9 22l0 625l-31 0q-14 0-23-9t-8-22l0-625z m187 16q0 15 16 15l250 0q15 0 15-15t-15-16l-250 0q-16 0-16 16z m0 93q0 16 16 16l250 0q15 0 15-16t-15-15l-250 0q-16 0-16 15z m0 94q0 16 16 16l250 0q15 0 15-16q0-6-5-11t-10-4l-250 0q-16 0-16 15z m0 94q0 16 16 16l593 0q16 0 16-16t-16-16l-593 0q-16 0-16 16z m0 94q0 15 16 15l593 0q16 0 16-15t-16-16l-593 0q-16 0-16 16z m0 109l0 219q0 13 9 22t22 9l219 0q14 0 22-9t9-22l0-219q0-14-9-22t-22-9l-219 0q-13 0-22 9t-9 22z m63 31l156 0l0 156l-156 0l0-156z m281-515q0 15 15 15l250 0q16 0 16-15t-16-16l-250 0q-15 0-15 16z m0 93q0 16 15 16l250 0q16 0 16-16t-16-15l-250 0q-15 0-15 15z m0 94q0 16 15 16l250 0q16 0 16-16q0-6-5-11t-11-5l-250 0q-15 0-15 16z m0 281q0 16 15 16l250 0q16 0 16-16t-16-15l-250 0q-15 0-15 15z m0 94q0 16 15 16l250 0q16 0 16-16t-16-16l-250 0q-15 0-15 16z m0 94q0 15 15 15l250 0q16 0 16-15t-16-16l-250 0q-15 0-15 16z" horiz-adv-x="1000" />
<glyph glyph-name="login" unicode="&#xe81c;" d="m800 800q42 0 71-29t29-71l0-700q0-40-29-70t-71-30l-450 0q-40 0-69 30t-29 70l0 100l98 0l0-100l450 0l0 700l-450 0l0-150l-98 0l0 150q0 42 29 71t69 29l450 0z m-350-670l0 120l-450 0l0 150l450 0l0 120l200-194z" horiz-adv-x="900" />
<glyph glyph-name="exchange" unicode="&#xe81a;" d="m911 127l-670 0l0-111l-223 168l223 167l0-112l670 0l0-112z m-893 335l0 112l670 0l0 111l223-166l-223-168l0 111l-670 0z" horiz-adv-x="928" />
<glyph glyph-name="money" unicode="&#xe819;" d="m238 378c13 16 35 21 65 24l0-85c-50 5-75 9-75 39c0 7 2 15 10 22z m107-241l0 91c59-5 78-9 78-35c0-30-24-49-78-56z m70 244c30-17 36-24 36-38l8-4l45 90l-6 5c-7-5-10-7-14-7s-8 0-13 4c-61 23-90 35-126 35l0 17c0 9 5 15 20 19l0 9l-79 0l0-9c14-4 17-11 17-19l0-15c-97-4-153-50-153-122c0-74 40-100 153-110l0-97c-78 8-117 38-117 64l-7 4l-41-94l6-4c6 4 9 5 12 5c2 0 7 0 9-2c48-24 94-38 138-40l0-19c0-10-3-16-17-20l0-9l79 0l0 9c-15 4-20 9-20 20l0 19c96 5 159 54 159 126c0 70-53 106-149 115l-10 0l0 88c23-2 46-8 70-20z m41 181c117-50 198-165 198-300c0-181-146-328-326-328c-182 0-328 147-328 328c0 135 81 250 198 300l-82 179c0 17 12 25 28 25l366 0c16 0 28-7 28-25z" horiz-adv-x="654" />
<glyph glyph-name="mail" unicode="&#xe814;" d="m0-29l324 342l176-100l176 100l324-342l-1000 0z m0 114l0 414l254-147z m0 503l0 141l1000 0l0-141l-500-285z m746-236l254 147l0-414z" horiz-adv-x="1000" />
@ -25,7 +26,7 @@
<glyph glyph-name="bell" unicode="&#xe817;" d="m0 10l0 45l197 170l0 266q0 107 68 190t171 105l0 62l130 0l0-62q102-22 170-105t69-190l0-266l195-170l0-45l-1000 0z m428-87q0 30 21 52t52 21t52-21t21-52t-21-51t-52-20t-52 20t-21 51z" horiz-adv-x="1000" />
<glyph glyph-name="trash" unicode="&#xe812;" d="m0 633l0 141l289 0l0 76l246 0l0-76l289 0l0-141l-824 0z m43-783l0 676l738 0l0-676l-738 0z" horiz-adv-x="824" />
<glyph glyph-name="cog" unicode="&#xe810;" d="m0 272l0 156l150 16q14 45 38 88l-96 117l109 109l117-95q41 23 88 37l16 150l156 0l16-150q45-14 88-37l117 95l109-109l-96-117q24-43 38-88l150-16l0-156l-150-16q-14-47-38-88l96-117l-109-109l-117 96q-43-24-88-38l-16-150l-156 0l-16 150q-47 14-88 38l-117-96l-109 109l96 117q-24 41-38 88z m355 78q0-60 42-102t103-42t103 42t42 102t-42 103t-103 42t-103-42t-42-103z" horiz-adv-x="1000" />
<glyph glyph-name="login" unicode="&#xe81c;" d="m800 800q42 0 71-29t29-71l0-700q0-40-29-70t-71-30l-450 0q-40 0-69 30t-29 70l0 100l98 0l0-100l450 0l0 700l-450 0l0-150l-98 0l0 150q0 42 29 71t69 29l450 0z m-350-670l0 120l-450 0l0 150l450 0l0 120l200-194z" horiz-adv-x="900" />
<glyph glyph-name="search" unicode="&#xe827;" d="m772 78q30-34 6-62l-46-46q-36-32-68 0l-190 190q-74-42-156-42q-128 0-223 95t-95 223t90 219t218 91t224-95t96-223q0-88-46-162z m-678 358q0-88 68-156t156-68t151 63t63 153q0 88-68 155t-156 67t-151-63t-63-151z" horiz-adv-x="789" />
<glyph glyph-name="resize-full-alt" unicode="&#xe824;" d="m0-150l0 342l119-119l278 277l-276 275l-121-121l0 346l342 0l-119-119l277-277l275 275l-121 121l346 0l0-342l-119 119l-277-277l275-275l121 121l0-346l-342 0l119 119l-277 278l-275-276l121-121l-346 0z" horiz-adv-x="1000" />
<glyph glyph-name="down-open" unicode="&#xe825;" d="m0 526l148 148l352-351l352 351l148-148l-352-352l-148-148l-148 148z" horiz-adv-x="1000" />
<glyph glyph-name="left-open" unicode="&#xe801;" d="m0 350l148 149l352 351l148-148l-351-352l351-352l-148-148l-352 352z" horiz-adv-x="648" />

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -33,6 +33,7 @@
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blocks">Block Stats</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=graphs">Hashrate Graphs</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=round">Round Stats</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blockfinder">Block Finder Stats</a></li>
{if $GLOBAL.config.monitoring_uptimerobot_api_keys|default:"0"}<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=uptime">Uptime Stats</a></li>{/if}
</ul>
</li>
@ -48,6 +49,9 @@
{if $GLOBAL.acl.round.statistics}
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=round">Round Stats</a></li>
{/if}
{if $GLOBAL.acl.blockfinder.statistics}
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blockfinder">Block Finder Stats</a></li>
{/if}
{if $GLOBAL.acl.uptime.statistics}
{if $GLOBAL.config.monitoring_uptimerobot_api_keys|default:"0"}<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=uptime">Uptime Stats</a></li>{/if}
{/if}

View File

@ -0,0 +1,4 @@
{include file="statistics/blockfinder/finder_top.tpl"}
{if $smarty.session.AUTHENTICATED|default}
{include file="statistics/blockfinder/finder_own.tpl" ALIGN="right" SHORT=true}
{/if}

View File

@ -0,0 +1,25 @@
{include file="global/block_header.tpl" ALIGN="right" BLOCK_HEADER="Blocks found by own Workers"}
<center>
<table width="100%" border="0" style="font-size:13px;">
<thead>
<tr>
<th align="center">Rank</th>
<th>Worker</th>
<th align="center">Blocks</th>
<th align="right" style="padding-right: 25px;">Coins Generated</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSSOLVEDBYWORKER}
<tr class="{cycle values="odd,even"}">
<td align="center">{$rank++}</td>
<td>{$BLOCKSSOLVEDBYWORKER[block].finder|default:"unknown/deleted"|escape}</td>
<td align="center">{$BLOCKSSOLVEDBYWORKER[block].solvedblocks}</td>
<td align="right" style="padding-right: 25px;">{$BLOCKSSOLVEDBYWORKER[block].generatedcoins|number_format}</td>
</tr>
{/section}
</tbody>
</table>
</center>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,25 @@
{include file="global/block_header.tpl" ALIGN="left" BLOCK_HEADER="Top 25 Blockfinder"}
<center>
<table width="100%" border="0" style="font-size:13px;">
<thead>
<tr>
<th align="center">Rank</th>
<th>Username</th>
<th align="center">Blocks</th>
<th align="right" style="padding-right: 25px;">Coins Generated</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSSOLVEDBYACCOUNT}
<tr class="{cycle values="odd,even"}">
<td align="center">{$rank++}</td>
<td>{if $BLOCKSSOLVEDBYACCOUNT[block].is_anonymous|default:"0" == 1 && $GLOBAL.userdata.is_admin|default:"0" == 0}anonymous{else}{$BLOCKSSOLVEDBYACCOUNT[block].finder|default:"unknown"|escape}{/if}</td>
<td align="center">{$BLOCKSSOLVEDBYACCOUNT[block].solvedblocks}</td>
<td align="right" style="padding-right: 25px;">{$BLOCKSSOLVEDBYACCOUNT[block].generatedcoins|number_format}</td>
</tr>
{/section}
</tbody>
</table>
</center>
{include file="global/block_footer.tpl"}

View File

@ -33,6 +33,7 @@
<li class="icon-th-large"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blocks">Blocks</a></li>
<li class="icon-chart"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=graphs">Graphs</a></li>
<li class="icon-record"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=round">Round</a></li>
<li class="icon-search"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blockfinder">Finder</a></li>
{if $GLOBAL.config.monitoring_uptimerobot_api_keys|default:"0"}<li class="icon-bell"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=uptime">Uptime</a></li>{/if}
</ul>
{else}
@ -49,6 +50,9 @@
{if $GLOBAL.acl.round.statistics}
<li class="icon-chart"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=round">Round</a></li>
{/if}
{if $GLOBAL.acl.blockfinder.statistics}
<li class="icon-search"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blockfinder">Finder</a></li>
{/if}
{if $GLOBAL.acl.uptime.statistics}
{if $GLOBAL.config.monitoring_uptimerobot_api_keys|default:"0"}<li class="icon-bell"><a href="{$smarty.server.PHP_SELF}?page=statistics&action=uptime">Uptime</a></li>{/if}
{/if}

View File

@ -0,0 +1,4 @@
{include file="statistics/blockfinder/finder_top.tpl"}
{if $smarty.session.AUTHENTICATED|default}
{include file="statistics/blockfinder/finder_own.tpl" ALIGN="right" SHORT=true}
{/if}

View File

@ -0,0 +1,25 @@
<article class="module width_half" style="min-height: 350px">
<header><h3>Blocks found by own Workers</h3></header>
<div>
<table class="tablesorter" cellspacing="0">
<thead>
<tr>
<th align="center">Rank</th>
<th>Worker</th>
<th align="center">Blocks</th>
<th align="right" style="padding-right: 25px;">Coins Generated</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSSOLVEDBYWORKER}
<tr class="{cycle values="odd,even"}">
<td align="center">{$rank++}</td>
<td>{$BLOCKSSOLVEDBYWORKER[block].finder|default:"unknown/deleted"|escape}</td>
<td align="center">{$BLOCKSSOLVEDBYWORKER[block].solvedblocks}</td>
<td align="right" style="padding-right: 25px;">{$BLOCKSSOLVEDBYWORKER[block].generatedcoins|number_format}</td>
</tr>
{/section}
</tbody>
</table>
</article>

View File

@ -0,0 +1,25 @@
<article class="module width_half" style="min-height: 350px">
<header><h3>Top 25 Blockfinder</h3></header>
<div>
<table class="tablesorter" cellspacing="0">
<thead>
<tr>
<th align="center">Rank</th>
<th>Username</th>
<th align="center">Blocks</th>
<th align="right" style="padding-right: 25px;">Coins Generated</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSSOLVEDBYACCOUNT}
<tr class="{cycle values="odd,even"}">
<td align="center">{$rank++}</td>
<td>{if $BLOCKSSOLVEDBYACCOUNT[block].is_anonymous|default:"0" == 1 && $GLOBAL.userdata.is_admin|default:"0" == 0}anonymous{else}{$BLOCKSSOLVEDBYACCOUNT[block].finder|default:"unknown"|escape}{/if}</td>
<td align="center">{$BLOCKSSOLVEDBYACCOUNT[block].solvedblocks}</td>
<td align="right" style="padding-right: 25px;">{$BLOCKSSOLVEDBYACCOUNT[block].generatedcoins|number_format}</td>
</tr>
{/section}
</tbody>
</table>
</article>

View File

@ -40,6 +40,7 @@ CREATE TABLE IF NOT EXISTS `blocks` (
`time` int(11) NOT NULL,
`accounted` tinyint(1) NOT NULL DEFAULT '0',
`account_id` int(255) unsigned DEFAULT NULL,
`worker_name` varchar(50) DEFAULT 'unknown',
`shares` int(255) unsigned DEFAULT NULL,
`share_id` int(255) DEFAULT NULL,
PRIMARY KEY (`id`),

View File

@ -0,0 +1 @@
ALTER TABLE `blocks` ADD `worker_name` varchar(50) DEFAULT 'unknown' AFTER `account_id`;