Merge pull request #219 from TheSerapher/next

Next
This commit is contained in:
Sebastian Grewe 2013-06-19 05:57:29 -07:00
commit f61bb5c11a
93 changed files with 3309 additions and 1352 deletions

View File

@ -29,6 +29,8 @@ Donors
These people have supported this project with a donation:
* [obigal](https://github.com/obigal)
* [vias](https://github.com/vias79)
* [WKNiGHT](https://github.com/WKNiGHT-)
Requirements
============
@ -57,10 +59,11 @@ The following feature have been implemented so far:
* Reward Systems
* Propotional
* (Planned) PPS
* PPS
* (Planned) PPLNS
* Use of memcache for statistics instead of a cronjob
* Web User accounts
* Re-Captcha protected registration form
* Worker accounts
* Worker activity (live, past 10 minutes)
* Worker hashrates (live, past 10 minutes)
@ -68,9 +71,23 @@ The following feature have been implemented so far:
* Minimal Block statistics
* Pool donations
* Pool fees
* Manual payout with 0.1 LTC fee
* Auto payout with 0.1 LTC fee
* Manual payout
* Auto payout
* Transaction list (confirmed and unconfirmed)
* Admin Panel
* User Listing including statistics
* Wallet information
* (Planned) News Posts
* (Planned) Pool Donations
* Notification system
* IDLE Workers
* New blocks found in pool
* Auto Payout
* Manual Payout
* Support for various Scrypt based coins via config
* MNC
* LTC
* ...
Installation
============

View File

@ -27,6 +27,9 @@ if ($bitcoin->can_connect() !== true) {
exit(1);
}
// Mark this job as active
$setting->setValue('auto_payout_active', 1);
// Fetch all users with setup AP
$users = $user->getAllAutoPayout();
@ -35,11 +38,12 @@ if (! empty($users)) {
verbose("UserID\tUsername\tBalance\tThreshold\tAddress\t\t\t\t\tStatus\n\n");
foreach ($users as $aUserData) {
$dBalance = $transaction->getBalance($aUserData['id']);
$aBalance = $transaction->getBalance($aUserData['id']);
$dBalance = $aBalance['confirmed'];
verbose($aUserData['id'] . "\t" . $aUserData['username'] . "\t" . $dBalance . "\t" . $aUserData['ap_threshold'] . "\t\t" . $aUserData['coin_address'] . "\t");
// Only run if balance meets threshold and can pay the transaction fee
if ($dBalance > $aUserData['ap_threshold'] && $dBalance > 0.1) {
// Only run if balance meets threshold and can pay the potential transaction fee
if ($dBalance > $aUserData['ap_threshold'] && $dBalance > $config['txfee']) {
// Validate address against RPC
try {
$bitcoin->validateaddress($aUserData['coin_address']);
@ -48,20 +52,29 @@ if (! empty($users)) {
continue;
}
// Send balance - 0.1 Fee to address
// Send balance, fees are reduced later by RPC Server
try {
$bitcoin->sendtoaddress($aUserData['coin_address'], $dBalance - 0.1);
$bitcoin->sendtoaddress($aUserData['coin_address'], $dBalance);
} catch (BitcoinClientException $e) {
verbose("SEND FAILED\n");
continue;
}
// Create transaction record
if ($transaction->addTransaction($aUserData['id'], $dBalance, 'Debit_AP', NULL, $aUserData['coin_address'], 0.1)) {
verbose("OK\n");
if ($transaction->addTransaction($aUserData['id'], $dBalance - $config['txfee'], 'Debit_AP', NULL, $aUserData['coin_address']) && $transaction->addTransaction($aUserData['id'], $config['txfee'], 'TXFee', NULL, $aUserData['coin_address'])) {
// Notify user via mail
$aMailData['email'] = $user->getUserEmail($user->getUserName($aUserData['id']));
$aMailData['subject'] = 'Auto Payout Completed';
$aMailData['amount'] = $dBalance;
if (!$notification->sendNotification($aUserData['id'], 'auto_payout', $aMailData)) {
verbose("NOTIFY FAILED\n");
} else {
verbose("OK\n");
}
} else {
verbose("FAILED\n");
}
} else {
verbose("SKIPPED\n");
}
@ -69,3 +82,8 @@ if (! empty($users)) {
} else {
verbose("No user has configured their AP > 0\n");
}
// Mark this job as inactive
$setting->setValue('auto_payout_active', 0);
?>

View File

@ -39,9 +39,8 @@ if ( $bitcoin->can_connect() === true ){
// Nothing to do so bail out
if (empty($aTransactions['transactions'])) {
verbose("No new transactions since last block\n");
verbose("No new RPC transactions since last block\n");
} else {
// Table header
verbose("Blockhash\t\tHeight\tAmount\tConfirmations\tDiff\t\tTime\t\t\tStatus\n");
@ -66,36 +65,67 @@ if (empty($aTransactions['transactions'])) {
}
}
verbose("\n");
// Now with our blocks added we can scan for their upstream shares
$aAllBlocks = $block->getAllUnaccounted('ASC');
if (empty($aAllBlocks)) {
verbose("No new unaccounted blocks found\n");
} else {
// Loop through our unaccounted blocks
verbose("\nBlock ID\tBlock Height\tShare ID\tShares\tFinder\t\t\tStatus\n");
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (empty($aBlock['share_id'])) {
// Fetch this blocks upstream ID
if ($share->setUpstream($block->getLastUpstreamId())) {
$iCurrentUpstreamId = $share->getUpstreamId();
$iAccountId = $user->getUserId($share->getUpstreamFinder());
} else {
verbose("\nUnable to fetch blocks upstream share. Aborting!\n");
verbose($share->getError() . "\n");
exit;
}
// Fetch share information
if (!$iPreviousShareId = $block->getLastShareId()) {
$iPreviousShareId = 0;
verbose("\nUnable to find highest share ID found so far\n");
verbose("If this is your first block, this is normal\n\n");
}
$iRoundShares = $share->getRoundShares($iPreviousShareId, $iCurrentUpstreamId);
// Loop through our unaccounted blocks
verbose("Block ID\tBlock Height\tShare ID\tFinder\t\t\tStatus\n");
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (empty($aBlock['share_id'])) {
// Fetch this blocks upstream ID
if ($share->setUpstream($block->getLastUpstreamId())) {
$iCurrentUpstreamId = $share->getUpstreamId();
$iAccountId = $user->getUserId($share->getUpstreamFinder());
} else {
verbose("Unable to fetch blocks upstream share\n");
verbose($share->getError() . "\n");
continue;
// Store new information
$strStatus = "OK";
if (!$block->setShareId($aBlock['id'], $iCurrentUpstreamId))
$strStatus = "Share ID Failed";
if (!$block->setFinder($aBlock['id'], $iAccountId))
$strStatus = "Finder Failed";
if (!$block->setShares($aBlock['id'], $iRoundShares))
$strStatus = "Shares Failed";
if ($config['block_bonus'] > 0 && !$transaction->addTransaction($iAccountId, $config['block_bonus'], 'Bonus', $aBlock['id'])) {
$strStatus = "Bonus Failed";
}
verbose(
$aBlock['id'] . "\t\t"
. $aBlock['height'] . "\t\t"
. $iCurrentUpstreamId . "\t\t"
. $iRoundShares . "\t"
. "[$iAccountId] " . $user->getUserName($iAccountId) . "\t\t"
. $strStatus
. "\n"
);
// Notify users
$aAccounts = $notification->getNotificationAccountIdByType('new_block');
if (is_array($aAccounts)) {
foreach ($aAccounts as $aData) {
$aMailData['height'] = $aBlock['height'];
$aMailData['subject'] = 'New Block';
$aMailData['email'] = $user->getUserEmail($user->getUserName($aData['account_id']));
$aMailData['shares'] = $iRoundShares;
$notification->sendNotification($aData['account_id'], 'new_block', $aMailData);
}
}
}
// Store new information
$strStatus = "OK";
if (!$block->setShareId($aBlock['id'], $iCurrentUpstreamId))
$strStatus = "Share ID Failed";
if (!$block->setFinder($aBlock['id'], $iAccountId))
$strStatus = "Finder Failed";
verbose(
$aBlock['id'] . "\t\t"
. $aBlock['height'] . "\t\t"
. $iCurrentUpstreamId . "\t\t"
. "[$iAccountId] " . $user->getUserName($iAccountId) . "\t\t"
. $strStatus
. "\n"
);
}
}
?>

56
cronjobs/notifications.php Executable file
View File

@ -0,0 +1,56 @@
#!/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');
// Find all IDLE workers
$aWorkers = $worker->getAllIdleWorkers();
if (empty($aWorkers)) {
verbose("No idle workers found\n");
} else {
foreach ($aWorkers as $aWorker) {
$aData = $aWorker;
$aData['username'] = $user->getUserName($aWorker['account_id']);
$aData['subject'] = 'IDLE Worker : ' . $aWorker['username'];
$aData['worker'] = $aWorker['username'];
$aData['email'] = $user->getUserEmail($aData['username']);
if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData))
verbose($notification->getError() . "\n");
}
}
// We notified, lets check which recovered
$aNotifications = $notification->getAllActive('idle_worker');
if (!empty($aNotifications)) {
foreach ($aNotifications as $aNotification) {
$aData = json_decode($aNotification['data'], true);
$aWorker = $worker->getWorker($aData['id']);
if ($aWorker['active'] == 1) {
if ($notification->setInactive($aNotification['id'])) {
verbose("Marked notification " . $aNotification['id'] . " as inactive\n");
} else {
verbose("Failed to set notification inactive for " . $aWorker['username'] . "\n");
}
}
}
}
?>

127
cronjobs/pps_payout.php Executable file
View File

@ -0,0 +1,127 @@
#!/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'] != 'pps') {
verbose("Please activate this cron in configuration via payout_system = pps\n");
exit(0);
}
// Fetch all transactions since our last block
if ( $bitcoin->can_connect() === true ){
$dDifficulty = $bitcoin->getdifficulty();
} else {
verbose("Aborted: " . $bitcoin->can_connect() . "\n");
exit(1);
}
// Value per share calculation
$pps_value = number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12);
// Find our last share accounted and last inserted share for PPS calculations
$iPreviousShareId = $setting->getValue('pps_last_share_id');
$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);
verbose("ID\tUsername\tInvalid\tValid\t\tPPS Value\t\tPayout\t\tDonation\tFee\t\tStatus\n");
foreach ($aAccountShares as $aData) {
// Take our valid shares and multiply by per share value
$aData['payout'] = number_format(round($aData['valid'] * $pps_value, 8), 8);
// Defaults
$aData['fee' ] = 0;
$aData['donation'] = 0;
// Calculate block fees
if ($config['fees'] > 0)
$aData['fee'] = number_format(round($config['fees'] / 100 * $aData['payout'], 8), 8);
// Calculate donation amount
$aData['donation'] = number_format(round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8), 8);
verbose($aData['id'] . "\t" .
$aData['username'] . "\t" .
$aData['invalid'] . "\t" .
$aData['valid'] . "\t*\t" .
$pps_value . "\t=\t" .
$aData['payout'] . "\t" .
$aData['donation'] . "\t" .
$aData['fee'] . "\t");
$strStatus = "OK";
// Add new credit transaction
if (!$transaction->addTransaction($aData['id'], $aData['payout'], 'Credit_PPS'))
$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_PPS'))
$strStatus = "Fee Failed";
// Add new donation debit
if ($aData['donation'] > 0)
if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation_PPS'))
$strStatus = "Donation Failed";
verbose($strStatus . "\n");
}
// Store our last inserted ID for the next run
$setting->setValue('pps_last_share_id', $iLastShareId);
verbose("\n\n------------------------------------------------------------------------------------\n\n");
// Fetch all unaccounted blocks
$aAllBlocks = $block->getAllUnaccounted('ASC');
if (empty($aAllBlocks)) {
verbose("No new unaccounted blocks found\n");
}
// Go through blocks and archive/delete shares that have been accounted for
foreach ($aAllBlocks as $iIndex => $aBlock) {
// If we are running through more than one block, check for previous share ID
$iLastBlockShare = @$aAllBlocks[$iIndex - 1]['share_id'] ? @$aAllBlocks[$iIndex - 1]['share_id'] : 0;
// Per account statistics
$aAccountShares = $share->getSharesForAccounts(@$iLastBlockShare, $aBlock['share_id']);
foreach ($aAccountShares as $key => $aData) {
if (!$statistics->updateShareStatistics($aData, $aBlock['id']))
verbose("Failed to update stats for this block on : " . $aData['username'] . "\n");
}
// Move shares to archive
if ($config['archive_shares'] && $aBlock['share_id'] < $iLastShareId) {
if (!$share->moveArchive($aBlock['share_id'], $aBlock['id'], @$iLastBlockShare))
verbose("Archving failed\n");
}
// Delete shares
if ($aBlock['share_id'] < $iLastShareId && !$share->deleteAccountedShares($aBlock['share_id'], $iLastBlockShare)) {
verbose("\nERROR : Failed to delete accounted shares from " . $aBlock['share_id'] . " to " . $iLastBlockShare . ", 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");
exit(1);
}
}
?>

View File

@ -22,6 +22,12 @@ 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'] != 'prop') {
verbose("Please activate this cron in configuration via payout_system = prop\n");
exit(0);
}
// Fetch all unaccounted blocks
$aAllBlocks = $block->getAllUnaccounted('ASC');
if (empty($aAllBlocks)) {
@ -32,25 +38,16 @@ if (empty($aAllBlocks)) {
$count = 0;
foreach ($aAllBlocks as $iIndex => $aBlock) {
if (!$aBlock['accounted']) {
$iPreviousShareId = $aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
$iPreviousShareId = @$aAllBlocks[$iIndex - 1]['share_id'] ? $aAllBlocks[$iIndex - 1]['share_id'] : 0;
$iCurrentUpstreamId = $aBlock['share_id'];
$aAccountShares = $share->getSharesForAccounts($iPreviousShareId, $aBlock['share_id']);
$iRoundShares = $share->getRoundShares($iPreviousShareId, $aBlock['share_id']);
// Table header for block details
verbose("ID\tHeight\tTime\t\tShares\tFinder\t\tShare ID\tPrev Share\t\tStatus\n");
verbose($aBlock['id'] . "\t" . $aBlock['height'] . "\t" . $aBlock['time'] . "\t" . $iRoundShares . "\t" . $user->getUserName($aBlock['account_id']) . "\t" . $iCurrentUpstreamId . "\t\t" . $iPreviousShareId);
if (empty($aAccountShares)) {
verbose("\nNo shares found for this block\n\n");
sleep(2);
continue;
}
$strStatus = "OK";
// Store share information for this block
if (!$block->setShares($aBlock['id'], $iRoundShares))
$strStatus = "Shares Failed";
verbose("\t\t$strStatus\n\n");
// Table header for account shares
verbose("ID\tUsername\tValid\tInvalid\tPercentage\tPayout\t\tDonation\tFee\t\tStatus\n");

View File

@ -16,7 +16,7 @@ PIDFILE='/tmp/mmcfe-ng-cron.pid'
CRONHOME='.'
# List of cruns to execute
CRONS="findblock.php proportional_payout.php blockupdate.php auto_payout.php tickerupdate.php"
CRONS="findblock.php proportional_payout.php pps_payout.php blockupdate.php auto_payout.php tickerupdate.php notifications.php statistics.php"
# Additional arguments to pass to cronjobs
CRONARGS="-v"

View File

@ -26,10 +26,10 @@ define("BASEPATH", "../public/");
define("SECURITY", 1);
// Include our configuration (holding defines for the requires)
require_once(BASEPATH . '/include/config/global.inc.php');
require_once(BASEPATH . 'include/config/global.inc.php');
// We include all needed files here, even though our templates could load them themself
require_once(BASEPATH . INCLUDE_DIR . '/autoloader.inc.php');
require_once(INCLUDE_DIR . '/autoloader.inc.php');
// Parse command line
$options = getopt("v");

49
cronjobs/statistics.php Executable file
View File

@ -0,0 +1,49 @@
#!/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');
// Fetch all cachable values but disable fetching from cache
$statistics->setGetCache(false);
// Since fetching from cache is disabled, overwrite our stats
if (!$statistics->getRoundShares())
verbose("Unable to fetch and store current round shares\n");
if (!$statistics->getTopContributors('shares'))
verbose("Unable to fetch and store top share contributors\n");
if (!$statistics->getTopContributors('hashes'))
verbose("Unable to fetch and store top hashrate contributors\n");
if (!$statistics->getCurrentHashrate())
verbose("Unable to fetch and store pool hashrate\n");
// Admin specific statistics, we cache the global query due to slowness
if (!$statistics->getAllUserStats('%'))
verbose("Unable to fetch and store admin panel full user list\n");
// Per user share statistics based on all shares submitted
$stmt = $mysqli->prepare("SELECT DISTINCT SUBSTRING_INDEX( `username` , '.', 1 ) AS username FROM " . $share->getTableName());
if ($stmt && $stmt->execute() && $result = $stmt->get_result()) {
while ($row = $result->fetch_assoc()) {
if (!$statistics->getUserShares($user->getUserId($row['username'])))
verbose("Failed to fetch and store user stats for " . $row['username'] . "\n");
}
}
?>

View File

@ -14,3 +14,5 @@ require_once(CLASS_DIR . '/worker.class.php');
require_once(CLASS_DIR . '/statistics.class.php');
require_once(CLASS_DIR . '/transaction.class.php');
require_once(CLASS_DIR . '/setting.class.php');
require_once(CLASS_DIR . '/mail.class.php');
require_once(CLASS_DIR . '/notification.class.php');

View File

@ -246,8 +246,8 @@ class BitcoinClientException extends ErrorException {
}
}
require_once(BASEPATH . INCLUDE_DIR . "/xmlrpc.inc.php");
require_once(BASEPATH . INCLUDE_DIR . "/jsonrpc.inc.php");
require_once(INCLUDE_DIR . "/xmlrpc.inc.php");
require_once(INCLUDE_DIR . "/jsonrpc.inc.php");
/**
* Bitcoin client class for access to a Bitcoin server via JSON-RPC-HTTP[S]

View File

@ -43,6 +43,18 @@ class Block {
return false;
}
/**
* Get our last, highest share ID inserted for a block
* @param none
* @return int data Share ID
**/
public function getLastShareId() {
$stmt = $this->mysqli->prepare("SELECT MAX(share_id) AS share_id FROM $this->table LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_object()->share_id;
return false;
}
/**
* Fetch all unaccounted blocks
* @param order string Sort order, default ASC

View File

@ -0,0 +1,67 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
class Mail {
private $sError = '';
public function setDebug($debug) {
$this->debug = $debug;
}
public function setMysql($mysqli) {
$this->mysqli = $mysqli;
}
public function setSmarty($smarty) {
$this->smarty = $smarty;
}
public function setUser($user) {
$this->user = $user;
}
public function setConfig($config) {
$this->config = $config;
}
public function setErrorMessage($msg) {
$this->sError = $msg;
}
public function getError() {
return $this->sError;
}
function checkStmt($bState) {
$this->debug->append("STA " . __METHOD__, 4);
if ($bState ===! true) {
$this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
$this->setErrorMessage('Internal application Error');
return false;
}
return true;
}
public function sendMail($template, $aData) {
$this->smarty->assign('WEBSITENAME', $this->config['website']['name']);
$this->smarty->assign('SUBJECT', $aData['subject']);
$this->smarty->assign('DATA', $aData);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
$headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
if (mail($aData['email'],
$this->smarty->fetch(BASEPATH . 'templates/mail/subject.tpl'),
$this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'),
$headers)) {
return true;
} else {
$this->setErrorMessage("Unable to send mail");
return false;
}
return false;
}
}
// Make our class available automatically
$mail = new Mail ();
$mail->setDebug($debug);
$mail->setMysql($mysqli);
$mail->setSmarty($smarty);
$mail->setConfig($config);
?>

View File

@ -0,0 +1,191 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
class Notification extends Mail {
var $table = 'notifications';
var $tableSettings = 'notification_settings';
public function setInactive($id) {
$field = array(
'name' => 'active',
'type' => 'i',
'value' => 0
);
return $this->updateSingle($id, $field);
}
/**
* Update a single row in a table
* @param userID int Account ID
* @param field string Field to update
* @return bool
**/
private function updateSingle($id, $field, $table='') {
if (empty($table)) $table = $this->table;
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("UPDATE $table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
return true;
$this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");
return false;
}
/**
* We check our notification table for existing data
* so we can avoid duplicate entries
**/
public function isNotified($aData) {
$this->debug->append("STA " . __METHOD__, 4);
$data = json_encode($aData);
$stmt = $this->mysqli->prepare("SELECT id FROM $this->table WHERE data = ? AND active = 1 LIMIT 1");
if ($stmt && $stmt->bind_param('s', $data) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows == 1)
return true;
// Catchall
// Does not seem to have a notification set
return false;
}
/**
* Get all active notifications
**/
public function getAllActive($strType) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt =$this->mysqli->prepare("SELECT id, data FROM $this->table WHERE active = 1 AND type = ?");
if ($stmt && $stmt->bind_param('s', $strType) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_all(MYSQLI_ASSOC);
// Catchall
return false;
}
/**
* Add a new notification to the table
* @param type string Type of the notification
* @return bool
**/
public function addNotification($account_id, $type, $data) {
$this->debug->append("STA " . __METHOD__, 4);
// Store notification data as json
$data = json_encode($data);
$stmt = $this->mysqli->prepare("INSERT INTO $this->table (account_id, type, data, active) VALUES (?, ?,?,1)");
if ($stmt && $stmt->bind_param('iss', $account_id, $type, $data) && $stmt->execute())
return true;
$this->debug->append("Failed to add notification for $type with $data: " . $this->mysqli->error);
$this->setErrorMessage("Unable to add new notification " . $this->mysqli->error);
return false;
}
/**
* Fetch notifications for a user account
* @param id int Account ID
* @return array Notification data
**/
public function getNofifications($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE account_id = ? ORDER BY time DESC");
if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_all(MYSQLI_ASSOC);
// Catchall
return false;
}
/**
* Fetch notification settings for user account
* @param id int Account ID
* @return array Notification settings
**/
public function getNotificationSettings($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("SELECT * FROM $this->tableSettings WHERE account_id = ?");
if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
while ($row = $result->fetch_assoc()) {
$aData[$row['type']] = $row['active'];
}
return $aData;
}
// Catchall
return false;
}
/**
* Get all accounts that wish to receive a specific notification
* @param strType string Notification type
* @return data array User Accounts
**/
public function getNotificationAccountIdByType($strType) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("SELECT account_id FROM $this->tableSettings WHERE type = ? AND active = 1");
if ($stmt && $stmt->bind_param('s', $strType) && $stmt->execute() && $result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_ASSOC);
}
// Catchall
return false;
}
/**
* Update accounts notification settings
* @param account_id int Account ID
* @param data array Data array
* @return bool
**/
public function updateSettings($account_id, $data) {
$this->debug->append("STA " . __METHOD__, 4);
$failed = $ok = 0;
foreach ($data as $type => $active) {
// Does an entry exist already
$stmt = $this->mysqli->prepare("SELECT * FROM $this->tableSettings WHERE account_id = ? AND type = ?");
if ($stmt && $stmt->bind_param('is', $account_id, $type) && $stmt->execute() && $stmt->store_result() && $stmt->num_rows() > 0) {
// We found a matching row
$stmt = $this->mysqli->prepare("UPDATE $this->tableSettings SET active = ? WHERE type = ? AND account_id = ?");
if ($stmt && $stmt->bind_param('isi', $active, $type, $account_id) && $stmt->execute() && $stmt->close()) {
$ok++;
} else {
$failed++;
}
} else {
$stmt = $this->mysqli->prepare("INSERT INTO $this->tableSettings (active, type, account_id) VALUES (?,?,?)");
if ($stmt && $stmt->bind_param('isi', $active, $type, $account_id) && $stmt->execute()) {
$ok++;
} else {
$failed++;
}
}
}
if ($failed > 0) {
$this->setErrorMessage('Failed to update ' . $failed . ' settings');
return false;
}
return true;
}
/**
* Send a specific notification setup in notification_settings
* @param type string Notification type
* @return bool
**/
public function sendNotification($account_id, $strType, $aMailData) {
// Check if we notified for this event already
if ( $this->isNotified($aMailData) ) {
$this->setErrorMessage('A notification for this event has been sent already');
return false;
}
// Check if this user wants strType notifications
$stmt = $this->mysqli->prepare("SELECT account_id FROM $this->tableSettings WHERE type = ? AND active = 1 AND account_id = ?");
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('User disabled ' . $strType . ' notifications');
}
return false;
}
}
$notification = new Notification();
$notification->setDebug($debug);
$notification->setMysql($mysqli);
$notification->setSmarty($smarty);
$notification->setConfig($config);
?>

View File

@ -44,6 +44,21 @@ class Share {
return $this->table;
}
/**
* Get last inserted Share ID from Database
* Used for PPS calculations without moving to archive
**/
public function getLastInsertedShareId() {
$stmt = $this->mysqli->prepare("
SELECT MAX(id) AS id FROM $this->table
");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_object()->id;
// Catchall
$this->setErrorMessage('Failed to fetch last inserted share ID');
return false;
}
/**
* Get all valid shares for this round
* @param previous_upstream int Previous found share accepted by upstream to limit results
@ -172,7 +187,8 @@ class Share {
ORDER BY id ASC LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $last) && $stmt->execute() && $result = $stmt->get_result()) {
$this->oUpstream = $result->fetch_object();
return true;
if (!empty($this->oUpstream->account) && is_int($this->oUpstream->id))
return true;
}
// Catchall
return false;

View File

@ -13,6 +13,7 @@ if (!defined('SECURITY'))
class Statistics {
private $sError = '';
private $table = 'statistics_shares';
private $getcache = true;
public function __construct($debug, $mysqli, $config, $share, $user, $block, $memcache) {
$this->debug = $debug;
@ -34,6 +35,14 @@ class Statistics {
return $this->sError;
}
// Disable fetching values from cache
public function setGetCache($set=false) {
$this->getcache = $set;
}
public function getGetCache() {
return $this->getcache;
}
private function checkStmt($bState) {
if ($bState ===! true) {
$this->debug->append("Failed to prepare statement: " . $this->mysqli->error);
@ -54,7 +63,7 @@ class Statistics {
$stmt = $this->mysqli->prepare("
SELECT b.*, a.username as finder
FROM " . $this->block->getTableName() . " AS b
LEFT JOIN accounts AS a
LEFT JOIN " . $this->user->getTableName() . " AS a
ON b.account_id = a.id
ORDER BY height DESC LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
@ -88,14 +97,10 @@ class Statistics {
**/
public function getCurrentHashrate() {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__)) return $data;
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT SUM(hashrate) AS hashrate FROM
(
SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
UNION
SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
) AS sum");
SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
");
// Catchall
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->hashrate);
$this->debug->append("Failed to get hashrate: " . $this->mysqli->error);
@ -111,12 +116,8 @@ class Statistics {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT ROUND(SUM(sharerate) / 600, 2) AS sharerate FROM
(
SELECT COUNT(id) AS sharerate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
UNION ALL
SELECT COUNT(id) AS sharerate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
) AS sum");
SELECT ROUND(COUNT(id) / 600, 2) AS sharerate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->sharerate);
// Catchall
$this->debug->append("Failed to fetch share rate: " . $this->mysqli->error);
@ -130,7 +131,7 @@ class Statistics {
**/
public function getRoundShares() {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__)) return $data;
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
( SELECT IFNULL(count(id), 0)
@ -155,7 +156,7 @@ class Statistics {
**/
public function getUserShares($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
(
@ -183,12 +184,42 @@ class Statistics {
return false;
}
/**
* Admin panel specific query
* @return data array invlid and valid shares for all accounts
**/
public function getAllUserStats($filter='%') {
$this->debug->append("STA " . __METHOD__, 4);
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $filter)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
a.id AS id,
a.is_admin as is_admin,
a.is_locked as is_locked,
a.username AS username,
a.donate_percent AS donate_percent,
a.email AS email,
COUNT(s.id) AS shares
FROM " . $this->user->getTableName() . " AS a
LEFT JOIN " . $this->share->getTableName() . " AS s
ON a.username = SUBSTRING_INDEX( s.username, '.', 1 )
WHERE
a.username LIKE ?
GROUP BY username
ORDER BY username
");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $filter) && $stmt->execute() && $result = $stmt->get_result()) {
return $this->memcache->setCache(__FUNCTION__ . $filter, $result->fetch_all(MYSQLI_ASSOC));
}
}
/**
* Same as getUserShares for Hashrate
* @param account_id integer User ID
* @return data integer Current Hashrate in khash/s
**/
public function getUserHashrate($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) AS hashrate
@ -204,6 +235,28 @@ class Statistics {
return false;
}
/**
* Same as getUserHashrate for Sharerate
* @param account_id integer User ID
* @return data integer Current Sharerate in shares/s
**/
public function getUserSharerate($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT COUNT(s.id)/600 AS sharerate
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 10 MINUTE)
AND u.id = ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result() )
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_object()->sharerate);
// Catchall
$this->debug->append("Failed to fetch sharerate: " . $this->mysqli->error);
return false;
}
/**
* Get hashrate for a specific worker
* @param worker_id int Worker ID to fetch hashrate for
@ -234,7 +287,7 @@ class Statistics {
**/
public function getTopContributors($type='shares', $limit=15) {
$this->debug->append("STA " . __METHOD__, 4);
if ($data = $this->memcache->get(__FUNCTION__ . $type . $limit)) return $data;
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $type . $limit)) return $data;
switch ($type) {
case 'shares':
$stmt = $this->mysqli->prepare("
@ -242,6 +295,7 @@ class Statistics {
COUNT(id) AS shares,
SUBSTRING_INDEX( username, '.', 1 ) AS account
FROM " . $this->share->getTableName() . "
WHERE our_result = 'Y'
GROUP BY account
ORDER BY shares DESC
LIMIT ?");
@ -258,6 +312,7 @@ class Statistics {
SUBSTRING_INDEX( username, '.', 1 ) AS account
FROM " . $this->share->getTableName() . "
WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE)
AND our_result = 'Y'
GROUP BY account
ORDER BY hashrate DESC LIMIT ?");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result())
@ -270,7 +325,6 @@ class Statistics {
/**
* get Hourly hashrate for a user
* Not working yet since I was not able to solve this via SQL queries
* @param account_id int User ID
* @return data array NOT FINISHED YET
**/
@ -279,24 +333,50 @@ class Statistics {
if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
ROUND(COUNT(s.id) * POW(2, 12)/600/1000) AS hashrate,
ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ") / 3600 / 1000) AS hashrate,
HOUR(s.time) AS hour
FROM " . $this->share->getTableName() . " AS s, accounts AS a
WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
FROM " . $this->share->getTableName() . " AS s, accounts AS a
WHERE time < NOW() - INTERVAL 1 HOUR
AND time > NOW() - INTERVAL 25 HOUR
AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
AND a.id = ?
GROUP BY HOUR(time)
UNION ALL
SELECT
ROUND(COUNT(s.id) * POW(2, 12)/600/1000) AS hashrate,
HOUR(s.time) AS hour
FROM " . $this->share->getArchiveTableName() . " AS s, accounts AS a
WHERE time < NOW() - INTERVAL 1 HOUR AND time > NOW() - INTERVAL 25 HOUR
AND a.username = SUBSTRING_INDEX( s.username, '.', 1 )
AND a.id = ?
GROUP BY HOUR(time)");
if ($this->checkStmt($stmt) && $stmt->bind_param("ii", $account_id, $account_id) && $stmt->execute() && $result = $stmt->get_result())
return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_all(MYSQLI_ASSOC), 3600);
GROUP BY HOUR(time)
");
if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result()) {
$aData = array();
while ($row = $result->fetch_assoc()) {
$aData[$row['hour']] = $row['hashrate'];
}
return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData);
}
// Catchall
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
return false;
}
/**
* get Hourly hashrate for the pool
* @param none
* @return data array NOT FINISHED YET
**/
public function getHourlyHashrateByPool() {
$this->debug->append("STA " . __METHOD__, 4);
if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data;
$stmt = $this->mysqli->prepare("
SELECT
ROUND(COUNT(s.id) * POW(2, " . $this->config['difficulty'] . ") / 3600 / 1000) AS hashrate,
HOUR(s.time) AS hour
FROM " . $this->share->getTableName() . " AS s
WHERE time < NOW() - INTERVAL 1 HOUR
AND time > NOW() - INTERVAL 25 HOUR
GROUP BY HOUR(time)
");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) {
while ($row = $result->fetch_assoc()) {
$aData[$row['hour']] = $row['hashrate'];
}
return $this->memcache->setCache(__FUNCTION__, @$aData);
}
// Catchall
$this->debug->append("Failed to fetch hourly hashrate: " . $this->mysqli->error);
return false;

View File

@ -55,35 +55,23 @@ class Transaction {
**/
public function setOrphan($block_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = 'Orphan_Credit'
WHERE type = 'Credit'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan credit transactions for $block_id");
return false;
}
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = 'Orphan_Fee'
WHERE type = 'Fee'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan fee transactions for $block_id");
return false;
}
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = 'Orphan_Donation'
WHERE type = 'Donation'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan donation transactions for $block_id");
return false;
$aOrphans = array(
'Credit' => 'Orphan_Credit',
'Fee' => 'Orphan_Fee',
'Donation' => 'Orphan_Donation',
'Bonus' => 'Orphan_Bonus'
);
foreach ($aOrphans as $from => $to) {
$stmt = $this->mysqli->prepare("
UPDATE $this->table
SET type = '$to'
WHERE type = '$from'
AND block_id = ?
");
if (!($this->checkStmt($stmt) && $stmt->bind_param('i', $block_id) && $stmt->execute())) {
$this->debug->append("Failed to set orphan $from => $to transactions for $block_id");
return false;
}
}
return true;
}
@ -130,6 +118,7 @@ class Transaction {
/**
* Get total balance for all users locked in wallet
* This includes any outstanding unconfirmed transactions!
* @param none
* @return data double Amount locked for users
**/
@ -142,8 +131,10 @@ class Transaction {
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type = 'Credit'
AND b.confirmations >= ?
WHERE (
( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR
( t.type = 'Credit_PPS' )
)
) AS t1,
(
SELECT sum(t.amount) AS debit
@ -152,10 +143,12 @@ class Transaction {
) AS t2,
(
SELECT sum(t.amount) AS other
FROM transactions AS t
FROM " . $this->table . " AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type IN ('Donation','Fee')
AND b.confirmations >= ?
WHERE (
( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
t.type IN ('Donation_PPS','Fee_PPS','TXFee')
)
) AS t3");
if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $this->config['confirmations'], $this->config['confirmations']) && $stmt->execute() && $stmt->bind_result($dBalance) && $stmt->fetch())
return $dBalance;
@ -173,14 +166,19 @@ class Transaction {
public function getBalance($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
SELECT ROUND(IFNULL(t1.credit, 0) - IFNULL(t2.debit, 0) - IFNULL(t3.other, 0), 8) AS balance
SELECT
ROUND(IFNULL(t1.credit, 0) - IFNULL(t2.debit, 0) - IFNULL(t3.other, 0), 8) AS confirmed,
ROUND(IFNULL(t4.credit, 0) - IFNULL(t5.other, 0), 8) AS unconfirmed
FROM
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type = 'Credit'
AND b.confirmations >= ?
WHERE
(
( t.type IN ('Credit','Bonus') AND b.confirmations >= ? ) OR
( t.type = 'Credit_PPS' )
)
AND t.account_id = ?
) AS t1,
(
@ -193,20 +191,41 @@ class Transaction {
SELECT sum(t.amount) AS other
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE t.type IN ('Donation','Fee')
AND b.confirmations >= ?
WHERE
(
( t.type IN ('Donation','Fee') AND b.confirmations >= ? ) OR
( t.type IN ('Donation_PPS', 'Fee_PPS', 'TXFee') )
)
AND t.account_id = ?
) AS t3
) AS t3,
(
SELECT sum(t.amount) AS credit
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE
t.type IN ('Credit','Bonus') AND b.confirmations < ?
AND t.account_id = ?
) AS t4,
(
SELECT sum(t.amount) AS other
FROM $this->table AS t
LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id
WHERE
(
t.type IN ('Donation','Fee') AND b.confirmations < ?
)
AND t.account_id = ?
) AS t5
");
if ($this->checkStmt($stmt)) {
$stmt->bind_param("iiiii", $this->config['confirmations'], $account_id, $account_id, $this->config['confirmations'], $account_id);
$stmt->bind_param("iiiiiiiii", $this->config['confirmations'], $account_id, $account_id, $this->config['confirmations'], $account_id, $this->config['confirmations'], $account_id, $this->config['confirmations'], $account_id);
if (!$stmt->execute()) {
$this->debug->append("Unable to execute statement: " . $stmt->error);
$this->setErrorMessage("Fetching balance failed");
}
$result = $stmt->get_result();
$stmt->close();
return $result->fetch_object()->balance;
return $result->fetch_assoc();
}
return false;
}

View File

@ -26,35 +26,75 @@ class User {
public function getError() {
return $this->sError;
}
public function getUserName($id) {
return $this->getSingle($id, 'username', 'id');
}
public function getUserId($username) {
return $this->getSingle($username, 'id', 'username', 's');
}
public function getUserEmail($username) {
return $this->getSingle($username, 'email', 'username', 's');
}
public function getUserAdmin($id) {
return $this->getSingle($id, 'is_admin', 'id');
}
public function getUserLocked($id) {
return $this->getSingle($id, 'is_locked', 'id');
}
public function getUserToken($id) {
return $this->getSingle($id, 'token', 'id');
}
public function getUserIp($id) {
return $this->getSingle($id, 'loggedIp', 'id');
}
public function getUserFailed($id) {
return $this->getSingle($id, 'failed_logins', 'id');
}
public function getIdFromToken($token) {
return $this->getSingle($token, 'id', 'token', 's');
}
public function setUserToken($id) {
$field = array(
'name' => 'token',
'type' => 's',
'value' => hash('sha256', $id.time().$this->salt)
);
public function isLocked($id) {
return $this->getUserLocked($id);
}
public function isAdmin($id) {
return $this->getUserAdmin($id);
}
public function changeLocked($id) {
$field = array('name' => 'is_locked', 'type' => 'i', 'value' => !$this->isLocked($id));
return $this->updateSingle($id, $field);
}
public function changeAdmin($id) {
$field = array('name' => 'is_admin', 'type' => 'i', 'value' => !$this->isAdmin($id));
return $this->updateSingle($id, $field);
}
public function setUserToken($id) {
$field = array('name' => 'token', 'type' => 's', 'value' => hash('sha256', $id.time().$this->salt));
return $this->updateSingle($id, $field);
}
private function setUserFailed($id, $value) {
$field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $value);
return $this->updateSingle($id, $field);
}
private function incUserFailed($id) {
$field = array( 'name' => 'failed_logins', 'type' => 'i', 'value' => $this->getUserFailed($id) + 1);
return $this->updateSingle($id, $field);
}
private function setUserIp($id, $ip) {
$field = array( 'name' => 'loggedIp', 'type' => 's', 'value' => $ip );
return $this->updateSingle($id, $field);
}
/**
* Fetch all users for administrative tasks
* @param none
* @return data array All users with db columns as array fields
**/
public function getUsers($filter='%') {
$stmt = $this->mysqli->prepare("SELECT * FROM " . $this->getTableName() . " WHERE username LIKE ?");
if ($this->checkStmt($stmt) && $stmt->bind_param('s', $filter) && $stmt->execute() && $result = $stmt->get_result()) {
return $result->fetch_all(MYSQLI_ASSOC);
}
}
/**
* Check user login
@ -65,10 +105,20 @@ class User {
public function checkLogin($username, $password) {
$this->debug->append("STA " . __METHOD__, 4);
$this->debug->append("Checking login for $username with password $password", 2);
if ( $this->checkUserPassword($username, $password) ) {
if ($this->isLocked($this->getUserId($username))) {
$this->setErrorMessage("Account is locked. Please contact site support.");
return false;
}
if ( $this->checkUserPassword($username, $password)) {
$this->createSession($username);
$this->setUserFailed($this->getUserId($username), 0);
$this->setUserIp($this->getUserId($username), $_SERVER['REMOTE_ADDR']);
return true;
}
$this->setErrorMessage("Invalid username or password");
if ($id = $this->getUserId($username))
$this->incUserFailed($id);
return false;
}
@ -166,7 +216,7 @@ class User {
**/
private function updateSingle($id, $field) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("UPDATE $this->table SET " . $field['name'] . " = ? WHERE id = ? LIMIT 1");
$stmt = $this->mysqli->prepare("UPDATE $this->table SET `" . $field['name'] . "` = ? WHERE id = ? LIMIT 1");
if ($this->checkStmt($stmt) && $stmt->bind_param($field['type'].'i', $field['value'], $id) && $stmt->execute())
return true;
$this->debug->append("Unable to update " . $field['name'] . " with " . $field['value'] . " for ID $id");
@ -224,20 +274,40 @@ class User {
* @param donat float donation % of income
* @return bool
**/
public function updateAccount($userID, $address, $threshold, $donate) {
public function updateAccount($userID, $address, $threshold, $donate, $email) {
$this->debug->append("STA " . __METHOD__, 4);
$bUser = false;
$threshold = min(250, max(0, floatval($threshold)));
if ($threshold < 1) $threshold = 0.0;
// number validation checks
if ($threshold < $this->config['ap_threshold']['min'] && $threshold != 0) {
$this->setErrorMessage('Threshold below configured minimum of ' . $this->config['ap_threshold']['min']);
return false;
} else if ($threshold > $this->config['ap_threshold']['max']) {
$this->setErrorMessage('Threshold above configured maximum of ' . $this->config['ap_threshold']['max']);
return false;
}
if ($donate < 0) {
$this->setErrorMessage('Donation below allowed 0% limit');
return false;
} else if ($donate > 100) {
$this->setErrorMessage('Donation above allowed 100% limit');
return false;
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$this->setErrorMessage('Invalid email address');
return false;
}
// Number sanitizer, just in case we fall through above
$threshold = min($this->config['ap_threshold']['max'], max(0, floatval($threshold)));
$donate = min(100, max(0, floatval($donate)));
$stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ? WHERE id = ?");
$stmt->bind_param('sddi', $address, $threshold, $donate, $userID);
$stmt->execute();
if ( $stmt->errno == 0 ) {
$stmt->close();
// We passed all validation checks so update the account
$stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ?, email = ? WHERE id = ?");
if ($this->checkStmt($stmt) && $stmt->bind_param('sddsi', $address, $threshold, $donate, $email, $userID) && $stmt->execute())
return true;
}
// Catchall
$this->setErrorMessage('Failed to update your account');
$this->debug->append('Account update failed: ' . $this->mysqli->error);
return false;
}
@ -266,15 +336,15 @@ class User {
private function checkUserPassword($username, $password) {
$this->debug->append("STA " . __METHOD__, 4);
$user = array();
$stmt = $this->mysqli->prepare("SELECT username, id FROM $this->table WHERE username=? AND pass=? LIMIT 1");
$stmt = $this->mysqli->prepare("SELECT username, id, is_admin FROM $this->table WHERE username=? AND pass=? LIMIT 1");
if ($this->checkStmt($stmt)) {
$stmt->bind_param('ss', $username, hash('sha256', $password.$this->salt));
$stmt->execute();
$stmt->bind_result($row_username, $row_id);
$stmt->bind_result($row_username, $row_id, $row_admin);
$stmt->fetch();
$stmt->close();
// Store the basic login information
$this->user = array('username' => $row_username, 'id' => $row_id);
$this->user = array('username' => $row_username, 'id' => $row_id, 'is_admin' => $row_admin);
return $username === $row_username;
}
return false;
@ -303,7 +373,8 @@ class User {
$this->debug->append("STA " . __METHOD__, 4);
session_destroy();
session_regenerate_id(true);
return true;
// Enforce a page reload
header("Location: index.php");
}
/**
@ -325,7 +396,7 @@ class User {
$this->debug->append("Fetching user information for user id: $userID");
$stmt = $this->mysqli->prepare("
SELECT
id, username, pin, api_key, admin,
id, username, pin, api_key, is_admin, email,
IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold
FROM $this->table
WHERE id = ? LIMIT 0,1");
@ -363,7 +434,7 @@ class User {
$this->setErrorMessage( 'Password do not match' );
return false;
}
if (!empty($email1) && !filter_var($email1, FILTER_VALIDATE_EMAIL)) {
if (empty($email1) || !filter_var($email1, FILTER_VALIDATE_EMAIL)) {
$this->setErrorMessage( 'Invalid e-mail address' );
return false;
}
@ -383,7 +454,7 @@ class User {
");
} else {
$stmt = $this->mysqli->prepare("
INSERT INTO $this->table (username, pass, email, pin, api_key, admin)
INSERT INTO $this->table (username, pass, email, pin, api_key, is_admin)
VALUES (?, ?, ?, ?, ?, 1)
");
}
@ -455,6 +526,7 @@ class User {
}
$smarty->assign('TOKEN', $token);
$smarty->assign('USERNAME', $username);
$smarty->assign('SUBJECT', 'Password Reset Request');
$smarty->assign('WEBSITENAME', $this->config['website']['name']);
$headers = 'From: Website Administration <' . $this->config['website']['email'] . ">\n";
$headers .= "MIME-Version: 1.0\n";
@ -470,6 +542,22 @@ class User {
}
return false;
}
/**
* Check if a user is authenticated and allowed to login
* Checks the $_SESSION for existing data
* Destroys the session if account is now locked
* @param none
* @return bool
**/
public function isAuthenticated() {
$this->debug->append("STA " . __METHOD__, 4);
if (@$_SESSION['AUTHENTICATED'] == true && ! $this->isLocked($_SESSION['USERDATA']['id']) && $this->getUserIp($_SESSION['USERDATA']['id']) == $_SERVER['REMOTE_ADDR'])
return true;
// Catchall
$this->logoutUser();
return false;
}
}
// Make our class available automatically

View File

@ -43,17 +43,60 @@ class Worker {
public function updateWorkers($account_id, $data) {
$this->debug->append("STA " . __METHOD__, 4);
$username = $this->user->getUserName($account_id);
$iFailed = 0;
foreach ($data as $key => $value) {
// Prefix the WebUser to Worker name
$value['username'] = "$username." . $value['username'];
$stmt = $this->mysqli->prepare("UPDATE $this->table SET password = ?, username = ? WHERE account_id = ? AND id = ?");
if ($this->checkStmt($stmt)) {
if (!$stmt->bind_param('ssii', $value['password'], $value['username'], $account_id, $key)) return false;
if (!$stmt->execute()) return false;
$stmt->close();
}
$stmt = $this->mysqli->prepare("UPDATE $this->table SET password = ?, username = ?, monitor = ? WHERE account_id = ? AND id = ?");
if ( ! ( $this->checkStmt($stmt) && $stmt->bind_param('ssiii', $value['password'], $value['username'], $value['monitor'], $account_id, $key) && $stmt->execute()) )
$iFailed++;
}
return true;
if ($iFailed == 0)
return true;
// Catchall
$this->setErrorMessage('Failed to update ' . $iFailed . ' worker.');
return false;
}
/**
* Fetch all IDLE workers that have monitoring enabled
* @param none
* @return data array Workers in IDLE state and monitoring enabled
**/
public function getAllIdleWorkers() {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
SELECT account_id, id, username
FROM " . $this->table . "
WHERE monitor = 1 AND ( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) = 0");
if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_all(MYSQLI_ASSOC);
// Catchall
$this->setErrorMessage("Unable to fetch IDLE, monitored workers");
echo $this->mysqli->error;
return false;
}
/**
* Fetch a specific worker and its status
* @param id int Worker ID
* @return mixed array Worker details
**/
public function getWorker($id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
SELECT id, username, password, monitor,
( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS active,
( SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS hashrate
FROM $this->table
WHERE id = ?
");
if ($this->checkStmt($stmt) && $stmt->bind_param('i', $id) && $stmt->execute() && $result = $stmt->get_result())
return $result->fetch_assoc();
// Catchall
echo $this->mysqli->error;
return false;
}
/**
@ -64,7 +107,7 @@ class Worker {
public function getWorkers($account_id) {
$this->debug->append("STA " . __METHOD__, 4);
$stmt = $this->mysqli->prepare("
SELECT id, username, password,
SELECT id, username, password, monitor,
( SELECT SIGN(COUNT(id)) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS active,
( SELECT ROUND(COUNT(id) * POW(2, " . $this->config['difficulty'] . ")/600/1000) FROM " . $this->share->getTableName() . " WHERE username = $this->table.username AND time > DATE_SUB(now(), INTERVAL 10 MINUTE)) AS hashrate
FROM $this->table

View File

@ -23,13 +23,29 @@ define('SALT', 'PLEASEMAKEMESOMETHINGRANDOM');
$config = array(
'price' => array(
'url' => 'https://btc-e.com/api/2',
'target' => '/ltc_usd/ticker'
'target' => '/ltc_usd/ticker',
'currency' => 'USD' // Used in ministats template
),
'ap_threshold' => array(
'min' => 1,
'max' => 250
),
'website' => array(
'registration' => true, // Allow new users to register
'name' => 'The Pool',
'slogan' => 'Resistance is futile',
'email' => 'test@example.com', // Mail address used for notifications
),
// See: http://www.google.com/recaptcha
'recaptcha' => array(
'enabled' => false, // Enable re-captcha during registraion
'public_key' => 'YOUR_PUBLIC_RECAPTCHA_KEY',
'private_key' => 'YOUR_PRIVATE_RECAPTCHA_KEY'
),
'currency' => 'LTC', // Currency name to be used on website
'txfee' => 0.1, // Default tx fee added by RPC server
'block_bonus' => 0,
'payout_system' => 'prop', // Set your payout here so template changes are activated
'archive_shares' => true, // Store accounted shares in archive table?
'blockexplorer' => 'http://explorer.litecoin.net/search?q=', // URL for block searches, prefixed to each block number
'chaininfo' => 'http://allchains.info', // Link to Allchains for Difficulty information

View File

@ -1,13 +1,10 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if (!defined('SECURITY')) die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) {
header('Location: index.php?page=home');
if ($user->isAuthenticated()) {
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -4,61 +4,77 @@
if (!defined('SECURITY'))
die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) {
header('Location: index.php?page=home');
}
if ( ! $user->checkPin($_SESSION['USERDATA']['id'], $_POST['authPin']) && $_POST['do']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN','TYPE' => 'errormsg');
} else {
switch ($_POST['do']) {
case 'cashOut':
$continue = true;
$dBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
$sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
if ($dBalance > 0.1) {
if ($bitcoin->can_connect() === true) {
try {
$bitcoin->validateaddress($sCoinAddress);
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid payment address: ' . $sUserSendAddress, 'TYPE' => 'errormsg');
$continue = false;
}
if ($continue == true) {
// Remove the transfer fee and send to address
try {
$bitcoin->sendtoaddress($sCoinAddress, $dBalance - 0.1);
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send LTC, please contact site support immidiately', 'TYPE' => 'errormsg');
$continue = false;
}
}
// Set balance to 0, add to paid out, insert to ledger
if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance, 'Debit_MP', NULL, $sCoinAddress))
$_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
if ($user->isAuthenticated()) {
if ( ! $user->checkPin($_SESSION['USERDATA']['id'], @$_POST['authPin']) && @$_POST['do']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN','TYPE' => 'errormsg');
} else {
switch (@$_POST['do']) {
case 'cashOut':
if ($setting->getValue('manual_payout_active') == 1) {
$_SESSION['POPUP'][] = array('CONTENT' => 'A manual payout is in progress. Please try again later.', 'TYPE' => 'errormsg');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
$setting->setValue('manual_payout_active', 1);
$continue = true;
$aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']);
$dBalance = $aBalance['confirmed'];
$sCoinAddress = $user->getCoinAddress($_SESSION['USERDATA']['id']);
// Ensure we can cover the potential transaction fee
if ($dBalance > $config['txfee']) {
if ($bitcoin->can_connect() === true) {
try {
$bitcoin->validateaddress($sCoinAddress);
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid payment address: ' . $sUserSendAddress, 'TYPE' => 'errormsg');
$continue = false;
}
if ($continue == true) {
// Send balance to address, mind fee for transaction!
try {
if ($setting->getValue('auto_payout_active') == 0) {
$bitcoin->sendtoaddress($sCoinAddress, $dBalance);
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Auto-payout active, please contact site support immidiately to revoke invalid transactions.', 'TYPE' => 'errormsg');
$continue = false;
}
} catch (BitcoinClientException $e) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send ' . $config['currency'] . ', please contact site support immidiately', 'TYPE' => 'errormsg');
$continue = false;
}
}
// Set balance to 0, add to paid out, insert to ledger
if ($continue == true && $transaction->addTransaction($_SESSION['USERDATA']['id'], $dBalance - $config['txfee'], 'Debit_MP', NULL, $sCoinAddress) && $transaction->addTransaction($_SESSION['USERDATA']['id'], $config['txfee'], 'TXFee', NULL, $sCoinAddress) ) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Transaction completed', 'TYPE' => 'success');
$aMailData['email'] = $user->getUserEmail($user->getUserName($_SESSION['USERDATA']['id']));
$aMailData['amount'] = $dBalance;
$aMailData['subject'] = 'Manual Payout Completed';
$notification->sendNotification($_SESSION['USERDATA']['id'], 'manual_payout', $aMailData);
}
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service', 'TYPE' => 'errormsg');
}
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee'] . ' ' . $conifg['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg');
}
$setting->setValue('manual_payout_active', 0);
}
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than 0.1 LTC to cover transaction fees', 'TYPE' => 'errormsg');
}
break;
break;
case 'updateAccount':
if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account', 'TYPE' => 'errormsg');
}
break;
case 'updateAccount':
if ($user->updateAccount($_SESSION['USERDATA']['id'], $_POST['paymentAddress'], $_POST['payoutThreshold'], $_POST['donatePercent'], $_POST['email'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg');
}
break;
case 'updatePassword':
if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
case 'updatePassword':
if ($user->updatePassword($_SESSION['USERDATA']['id'], $_POST['currentPassword'], $_POST['newPassword'], $_POST['newPassword2'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'success');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg');
}
break;
}
break;
}
}

View File

@ -0,0 +1,25 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
if ($user->isAuthenticated()) {
if (@$_REQUEST['do'] == 'save') {
if ($notification->updateSettings($_SESSION['USERDATA']['id'], $_REQUEST['data'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update settings', 'TYPE' => 'errormsg');
}
}
// Fetch notifications
$aNotifications = $notification->getNofifications($_SESSION['USERDATA']['id']);
if (!$aNotifications) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any notifications', 'TYPE' => 'errormsg');
// Fetch user notification settings
$aSettings = $notification->getNotificationSettings($_SESSION['USERDATA']['id']);
$smarty->assign('NOTIFICATIONS', $aNotifications);
$smarty->assign('SETTINGS', $aSettings);
$smarty->assign('CONTENT', 'default.tpl');
}
?>

View File

@ -2,11 +2,10 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
$aTransactions = $transaction->getTransactions($_SESSION['USERDATA']['id']);
if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg');
$smarty->assign('TRANSACTIONS', $aTransactions);
$smarty->assign('CONTENT', 'default.tpl');
if ($user->isAuthenticated()) {
$aTransactions = $transaction->getTransactions($_SESSION['USERDATA']['id']);
if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg');
$smarty->assign('TRANSACTIONS', $aTransactions);
$smarty->assign('CONTENT', 'default.tpl');
}
?>

View File

@ -2,35 +2,38 @@
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
if (!$_SESSION['AUTHENTICATED']) header('Location: index.php?page=home');
switch ($_REQUEST['do']) {
case 'delete':
if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
if ($user->isAuthenticated()) {
switch (@$_REQUEST['do']) {
case 'delete':
if ($worker->deleteWorker($_SESSION['USERDATA']['id'], $_GET['id'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
}
break;
case 'add':
if ($worker->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker added');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
}
break;
case 'update':
if ($worker->updateWorkers($_SESSION['USERDATA']['id'], $_POST['data'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
}
break;
}
break;
case 'add':
if ($worker->addWorker($_SESSION['USERDATA']['id'], $_POST['username'], $_POST['password'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker added');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
}
break;
case 'update':
if ($worker->updateWorkers($_SESSION['USERDATA']['id'], $_POST['data'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg');
}
break;
$aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']);
if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg');
$smarty->assign('WORKERS', $aWorkers);
}
$aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']);
if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg');
$smarty->assign('CONTENT', 'default.tpl');
$smarty->assign('WORKERS', $aWorkers);
?>

View File

@ -0,0 +1,14 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
// Check user to ensure they are admin
if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
header("HTTP/1.1 404 Page not found");
die("404 Page not found");
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,50 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
// Check user to ensure they are admin
if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
header("HTTP/1.1 404 Page not found");
die("404 Page not found");
}
$aRoundShares = $statistics->getRoundShares();
// Change account lock
if (@$_POST['do'] == 'lock') {
$supress_master = 1;
$user->changeLocked($_POST['account_id']);
}
// Change account admin
if (@$_POST['do'] == 'admin') {
$supress_master = 1;
$user->changeAdmin($_POST['account_id']);
}
if (@$_POST['query']) {
// Fetch requested users
$aUsers = $statistics->getAllUserStats($_POST['query']);
// Add additional stats to each user
// This is not optimized yet, best is a proper SQL
// Query against the stats table? Currently cached though.
foreach ($aUsers as $iKey => $aUser) {
$aBalance = $transaction->getBalance($aUser['id']);
$aUser['balance'] = $aBalance['confirmed'];
$aUser['hashrate'] = $statistics->getUserHashrate($aUser['id']);
$aUser['payout']['est_block'] = round(( (int)$aUser['shares'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
$aUser['payout']['est_fee'] = round(($config['fees'] / 100) * $aUser['payout']['est_block'], 3);
$aUser['payout']['est_donation'] = round((( $aUser['donate_percent'] / 100) * ($aUser['payout']['est_block'] - $aUser['payout']['est_fee'])), 3);
$aUser['payout']['est_payout'] = round($aUser['payout']['est_block'] - $aUser['payout']['est_donation'] - $aUser['payout']['est_fee'], 3);
$aUsers[$iKey] = $aUser;
}
// Assign our variables
$smarty->assign("USERS", $aUsers);
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,24 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY')) die('Hacking attempt');
// Check user to ensure they are admin
if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) {
header("HTTP/1.1 404 Page not found");
die("404 Page not found");
}
if ($bitcoin->can_connect() === true){
$dBalance = $bitcoin->query('getbalance');
} else {
$dBalance = 0;
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
}
$smarty->assign("BALANCE", $dBalance);
$smarty->assign("LOCKED", $transaction->getLockedBalance());
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,29 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Check user token
$id = $user->checkApiKey($_REQUEST['api_key']);
// We have to check if that user is admin too
if ( ! $user->isAdmin($id) ) {
header("HTTP/1.1 401 Unauthorized");
die("Access denied");
}
// Is it a username or a user ID
ctype_digit($_REQUEST['id']) ? $username = $user->getUserName($_REQUEST['id']) : $username = $_REQUEST['id'];
ctype_digit($_REQUEST['id']) ? $id = $_REQUEST['id'] : $id = $user->getUserId($_REQUEST['id']);
// Output JSON format
echo json_encode(array('getuserstatus' => array(
'username' => $username,
'shares' => $statistics->getUserShares($id),
'hashrate' => $statistics->getUserHashrate($id)
)));
// Supress master template
$supress_master = 1;
?>

View File

@ -0,0 +1,24 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Check user token
$id = $user->checkApiKey($_REQUEST['api_key']);
// We have to check if that user is admin too
if ( ! $user->isAdmin($id) ) {
header("HTTP/1.1 401 Unauthorized");
die("Access denied");
}
// Is it a username or a user ID
ctype_digit($_REQUEST['id']) ? $id = $_REQUEST['id'] : $id = $user->getUserId($_REQUEST['id']);
// Output JSON format
echo json_encode(array('getuserworkers' => $worker->getWorkers($id)));
// Supress master template
$supress_master = 1;
?>

View File

@ -0,0 +1,26 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// {"pool_name":"Pool-X.eu","hashrate":"511128.99","workers":"2104","shares_this_round":92450,"last_block":"365294","network_hashrate":17327056.06}
// Fetch last block information
$aLastBlock = $block->getLast();
$aShares = $statistics->getRoundShares();
echo json_encode(
array(
'pool_name' => $config['website']['name'],
'hashrate' => $statistics->getCurrentHashrate(),
'workers' => $worker->getCountAllActiveWorkers(),
'shares_this_round' => $aShares['valid'],
'last_block' => $aLastBlock['height'],
'network_hashrate' => '0'
)
);
// Supress master template
$supress_master = 1;
?>

View File

@ -7,7 +7,7 @@ if (!defined('SECURITY'))
if ( $user->checkLogin($_POST['username'],$_POST['password']) ) {
header('Location: index.php?page=home');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid username or password', 'TYPE' => 'errormsg');
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '. $user->getError(), 'TYPE' => 'errormsg');
}
$smarty->assign('CONTENT', 'default.tpl');
?>

View File

@ -1,9 +1,17 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if (!defined('SECURITY')) die('Hacking attempt');
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
if (!$config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
$smarty->assign("CONTENT", "disabled.tpl");
} else {
if ($config['recaptcha']['enabled']) {
require_once(INCLUDE_DIR . '/recaptchalib.php');
$smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key']));
}
// Tempalte specifics
$smarty->assign("CONTENT", "default.tpl");
}
?>

View File

@ -1,14 +1,46 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if (!defined('SECURITY')) die('Hacking attempt');
if ($config['recaptcha']['enabled']) {
// Load re-captcha specific data
require_once(INCLUDE_DIR . '/recaptchalib.php');
$rsp = recaptcha_check_answer (
$config['recaptcha']['private_key'],
$_SERVER["REMOTE_ADDR"],
$_POST["recaptcha_challenge_field"],
$_POST["recaptcha_response_field"]
);
}
if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2'])) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
// Check if recaptcha is enabled, process form data if valid
if($config['recaptcha']['enabled'] && $_POST["recaptcha_response_field"] && $_POST["recaptcha_response_field"]!=''){
if ($rsp->is_valid) {
$smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key']));
if (!$config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
} else if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2']) && $config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
}
} else {
$smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key'], $rsp->error));
$_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again. (' . $rsp->error . ')', 'TYPE' => 'errormsg');
}
// Empty captcha
} else if ($config['recaptcha']['enabled']) {
$smarty->assign("RECAPTCHA", recaptcha_get_html($config['recaptcha']['public_key'], $rsp->error));
$_SESSION['POPUP'][] = array('CONTENT' => 'Empty Captcha, please try again.', 'TYPE' => 'errormsg');
// Captcha disabled
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
if (!$config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg');
} else if ($user->register($_POST['username'], $_POST['password1'], $_POST['password2'], $_POST['pin'], $_POST['email1'], $_POST['email2']) && $config['website']['registration']) {
$_SESSION['POPUP'][] = array('CONTENT' => 'Account created, please login');
} else {
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg');
}
}
// We load the default registration template instead of an action specific one

View File

@ -5,14 +5,14 @@ if (!defined('SECURITY'))
die('Hacking attempt');
if ($bitcoin->can_connect() === true){
$iDifficulty = $bitcoin->query('getdifficulty');
$dDifficulty = $bitcoin->query('getdifficulty');
$iBlock = $bitcoin->query('getblockcount');
} else {
$iDifficulty = 1;
$dDifficulty = 1;
$iBlock = 0;
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
}
$smarty->assign("CURRENTBLOCK", $iBlock);
$smarty->assign("CURRENTDIFFICULTY", $iDifficulty);
$smarty->assign("CONTENT", "pool/default.tpl");
$smarty->assign("DIFFICULTY", $dDifficulty);
$smarty->assign("CONTENT", "default.tpl");

View File

@ -1,9 +1,8 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if (!defined('SECURITY')) die('Hacking attempt');
if (!$user->isAuthenticated()) header("Location: index.php?page=home");
// Grab the last blocks found
$iLimit = 30;
@ -14,9 +13,5 @@ $aBlockData = $aBlocksFoundData[0];
$smarty->assign("BLOCKSFOUND", $aBlocksFoundData);
$smarty->assign("BLOCKLIMIT", $iLimit);
if ($_SESSION['AUTHENTICATED']) {
$smarty->assign("CONTENT", "blocks_found.tpl");
} else {
$smarty->assign("CONTENT", "default.tpl");
}
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -0,0 +1,16 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
if ($user->isAuthenticated()) {
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
$aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool();
}
// Propagate content our template
$smarty->assign("YOURHASHRATES", @$aHourlyHashRates);
$smarty->assign("POOLHASHRATES", @$aPoolHourlyHashRates);
$smarty->assign("CONTENT", "default.tpl");
?>

View File

@ -21,12 +21,14 @@ $aContributorsShares = $statistics->getTopContributors('shares', 15);
$aContributorsHashes = $statistics->getTopContributors('hashes', 15);
// Grab the last 10 blocks found
$iLimit = 10;
$iLimit = 5;
$aBlocksFoundData = $statistics->getBlocksFound($iLimit);
$aBlockData = $aBlocksFoundData[0];
// Estimated time to find the next block
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
$iCurrentPoolHashrate == 0 ? $iCurrentPoolHashrate = 1 : true;
// Time in seconds, not hours, using modifier in smarty to translate
$iEstTime = $dDifficulty * pow(2,32) / ($iCurrentPoolHashrate * 1000);
@ -50,9 +52,9 @@ $smarty->assign("LASTBLOCK", $aBlockData['height']);
$smarty->assign("DIFFICULTY", $dDifficulty);
$smarty->assign("REWARD", $config['reward']);
if ($_SESSION['AUTHENTICATED']) {
if ($user->isAuthenticated()) {
$smarty->assign("CONTENT", "authenticated.tpl");
} else {
$smarty->assign("CONTENT", "default.tpl");
$smarty->assign("CONTENT", "../default.tpl");
}
?>

View File

@ -1,26 +0,0 @@
<?php
// Make sure we are called from index.php
if (!defined('SECURITY'))
die('Hacking attempt');
// Fetch data from litecoind
if ($bitcoin->can_connect() === true){
$dDifficulty = $bitcoin->getdifficulty();
$iBlock = $bitcoin->getblockcount();
} else {
$iDifficulty = 1;
$iBlock = 0;
$_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg');
}
$aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']);
// Propagate content our template
$smarty->assign("YOURHASHRATES", $aHourlyHashRates);
$smarty->assign("DIFFICULTY", $dDifficulty);
if ($_SESSION['AUTHENTICATED']) {
$smarty->assign("CONTENT", "default.tpl");
}
?>

View File

@ -0,0 +1,277 @@
<?php
/*
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* http://recaptcha.net/plugins/php/
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
* AUTHORS:
* Mike Crawford
* Ben Maurer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The reCAPTCHA server URL's
*/
define("RECAPTCHA_API_SERVER", "http://www.google.com/recaptcha/api");
define("RECAPTCHA_API_SECURE_SERVER", "https://www.google.com/recaptcha/api");
define("RECAPTCHA_VERIFY_SERVER", "www.google.com");
/**
* Encodes the given data into a query string format
* @param $data - array of string elements to be encoded
* @return string - encoded request
*/
function _recaptcha_qsencode ($data) {
$req = "";
foreach ( $data as $key => $value )
$req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
// Cut the last '&'
$req=substr($req,0,strlen($req)-1);
return $req;
}
/**
* Submits an HTTP POST to a reCAPTCHA server
* @param string $host
* @param string $path
* @param array $data
* @param int port
* @return array response
*/
function _recaptcha_http_post($host, $path, $data, $port = 80) {
$req = _recaptcha_qsencode ($data);
$http_request = "POST $path HTTP/1.0\r\n";
$http_request .= "Host: $host\r\n";
$http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
$http_request .= "Content-Length: " . strlen($req) . "\r\n";
$http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
$http_request .= "\r\n";
$http_request .= $req;
$response = '';
if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
die ('Could not open socket');
}
fwrite($fs, $http_request);
while ( !feof($fs) )
$response .= fgets($fs, 1160); // One TCP-IP packet
fclose($fs);
$response = explode("\r\n\r\n", $response, 2);
return $response;
}
/**
* Gets the challenge HTML (javascript and non-javascript version).
* This is called from the browser, and the resulting reCAPTCHA HTML widget
* is embedded within the HTML form it was called from.
* @param string $pubkey A public key for reCAPTCHA
* @param string $error The error given by reCAPTCHA (optional, default is null)
* @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
* @return string - The HTML to be embedded in the user's form.
*/
function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
{
if ($pubkey == null || $pubkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($use_ssl) {
$server = RECAPTCHA_API_SECURE_SERVER;
} else {
$server = RECAPTCHA_API_SERVER;
}
$errorpart = "";
if ($error) {
$errorpart = "&amp;error=" . $error;
}
return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
<noscript>
<iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
<textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
<input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
</noscript>';
}
/**
* A ReCaptchaResponse is returned from recaptcha_check_answer()
*/
class ReCaptchaResponse {
var $is_valid;
var $error;
}
/**
* Calls an HTTP POST function to verify if the user's guess was correct
* @param string $privkey
* @param string $remoteip
* @param string $challenge
* @param string $response
* @param array $extra_params an array of extra variables to post to the server
* @return ReCaptchaResponse
*/
function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
{
if ($privkey == null || $privkey == '') {
die ("To use reCAPTCHA you must get an API key from <a href='https://www.google.com/recaptcha/admin/create'>https://www.google.com/recaptcha/admin/create</a>");
}
if ($remoteip == null || $remoteip == '') {
die ("For security reasons, you must pass the remote ip to reCAPTCHA");
}
//discard spam submissions
if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
$recaptcha_response = new ReCaptchaResponse();
$recaptcha_response->is_valid = false;
$recaptcha_response->error = 'incorrect-captcha-sol';
return $recaptcha_response;
}
$response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/recaptcha/api/verify",
array (
'privatekey' => $privkey,
'remoteip' => $remoteip,
'challenge' => $challenge,
'response' => $response
) + $extra_params
);
$answers = explode ("\n", $response [1]);
$recaptcha_response = new ReCaptchaResponse();
if (trim ($answers [0]) == 'true') {
$recaptcha_response->is_valid = true;
}
else {
$recaptcha_response->is_valid = false;
$recaptcha_response->error = $answers [1];
}
return $recaptcha_response;
}
/**
* gets a URL where the user can sign up for reCAPTCHA. If your application
* has a configuration page where you enter a key, you should provide a link
* using this function.
* @param string $domain The domain where the page is hosted
* @param string $appname The name of your application
*/
function recaptcha_get_signup_url ($domain = null, $appname = null) {
return "https://www.google.com/recaptcha/admin/create?" . _recaptcha_qsencode (array ('domains' => $domain, 'app' => $appname));
}
function _recaptcha_aes_pad($val) {
$block_size = 16;
$numpad = $block_size - (strlen ($val) % $block_size);
return str_pad($val, strlen ($val) + $numpad, chr($numpad));
}
/* Mailhide related code */
function _recaptcha_aes_encrypt($val,$ky) {
if (! function_exists ("mcrypt_encrypt")) {
die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
}
$mode=MCRYPT_MODE_CBC;
$enc=MCRYPT_RIJNDAEL_128;
$val=_recaptcha_aes_pad($val);
return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
}
function _recaptcha_mailhide_urlbase64 ($x) {
return strtr(base64_encode ($x), '+/', '-_');
}
/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
function recaptcha_mailhide_url($pubkey, $privkey, $email) {
if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
"you can do so at <a href='http://www.google.com/recaptcha/mailhide/apikey'>http://www.google.com/recaptcha/mailhide/apikey</a>");
}
$ky = pack('H*', $privkey);
$cryptmail = _recaptcha_aes_encrypt ($email, $ky);
return "http://www.google.com/recaptcha/mailhide/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
}
/**
* gets the parts of the email to expose to the user.
* eg, given johndoe@example,com return ["john", "example.com"].
* the email is then displayed as john...@example.com
*/
function _recaptcha_mailhide_email_parts ($email) {
$arr = preg_split("/@/", $email );
if (strlen ($arr[0]) <= 4) {
$arr[0] = substr ($arr[0], 0, 1);
} else if (strlen ($arr[0]) <= 6) {
$arr[0] = substr ($arr[0], 0, 3);
} else {
$arr[0] = substr ($arr[0], 0, 4);
}
return $arr;
}
/**
* Gets html to display an email address given a public an private key.
* to get a key, go to:
*
* http://www.google.com/recaptcha/mailhide/apikey
*/
function recaptcha_mailhide_html($pubkey, $privkey, $email) {
$emailparts = _recaptcha_mailhide_email_parts ($email);
$url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
"' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
}
?>

View File

@ -5,7 +5,7 @@ if (!defined('SECURITY'))
die('Hacking attempt');
$debug->append('Loading Smarty libraries', 2);
define('SMARTY_DIR', BASEPATH . INCLUDE_DIR . '/smarty/libs/');
define('SMARTY_DIR', INCLUDE_DIR . '/smarty/libs/');
// Include the actual smarty class file
include(SMARTY_DIR . 'Smarty.class.php');
@ -16,10 +16,10 @@ $smarty = new Smarty;
// Assign our local paths
$debug->append('Define Smarty Paths', 3);
$smarty->template_dir = 'templates/' . THEME . '/';
$smarty->compile_dir = 'templates/compile/';
$smarty->template_dir = BASEPATH . 'templates/' . THEME . '/';
$smarty->compile_dir = BASEPATH . 'templates/compile/';
// Optional smarty caching, check Smarty documentation for details
$smarty->caching = $config['cache'];
$smarty->cache_dir = "templates/cache";
$smarty->cache_dir = BASEPATH . "templates/cache";
?>

View File

@ -7,17 +7,29 @@ if (!defined('SECURITY'))
// Globally available variables
$debug->append('Global smarty variables', 3);
// Defaults to get rid of PHP Notice warnings
$dDifficulty = 1;
$aRoundShares = 1;
// Only run these if the user is logged in
if (@$_SESSION['AUTHENTICATED']) {
$aRoundShares = $statistics->getRoundShares();
if ($bitcoin->can_connect() === true)
$dDifficulty = $bitcoin->query('getdifficulty');
}
// Fetch some data
$aRoundShares = $statistics->getRoundShares();
$iCurrentActiveWorkers = $worker->getCountAllActiveWorkers();
$iCurrentPoolHashrate = $statistics->getCurrentHashrate();
$iCurrentPoolShareRate = $statistics->getCurrentShareRate();
// Global data for Smarty
$aGlobal = array(
'slogan' => $config['website']['slogan'],
'websitename' => $config['website']['name'],
'hashrate' => $iCurrentPoolHashrate,
'sharerate' => $iCurrentPoolShareRate,
'ppsvalue' => number_format(round(50 / (pow(2,32) * $dDifficulty) * pow(2, $config['difficulty']), 12) ,12),
'workers' => $iCurrentActiveWorkers,
'roundshares' => $aRoundShares,
'fees' => $config['fees'],
@ -25,7 +37,18 @@ $aGlobal = array(
'reward' => $config['reward'],
'price' => $setting->getValue('price'),
'blockexplorer' => $config['blockexplorer'],
'chaininfo' => $config['chaininfo']
'chaininfo' => $config['chaininfo'],
'config' => array(
'price' => array( 'currency' => $config['price']['currency'] ),
'targetdiff' => $config['difficulty'],
'currency' => $config['currency'],
'txfee' => $config['txfee'],
'payout_system' => $config['payout_system'],
'ap_threshold' => array(
'min' => $config['ap_threshold']['min'],
'max' => $config['ap_threshold']['max']
)
)
);
// We don't want these session infos cached
@ -36,12 +59,19 @@ if (@$_SESSION['USERDATA']['id']) {
// Other userdata that we can cache savely
$aGlobal['userdata']['shares'] = $statistics->getUserShares($_SESSION['USERDATA']['id']);
$aGlobal['userdata']['hashrate'] = $statistics->getUserHashrate($_SESSION['USERDATA']['id']);
$aGlobal['userdata']['sharerate'] = $statistics->getUserSharerate($_SESSION['USERDATA']['id']);
// Some estimations
$aGlobal['userdata']['est_block'] = round(( (int)$aGlobal['userdata']['shares']['valid'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
$aGlobal['userdata']['est_fee'] = round(($config['fees'] / 100) * $aGlobal['userdata']['est_block'], 3);
$aGlobal['userdata']['est_donation'] = round((( $aGlobal['userdata']['donate_percent'] / 100) * ($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_fee'])), 3);
$aGlobal['userdata']['est_payout'] = round($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_donation'] - $aGlobal['userdata']['est_fee'], 3);
switch ($config['payout_system']) {
case 'pps':
break;
default:
// Some estimations
$aGlobal['userdata']['est_block'] = round(( (int)$aGlobal['userdata']['shares']['valid'] / (int)$aRoundShares['valid'] ) * (int)$config['reward'], 3);
$aGlobal['userdata']['est_fee'] = round(($config['fees'] / 100) * $aGlobal['userdata']['est_block'], 3);
$aGlobal['userdata']['est_donation'] = round((( $aGlobal['userdata']['donate_percent'] / 100) * ($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_fee'])), 3);
$aGlobal['userdata']['est_payout'] = round($aGlobal['userdata']['est_block'] - $aGlobal['userdata']['est_donation'] - $aGlobal['userdata']['est_fee'], 3);
break;
}
}
// Make it available in Smarty

View File

@ -465,6 +465,12 @@ a:hover {
.block table tr th.right{
text-align: right;
}
.block table tr td.center{
text-align: center;
}
.block table tr th.center{
text-align: center;
}
.block table tr td.delete a { color: #666; }
@ -1032,3 +1038,25 @@ a:hover {
padding-left:5px;
}
/* Custom checkboxes */
input[type=checkbox] {
display:none;
}
input[type=checkbox] + label
{
background: url('../images/error.gif');
height: 16px;
width: 16px;
display:inline-block;
padding: 0 0 0 0px;
}
input[type=checkbox]:checked + label
{
background: url('../images/success.gif');
height: 16px;
width: 16px;
display:inline-block;
padding: 0 0 0 0px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

View File

@ -16,19 +16,12 @@ $(function () {
var statsType = 'area';
}
// calculate width of graph so it doesnt overflow its parent div
//var chart_width = ($(this).parent('div').width()) - 60;
// hack to statically set width as something is broken with div width calculation - anni
var chart_width = $(document).width() - 340;
if (statsType == 'line' || statsType == 'pie') {
$(this).hide().visualize({
type: statsType,
// 'bar', 'area', 'pie', 'line'
width: chart_width,
height: '240px',
colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c'],
lineDots: 'double',
interaction: true,
multiHover: 5,
@ -43,9 +36,8 @@ $(function () {
});
} else {
$(this).hide().visualize({
type: statsType,
// 'bar', 'area', 'pie', 'line'
width: chart_width,
type: statsType,
height: '240px',
colors: ['#6fb9e8', '#ec8526', '#9dc453', '#ddd74c']
});
@ -66,6 +58,16 @@ $(function () {
widgets: ['zebra']
});
$("table.pagesort")
.tablesorter({ widgets: ['zebra'] })
.tablesorterPager({ positionFixed: false, container: $("#pager") });
$("table.pagesort2")
.tablesorter({ widgets: ['zebra'] })
.tablesorterPager({ positionFixed: false, container: $("#pager2") });
$("table.pagesort4")
.tablesorter({ widgets: ['zebra'] })
.tablesorterPager({ positionFixed: false, container: $("#pager3") });
$('.block table tr th.header').css('cursor', 'pointer');
// Check / uncheck all checkboxes

View File

@ -0,0 +1,106 @@
/**
* --------------------------------------------------------------------
* Tooltip plugin for the jQuery-Plugin "Visualize"
* Tolltip by Iraê Carvalho, irae@irae.pro.br, http://irae.pro.br/en/
* Copyright (c) 2010 Iraê Carvalho
* Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
*
* Visualize plugin by Scott Jehl, scott@filamentgroup.com
* Copyright (c) 2009 Filament Group, http://www.filamentgroup.com
*
* --------------------------------------------------------------------
*/
(function($){
$.visualizePlugins.push(function visualizeTooltip(options,tableData) {
//configuration
var o = $.extend({
tooltip: false,
tooltipalign: 'auto', // also available 'left' and 'right'
tooltipvalign: 'top',
tooltipclass: 'visualize-tooltip',
tooltiphtml: function(data){
if(options.multiHover) {
var html='';
for(var i=0;i<data.point.length;i++){
html += '<p>'+data.point[i].value+' - '+data.point[i].yLabels[0]+'</p>';
}
return html;
} else {
return '<p>'+data.point.value+' - '+data.point.yLabels[0]+'</p>';
}
},
delay:false
},options);
// don't go any further if we are not to show anything
if(!o.tooltip) {return;}
var self = $(this),
canvasContain = self.next(),
scroller = canvasContain.find('.visualize-scroller'),
scrollerW = scroller.width(),
tracker = canvasContain.find('.visualize-interaction-tracker');
// IE needs background color and opacity white or the tracker stays behind the tooltip
tracker.css({
backgroundColor:'white',
opacity:0,
zIndex:100
});
var tooltip = $('<div class="'+o.tooltipclass+'"/>').css({
position:'absolute',
display:'none',
zIndex:90
})
.insertAfter(scroller.find('canvas'));
var usescroll = true;
if( typeof(G_vmlCanvasManager) != 'undefined' ){
scroller.css({'position':'absolute'});
tracker.css({marginTop:'-'+(o.height)+'px'});
}
self.bind('vizualizeOver',function visualizeTooltipOver(e,data){
if(data.canvasContain.get(0) != canvasContain.get(0)) {return;} // for multiple graphs originated from same table
if(o.multiHover) {
var p = data.point[0].canvasCords;
} else {
var p = data.point.canvasCords;
}
var left,right,top,clasRem,clasAd,bottom,x=Math.round(p[0]+data.tableData.zeroLocX),y=Math.round(p[1]+data.tableData.zeroLocY);
if(o.tooltipalign == 'left' || ( o.tooltipalign=='auto' && x-scroller.scrollLeft()<=scrollerW/2 ) ) {
if($.browser.msie && ($.browser.version == 7 || $.browser.version == 6) ) {usescroll=false;} else {usescroll=true;}
left = (x-(usescroll?scroller.scrollLeft():0))+'px';
right = '';
clasAdd="tooltipleft";
clasRem="tooltipright";
} else {
if($.browser.msie && $.browser.version == 7) {usescroll=false;} else {usescroll=true;}
left = '';
right = (Math.abs(x-o.width)- (o.width-(usescroll?scroller.scrollLeft():0)-scrollerW) )+'px';
clasAdd="tooltipright";
clasRem="tooltipleft";
}
tooltip
.addClass(clasAdd)
.removeClass(clasRem)
.html(o.tooltiphtml(data))
.css({
display:'block',
top: y+'px',
left: left,
right: right
});
});
self.bind('vizualizeOut',function visualizeTooltipOut(e,data){
tooltip.css({display:'none'});
});
});
})(jQuery);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
<html>
<body>
<p>An automated payout completed.</p>
<p>Amount: {$DATA.amount}</p>
<br/>
<br/>
</body>
</html>

View File

@ -0,0 +1,11 @@
<html>
<body>
<p>One of your workers is currently IDLE: {$DATA.worker}</p>
<p>We have not received any shares for this worker in the past 10 minutes.</p>
<p>Since monitoring is enabled for this worker, this notification was sent.</p>
<br />
<p>Please check your workers!</p>
<br/>
<br/>
</body>
</html>

View File

@ -0,0 +1,8 @@
<html>
<body>
<p>An manual payout request completed.</p>
<p>Amount: {$DATA.amount}</p>
<br/>
<br/>
</body>
</html>

View File

@ -0,0 +1,7 @@
<html>
<body>
<p>A new block has been discovered!</p>
<br/>
<br/>
</body>
</html>

View File

@ -1 +1 @@
[ {$WEBSITENAME} ] Password Reset Request
[ {$WEBSITENAME} ] {$SUBJECT}

View File

@ -7,22 +7,23 @@
<tbody><tr><td>Username: </td><td>{$GLOBAL.userdata.username}</td></tr>
<tr><td>User Id: </td><td>{$GLOBAL.userdata.id}</td></tr>
<tr><td>API Key: </td><td>{$GLOBAL.userdata.api_key}</td></tr>
<tr><td>E-Mail: </td><td><input type="text" name="email" value="{$GLOBAL.userdata.email|escape}" size="20"></td></tr>
<tr><td>Payment Address: </td><td><input type="text" name="paymentAddress" value="{$smarty.request.paymentAddress|default:$GLOBAL.userdata.coin_address|escape}" size="40"></td></tr>
<tr><td>Donation %: </td><td><input type="text" name="donatePercent" value="{$smarty.request.donatePercent|default:$GLOBAL.userdata.donate_percent|escape}" size="4"><font size="1"> [donation amount in percent (example: 0.5)]</font></td></tr>
<tr><td>Automatic Payout Threshold: </td><td valign="top"><input type="text" name="payoutThreshold" value="{$smarty.request.payoutThreshold|default:$GLOBAL.userdata.ap_threshold|escape}" size="5" maxlength="5"> <font size="1">[1-250 LTC. Set to '0' for no auto payout]</font></td></tr>
<tr><td>Automatic Payout Threshold: </td><td valign="top"><input type="text" name="payoutThreshold" value="{$smarty.request.payoutThreshold|default:$GLOBAL.userdata.ap_threshold|escape}" size="5" maxlength="5"> <font size="1">[{$GLOBAL.config.ap_threshold.min}-{$GLOBAL.config.ap_threshold.max} {$GLOBAL.config.currency}. Set to '0' for no auto payout]</font></td></tr>
<tr><td>4 digit PIN: </td><td><input type="password" name="authPin" size="4" maxlength="4"><font size="1"> [The 4 digit PIN you chose when registering]</font></td></tr>
</tbody></table>
<input type="submit" class="submit long" value="Update Settings"></form>
{include file="global/block_footer.tpl"}
{include file="global/block_header.tpl" BLOCK_HEADER="Cash Out"}
<ul><li><font color="">Please note: a 0.1 ltc transaction will apply when processing "On-Demand" manual payments</font></li></ul>
<ul><li><font color="">Please note: a {$GLOBAL.config.txfee} {$GLOBAL.config.currency} transaction will apply when processing "On-Demand" manual payments</font></li></ul>
<form action="{$smarty.server.PHP_SELF}" method="post">
<input type="hidden" name="page" value="{$smarty.request.page|escape}">
<input type="hidden" name="action" value="{$smarty.request.action|escape}">
<input type="hidden" name="do" value="cashOut">
<table>
<tbody><tr><td>Account Balance: &nbsp;&nbsp;&nbsp;</td><td>{$GLOBAL.userdata.balance|escape} LTC</td></tr>
<tbody><tr><td>Account Balance: &nbsp;&nbsp;&nbsp;</td><td>{$GLOBAL.userdata.balance.confirmed|escape} {$GLOBAL.config.currency}</td></tr>
<tr><td>Payout to: </td><td><h6>{$GLOBAL.userdata.coin_address|escape}</h6></td></tr>
<tr><td>4 digit PIN: </td><td><input type="password" name="authPin" size="4" maxlength="4"></td></tr>
</tbody></table>

View File

@ -0,0 +1,84 @@
{include file="global/block_header.tpl" ALIGN="left" BLOCK_HEADER="Notification Settings"}
<form action="{$smarty.server.PHP_SELF}" method="POST">
<input type="hidden" name="page" value="{$smarty.request.page}">
<input type="hidden" name="action" value="{$smarty.request.action}">
<input type="hidden" name="do" value="save">
<table width="100%">
<tr>
<th class="left">Type</th>
<th class="center">Active</th>
</tr>
<tr>
<td class="left">IDLE Worker</td>
<td class="center">
<input type="hidden" name="data[idle_worker]" value="0" />
<input type="checkbox" name="data[idle_worker]" id="data[idle_worker]" value="1"{if $SETTINGS['idle_worker']}checked{/if} />
<label for="data[idle_worker]"></label>
</td>
</tr>
<tr>
<td class="left">New Blocks</td>
<td class="center">
<input type="hidden" name="data[new_block]" value="0" />
<input type="checkbox" name="data[new_block]" id="data[new_block]" value="1"{if $SETTINGS['new_block']}checked{/if} />
<label for="data[new_block]"></label>
</td>
</tr>
<tr>
<td class="left">Auto Payout</td>
<td class="center">
<input type="hidden" name="data[auto_payout]" value="0" />
<input type="checkbox" name="data[auto_payout]" id="data[auto_payout]" value="1"{if $SETTINGS['auto_payout']}checked{/if} />
<label for="data[auto_payout]"></label>
</td>
</tr>
<tr>
<td class="left">Manual Payout</td>
<td class="center">
<input type="hidden" name="data[manual_payout]" value="0" />
<input type="checkbox" name="data[manual_payout]" id="data[manual_payout]" value="1"{if $SETTINGS['manual_payout']}checked{/if} />
<label for="data[manual_payout]"></label>
</td>
</tr>
<tr>
<td colspan="2" class="center">
<input type="submit" class="submit small" value="Update">
</td>
</tr>
</table>
</form>
{include file="global/block_footer.tpl"}
{include file="global/block_header.tpl" ALIGN="right" BLOCK_HEADER="Notification History"}
<center>
{include file="global/pagination.tpl"}
<table width="100%" class="pagesort">
<thead style="font-size:13px;">
<tr>
<th class="center" style="cursor: pointer;">ID</th>
<th class="center" style="cursor: pointer;">Time</th>
<th class="center" style="cursor: pointer;">Type</th>
<th class="center" style="cursor: pointer;">Active</th>
</tr>
</thead>
<tbody style="font-size:12px;">
{section notification $NOTIFICATIONS}
<tr class="{cycle values="odd,even"}">
<td class="center">{$NOTIFICATIONS[notification].id}</td>
<td class="center">{$NOTIFICATIONS[notification].time}</td>
<td class="center">
{if $NOTIFICATIONS[notification].type == new_block}New Block
{else if $NOTIFICATIONS[notification].type == auto_payout}Auto Payout
{else if $NOTIFICATIONS[notification].type == idle_worker}IDLE Worker
{else if $NOTIFICATIONS[notification].type == manual_payout}Manual Payout
{/if}
</td>
<td class="center">
<img src="{$PATH}/images/{if $NOTIFICATIONS[notification].active}success{else}error{/if}.gif" />
</td>
</tr>
{/section}
</tbody>
</table>
</center>
{include file="global/block_footer.tpl"}

View File

@ -1,7 +1,8 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Transaction Log" BUTTONS=array(Confirmed,Unconfirmed,Orphan)}
<div class="block_content tab_content" id="Confirmed" style="clear:;">
<center>
<table cellpadding="1" cellspacing="1" width="98%" class="sortable">
{include file="global/pagination.tpl"}
<table cellpadding="1" cellspacing="1" width="98%" class="pagesort">
<thead style="font-size:13px;">
<tr>
<th class="header" style="cursor: pointer;">TX #</th>
@ -15,11 +16,15 @@
<tbody style="font-size:12px;">
{section transaction $TRANSACTIONS}
{if (
($TRANSACTIONS[transaction].type == 'Credit' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
(($TRANSACTIONS[transaction].type == 'Credit' or $TRANSACTIONS[transaction].type == 'Bonus')and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Donation' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Fee' and $TRANSACTIONS[transaction].confirmations >= $GLOBAL.confirmations)
or $TRANSACTIONS[transaction].type == 'Credit_PPS'
or $TRANSACTIONS[transaction].type == 'Fee_PPS'
or $TRANSACTIONS[transaction].type == 'Donation_PPS'
or $TRANSACTIONS[transaction].type == 'Debit_AP'
or $TRANSACTIONS[transaction].type == 'Debit_MP'
or $TRANSACTIONS[transaction].type == 'TXFee'
)}
<tr class="{cycle values="odd,even"}">
<td>{$TRANSACTIONS[transaction].id}</td>
@ -27,7 +32,7 @@
<td>{$TRANSACTIONS[transaction].type}</td>
<td>{$TRANSACTIONS[transaction].coin_address}</td>
<td>{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == Credit}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == 'Credit' or $TRANSACTIONS[transaction].type == 'Credit_PPS' or $TRANSACTIONS[transaction].type == 'Bonus'}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
</tr>
{/if}
{/section}
@ -42,7 +47,8 @@
</div>
<div class="block_content tab_content" id="Unconfirmed" style="">
<center>
<table cellpadding="1" cellspacing="1" width="98%" class="sortable">
{include file="global/pagination.tpl" ID=2}
<table cellpadding="1" cellspacing="1" width="98%" class="pagesort2">
<thead style="font-size:13px;">
<tr>
<th class="header" style="cursor: pointer;">TX #</th>
@ -56,7 +62,7 @@
<tbody style="font-size:12px;">
{section transaction $TRANSACTIONS}
{if (
$TRANSACTIONS[transaction].type == 'Credit' && $TRANSACTIONS[transaction].confirmations < $GLOBAL.confirmations
($TRANSACTIONS[transaction].type == 'Credit' or $TRANSACTIONS[transaction].type == 'Bonus') and $TRANSACTIONS[transaction].confirmations < $GLOBAL.confirmations
or ($TRANSACTIONS[transaction].type == 'Donation' and $TRANSACTIONS[transaction].confirmations < $GLOBAL.confirmations)
or ($TRANSACTIONS[transaction].type == 'Fee' and $TRANSACTIONS[transaction].confirmations < $GLOBAL.confirmations)
)}
@ -66,9 +72,9 @@
<td>{$TRANSACTIONS[transaction].type}</td>
<td>{$TRANSACTIONS[transaction].coin_address}</td>
<td>{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == Credit}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == 'Credit' or $TRANSACTIONS[transaction].type == 'Bonus'}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
</tr>
{if $TRANSACTIONS[transaction].type == Credit}
{if $TRANSACTIONS[transaction].type == 'Credit' or $TRANSACTIONS[transaction].type == 'Bonus'}
{assign var="credits" value="`$credits+$TRANSACTIONS[transaction].amount`"}
{else}
{assign var="debits" value="`$debits+$TRANSACTIONS[transaction].amount`"}
@ -86,7 +92,8 @@
</div>
<div class="block_content tab_content" id="Orphan" style="">
<center>
<table cellpadding="1" cellspacing="1" width="98%" class="sortable">
{include file="global/pagination.tpl"}
<table cellpadding="1" cellspacing="1" width="98%" class="pagesort3">
<thead style="font-size:13px;">
<tr>
<th class="header" style="cursor: pointer;">TX #</th>
@ -103,6 +110,7 @@
$TRANSACTIONS[transaction].type == 'Orphan_Credit'
or $TRANSACTIONS[transaction].type == 'Orphan_Donation'
or $TRANSACTIONS[transaction].type == 'Orphan_Fee'
or $TRANSACTIONS[transaction].type == 'Orphan_Bonus'
)}
<tr class="{cycle values="odd,even"}">
<td>{$TRANSACTIONS[transaction].id}</td>
@ -110,9 +118,9 @@
<td>{$TRANSACTIONS[transaction].type}</td>
<td>{$TRANSACTIONS[transaction].coin_address}</td>
<td>{if $TRANSACTIONS[transaction].height == 0}n/a{else}{$TRANSACTIONS[transaction].height}{/if}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == Orphan_Credit}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
<td><font color="{if $TRANSACTIONS[transaction].type == 'Orphan_Credit' or $TRANSACTIONS[transaction].type == 'Orphan_Bonus'}green{else}red{/if}">{$TRANSACTIONS[transaction].amount}</td>
</tr>
{if $TRANSACTIONS[transaction].type == Orphan_Credit}
{if $TRANSACTIONS[transaction].type == 'Orphan_Credit' or $TRANSACTIONS[transaction].type == 'Orphan_Bonus'}
{assign var="orphan_credits" value="`$orphan_credits+$TRANSACTIONS[transaction].amount`"}
{else}
{assign var="orphan_debits" value="`$orphan_debits+$TRANSACTIONS[transaction].amount`"}

View File

@ -1,9 +1,4 @@
{include file="global/block_header.tpl" BLOCK_HEADER="My Workers"}
<ul><li><font color="red">
CAUTION! </font>Deletion of a worker could cause all associated shares for that worker to be lost.
Do not delete Workers unless you are certain all of their shares have been counted or that you have never used that worker account.
</li></ul>
<center>
<form action="{$smarty.server.PHP_SELF}" method="post">
<input type="hidden" name="page" value="{$smarty.request.page}">
@ -14,18 +9,23 @@
<tr>
<td>Worker Name</td>
<td>Password</td>
<td>Active</td>
<td>Khash/s</td>
<td class="center">Active</td>
<td class="center">Monitor</td>
<td class="right">Khash/s</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
{section worker $WORKERS}
{assign var="username" value="."|escape|explode:$WORKERS[worker].username:2}
<tr>
<td{if $WORKERS[worker].active == 1} style="color: orange"{/if}>{$username.0|escape}.<input name="data[{$WORKERS[worker].id}][username]" value="{$username.1|escape}" size="10" /></td>
<td{if $WORKERS[worker].active} style="color: orange"{/if}>{$username.0|escape}.<input name="data[{$WORKERS[worker].id}][username]" value="{$username.1|escape}" size="10" /></td>
<td><input type="text" name="data[{$WORKERS[worker].id}][password]" value="{$WORKERS[worker].password|escape}" size="10"></td>
<td>{if $WORKERS[worker].active == 1}Y{else}N{/if}</td>
<td>{$WORKERS[worker].hashrate}</td>
<td class="center"><img src="{$PATH}/images/{if $WORKERS[worker].active}success{else}error{/if}.gif" /></td>
<td class="center">
<input type="checkbox" name="data[{$WORKERS[worker].id}][monitor]" value="1" id="data[{$WORKERS[worker].id}][monitor]" {if $WORKERS[worker].monitor}checked{/if} />
<label for="data[{$WORKERS[worker].id}][monitor]"></label>
</td>
<td class="right">{$WORKERS[worker].hashrate|number_format}</td>
<td align="right"><a href="{$smarty.server.PHP_SELF}?page={$smarty.request.page|escape}&action={$smarty.request.action|escape}&do=delete&id={$WORKERS[worker].id|escape}"><button style="padding:5px" type="button">Delete</button></a></td>
</tr>
{/section}

View File

@ -0,0 +1,3 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Admin Panel"}
<p>Welcome to the admin panel. Please select an option from the drop-down menu.</p>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,89 @@
<script language="javascript">
function storeLock(id) {
$.ajax({
type: "POST",
url: "{$smarty.server.PHP_SELF}",
data: "page={$smarty.request.page}&action={$smarty.request.action}&do=lock&account_id=" + id,
});
}
function storeAdmin(id) {
$.ajax({
type: "POST",
url: "{$smarty.server.PHP_SELF}",
data: "page={$smarty.request.page}&action={$smarty.request.action}&do=admin&account_id=" + id,
});
}
</script>
{include file="global/block_header.tpl" BLOCK_HEADER="Query User Database"}
<form action="{$smarty.server.PHP_SELF}" method="POST" id='query'>
<input type="hidden" name="page" value="{$smarty.request.page}">
<input type="hidden" name="action" value="{$smarty.request.action}">
<input type="text" class="pin" name="query" value="{$smarty.request.query|default:"%"}">
<input type="submit" class="submit small" value="Query">
</form>
{include file="global/block_footer.tpl"}
{include file="global/block_header.tpl" BLOCK_HEADER="User Information"}
<center>
{include file="global/pagination.tpl"}
</center>
<table width="100%" class="pagesort">
<thead>
<tr>
<th class="center">ID</th>
<th>Username</th>
<th>E-Mail</th>
<th class="right">Shares&nbsp;&nbsp;</th>
<th class="right">Hashrate&nbsp;&nbsp;</th>
<th class="right">Est. Donation&nbsp;&nbsp;</th>
<th class="right">Est. Payout&nbsp;&nbsp;&nbsp;</th>
<th class="right">Balance&nbsp;&nbsp;&nbsp;</th>
<th class="center">Admin</th>
<th class="center">Locked</th>
</tr>
</thead>
<tbody>
{section name=user loop=$USERS|default}
<tr>
<td class="center">{$USERS[user].id}</td>
<td>{$USERS[user].username}</td>
<td>{$USERS[user].email}</td>
<td class="right">{$USERS[user].shares}</td>
<td class="right">{$USERS[user].hashrate}</td>
<td class="right">{$USERS[user].payout.est_donation|number_format:"8"}</td>
<td class="right">{$USERS[user].payout.est_payout|number_format:"8"}</td>
<td class="right">{$USERS[user].balance|number_format:"8"}</td>
<td class="center">
<input type="hidden" name="admin[{$USERS[user].id}]" value="0"/>
<input type="checkbox" onclick="storeAdmin({$USERS[user].id})" name="admin[{$USERS[user].id}]" value="1" id="admin[{$USERS[user].id}]" {if $USERS[user].is_admin}checked{/if} />
<label for="admin[{$USERS[user].id}]"></label>
</td>
<td class="center">
<input type="hidden" name="locked[{$USERS[user].id}]" value="0"/>
<input type="checkbox" onclick="storeLock({$USERS[user].id})" name="locked[{$USERS[user].id}]" value="1" id="locked[{$USERS[user].id}]" {if $USERS[user].is_locked}checked{/if} />
<label for="locked[{$USERS[user].id}]"></label>
</td>
</tr>
{sectionelse}
<tr>
<td colspan="10"></td>
</tr>
{/section}
</tbody>
<tfoot>
<tr>
<th class="center">ID</th>
<th>Username</th>
<th>E-Mail</th>
<th class="right">Shares&nbsp;&nbsp;</th>
<th class="right">Hashrate&nbsp;&nbsp;</th>
<th class="right">Est. Donation&nbsp;&nbsp;</th>
<th class="right">Est. Payout&nbsp;&nbsp;&nbsp;</th>
<th class="right">Balance&nbsp;&nbsp;&nbsp;</th>
<th class="center">Admin</th>
<th class="center">Locked</th>
</tr>
</tfoot>
</table>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,16 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Wallet Information"}
<table width="350px">
<tr>
<th>Wallet Balance</th>
<td class="right">{$BALANCE|number_format:"8"}</td>
</tr>
<tr>
<th>Locked for users</th>
<td class="right">{$LOCKED|number_format:"8"}</td>
</tr>
<tr>
<th>Liquid Assets</th>
<td class="right">{($BALANCE - $LOCKED)|number_format:"8"}</td>
</tr>
</table>
{include file="global/block_footer.tpl"}

View File

@ -1,5 +1,5 @@
<center>
Litecoin Pool using <a href="https://github.com/litecoin-project/litecoin">litecoind</a>, <a href="https://github.com/ArtForz/pushpool/tree/tenebrix">pushpoold</a><br/>
<a href="https://github.com/TheSerapher/php-mmcfe-ng">mmcfe-ng</a> Website based on <a href="https://github.com/Greedi/mmcFE">mmcfe</a>, overhauled by TheSerapher, available on <a href="https://github.com/TheSerapher/php-mmcfe-ng">GitHub</a><br/>
Litecoin Pool using <a href="https://github.com/litecoin-project/litecoin">litecoind</a>, <a href="https://github.com/ArtForz/pushpool/tree/tenebrix">pushpoold</a>, <a href="https://github.com/viperaus/stratum-mining">stratum-mining</a></br>
<a href="https://github.com/TheSerapher/php-mmcfe-ng">mmcfe-ng</a> Website based on mmcfe by <a href="https://bitcointalk.org/index.php?action=profile;u=19135">AnnihilaT</a> overhauled by TheSerapher, available on <a href="https://github.com/TheSerapher/php-mmcfe-ng">GitHub</a><br/>
<i style="color: grey">LTC: Lge95QR2frp9y1wJufjUPCycVsg5gLJPW8<br/></i><br/><br/>
</center>

View File

@ -4,9 +4,9 @@
<div id="ministats">
<table border="0">
<tr>
<td><li>LTC/usd: {$GLOBAL.price|default:"n/a"}&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
<td><li>Pool Hashrate: {$GLOBAL.hashrate / 1000} MH/s&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
<td><li>Pool Sharerate: {$GLOBAL.sharerate} Shares/s&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
<td><li>{$GLOBAL.config.currency}/{$GLOBAL.config.price.currency}: {$GLOBAL.price|default:"n/a"|number_format:"4"}&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
<td><li>Pool Hashrate: {($GLOBAL.hashrate / 1000)|number_format:"3"} MH/s&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
<td><li>Pool Sharerate: {$GLOBAL.sharerate|number_format:"2"} Shares/s&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
<td><li>Pool Workers: {$GLOBAL.workers}&nbsp;&nbsp;&nbsp;&nbsp;</li></td>
</tr>
</table>

View File

@ -5,16 +5,24 @@
<ul>
<li><a href="{$smarty.server.PHP_SELF}?page=account&action=edit">Edit Account</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=account&action=workers">My Workers</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=user">My Graphs</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=account&action=transactions">Transactions</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=account&action=notifications">Notifications</a></li>
</ul>
</li>
{/if}
{if $smarty.session.AUTHENTICATED|default:"0" == 1 && $GLOBAL.userdata.admin == 1}<li><a href="#">Admin Panel</a></li>{/if}
<li><a href="{$smarty.server.PHP_SELF}?page=statistics">Statistics</a>
{if $smarty.session.AUTHENTICATED|default:"0" == 1 && $GLOBAL.userdata.is_admin == 1}
<li><a href="{$smarty.server.PHP_SELF}?page=admin">Admin Panel</a>
<ul>
<li><a href="{$smarty.server.PHP_SELF}?page=admin&action=user">User Info</a></li>
<li><a href="{$smarty.server.PHP_SELF}?page=admin&action=wallet">Wallet Info</a></li>
</ul>
</li>
{/if}
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=pool">Statistics</a>
<ul>
<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=pool">Pool Stats</a></li>
{if $smarty.session.AUTHENTICATED|default}<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=blocks">Block Stats</a></li>{/if}
{if $smarty.session.AUTHENTICATED|default}<li><a href="{$smarty.server.PHP_SELF}?page=statistics&action=graphs">Hashrate Graphs</a></li>{/if}
</ul>
</li>
<li><a href="{$smarty.server.PHP_SELF}?page=gettingstarted">Getting Started</a></li>

View File

@ -0,0 +1,15 @@
<div id="pager{$ID|default:""}">
<form>
<img src="{$PATH}/images/first.png" class="first"/>
<img src="{$PATH}/images/prev.png" class="prev"/>
<input type="text" class="pagedisplay"/>
<img src="{$PATH}/images/next.png" class="next"/>
<img src="{$PATH}/images/last.png" class="last"/>
<select class="pagesize">
<option selected="selected" value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="40">40</option>
</select>
</form>
</div>

View File

@ -6,8 +6,13 @@
</div>
<div class="block_content" style="padding-top:10px;">
<table class="sidebar" style="width: 196px">
<tr><td colspan="2"><b>Your Hashrate</b></td></tr>
<tr><td colspan="2" class="right">{$GLOBAL.userdata.hashrate|number_format} KH/s</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>
@ -35,7 +40,7 @@
<td class="right"><i>{$GLOBAL.userdata.shares.invalid|number_format}</i><font size='1px'></font></td>
</tr>
<tr>
<td colspan="2"><b><u>LTC Round Estimate</u></b></td>
<td colspan="2"><b><u>{$GLOBAL.config.currency} Round Estimate</u></b></td>
</tr>
<tr>
<td><b>Block</b></td>
@ -54,8 +59,9 @@
<td class="right">{$GLOBAL.userdata.est_payout|number_format:"3"}</td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
<tr><td colspan="2"><b><u>Account Balance</u></b></td></tr>
<tr><td colspan="2" class="right"><b>{$GLOBAL.userdata.balance|default:"0"} LTC</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>

View File

@ -0,0 +1,61 @@
<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 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><b>Share Rate</b></td>
<td class="right">{$GLOBAL.userdata.sharerate|number_format:"2"} S/s</td>
</tr>
<tr>
<td><b>PPS Value</b></td>
<td class="right">{$GLOBAL.ppsvalue}</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></td>
</tr>
<tr>
<td><b>Your Invalid</b></td>
<td class="right"><i>{$GLOBAL.userdata.shares.invalid|number_format}</i><font size='1px'></font></td>
</tr>
<tr><td colspan="2">&nbsp;</td></tr>
<tr><td colspan="2"><b><u>{$GLOBAL.config.currency} Estimates</u></b></td></tr>
<tr>
<td><b>in 24 hours</b></td>
<td class="right">{($GLOBAL.userdata.sharerate * 24 * 60 * 60 * $GLOBAL.ppsvalue)|number_format:"8"}</td>
</tr>
<tr>
<td><b>in 7 days</b></td>
<td class="right">{($GLOBAL.userdata.sharerate * 7 * 24 * 60 * 60 * $GLOBAL.ppsvalue)|number_format:"8"}</td>
</tr>
<tr>
<td><b>in 14 days</b></td>
<td class="right">{($GLOBAL.userdata.sharerate * 14 * 24 * 60 * 60 * $GLOBAL.ppsvalue)|number_format:"8"}</td>
</tr>
<tr><td colspan="2">&nbsp;</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>

View File

@ -11,6 +11,7 @@
<script src="{$PATH}/js/jquery.tablesorter.min.js"></script>
<script src="{$PATH}/js/jquery.tablesorter.pager.js"></script>
<script src="{$PATH}/js/jquery.visualize.js"></script>
<script src="{$PATH}/js/jquery.tooltip.visualize.js"></script>
<script src="{$PATH}/js/custom.js"></script>
<script src="{$PATH}/js/tools.js"></script>
<!--[if IE]><script type="text/javascript" src="{$PATH}/js/excanvas.js"></script><![endif]-->
@ -46,7 +47,11 @@
<div class="block_content">
<div class="sidebar">
{if $smarty.session.AUTHENTICATED|default}
{include file="global/sidebar.tpl"}
{if $GLOBAL.config.payout_system == 'pps'}
{include file="global/sidebar_pps.tpl"}
{else}
{include file="global/sidebar.tpl"}
{/if}
{else}
{include file="global/login.tpl"}
{/if}

View File

@ -3,13 +3,16 @@
<input type="hidden" name="page" value="{$smarty.request.page|escape}">
<input type="hidden" name="action" value="register">
<table width="90%" border="0">
<tbody><tr><td>Username:</td><td><input type="text" class="text tiny" name="username" value="{$smarty.post.username|escape}" size="15" maxlength="20"></td></tr>
<tr><td>Password:</td><td><input type="password" class="text tiny" name="password1" value="" size="15" maxlength="20"></td></tr>
<tr><td>Repeat Password:</td><td><input type="password" class="text tiny" name="password2" value="" size="15" maxlength="20"></td></tr>
<tr><td>Email:</td><td><input type="text" name="email1" class="text small" value="{$smarty.post.email1|escape}" size="15"><font size="1"> (Optional) </font></td></tr>
<tr><td>Email Repeat:</td><td><input type="text" class="text small" name="email2" value="{$smarty.post.email2|escape}" size="15"><font size="1"> (Optional) </font></td></tr>
<tr><td>PIN:</td><td><input type="password" class="text pin" name="pin" value="" size="4" maxlength="4"><font size="1"> (4 digit number. <b>Remember this pin!</b>)</font></td></tr>
</tbody></table>
<input type="submit" class="submit small" value="Register">
<tbody>
<tr><td>Username:</td><td><input type="text" class="text tiny" name="username" value="{$smarty.post.username|escape}" size="15" maxlength="20"></td></tr>
<tr><td>Password:</td><td><input type="password" class="text tiny" name="password1" value="" size="15" maxlength="20"></td></tr>
<tr><td>Repeat Password:</td><td><input type="password" class="text tiny" name="password2" value="" size="15" maxlength="20"></td></tr>
<tr><td>Email:</td><td><input type="text" name="email1" class="text small" value="{$smarty.post.email1|escape}" size="15"></td></tr>
<tr><td>Email Repeat:</td><td><input type="text" class="text small" name="email2" value="{$smarty.post.email2|escape}" size="15"></td></tr>
<tr><td>PIN:</td><td><input type="password" class="text pin" name="pin" value="" size="4" maxlength="4"><font size="1"> (4 digit number. <b>Remember this pin!</b>)</font></td></tr>
<tr><td colspan="2">{nocache}{$RECAPTCHA}{/nocache}</td></tr>
<tr><td class="center"><input type="submit" class="submit small" value="Register"></td><td></td></tr>
</tbody>
</table>
</form>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,3 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Registration disabled" BLOCK_STYLE="clear:none;"}
<br /><center><p><font size="5px">We are currently not accepting new user registrations.</font></p></center>
{include file="global/block_footer.tpl"}

View File

@ -1,37 +0,0 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Last $BLOCKLIMIT Blocks Found" BLOCK_STYLE="clear:none;"}
<center>
<table class="stats_lastblocks" width="100%" style="font-size:13px;">
<thead>
<tr style="background-color:#B6DAFF;">
<th scope="col" align="left">Block</th>
<th scope="col" align="left">Validity</th>
<th scope="col" align="left">Finder</th>
<th scope="col" align="left">Date / Time</th>
<th class="right" scope="col">Difficulty</th>
<th class="right" scope="col">Shares</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSFOUND}
<tr class="{cycle values="odd,even"}">
<td><a href="{$GLOBAL.blockexplorer}{$BLOCKSFOUND[block].height}" target="_blank">{$BLOCKSFOUND[block].height}</a></td>
<td>
{if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}
<font color="green">Confirmed</font>
{else if $BLOCKSFOUND[block].confirmations == -1}
<font color="red">Orphan</font>
{else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}</td>
<td>{$BLOCKSFOUND[block].finder|default:"unknown"}</td>
<td>{$BLOCKSFOUND[block].time|date_format:"%d/%m/%Y %H:%M:%S"}</td>
<td class="right">{$BLOCKSFOUND[block].difficulty|number_format:"8"}</td>
<td class="right">{$BLOCKSFOUND[block].shares|number_format}</td>
</tr>
{/section}
</tbody>
</table>
</center>
<ul>
<li>Note: <font color="orange">Round Earnings are not credited until {$GLOBAL.confirmations} confirms.</font></li>
</ul>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,73 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Block Shares" BLOCK_STYLE="clear:none;"}
<table width="70%" class="stats" rel="line">
<caption>Block Shares</caption>
<thead>
<tr>
{section block $BLOCKSFOUND step=-1 max=20}
<th scope="col">{$BLOCKSFOUND[block].height}</th>
{/section}
</th>
</thead>
<tbody>
<tr>
<th scope="row">Expected</th>
{section block $BLOCKSFOUND step=-1 max=20}
<td>{round(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)}</td>
{/section}
</tr>
<tr>
<th scope="row">Actual</th>
{section block $BLOCKSFOUND step=-1 max=20}
<td>{$BLOCKSFOUND[block].shares}</td>
{/section}
</tr>
</tbody>
</table>
<center><br>
<p style="padding-left:30px; padding-redight:30px; font-size:10px;">
The graph above illustrates N shares to find a block vs. E Shares expected to find a block based on
target and network difficulty and assuming a zero variance scenario.
</p></center>
{include file="global/block_footer.tpl"}
{include file="global/block_header.tpl" BLOCK_HEADER="Last $BLOCKLIMIT Blocks Found" BLOCK_STYLE="clear:none;"}
<center>
<table width="100%" style="font-size:13px;">
<thead>
<tr style="background-color:#B6DAFF;">
<th class="center">Block</th>
<th class="center">Validity</th>
<th>Finder</th>
<th class="center">Time</th>
<th class="right">Difficulty</th>
<th class="right">Expected Shares</th>
<th class="right">Actual Shares</th>
<th class="right">Percentage</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSFOUND}
<tr class="{cycle values="odd,even"}">
<td class="center"><a href="{$GLOBAL.blockexplorer}{$BLOCKSFOUND[block].height}" target="_blank">{$BLOCKSFOUND[block].height}</a></td>
<td class="center">
{if $BLOCKSFOUND[block].confirmations >= $GLOBAL.confirmations}
<font color="green">Confirmed</font>
{else if $BLOCKSFOUND[block].confirmations == -1}
<font color="red">Orphan</font>
{else}{$GLOBAL.confirmations - $BLOCKSFOUND[block].confirmations} left{/if}</td>
<td>{$BLOCKSFOUND[block].finder|default:"unknown"}</td>
<td class="center">{$BLOCKSFOUND[block].time|date_format:"%d/%m %H:%M:%S"}</td>
<td class="right">{$BLOCKSFOUND[block].difficulty|number_format:"2"}</td>
<td class="right">{(pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty)|number_format}</td>
<td class="right">{$BLOCKSFOUND[block].shares|number_format}</td>
<td class="right">{($BLOCKSFOUND[block].shares / (pow(2,32 - $GLOBAL.config.targetdiff) * $BLOCKSFOUND[block].difficulty) * 100)|number_format:"2"}</td>
</tr>
{/section}
</tbody>
</table>
</center>
<ul>
<li>Note: <font color="orange">Round Earnings are not credited until {$GLOBAL.confirmations} confirms.</font></li>
</ul>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,28 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Last $BLOCKLIMIT Blocks Found" BLOCK_STYLE="clear:none;"}
<center>
<table width="100%" style="font-size:13px;">
<thead>
<tr style="background-color:#B6DAFF;">
<th class="center">Block</th>
<th>Finder</th>
<th class="center">Time</th>
<th class="right">Actual Shares</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{section block $BLOCKSFOUND}
<tr class="{cycle values="odd,even"}">
<td class="center"><a href="{$GLOBAL.blockexplorer}{$BLOCKSFOUND[block].height}" target="_blank">{$BLOCKSFOUND[block].height}</a></td>
<td>{$BLOCKSFOUND[block].finder|default:"unknown"}</td>
<td class="center">{$BLOCKSFOUND[block].time|date_format:"%d/%m %H:%M:%S"}</td>
<td class="right">{$BLOCKSFOUND[block].shares|number_format}</td>
</tr>
{/section}
</tbody>
</table>
</center>
<ul>
<li>Note: <font color="orange">Round Earnings are not credited until {$GLOBAL.confirmations} confirms.</font></li>
</ul>
{include file="global/block_footer.tpl"}

View File

@ -19,4 +19,5 @@
</tr>
</tbody>
</table>
<li>These stats are also available in JSON format <a href="{$smarty.server.PHP_SELF}?page=api&action=public" target="_api">HERE</a></li>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,43 @@
{if is_array($YOURHASHRATES) && is_array($POOLHASHRATES)}
<div class="block_content tab_content" id="both" style="padding-left:30px;">
{foreach from=array('area','pie') item=chartType}
<table width="60%" class="stats" rel="{$chartType}">
<caption>Your vs Pool Hashrate</caption>
<thead>
<tr>
<td></td>
{for $i=date('G') to 23}
<th scope="col">{$i}:00</th>
{/for}
{for $i=0 to date('G', time () - 60 * 60)}
<th scope="col">{$i}:00</th>
{/for}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{$smarty.session.USERDATA.username}</th>
{for $i=date('G') to 23}
<td>{$YOURHASHRATES.$i|default:"0"}</td>
{/for}
{for $i=0 to date('G', time() - 60 * 60)}
<td>{$YOURHASHRATES.$i|default:"0"}</td>
{/for}
</tr>
<tr>
<th scope="row">Pool</th>
{for $i=date('G') to 23}
<td>{$POOLHASHRATES.$i|default:"0"}</td>
{/for}
{for $i=0 to date('G', time() - 60 * 60)}
<td>{$POOLHASHRATES.$i|default:"0"}</td>
{/for}
</tr>
</tbody>
</table>
<br />
{/foreach}
</div>
{else}
<p><li>No shares available to start calculations</li></p>
{/if}

View File

@ -0,0 +1,5 @@
{include file="global/block_header.tpl" BLOCK_HEADER="24h Hashrate Statistics" BUTTONS=array(mine,pool,both)}
{include file="{$smarty.request.page}/{$smarty.request.action}/mine.tpl"}
{include file="{$smarty.request.page}/{$smarty.request.action}/pool.tpl"}
{include file="{$smarty.request.page}/{$smarty.request.action}/both.tpl"}
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,31 @@
{if is_array($YOURHASHRATES)}
<div class="block_content tab_content" id="mine" style="padding-left:30px;">
<table width="60%" class="stats" rel="area">
<caption>Your Hashrate</caption>
<thead>
<tr>
<td></td>
{for $i=date('G') to 23}
<th scope="col">{$i}:00</th>
{/for}
{for $i=0 to date('G', time () - 60 * 60)}
<th scope="col">{$i}:00</th>
{/for}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{$smarty.session.USERDATA.username}</th>
{for $i=date('G') to 23}
<td>{$YOURHASHRATES.$i|default:"0"}</td>
{/for}
{for $i=0 to date('G', time() - 60 * 60)}
<td>{$YOURHASHRATES.$i|default:"0"}</td>
{/for}
</tr>
</tbody>
</table>
</div>
{else}
<p><li>No shares available to start calculations</li></p>
{/if}

View File

@ -0,0 +1,31 @@
{if is_array($POOLHASHRATES)}
<div class="block_content tab_content" id="pool" style="padding-left:30px;">
<table width="60%" class="stats" rel="area">
<caption>Pool Hashrate</caption>
<thead>
<tr>
<td></td>
{for $i=date('G') to 23}
<th scope="col">{$i}:00</th>
{/for}
{for $i=0 to date('G', time () - 60 * 60)}
<th scope="col">{$i}:00</th>
{/for}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Pool</th>
{for $i=date('G') to 23}
<td>{$POOLHASHRATES.$i|default:"0"}</td>
{/for}
{for $i=0 to date('G', time() - 60 * 60)}
<td>{$POOLHASHRATES.$i|default:"0"}</td>
{/for}
</tr>
</tbody>
</table>
</div>
{else}
<p><li>No shares available to start calculations</li></p>
{/if}

View File

@ -4,15 +4,19 @@
{include file="statistics/pool/contributors_hashrate.tpl"}
{include file="global/block_header.tpl" BLOCK_HEADER="Server Stats" BLOCK_STYLE="clear:all;" STYLE="padding-left:5px;padding-right:5px;"}
{include file="global/block_header.tpl" ALIGN="left" BLOCK_HEADER="Server Stats" BLOCK_STYLE="clear:all;" STYLE="padding-left:5px;padding-right:5px;"}
<table class="" width="100%" style="font-size:13px;">
<tbody>
<tr>
<td class="leftheader">Pool Hash Rate</td>
<td>{$GLOBAL.hashrate / 1000} Mhash/s</td>
<td>{($GLOBAL.hashrate / 1000)|number_format:"3"} Mhash/s</td>
</tr>
<tr>
<td class="leftheader">Current Workers Mining</td>
<td class="leftheader">Pool Efficiency</td>
<td>{(100 - (100 / $GLOBAL.roundshares.valid * $GLOBAL.roundshares.invalid))|number_format:"2"} %</td>
</tr>
<tr>
<td class="leftheader">Current Active Workers</td>
<td>{$GLOBAL.workers}</td>
</tr>
<tr>
@ -32,8 +36,8 @@
<td>{$ESTTIME|seconds_to_words}</td>
</tr>
<tr>
<td class="leftheader">Est. Avg. Shares per Round</td>
<td>{($ESTTIME * $GLOBAL.sharerate)|number_format:"0"}</td>
<td class="leftheader">Est. Shares this Round</td>
<td>{(pow(2, 32 - $GLOBAL.config.targetdiff) * $DIFFICULTY)|number_format:"0"} <font size="1">(done: {(100 / (pow(2, 32 - $GLOBAL.config.targetdiff) * $DIFFICULTY) * $GLOBAL.roundshares.valid)|number_format:"2"} %)</td>
</tr>
<tr>
<td class="leftheader">Time Since Last Block</td>
@ -44,6 +48,6 @@
{include file="global/block_footer.tpl"}
{include file="statistics/blocks/blocks_found.tpl"}
{include file="statistics/blocks/small_table.tpl" ALIGN="right" SHORT=true}
{include file="global/block_footer.tpl"}

View File

@ -6,18 +6,21 @@
<th align="left">Rank</th>
<th align="left" scope="col">User Name</th>
<th class="right" scope="col">KH/s</th>
<th class="right">Ł/Day<font size="1"> (est)</font></th>
<th class="right">{$GLOBAL.config.currency}/Day</th>
<th class="right">{$GLOBAL.config.price.currency}/Day</th>
</tr>
</thead>
<tbody>
{assign var=rank value=1}
{assign var=listed value=0}
{section contrib $CONTRIBHASHES}
{math assign="estday" equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24), 3)" diff=$DIFFICULTY reward=$REWARD hashrate=$CONTRIBHASHES[contrib].hashrate}
<tr{if $GLOBAL.userdata.username == $CONTRIBHASHES[contrib].account}{assign var=listed value=1} style="background-color:#99EB99;"{else} class="{cycle values="odd,even"}"{/if}>
<td>{$rank++}</td>
<td>{$CONTRIBHASHES[contrib].account}</td>
<td class="right">{$CONTRIBHASHES[contrib].hashrate|number_format}</td>
<td class="right">{math equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24), 3)" diff=$DIFFICULTY reward=$REWARD hashrate=$CONTRIBHASHES[contrib].hashrate}</td>
<td class="right">{$estday|number_format:"3"}</td>
<td class="right">{($estday * $GLOBAL.price)|default:"n/a"|number_format:"2"}</td>
</tr>
{/section}
{if $listed != 1}
@ -25,7 +28,8 @@
<td>n/a</td>
<td>{$GLOBAL.userdata.username}</td>
<td class="right">{$GLOBAL.userdata.hashrate}</td>
<td class="right">{math equation="round(reward / ( diff * pow(2,32) / ( hashrate * 1000 ) / 3600 / 24), 3)" diff=$DIFFICULTY reward=$REWARD hashrate=$GLOBAL.userdata.hashrate}</td>
<td class="right">{$estday|number_format:"3"|default:"n/a"}</td>
<td class="right">{($estday * $GLOBAL.price)|default:"n/a"|number_format:"2"}</td>
</tr>
{/if}
</tbody>

View File

@ -22,7 +22,7 @@
<tr style="background-color:#99EB99;">
<td>n/a</td>
<td>{$GLOBAL.userdata.username}</td>
<td class="right">{$GLOBAL.userdata.shares.valid}</td>
<td class="right">{$GLOBAL.userdata.shares.valid|number_format}</td>
</tr>
{/if}
</tbody>

View File

@ -1,22 +0,0 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Pool Statistics"}
<table class="" width="50%" style="font-size:14px;">
<tbody>
<tr>
<td class="leftheader">Pool Hash Rate</td>
<td>{$GLOBAL.hashrate / 1000} Mhash/s</td>
</tr>
<tr>
<td class="leftheader">Current Total Miners</td>
<td>{$GLOBAL.workers}</td>
</tr>
<tr>
<td class="leftheader">Current Block</td>
<td><a href="http://explorer.litecoin.net/search?q={$CURRENTBLOCK}" target="_new">{$CURRENTBLOCK}</a></td>
</tr>
<tr>
<td class="leftheader">Current Difficulty</td>
<td><a href="http://allchains.info/" target="_new">{$DIFFICULTY}</a></td>
</tr>
</tbody>
</table>
{include file="global/block_footer.tpl"}

View File

@ -1,23 +0,0 @@
{include file="global/block_header.tpl" BLOCK_HEADER="Your Average Hourly Hash Rate" BUTTONS=array(mine,pool,both)}
<div class="block_content tab_content" id="mine" style="padding-left:30px;">
<table class="stats" rel="area" cellpadding="0">
<caption>Your Hashrate&nbsp;</caption>
<thead>
<tr>
<td></td>
{section hashrate $YOURHASHRATES}
<th scope="col">{$YOURHASHRATES[hashrate].hour}</th>
{/section}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">{$GLOBAL.USERDATA.username}</th>
{section hashrate $YOURHASHRATES}
<td>{$YOURHASHRATES[hashrate].hashrate|number_format}</td>
{/section}
</tr>
</tbody>
</table>
</div>
{include file="global/block_footer.tpl"}

View File

@ -0,0 +1,17 @@
CREATE TABLE IF NOT EXISTS `notifications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(25) NOT NULL,
`data` varchar(255) NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`account_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `active` (`active`),
KEY `data` (`data`),
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `notification_settings` (
`type` varchar(15) NOT NULL,
`account_id` int(11) NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@ -0,0 +1,2 @@
ALTER TABLE `accounts` ADD `is_locked` BOOLEAN NOT NULL DEFAULT FALSE AFTER `email` ;
ALTER TABLE `accounts` CHANGE `admin` `is_admin` BOOLEAN NOT NULL DEFAULT FALSE ;

View File

@ -0,0 +1 @@
ALTER TABLE `transactions` CHANGE `type` `type` ENUM( 'Credit', 'Debit_MP', 'Debit_AP', 'Donation', 'Fee', 'Orphan_Credit', 'Orphan_Fee', 'Orphan_Donation', 'Bonus', 'Orphan_Bonus' ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;

View File

@ -0,0 +1 @@
ALTER TABLE `settings` CHANGE `setting` `name` VARCHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ;

View File

@ -0,0 +1 @@
ALTER TABLE `accounts` ADD `failed_logins` INT( 5 ) UNSIGNED NULL DEFAULT '0' AFTER `is_locked` ;

View File

@ -0,0 +1 @@
ALTER TABLE `transactions` CHANGE `type` `type` ENUM( 'Credit', 'Debit_MP', 'Debit_AP', 'Donation', 'Fee', 'Orphan_Credit', 'Orphan_Fee', 'Orphan_Donation', 'Credit_PPS', 'Fee_PPS', 'Donation_PPS', 'TXFee' ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ;

View File

@ -0,0 +1 @@
ALTER TABLE `notification_settings` ADD `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST ;

View File

@ -0,0 +1 @@
ALTER TABLE `transactions` CHANGE `type` `type` ENUM( 'Credit', 'Debit_MP', 'Debit_AP', 'Donation', 'Fee', 'Orphan_Credit', 'Orphan_Fee', 'Orphan_Donation', 'Bonus', 'Orphan_Bonus', 'Credit_PPS', 'Debit_PPS', 'Donation_PPS' ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL;

View File

@ -1,37 +1,22 @@
-- phpMyAdmin SQL Dump
-- version 3.5.8.1deb1
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: May 31, 2013 at 02:31 PM
-- Server version: 5.5.31-0ubuntu0.13.04.1
-- PHP Version: 5.4.9-4ubuntu2
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
--
-- Database: `mmcfe_ng`
--
-- --------------------------------------------------------
--
-- Table structure for table `accounts`
--
CREATE DATABASE IF NOT EXISTS `mmcfe_ng` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `mmcfe_ng`;
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`admin` int(1) NOT NULL DEFAULT '0',
`is_admin` tinyint(1) NOT NULL DEFAULT '0',
`username` varchar(40) NOT NULL,
`pass` varchar(255) NOT NULL,
`email` varchar(255) DEFAULT NULL COMMENT 'Assocaited email: used for validating users, and re-setting passwords',
`is_locked` tinyint(1) NOT NULL DEFAULT '0',
`failed_logins` int(5) unsigned DEFAULT '0',
`loggedIp` varchar(255) DEFAULT NULL,
`sessionTimeoutStamp` int(255) DEFAULT NULL,
`pin` varchar(255) NOT NULL COMMENT 'four digit pin to allow account changes',
@ -44,12 +29,6 @@ CREATE TABLE IF NOT EXISTS `accounts` (
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `blocks`
--
CREATE TABLE IF NOT EXISTS `blocks` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`height` int(10) unsigned NOT NULL,
@ -65,13 +44,39 @@ CREATE TABLE IF NOT EXISTS `blocks` (
PRIMARY KEY (`id`),
UNIQUE KEY `height` (`height`,`blockhash`),
KEY `time` (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service';
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service';
-- --------------------------------------------------------
CREATE TABLE IF NOT EXISTS `notifications` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(25) NOT NULL,
`data` varchar(255) NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`account_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `active` (`active`),
KEY `data` (`data`),
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table structure for table `settings`
--
CREATE TABLE IF NOT EXISTS `notification_settings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(15) NOT NULL,
`account_id` int(11) NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `pool_worker` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`account_id` int(255) NOT NULL,
`username` char(50) DEFAULT NULL,
`password` char(255) DEFAULT NULL,
`monitor` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `settings` (
`name` varchar(255) NOT NULL,
@ -80,12 +85,6 @@ CREATE TABLE IF NOT EXISTS `settings` (
UNIQUE KEY `setting` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `shares`
--
CREATE TABLE IF NOT EXISTS `shares` (
`id` bigint(30) NOT NULL AUTO_INCREMENT,
`rem_host` varchar(255) NOT NULL,
@ -100,13 +99,7 @@ CREATE TABLE IF NOT EXISTS `shares` (
KEY `upstream_result` (`upstream_result`),
KEY `our_result` (`our_result`),
KEY `username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `shares_archive`
--
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `shares_archive` (
`id` int(255) unsigned NOT NULL AUTO_INCREMENT,
@ -119,13 +112,7 @@ CREATE TABLE IF NOT EXISTS `shares_archive` (
PRIMARY KEY (`id`),
UNIQUE KEY `share_id` (`share_id`),
KEY `time` (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
-- --------------------------------------------------------
--
-- Table structure for table `statistics_shares`
--
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Archive shares for potential later debugging purposes';
CREATE TABLE IF NOT EXISTS `statistics_shares` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
@ -136,18 +123,12 @@ CREATE TABLE IF NOT EXISTS `statistics_shares` (
PRIMARY KEY (`id`),
KEY `account_id` (`account_id`),
KEY `block_id` (`block_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `transactions`
--
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `transactions` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`account_id` int(255) unsigned NOT NULL,
`type` enum('Credit','Debit_MP','Debit_AP','Donation','Fee','Orphan_Credit','Orphan_Fee','Orphan_Donation') DEFAULT NULL,
`type` enum('Credit','Debit_MP','Debit_AP','Donation','Fee','Orphan_Credit','Orphan_Fee','Orphan_Donation','Credit_PPS','Fee_PPS','Donation_PPS','TXFee') DEFAULT NULL,
`coin_address` varchar(255) DEFAULT NULL,
`amount` double DEFAULT '0',
`block_id` int(255) DEFAULT NULL,
@ -156,24 +137,7 @@ CREATE TABLE IF NOT EXISTS `transactions` (
KEY `block_id` (`block_id`),
KEY `account_id` (`account_id`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `pool_worker`
--
CREATE TABLE IF NOT EXISTS `pool_worker` (
`id` int(255) NOT NULL AUTO_INCREMENT,
`account_id` int(255) NOT NULL,
`username` char(50) DEFAULT NULL,
`password` char(255) DEFAULT NULL,
`hashrate` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`),
KEY `account_id` (`account_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;