From 88eaf66668336d2b8bd598471f02883553994156 Mon Sep 17 00:00:00 2001 From: VictorMezrin Date: Thu, 15 May 2014 11:15:52 +0400 Subject: [PATCH 01/38] Add a script to send a test email --- scripts/test_email.php | 19 +++++++++++++++++++ templates/mail/notifications/test_email.tpl | 6 ++++++ 2 files changed, 25 insertions(+) create mode 100755 scripts/test_email.php create mode 100644 templates/mail/notifications/test_email.tpl diff --git a/scripts/test_email.php b/scripts/test_email.php new file mode 100755 index 00000000..838e846b --- /dev/null +++ b/scripts/test_email.php @@ -0,0 +1,19 @@ + $setting->getValue('system_error_email'), + 'subject' => 'Test email from mining pool', + 'coinname' => $config['gettingstarted']['coinname'], + 'stratumurl' => $config['gettingstarted']['stratumurl'], + 'stratumport' => $config['gettingstarted']['stratumport'] +); + +if (!$mail->sendMail('notifications/test_email', $aMailData)) + echo "Failed to send test email" . PHP_EOL; diff --git a/templates/mail/notifications/test_email.tpl b/templates/mail/notifications/test_email.tpl new file mode 100644 index 00000000..b4595b13 --- /dev/null +++ b/templates/mail/notifications/test_email.tpl @@ -0,0 +1,6 @@ +{include file="../global/header.tpl"} +

Test email

+

If you see this email - your email protocol is configured correctly

+

Coin name: {$DATA.coinname}

+

Stratum: {$DATA.stratumurl}:{$DATA.stratumport}

+{include file="../global/footer.tpl"} From e83dea481fe17c3646145b0df250a9dfcde86780 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Wed, 25 Jun 2014 10:14:13 +0200 Subject: [PATCH 02/38] [ADDED] Server port unless it's behind SSL Fixes #2246 --- templates/mail/invitations/body.tpl | 2 +- templates/mail/notifications/account_edit.tpl | 2 +- templates/mail/notifications/change_pw.tpl | 2 +- templates/mail/notifications/locked.tpl | 2 +- templates/mail/password/reset.tpl | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/mail/invitations/body.tpl b/templates/mail/invitations/body.tpl index 7d5ed687..57933250 100644 --- a/templates/mail/invitations/body.tpl +++ b/templates/mail/invitations/body.tpl @@ -2,7 +2,7 @@

Hello valued miner,


{nocache}{$DATA.username}{/nocache} invited you to participate on this pool: -

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}

{if $DATA.message}

Personal message:

{nocache}{$DATA.message}{/nocache}

{/if}

Cheers,

diff --git a/templates/mail/notifications/account_edit.tpl b/templates/mail/notifications/account_edit.tpl index 8ea77def..db292c6d 100644 --- a/templates/mail/notifications/account_edit.tpl +++ b/templates/mail/notifications/account_edit.tpl @@ -2,7 +2,7 @@

You have a pending request to change your account details.

If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}



diff --git a/templates/mail/notifications/change_pw.tpl b/templates/mail/notifications/change_pw.tpl index 4f8a02b6..4dac112c 100644 --- a/templates/mail/notifications/change_pw.tpl +++ b/templates/mail/notifications/change_pw.tpl @@ -2,7 +2,7 @@

You have a pending request to change your password.

If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}



diff --git a/templates/mail/notifications/locked.tpl b/templates/mail/notifications/locked.tpl index 04a5ccc3..d7bd95b8 100644 --- a/templates/mail/notifications/locked.tpl +++ b/templates/mail/notifications/locked.tpl @@ -1,7 +1,7 @@

You account has been locked due to too many failed password or PIN attempts. Please follow the URL below to unlock your account.

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}



diff --git a/templates/mail/password/reset.tpl b/templates/mail/password/reset.tpl index 514c915f..d4dd939f 100644 --- a/templates/mail/password/reset.tpl +++ b/templates/mail/password/reset.tpl @@ -2,7 +2,7 @@

Hello {nocache}{$DATA.username}{/nocache},


You have requested a password reset through our online form. In order to complete the request please follow this link:

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}

You will be asked to change your password. You can then use this new password to login to your account.

Cheers,

{$WEBSITENAME}

From e39d90fffc2afb1ba44c0ce5cf264e77c50aaf43 Mon Sep 17 00:00:00 2001 From: phoneman13 Date: Thu, 26 Jun 2014 20:24:25 -0500 Subject: [PATCH 03/38] Update tools.class.php Added Bittrex support --- include/classes/tools.class.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/classes/tools.class.php b/include/classes/tools.class.php index c42f5159..06b3626e 100644 --- a/include/classes/tools.class.php +++ b/include/classes/tools.class.php @@ -81,6 +81,8 @@ class Tools extends Base { return 'cryptorush'; } else if (preg_match('/mintpal.com/', $url)) { return 'mintpal'; + } else if (preg_match('/bittrex.com/', $url)) { + return 'bittrex'; } $this->setErrorMessage("API URL unknown"); return false; @@ -116,6 +118,9 @@ class Tools extends Base { case 'mintpal': return @$aData['0']['last_price']; break; + case 'bittrex': + return @$aData['result']['Last']; + break; } } else { $this->setErrorMessage("Got an invalid response from ticker API"); From 4acb3103d3783cee52760f3c8342f568b76b12e3 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Mon, 30 Jun 2014 07:03:32 +0200 Subject: [PATCH 04/38] [FIX] Proper port detection on templates --- templates/bootstrap/account/qrcode/default.tpl | 2 +- templates/mail/invitations/body.tpl | 2 +- templates/mail/notifications/account_edit.tpl | 2 +- templates/mail/notifications/change_pw.tpl | 2 +- templates/mail/notifications/locked.tpl | 2 +- templates/mail/password/reset.tpl | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/templates/bootstrap/account/qrcode/default.tpl b/templates/bootstrap/account/qrcode/default.tpl index 76935d09..5b738407 100644 --- a/templates/bootstrap/account/qrcode/default.tpl +++ b/templates/bootstrap/account/qrcode/default.tpl @@ -4,7 +4,7 @@ {literal} $(document).ready(function(){ $('#qrcodeholder').qrcode({ - text : "{/literal}|http{if $smarty.server.HTTPS|default:"0" eq 'on'}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=api|{$GLOBAL.userdata.api_key}|{$GLOBAL.userdata.id}|{$GLOBAL.config.currency|upper}|{literal}", + text : "{/literal}|http{if $smarty.server.HTTPS|default:"0" eq 'on'}s{/if}://{$smarty.server.SERVER_NAME}{if $smarty.server.SERVER_PORT != "443" && $smarty.server.SERVER_PORT != "80"}:{$smarty.server.SERVER_PORT}{/if}{$smarty.server.SCRIPT_NAME}?page=api|{$GLOBAL.userdata.api_key}|{$GLOBAL.userdata.id}|{$GLOBAL.config.currency|upper}|{literal}", render : "canvas", // 'canvas' or 'table'. Default value is 'canvas' background : "#ffffff", foreground : "#000000", diff --git a/templates/mail/invitations/body.tpl b/templates/mail/invitations/body.tpl index 57933250..67ec28b4 100644 --- a/templates/mail/invitations/body.tpl +++ b/templates/mail/invitations/body.tpl @@ -2,7 +2,7 @@

Hello valued miner,


{nocache}{$DATA.username}{/nocache} invited you to participate on this pool: -

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=register&token={nocache}{$DATA.token}{/nocache}

{if $DATA.message}

Personal message:

{nocache}{$DATA.message}{/nocache}

{/if}

Cheers,

diff --git a/templates/mail/notifications/account_edit.tpl b/templates/mail/notifications/account_edit.tpl index db292c6d..13917742 100644 --- a/templates/mail/notifications/account_edit.tpl +++ b/templates/mail/notifications/account_edit.tpl @@ -2,7 +2,7 @@

You have a pending request to change your account details.

If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&ea_token={nocache}{$DATA.token}{/nocache}



diff --git a/templates/mail/notifications/change_pw.tpl b/templates/mail/notifications/change_pw.tpl index 4dac112c..90a02ae9 100644 --- a/templates/mail/notifications/change_pw.tpl +++ b/templates/mail/notifications/change_pw.tpl @@ -2,7 +2,7 @@

You have a pending request to change your password.

If you initiated this request, please follow the link below to confirm your changes. If you did NOT, please notify an administrator.

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=edit&cp_token={nocache}{$DATA.token}{/nocache}



diff --git a/templates/mail/notifications/locked.tpl b/templates/mail/notifications/locked.tpl index d7bd95b8..7783e456 100644 --- a/templates/mail/notifications/locked.tpl +++ b/templates/mail/notifications/locked.tpl @@ -1,7 +1,7 @@

You account has been locked due to too many failed password or PIN attempts. Please follow the URL below to unlock your account.

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=account&action=unlock&token={nocache}{$DATA.token}{/nocache}



diff --git a/templates/mail/password/reset.tpl b/templates/mail/password/reset.tpl index d4dd939f..d942fe2c 100644 --- a/templates/mail/password/reset.tpl +++ b/templates/mail/password/reset.tpl @@ -2,7 +2,7 @@

Hello {nocache}{$DATA.username}{/nocache},


You have requested a password reset through our online form. In order to complete the request please follow this link:

-

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}

+

http{if $smarty.server.HTTPS|default:"" eq "on"}s{/if}://{$smarty.server.SERVER_NAME}{$smarty.server.SCRIPT_NAME}?page=password&action=change&token={nocache}{$DATA.token}{/nocache}

You will be asked to change your password. You can then use this new password to login to your account.

Cheers,

{$WEBSITENAME}

From 3248a487df3a2556eaf3d564dfef56de8e7c7df4 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 12 Jun 2014 12:32:05 +0200 Subject: [PATCH 05/38] [ADDED] coin_addresses table and support * [ADDED] New coin_addresses table to upgrade script and base file * [MIGRATE] Move coin_address from accounts to coin_addresses table * [UPDATE] Updated all classes/pages/scripts to use new coin address class * [UPDATE] DB_VERSION 0.0.12 --- include/autoloader.inc.php | 1 + include/classes/base.class.php | 3 + include/classes/coin_address.class.php | 92 ++++++++++++++++++++ include/classes/transaction.class.php | 17 ++-- include/classes/user.class.php | 86 ++++++++---------- include/pages/account/edit.inc.php | 2 +- include/pages/account/workers.inc.php | 4 +- include/version.inc.php | 2 +- scripts/validate_addresses.php | 1 + scripts/validate_users.php | 1 - sql/000_base_structure.sql | 10 +++ upgrade/definitions/0.0.11_to_0.0.12.inc.php | 32 +++++++ 12 files changed, 190 insertions(+), 61 deletions(-) create mode 100644 include/classes/coin_address.class.php create mode 100644 upgrade/definitions/0.0.11_to_0.0.12.inc.php diff --git a/include/autoloader.inc.php b/include/autoloader.inc.php index 4d14e17e..eb44f86f 100644 --- a/include/autoloader.inc.php +++ b/include/autoloader.inc.php @@ -16,6 +16,7 @@ require_once(INCLUDE_DIR . '/config/error_codes.inc.php'); // We need to load these first require_once(CLASS_DIR . '/base.class.php'); require_once(CLASS_DIR . '/coins/coin_base.class.php'); +require_once(CLASS_DIR . '/coin_address.class.php'); require_once(CLASS_DIR . '/setting.class.php'); require_once(INCLUDE_DIR . '/version.inc.php'); if (PHP_OS == 'WINNT') require_once(CLASS_DIR . '/memcached.class.php'); diff --git a/include/classes/base.class.php b/include/classes/base.class.php index 1bb27e3a..d9f950ad 100644 --- a/include/classes/base.class.php +++ b/include/classes/base.class.php @@ -22,6 +22,9 @@ class Base { public function setCoin($coin) { $this->coin = $coin; } + public function setCoinAddress($coin_address) { + $this->coin_address = $coin_address; + } public function setLog($log) { $this->log = $log; } diff --git a/include/classes/coin_address.class.php b/include/classes/coin_address.class.php new file mode 100644 index 00000000..e5f108ac --- /dev/null +++ b/include/classes/coin_address.class.php @@ -0,0 +1,92 @@ +config['currency']; + $this->debug->append("STA " . __METHOD__, 4); + $stmt = $this->mysqli->prepare(" + SELECT coin_address + FROM " . $this->getTableName() . " + WHERE account_id = ? AND currency = ? + "); + if ( $this->checkStmt($stmt) && $stmt->bind_param('is', $userID, $currency) && $stmt->execute() && $result = $stmt->get_result()) { + if ($result->num_rows == 1) { + return $result->fetch_object()->coin_address; + } + } + $this->debug->append("Unable to fetch users coin address for " . $currency); + return $this->sqlError(); + } + + /** + * Check if a coin address is already set + * @param address string Coin Address to check for + * @return bool true or false + **/ + public function existsCoinAddress($address) { + $this->debug->append("STA " . __METHOD__, 4); + return $this->getSingle($address, 'coin_address', 'coin_address', 's') === $address; + } + + /** + * Add a new coin address record for a user + * @param userID int Account ID + * @param address string Coin Address + * @param currency string Currency short handle, defaults to config option + * @return bool true or false + **/ + public function add($userID, $address, $currency=NULL) { + if ($currency === NULL) $currency = $this->config['currency']; + if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) { + $this->setErrorMessage('Unable to update coin address, address already exists'); + return false; + } + $stmt = $this->mysqli->prepare("INSERT INTO " . $this->getTableName() . " (account_id, currency, coin_address) VALUES (?, ?, ?)"); + if ( $this->checkStmt($stmt) && $stmt->bind_param('sis', $userID, $currency, $address) && $stmt->execute()) { + return true; + } + return $this->sqlError(); + } + + /** + * Update a coin address record for a user and a currency + * @param userID int Account ID + * @param address string Coin Address + * @param currency string Currency short handle, defaults to config option + * @return bool true or false + **/ + public function update($userID, $address, $currency=NULL) { + if ($currency === NULL) $currency = $this->config['currency']; + if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) { + $this->setErrorMessage('Unable to update coin address, address already exists'); + return false; + } + if ($this->getCoinAddress($userID) != NULL) { + $stmt = $this->mysqli->prepare("UPDATE " . $this->getTableName() . " SET coin_address = ? WHERE account_id = ? AND currency = ?"); + if ( $this->checkStmt($stmt) && $stmt->bind_param('sis', $address, $userID, $currency) && $stmt->execute()) { + return true; + } + } else { + $stmt = $this->mysqli->prepare("INSERT INTO " . $this->getTableName() . " (coin_address, account_id, currency) VALUES (?, ?, ?)"); + if ( $this->checkStmt($stmt) && $stmt->bind_param('sis', $address, $userID, $currency) && $stmt->execute()) { + return true; + } + } + return $this->sqlError(); + } +} + +$coin_address = new CoinAddress(); +$coin_address->setDebug($debug); +$coin_address->setConfig($config); +$coin_address->setMysql($mysqli); +$coin_address->setErrorCodes($aErrorCodes); diff --git a/include/classes/transaction.class.php b/include/classes/transaction.class.php index d01b53e3..8920419b 100644 --- a/include/classes/transaction.class.php +++ b/include/classes/transaction.class.php @@ -355,7 +355,7 @@ class Transaction extends Base { a.id, a.username, a.ap_threshold, - a.coin_address, + ca.coin_address, IFNULL( ROUND( ( @@ -370,11 +370,13 @@ class Transaction extends Base { ON t.block_id = b.id LEFT JOIN " . $this->user->getTableName() . " AS a ON t.account_id = a.id - WHERE t.archived = 0 AND a.ap_threshold > 0 AND a.coin_address IS NOT NULL AND a.coin_address != '' + LEFT JOIN " . $this->coin_address->getTableName() . " AS ca + ON ca.account_id = a.id + WHERE t.archived = 0 AND a.ap_threshold > 0 AND ca.coin_address IS NOT NULL AND ca.coin_address != '' AND ca.currency = ? GROUP BY t.account_id HAVING confirmed > a.ap_threshold AND confirmed > " . $this->config['txfee_auto'] . " LIMIT ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return $this->sqlError(); } @@ -446,7 +448,7 @@ class Transaction extends Base { a.id, a.username, a.ap_threshold, - a.coin_address, + ca.coin_address, p.id AS payout_id, IFNULL( ROUND( @@ -464,11 +466,13 @@ class Transaction extends Base { ON t.account_id = p.account_id LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id - WHERE p.completed = 0 AND t.archived = 0 AND a.coin_address IS NOT NULL AND a.coin_address != '' + LEFT JOIN " . $this->coin_address->getTableName() . " AS ca + ON ca.account_id = a.id + WHERE p.completed = 0 AND t.archived = 0 AND ca.currency = ? AND ca.coin_address IS NOT NULL AND ca.coin_address != '' GROUP BY t.account_id HAVING confirmed > " . $this->config['txfee_manual'] . " LIMIT ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('i', $limit) && $stmt->execute() && $result = $stmt->get_result()) + if ($this->checkStmt($stmt) && $stmt->bind_param('si', $this->config['currency'], $limit) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return $this->sqlError('E0050'); } @@ -478,6 +482,7 @@ $transaction = new Transaction(); $transaction->setMemcache($memcache); $transaction->setNotification($notification); $transaction->setDebug($debug); +$transaction->setCoinAddress($coin_address); $transaction->setMysql($mysqli); $transaction->setConfig($config); $transaction->setBlock($block); diff --git a/include/classes/user.class.php b/include/classes/user.class.php index 7cb0d58b..5e59b853 100644 --- a/include/classes/user.class.php +++ b/include/classes/user.class.php @@ -163,7 +163,7 @@ class User extends Base { $invitation->setDebug($this->debug); $invitation->setLog($this->log); $stmt = $this->mysqli->prepare(" - SELECT COUNT(i.account_id) AS invitationcount,a.id,a.username,a.email, + SELECT COUNT(i.account_id) AS invitationcount,a.id,a.username,a.email, (SELECT COUNT(account_id) FROM " . $invitation->getTableName() . " WHERE account_id = i.account_id AND is_activated = 1 GROUP BY account_id) AS activated FROM " . $invitation->getTableName() . " AS i LEFT JOIN " . $this->getTableName() . " AS a @@ -340,38 +340,20 @@ class User extends Base { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT - id, username, coin_address, ap_threshold - FROM " . $this->getTableName() . " - WHERE ap_threshold > 0 - AND coin_address IS NOT NULL + a.id, a.username, ca.coin_address AS coin_address, a.ap_threshold + FROM " . $this->getTableName() . " AS a + LEFT JOIN " . $this->coin_address->getTableName() . " AS ca + ON a.id = ca.account_id + WHERE ap_threshold > 0 AND ca.currency = ? + AND ca.coin_address IS NOT NULL "); - if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { + if ( $this->checkStmt($stmt) && $stmt->bind_param('s', $this->config['currency']) && $stmt->execute() && $result = $stmt->get_result()) { return $result->fetch_all(MYSQLI_ASSOC); } $this->debug->append("Unable to fetch users with AP set"); return false; } - /** - * Fetch users coin address - * @param userID int UserID - * @return data string Coin Address - **/ - public function getCoinAddress($userID) { - $this->debug->append("STA " . __METHOD__, 4); - return $this->getSingle($userID, 'coin_address', 'id'); - } - - /** - * Check if a coin address exists already - * @param address string Coin Address - * @return bool True of false - **/ - public function existsCoinAddress($address) { - $this->debug->append("STA " . __METHOD__, 4); - return $this->getSingle($address, 'coin_address', 'coin_address', 's') === $address; - } - /** * Fetch users donation value * @param userID int UserID @@ -519,7 +501,7 @@ class User extends Base { return false; } if (!empty($address)) { - if ($address != $this->getCoinAddress($userID) && $this->existsCoinAddress($address)) { + if ($address != $this->coin_address->getCoinAddress($userID) && $this->coin_address->existsCoinAddress($address)) { $this->setErrorMessage('Address is already in use'); return false; } @@ -559,10 +541,12 @@ class User extends Base { } // We passed all validation checks so update the account - $stmt = $this->mysqli->prepare("UPDATE $this->table SET coin_address = ?, ap_threshold = ?, donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param('sddssii', $address, $threshold, $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) { + $stmt = $this->mysqli->prepare("UPDATE $this->table SET ap_threshold = ?, donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param('ddssii', $threshold, $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) { $this->log->log("info", $this->getUserName($userID)." updated their account details"); - return true; + // Update coin address too + if ($this->coin_address->update($userID, $address)) + return true; } // Catchall $this->setErrorMessage('Failed to update your account'); @@ -703,22 +687,18 @@ class User extends Base { $this->debug->append("Fetching user information for user id: $userID"); $stmt = $this->mysqli->prepare(" SELECT - id, username, pin, api_key, is_admin, is_anonymous, email, timezone, no_fees, - IFNULL(donate_percent, '0') as donate_percent, coin_address, ap_threshold - FROM $this->table + id AS id, username, pin, api_key, is_admin, is_anonymous, email, timezone, no_fees, + IFNULL(donate_percent, '0') as donate_percent, ap_threshold + FROM " . $this->getTableName() . " WHERE id = ? LIMIT 0,1"); - if ($this->checkStmt($stmt)) { - $stmt->bind_param('i', $userID); - if (!$stmt->execute()) { - $this->debug->append('Failed to execute statement'); - return false; - } - $result = $stmt->get_result(); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $userID) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = $result->fetch_assoc(); + $aData['coin_address'] = $this->coin_address->getCoinAddress($userID); $stmt->close(); - return $result->fetch_assoc(); + return $aData; } $this->debug->append("Failed to fetch user information for $userID"); - return false; + return $this->sqlError(); } /** @@ -742,6 +722,10 @@ class User extends Base { return false; } if (!is_null($coinaddress)) { + if ($this->coin_address->existsCoinAddress($coinaddress)) { + $this->setErrorMessage('Coin address is already taken'); + return false; + } if (!$this->bitcoin->validateaddress($coinaddress)) { $this->setErrorMessage('Coin address is not valid'); return false; @@ -755,7 +739,7 @@ class User extends Base { $this->setErrorMessage( 'This e-mail address is already taken' ); return false; } - if (strlen($password1) < 8) { + if (strlen($password1) < 8) { $this->setErrorMessage( 'Password is too short, minimum of 8 characters required' ); return false; } @@ -801,15 +785,15 @@ class User extends Base { ! $this->setting->getValue('accounts_confirm_email_disabled') ? $is_locked = 1 : $is_locked = 0; $is_admin = 0; $stmt = $this->mysqli->prepare(" - INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_locked, coin_address) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) + INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_locked) + VALUES (?, ?, ?, ?, ?, ?, ?) "); } else { $is_locked = 0; $is_admin = 1; $stmt = $this->mysqli->prepare(" - INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_admin, is_locked, coin_address) - VALUES (?, ?, ?, ?, ?, ?, 1, ?, ?) + INSERT INTO $this->table (username, pass, email, signup_timestamp, pin, api_key, is_admin, is_locked) + VALUES (?, ?, ?, ?, ?, ?, 1, ?) "); } @@ -820,7 +804,9 @@ class User extends Base { $username_clean = strip_tags($username); $signup_time = time(); - if ($this->checkStmt($stmt) && $stmt->bind_param('sssissis', $username_clean, $password_hash, $email1, $signup_time, $pin_hash, $apikey_hash, $is_locked, $coinaddress) && $stmt->execute()) { + if ($this->checkStmt($stmt) && $stmt->bind_param('sssissi', $username_clean, $password_hash, $email1, $signup_time, $pin_hash, $apikey_hash, $is_locked) && $stmt->execute()) { + $new_account_id = $this->mysqli->insert_id; + if (!is_null($coinaddress)) $this->coin_address->add($new_account_id, $coinaddress); if (! $this->setting->getValue('accounts_confirm_email_disabled') && $is_admin != 1) { if ($token = $this->token->createToken('confirm_email', $stmt->insert_id)) { $aData['username'] = $username_clean; @@ -843,7 +829,8 @@ class User extends Base { } else { $this->setErrorMessage( 'Unable to register' ); $this->debug->append('Failed to insert user into DB: ' . $this->mysqli->error); - if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username, email or Coinaddress already registered' ); + echo $this->mysqli->error; + if ($stmt->sqlstate == '23000') $this->setErrorMessage( 'Username or email already registered' ); return false; } return false; @@ -997,4 +984,5 @@ $user->setMail($mail); $user->setToken($oToken); $user->setBitcoin($bitcoin); $user->setSetting($setting); +$user->setCoinAddress($coin_address); $user->setErrorCodes($aErrorCodes); diff --git a/include/pages/account/edit.inc.php b/include/pages/account/edit.inc.php index 78782ad4..234f68d6 100644 --- a/include/pages/account/edit.inc.php +++ b/include/pages/account/edit.inc.php @@ -104,7 +104,7 @@ if ($user->isAuthenticated()) { $_SESSION['POPUP'][] = array('CONTENT' => 'You have not yet unlocked account withdrawls.', 'TYPE' => 'alert alert-danger'); } else if ($aBalance['confirmed'] < $config['mp_threshold']) { $_SESSION['POPUP'][] = array('CONTENT' => 'Payout must be greater or equal than ' . $config['mp_threshold'] . '.', 'TYPE' => 'info'); - } else if (!$user->getCoinAddress($_SESSION['USERDATA']['id'])) { + } else if (!$coin_address->getCoinAddress($_SESSION['USERDATA']['id'])) { $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); } else { $user->log->log("info", $_SESSION['USERDATA']['username']." requesting manual payout"); diff --git a/include/pages/account/workers.inc.php b/include/pages/account/workers.inc.php index eeb9fb26..a672e11c 100644 --- a/include/pages/account/workers.inc.php +++ b/include/pages/account/workers.inc.php @@ -4,12 +4,10 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($user->isAuthenticated()) { - if (!$user->getCoinAddress($_SESSION['USERDATA']['id']) AND $setting->getValue('disable_worker_edit')) { - + if (!$coin_address->getCoinAddress($_SESSION['USERDATA']['id']) AND $setting->getValue('disable_worker_edit')) { $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); $_SESSION['POPUP'][] = array('CONTENT' => 'You can not add workers unless a valid Payout Address is set in your User Settings.', 'TYPE' => 'alert alert-danger'); $smarty->assign('CONTENT', 'disabled.tpl'); - } else { switch (@$_REQUEST['do']) { case 'delete': diff --git a/include/version.inc.php b/include/version.inc.php index 91d93ee8..a4e0d533 100644 --- a/include/version.inc.php +++ b/include/version.inc.php @@ -2,7 +2,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; define('MPOS_VERSION', '0.0.4'); -define('DB_VERSION', '0.0.11'); +define('DB_VERSION', '0.0.12'); define('CONFIG_VERSION', '0.0.8'); define('HASH_VERSION', 1); diff --git a/scripts/validate_addresses.php b/scripts/validate_addresses.php index 15ad46b2..83c314cc 100755 --- a/scripts/validate_addresses.php +++ b/scripts/validate_addresses.php @@ -42,6 +42,7 @@ echo 'Validating all coin addresses. This may take some time.' . PHP_EOL . PHP_E printf($mask, 'Username', 'E-Mail', 'Address', 'Status'); foreach ($users as $aData) { + $aData['coin_address'] = $coin_address->getCoinAddress($aData['id']); if (empty($aData['coin_address']) && $aData['is_locked'] == 0) { $status = 'UNSET'; } else if ($aData['is_locked'] == 1) { diff --git a/scripts/validate_users.php b/scripts/validate_users.php index fe80e2aa..cd99bbb6 100755 --- a/scripts/validate_users.php +++ b/scripts/validate_users.php @@ -36,7 +36,6 @@ $username = $user['username']; $loggedIp = $user['loggedIp']; $lastLogin = $user['last_login']; - $coinAddress = $user['coin_address']; $mailAddress = $user['email']; $everLoggedIn = !empty($lastLogin); diff --git a/sql/000_base_structure.sql b/sql/000_base_structure.sql index 85e3e67c..2299c3b3 100644 --- a/sql/000_base_structure.sql +++ b/sql/000_base_structure.sql @@ -53,6 +53,16 @@ CREATE TABLE IF NOT EXISTS `blocks` ( KEY `time` (`time`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Discovered blocks persisted from Litecoin Service'; +CREATE TABLE IF NOT EXISTS `coin_addresses` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `account_id` int(11) NOT NULL, + `currency` varchar(5) NOT NULL, + `coin_address` varchar(255) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `coin_address` (`coin_address`), + KEY `account_id` (`account_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 + CREATE TABLE IF NOT EXISTS `invitations` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `account_id` int(11) unsigned NOT NULL, diff --git a/upgrade/definitions/0.0.11_to_0.0.12.inc.php b/upgrade/definitions/0.0.11_to_0.0.12.inc.php new file mode 100644 index 00000000..f4ad2b30 --- /dev/null +++ b/upgrade/definitions/0.0.11_to_0.0.12.inc.php @@ -0,0 +1,32 @@ +getValue('DB_VERSION'); // Our actual version installed + + // Upgrade specific variables + $aSql[] = "CREATE TABLE `coin_addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, `currency` varchar(55555) NOT NULL, `coin_address` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8"; + $aSql[] = "INSERT INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName(); + $aSql[] = "ALTER TABLE `" . $user->getTableName() . "` DROP `coin_address`"; + $aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.12' WHERE name = 'DB_VERSION'"; + + if ($db_version_now == $db_version_old && version_compare($db_version_now, DB_VERSION, '<')) { + // Run the upgrade + echo '- Starting database migration to version ' . $db_version_new . PHP_EOL; + foreach ($aSql as $sql) { + echo '- Preparing: ' . $sql . PHP_EOL; + $stmt = $mysqli->prepare($sql); + if ($stmt && $stmt->execute()) { + echo '- success' . PHP_EOL; + } else { + echo '- failed: ' . $mysqli->error . PHP_EOL; + exit(1); + } + } + } +} +?> From 370d66c1473fb85e55e587e2da39df235612b4d9 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Fri, 20 Jun 2014 16:52:12 +0200 Subject: [PATCH 06/38] [FIX] Base Strucutre Import --- sql/000_base_structure.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/000_base_structure.sql b/sql/000_base_structure.sql index 2299c3b3..ef45e0a5 100644 --- a/sql/000_base_structure.sql +++ b/sql/000_base_structure.sql @@ -61,7 +61,7 @@ CREATE TABLE IF NOT EXISTS `coin_addresses` ( PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `invitations` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, From 1c16cad44243b00ba9f30bf77c9770c2b3ccc47f Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 26 Jun 2014 11:31:07 +0200 Subject: [PATCH 07/38] [FIX] Only move existing addresses --- upgrade/definitions/0.0.11_to_0.0.12.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade/definitions/0.0.11_to_0.0.12.inc.php b/upgrade/definitions/0.0.11_to_0.0.12.inc.php index f4ad2b30..7c065da7 100644 --- a/upgrade/definitions/0.0.11_to_0.0.12.inc.php +++ b/upgrade/definitions/0.0.11_to_0.0.12.inc.php @@ -10,7 +10,7 @@ function run_0012() { // Upgrade specific variables $aSql[] = "CREATE TABLE `coin_addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, `currency` varchar(55555) NOT NULL, `coin_address` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8"; - $aSql[] = "INSERT INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName(); + $aSql[] = "INSERT INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName() . " WHERE coin_address != NULL AND coin_address != ''"; $aSql[] = "ALTER TABLE `" . $user->getTableName() . "` DROP `coin_address`"; $aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.12' WHERE name = 'DB_VERSION'"; From 1e922829dd0891dd35e18036acb9818407ac0c9f Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 26 Jun 2014 11:53:31 +0200 Subject: [PATCH 08/38] [FIX] FIX import of coin addresses, ignore duplicates --- upgrade/definitions/0.0.11_to_0.0.12.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade/definitions/0.0.11_to_0.0.12.inc.php b/upgrade/definitions/0.0.11_to_0.0.12.inc.php index 7c065da7..3f8a2c53 100644 --- a/upgrade/definitions/0.0.11_to_0.0.12.inc.php +++ b/upgrade/definitions/0.0.11_to_0.0.12.inc.php @@ -10,7 +10,7 @@ function run_0012() { // Upgrade specific variables $aSql[] = "CREATE TABLE `coin_addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, `currency` varchar(55555) NOT NULL, `coin_address` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8"; - $aSql[] = "INSERT INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName() . " WHERE coin_address != NULL AND coin_address != ''"; + $aSql[] = "INSERT IGNORE INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName() . " WHERE coin_address IS NOT NULL"; $aSql[] = "ALTER TABLE `" . $user->getTableName() . "` DROP `coin_address`"; $aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.12' WHERE name = 'DB_VERSION'"; From a4e17e6a31041d8a6b5388b93d27b06f00885f59 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 26 Jun 2014 12:04:48 +0200 Subject: [PATCH 09/38] [FIX] Clearing coin address for account --- include/classes/coin_address.class.php | 17 ++++++++++++++++- include/classes/user.class.php | 11 +++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/classes/coin_address.class.php b/include/classes/coin_address.class.php index e5f108ac..1e9bbb08 100644 --- a/include/classes/coin_address.class.php +++ b/include/classes/coin_address.class.php @@ -51,7 +51,22 @@ class CoinAddress extends Base { return false; } $stmt = $this->mysqli->prepare("INSERT INTO " . $this->getTableName() . " (account_id, currency, coin_address) VALUES (?, ?, ?)"); - if ( $this->checkStmt($stmt) && $stmt->bind_param('sis', $userID, $currency, $address) && $stmt->execute()) { + if ( $this->checkStmt($stmt) && $stmt->bind_param('iss', $userID, $currency, $address) && $stmt->execute()) { + return true; + } + return $this->sqlError(); + } + + /** + * Remove a coin address record for a user + * @param userID int Account ID + * @param currency string Currency short handle, defaults to config option + * @return bool true or false + **/ + public function remove ($userID, $currency=NULL) { + if ($currency === NULL) $currency = $this->config['currency']; + $stmt = $this->mysqli->prepare("DELETE FROM " . $this->getTableName() . " WHERE account_id = ? AND currency = ?"); + if ( $this->checkStmt($stmt) && $stmt->bind_param('is', $userID, $currency) && $stmt->execute()) { return true; } return $this->sqlError(); diff --git a/include/classes/user.class.php b/include/classes/user.class.php index 5e59b853..ec672517 100644 --- a/include/classes/user.class.php +++ b/include/classes/user.class.php @@ -545,8 +545,15 @@ class User extends Base { if ($this->checkStmt($stmt) && $stmt->bind_param('ddssii', $threshold, $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) { $this->log->log("info", $this->getUserName($userID)." updated their account details"); // Update coin address too - if ($this->coin_address->update($userID, $address)) - return true; + if ($address) { + if ($this->coin_address->update($userID, $address)) { + return true; + } + } else { + if ($this->coin_address->remove($userID, $address)) { + return true; + } + } } // Catchall $this->setErrorMessage('Failed to update your account'); From d3779bd58e851c0b119787f51e844224f8820f17 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 10 Jul 2014 08:56:29 +0200 Subject: [PATCH 10/38] [FIX] Wrong sql data length --- upgrade/definitions/0.0.11_to_0.0.12.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upgrade/definitions/0.0.11_to_0.0.12.inc.php b/upgrade/definitions/0.0.11_to_0.0.12.inc.php index 3f8a2c53..00328165 100644 --- a/upgrade/definitions/0.0.11_to_0.0.12.inc.php +++ b/upgrade/definitions/0.0.11_to_0.0.12.inc.php @@ -9,7 +9,7 @@ function run_0012() { $db_version_now = $setting->getValue('DB_VERSION'); // Our actual version installed // Upgrade specific variables - $aSql[] = "CREATE TABLE `coin_addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, `currency` varchar(55555) NOT NULL, `coin_address` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8"; + $aSql[] = "CREATE TABLE `coin_addresses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `account_id` int(11) NOT NULL, `currency` varchar(5) NOT NULL, `coin_address` varchar(255) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `coin_address` (`coin_address`), KEY `account_id` (`account_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8"; $aSql[] = "INSERT IGNORE INTO coin_addresses (account_id, currency, coin_address) SELECT id, '" . $config['currency'] . "', coin_address FROM " . $user->getTableName() . " WHERE coin_address IS NOT NULL"; $aSql[] = "ALTER TABLE `" . $user->getTableName() . "` DROP `coin_address`"; $aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.12' WHERE name = 'DB_VERSION'"; From 0c227cb741efbddb3bf2613cb883321db12f2f1f Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 10 Jul 2014 11:50:28 +0200 Subject: [PATCH 11/38] [FIX] Base structure, DB_VERSION --- sql/000_base_structure.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/000_base_structure.sql b/sql/000_base_structure.sql index ef45e0a5..a52829b5 100644 --- a/sql/000_base_structure.sql +++ b/sql/000_base_structure.sql @@ -144,7 +144,7 @@ CREATE TABLE IF NOT EXISTS `settings` ( UNIQUE KEY `setting` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `settings` (`name`, `value`) VALUES ('DB_VERSION', '0.0.11'); +INSERT INTO `settings` (`name`, `value`) VALUES ('DB_VERSION', '0.0.12'); CREATE TABLE IF NOT EXISTS `shares` ( `id` bigint(30) NOT NULL AUTO_INCREMENT, From e542afc952284343a11aaaffb1e4ad50a6ea1237 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Sun, 13 Jul 2014 12:16:57 +0200 Subject: [PATCH 12/38] [UPDATE] Hide e-mail address on account screen --- include/classes/user.class.php | 5 ++++- templates/bootstrap/account/edit/detail.tpl | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/classes/user.class.php b/include/classes/user.class.php index ec672517..91172e90 100644 --- a/include/classes/user.class.php +++ b/include/classes/user.class.php @@ -496,7 +496,7 @@ class User extends Base { $this->setErrorMessage('Donation above allowed 100% limit'); return false; } - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + if ($email != 'hidden' && $email != NULL && !filter_var($email, FILTER_VALIDATE_EMAIL)) { $this->setErrorMessage('Invalid email address'); return false; } @@ -540,6 +540,9 @@ class User extends Base { } } + // If we hide our email or it's not set, fetch current one to update + if ($email == 'hidden' || $email == NULL) + $email = $this->getUserEmailById($userID); // We passed all validation checks so update the account $stmt = $this->mysqli->prepare("UPDATE $this->table SET ap_threshold = ?, donate_percent = ?, email = ?, timezone = ?, is_anonymous = ? WHERE id = ?"); if ($this->checkStmt($stmt) && $stmt->bind_param('ddssii', $threshold, $donate, $email, $timezone, $is_anonymous, $userID) && $stmt->execute()) { diff --git a/templates/bootstrap/account/edit/detail.tpl b/templates/bootstrap/account/edit/detail.tpl index 582deb94..a59574b1 100644 --- a/templates/bootstrap/account/edit/detail.tpl +++ b/templates/bootstrap/account/edit/detail.tpl @@ -28,7 +28,7 @@ {/if}
- {nocache}{/nocache} + {nocache}{/nocache}
From a56ef55001595bc6aa45e64ec24c621e1b18b343 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Tue, 15 Jul 2014 09:02:55 +0200 Subject: [PATCH 13/38] [FIX] Do not verify SSL connections --- include/lib/jsonRPCClient.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/lib/jsonRPCClient.php b/include/lib/jsonRPCClient.php index ba09ba63..33947440 100644 --- a/include/lib/jsonRPCClient.php +++ b/include/lib/jsonRPCClient.php @@ -108,7 +108,10 @@ class jsonRPCClient { curl_setopt($ch, CURLOPT_USERPWD, $url['user'] . ":" . $url['pass']); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $request); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); $response = curl_exec($ch); + if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch)); if ($this->debug) $this->debug_output[] = 'Response: ' . $response; $response = json_decode($response, true); $resultStatus = curl_getinfo($ch); @@ -116,7 +119,6 @@ class jsonRPCClient { if ($resultStatus['http_code'] == '401') throw new Exception('RPC call did not return 200: Authentication failed'); throw new Exception('RPC call did not return 200: HTTP error: ' . $resultStatus['http_code'] . ' - JSON Response: [' . @$response['error']['code'] . '] ' . @$response['error']['message']); } - if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch)); curl_close($ch); // final checks and return From 0138b82c135cbaad24f4772baf328d0448c1dd09 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Tue, 15 Jul 2014 09:13:37 +0200 Subject: [PATCH 14/38] [UPDATE] Confirm the certificates CN at least --- include/lib/jsonRPCClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/lib/jsonRPCClient.php b/include/lib/jsonRPCClient.php index 33947440..b6675f2d 100644 --- a/include/lib/jsonRPCClient.php +++ b/include/lib/jsonRPCClient.php @@ -109,7 +109,7 @@ class jsonRPCClient { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $request); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + // curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); $response = curl_exec($ch); if (curl_errno($ch)) throw new Exception('RPC call failed: ' . curl_error($ch)); if ($this->debug) $this->debug_output[] = 'Response: ' . $response; From 2f2c625284a9960d9e82181555eacd9dcb87963c Mon Sep 17 00:00:00 2001 From: David Meyer Date: Tue, 15 Jul 2014 23:42:02 -0700 Subject: [PATCH 15/38] [FIX] Default case to allow for custom payout methods --- include/config/monitor_crons.inc.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/config/monitor_crons.inc.php b/include/config/monitor_crons.inc.php index 732c1bdc..d3726539 100644 --- a/include/config/monitor_crons.inc.php +++ b/include/config/monitor_crons.inc.php @@ -3,15 +3,13 @@ // Small helper array that may be used on some page controllers to // fetch the crons we wish to monitor switch ($config['payout_system']) { - case 'pplns': - $sPayoutSystem = $config['payout_system'] . '_payout'; - break; - case 'pps': - $sPayoutSystem = $config['payout_system'] . '_payout'; - break; case 'prop': $sPayoutSystem = 'proportional_payout'; break; + default: // pps && pplns land here + $sPayoutSystem = $config['payout_system'] . '_payout'; } $aMonitorCrons = array('statistics','tickerupdate','notifications','tables_cleanup','findblock',$sPayoutSystem,'blockupdate','payouts'); + +?> From 3cbc05dd09fb01f33a99fce3bc66e55a6d856584 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Fri, 18 Jul 2014 08:09:05 +0200 Subject: [PATCH 16/38] [FIX] Pool Hashrate for < diff1 shares --- include/classes/statistics.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index 191bb00d..ae6736b4 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -223,12 +223,12 @@ class Statistics extends Base { SELECT ( ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty))), 0) AS shares + SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) + ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty))), 0) AS shares + SELECT IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' From 8311e91c764ec98b9672f55d754f61f41abda70f Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Sat, 19 Jul 2014 07:40:36 +0200 Subject: [PATCH 17/38] [UPDATE] First attemp to fix low diff shares --- include/classes/coins/coin_base.class.php | 10 +++++ include/classes/coins/coin_x11.class.php | 1 + include/classes/statistics.class.php | 42 +++++++++---------- include/smarty_globals.inc.php | 1 + templates/bootstrap/dashboard/js/api.tpl | 8 ++-- .../round_statistics/pplns/shares.tpl | 8 ++-- .../dashboard/round_statistics/pps/shares.tpl | 8 ++-- .../round_statistics/prop/shares.tpl | 8 ++-- 8 files changed, 49 insertions(+), 37 deletions(-) diff --git a/include/classes/coins/coin_base.class.php b/include/classes/coins/coin_base.class.php index 7eeb3ee1..b9242822 100644 --- a/include/classes/coins/coin_base.class.php +++ b/include/classes/coins/coin_base.class.php @@ -12,6 +12,9 @@ class CoinBase extends Base { // Our coins target bits protected $target_bits = NULL; + // Our coins share difficulty precision + protected $share_difficulty_precision = 0; + /** * Read our target bits **/ @@ -19,6 +22,13 @@ class CoinBase extends Base { return $this->target_bits; } + /** + * Read our share difficulty precision + **/ + public function getShareDifficultyPrecision() { + return $this->share_difficulty_precision; + } + /** * Calculate the PPS value for this coin * WARNING: Get this wrong and you will over- or underpay your miners! diff --git a/include/classes/coins/coin_x11.class.php b/include/classes/coins/coin_x11.class.php index 6e356be3..60c14f63 100644 --- a/include/classes/coins/coin_x11.class.php +++ b/include/classes/coins/coin_x11.class.php @@ -8,6 +8,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; **/ class Coin extends CoinBase { protected $target_bits = 24; + protected $share_difficulty_precision = 4; } ?> diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index ae6736b4..2da85448 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -45,37 +45,37 @@ class Statistics extends Base { IFNULL(SUM(IF(confirmations > 0, 1, 0)), 0) AS TotalValid, IFNULL(SUM(IF(confirmations = -1, 1, 0)), 0) AS TotalOrphan, IFNULL(SUM(IF(confirmations > 0, difficulty, 0)), 0) AS TotalDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1, shares, 0))), 0) AS TotalShares, + IFNULL(SUM(IF(confirmations > -1, shares, 0)), 0) AS TotalShares, IFNULL(SUM(IF(confirmations > -1, amount, 0)), 0) AS TotalAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), 1, 0)), 0) AS 1HourOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), difficulty, 0)), 0) AS 1HourDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0))), 0) AS 1HourShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), shares, 0)), 0) AS 1HourShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), amount, 0)), 0) AS 1HourAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), 1, 0)), 0) AS 24HourOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), difficulty, 0)), 0) AS 24HourDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0))), 0) AS 24HourShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), shares, 0)), 0) AS 24HourShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), amount, 0)), 0) AS 24HourAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), 1, 0)), 0) AS 7DaysOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), difficulty, 0)), 0) AS 7DaysDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0))), 0) AS 7DaysShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), shares, 0)), 0) AS 7DaysShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), amount, 0)), 0) AS 7DaysAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), 1, 0)), 0) AS 4WeeksOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), difficulty, 0)), 0) AS 4WeeksDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0))), 0) AS 4WeeksShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), shares, 0)), 0) AS 4WeeksShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), amount, 0)), 0) AS 4WeeksAmount, IFNULL(SUM(IF(FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthTotal, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthValid, IFNULL(SUM(IF(confirmations = -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), 1, 0)), 0) AS 12MonthOrphan, IFNULL(SUM(IF(confirmations > 0 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), difficulty, 0)), 0) AS 12MonthDifficulty, - IFNULL(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0))), 0) AS 12MonthShares, + IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), shares, 0)), 0) AS 12MonthShares, IFNULL(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), amount, 0)), 0) AS 12MonthAmount FROM " . $this->block->getTableName()); if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { @@ -104,7 +104,7 @@ class Statistics extends Base { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0), 4) AS estshares FROM " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id @@ -127,7 +127,7 @@ class Statistics extends Base { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 4) AS estshares FROM " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id @@ -163,7 +163,7 @@ class Statistics extends Base { return $this->memcache->setCache(__FUNCTION__ . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->sqlError(); } - + /** * Get SUM of blocks found and generated Coins for each worker * @param limit int Last limit blocks @@ -185,7 +185,7 @@ class Statistics extends Base { return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->sqlError(); } - + /** * Currently the only function writing to the database * Stored per block user statistics of valid and invalid shares @@ -293,8 +293,8 @@ class Statistics extends Base { } $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS invalid + IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid, + IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid FROM " . $this->share->getTableName() . " WHERE UNIX_TIMESTAMP(time) > IFNULL((SELECT MAX(time) FROM " . $this->block->getTableName() . "), 0)"); if ( $this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result() ) @@ -316,8 +316,8 @@ class Statistics extends Base { } $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0), 0) AS invalid, + IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS valid, + IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) AS invalid, u.id AS id, u.donate_percent AS donate_percent, u.is_anonymous AS is_anonymous, @@ -368,11 +368,11 @@ class Statistics extends Base { if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0), 0) AS invalid + IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS valid, + IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) AS invalid FROM " . $this->share->getTableName() . " WHERE username LIKE ? - AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)"); + AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)"); $username = $username . ".%"; if ($stmt && $stmt->bind_param("s", $username) && $stmt->execute() && $result = $stmt->get_result()) return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc()); @@ -500,7 +500,7 @@ class Statistics extends Base { if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0), 0) AS total + IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS total FROM " . $this->share->getTableName() . " WHERE username LIKE ? AND id > ? @@ -603,7 +603,7 @@ class Statistics extends Base { a.username AS account, a.donate_percent AS donate_percent, a.is_anonymous AS is_anonymous, - ROUND(IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0), 0) AS shares + IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares FROM " . $this->share->getTableName() . " AS s LEFT JOIN " . $this->user->getTableName() . " AS a ON SUBSTRING_INDEX( s.username, '.', 1 ) = a.username @@ -744,7 +744,7 @@ class Statistics extends Base { if ($this->config['payout_system'] != 'pps') { if (@$value1['valid'] > 0 && @$value2['valid'] > 0) { $this->config['reward_type'] == 'fixed' ? $reward = $this->config['reward'] : $reward = $this->block->getAverageAmount(); - $aEstimates['block'] = round(( (int)$value2['valid'] / (int)$value1['valid'] ) * (float)$reward, 8); + $aEstimates['block'] = round(( (float)$value2['valid'] / (float)$value1['valid'] ) * (float)$reward, 8); $bNoFees == 0 ? $aEstimates['fee'] = round(((float)$this->config['fees'] / 100) * (float)$aEstimates['block'], 8) : $aEstimates['fee'] = 0; $aEstimates['donation'] = round((( (float)$dDonate / 100) * ((float)$aEstimates['block'] - (float)$aEstimates['fee'])), 8); $aEstimates['payout'] = round((float)$aEstimates['block'] - (float)$aEstimates['donation'] - (float)$aEstimates['fee'], 8); @@ -789,7 +789,7 @@ class Statistics extends Base { SELECT IFNULL(COUNT(id), 0) as count, IFNULL(AVG(difficulty), 0) as average, - IFNULL(ROUND(SUM(shares)), 0) as shares, + IFNULL(SUM(shares), 0) as shares, IFNULL(SUM(amount), 0) as rewards FROM " . $this->block->getTableName() . " WHERE FROM_UNIXTIME(time) > DATE_SUB(now(), INTERVAL ? HOUR) diff --git a/include/smarty_globals.inc.php b/include/smarty_globals.inc.php index ea13a6d1..f8549287 100644 --- a/include/smarty_globals.inc.php +++ b/include/smarty_globals.inc.php @@ -66,6 +66,7 @@ $aGlobal = array( 'coinaddresscheck' => $config['check_valid_coinaddress'], 'csrf' => $config['csrf'], 'config' => array( + 'sharediffprecision' => $coin->getShareDifficultyPrecision(), 'date' => $setting->getValue('system_date_format', '%m/%d/%Y %H:%M:%S'), 'website_design' => $setting->getValue('website_design'), 'poolnav_enabled' => $setting->getValue('poolnav_enabled'), diff --git a/templates/bootstrap/dashboard/js/api.tpl b/templates/bootstrap/dashboard/js/api.tpl index e73b4859..731ee9a6 100644 --- a/templates/bootstrap/dashboard/js/api.tpl +++ b/templates/bootstrap/dashboard/js/api.tpl @@ -108,15 +108,15 @@ $(document).ready(function(){ $('#b-nethashrate').html('n/a'); } $('#b-sharerate').html((parseFloat(data.getdashboarddata.data.personal.sharerate).toFixed(2))); - $('#b-yvalid').html(number_format(data.getdashboarddata.data.personal.shares.valid)); - $('#b-yivalid').html(number_format(data.getdashboarddata.data.personal.shares.invalid)); + $('#b-yvalid').html(number_format(data.getdashboarddata.data.personal.shares.valid, {/literal}{$GLOBAL.config.sharediffprecision}{literal})); + $('#b-yivalid').html(number_format(data.getdashboarddata.data.personal.shares.invalid, {/literal}{$GLOBAL.config.sharediffprecision}{literal})); if ( data.getdashboarddata.data.personal.shares.valid > 0 ) { $('#b-yefficiency').html(number_format(100 - data.getdashboarddata.data.personal.shares.invalid_percent, 2) + "%"); } else { $('#b-yefficiency').html(number_format(0, 2) + "%"); } - $('#b-pvalid').html(number_format(data.getdashboarddata.data.pool.shares.valid)); - $('#b-pivalid').html(number_format(data.getdashboarddata.data.pool.shares.invalid)); + $('#b-pvalid').html(number_format(data.getdashboarddata.data.pool.shares.valid, {/literal}{$GLOBAL.config.sharediffprecision}{literal})); + $('#b-pivalid').html(number_format(data.getdashboarddata.data.pool.shares.invalid, {/literal}{$GLOBAL.config.sharediffprecision}{literal})); if ( data.getdashboarddata.data.pool.shares.valid > 0 ) { $('#b-pefficiency').html(number_format(100 - data.getdashboarddata.data.pool.shares.invalid_percent, 2) + "%"); } else { diff --git a/templates/bootstrap/dashboard/round_statistics/pplns/shares.tpl b/templates/bootstrap/dashboard/round_statistics/pplns/shares.tpl index bd1218b1..68e8ee60 100644 --- a/templates/bootstrap/dashboard/round_statistics/pplns/shares.tpl +++ b/templates/bootstrap/dashboard/round_statistics/pplns/shares.tpl @@ -9,12 +9,12 @@
Valid
-
{$GLOBAL.userdata.shares.valid|number_format}
+
{$GLOBAL.userdata.shares.valid|number_format:$GLOBAL.config.sharediffprecision}
-
{$GLOBAL.roundshares.valid|number_format}
+
{$GLOBAL.roundshares.valid|number_format:$GLOBAL.config.sharediffprecision}
@@ -22,12 +22,12 @@
Invalid
-
{$GLOBAL.userdata.shares.invalid|number_format}
+
{$GLOBAL.userdata.shares.invalid|number_format:$GLOBAL.config.sharediffprecision}
-
{$GLOBAL.roundshares.invalid|number_format}
+
{$GLOBAL.roundshares.invalid|number_format:$GLOBAL.config.sharediffprecision}
diff --git a/templates/bootstrap/dashboard/round_statistics/pps/shares.tpl b/templates/bootstrap/dashboard/round_statistics/pps/shares.tpl index 043df82d..19968d36 100644 --- a/templates/bootstrap/dashboard/round_statistics/pps/shares.tpl +++ b/templates/bootstrap/dashboard/round_statistics/pps/shares.tpl @@ -9,12 +9,12 @@
Valid
-
{$GLOBAL.userdata.shares.valid|number_format}
+
{$GLOBAL.userdata.shares.valid|number_format:$GLOBAL.config.sharediffprecision}
-
{$GLOBAL.roundshares.valid|number_format}
+
{$GLOBAL.roundshares.valid|number_format:$GLOBAL.config.sharediffprecision}
@@ -22,12 +22,12 @@
Invalid
-
{$GLOBAL.userdata.shares.invalid|number_format}
+
{$GLOBAL.userdata.shares.invalid|number_format:$GLOBAL.config.sharediffprecision}
-
{$GLOBAL.roundshares.invalid|number_format}
+
{$GLOBAL.roundshares.invalid|number_format:$GLOBAL.config.sharediffprecision}
diff --git a/templates/bootstrap/dashboard/round_statistics/prop/shares.tpl b/templates/bootstrap/dashboard/round_statistics/prop/shares.tpl index bd1218b1..68e8ee60 100644 --- a/templates/bootstrap/dashboard/round_statistics/prop/shares.tpl +++ b/templates/bootstrap/dashboard/round_statistics/prop/shares.tpl @@ -9,12 +9,12 @@
Valid
-
{$GLOBAL.userdata.shares.valid|number_format}
+
{$GLOBAL.userdata.shares.valid|number_format:$GLOBAL.config.sharediffprecision}
-
{$GLOBAL.roundshares.valid|number_format}
+
{$GLOBAL.roundshares.valid|number_format:$GLOBAL.config.sharediffprecision}
@@ -22,12 +22,12 @@
Invalid
-
{$GLOBAL.userdata.shares.invalid|number_format}
+
{$GLOBAL.userdata.shares.invalid|number_format:$GLOBAL.config.sharediffprecision}
-
{$GLOBAL.roundshares.invalid|number_format}
+
{$GLOBAL.roundshares.invalid|number_format:$GLOBAL.config.sharediffprecision}
From 14800f3a2fac39c759a86bf8f70d121dc61f42e1 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Sat, 19 Jul 2014 07:41:32 +0200 Subject: [PATCH 18/38] [FIX] Proper index check for confirmations in block info --- cronjobs/findblock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php index 42e347a0..3516fe2c 100755 --- a/cronjobs/findblock.php +++ b/cronjobs/findblock.php @@ -59,7 +59,7 @@ if (empty($aTransactions['transactions'])) { $config['reward_type'] == 'block' ? $aData['amount'] = $aData['amount'] : $aData['amount'] = $config['reward']; $aData['height'] = $aBlockRPCInfo['height']; $aTxDetails = $bitcoin->gettransaction($aBlockRPCInfo['tx'][0]); - if (!isset($aBlockRPCInfo['confirmations'])) { + if (isset($aBlockRPCInfo['confirmations'])) { $aData['confirmations'] = $aBlockRPCInfo['confirmations']; } else if (isset($aTxDetails['confirmations'])) { $aData['confirmations'] = $aTxDetails['confirmations']; From b758ee9395b807c3ca82847cf3c8c1782de4a35a Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 10 Jul 2014 11:49:33 +0200 Subject: [PATCH 19/38] [PoC] Cronjob based Hashrate graphs --- cronjobs/statistics.php | 12 +- include/classes/statistics.class.php | 113 +++++++++++-------- include/pages/statistics/graphs.inc.php | 2 +- include/version.inc.php | 2 +- sql/000_base_structure.sql | 17 +-- upgrade/definitions/0.0.12_to_0.0.13.inc.php | 39 +++++++ 6 files changed, 128 insertions(+), 57 deletions(-) create mode 100644 upgrade/definitions/0.0.12_to_0.0.13.inc.php diff --git a/cronjobs/statistics.php b/cronjobs/statistics.php index 6530fab7..eb564c1a 100755 --- a/cronjobs/statistics.php +++ b/cronjobs/statistics.php @@ -27,7 +27,7 @@ require_once('shared.inc.php'); // Header $log->logInfo('Running statistical queries, errors may just mean no shares were available'); -$strLogMask = "| %-26.26s | %8.8s | %-6.6s |"; +$strLogMask = "| %-33.33s | %8.8s | %-6.6s |"; $log->logInfo(sprintf($strLogMask, 'Method', 'Runtime', 'Status')); // Per user share statistics based on all shares submitted @@ -37,9 +37,15 @@ $log->logInfo(sprintf($strLogMask, 'getAllUserShares', number_format(microtime(t // Get all user hashrate statistics for caching $start = microtime(true); -$statistics->getAllUserMiningStats() ? $status = 'OK' : $status = 'ERROR'; -$log->logInfo(sprintf($strLogMask, 'getAllUserMiningStats', number_format(microtime(true) - $start, 3), $status)); +$statistics->fetchAllUserMiningStats() ? $status = 'OK' : $status = 'ERROR'; +$log->logInfo(sprintf($strLogMask, 'fetchAllUserMiningStats', number_format(microtime(true) - $start, 3), $status)); +// Store our statistical data into our `statistics_users` table +$start = microtime(true); +$statistics->storeAllUserMiningStatsSnapshot($statistics->getAllUserMiningStats()) ? $status = 'OK' : $status = 'ERROR'; +$log->logInfo(sprintf($strLogMask, 'storeAllUserMiningStatsSnapshot', number_format(microtime(true) - $start, 3), $status)); + +// Get stats for pool overview $start = microtime(true); $statistics->getTopContributors('hashes') ? $status = 'OK' : $status = 'ERROR'; $log->logInfo(sprintf($strLogMask, 'getTopContributors(hashes)', number_format(microtime(true) - $start, 3), $status)); diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index ae6736b4..51a63410 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -9,6 +9,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; **/ class Statistics extends Base { protected $table = 'statistics_shares'; + protected $table_user_stats = 'statistics_users'; private $getcache = true; // Disable fetching values from cache @@ -18,6 +19,12 @@ class Statistics extends Base { public function getGetCache() { return $this->getcache; } + public function getAllUserMiningStats() { + return $this->allUserMiningStats; + } + public function getUserStatsTableName() { + return $this->table_user_stats; + } /** * Get our first block found @@ -451,14 +458,17 @@ class Statistics extends Base { /** * Fetch all user hashrates based on shares and archived shares + * Store it in cache, also keep a copy of the data internally to + * return it for further processing * @return data array Set of all user stats **/ - public function getAllUserMiningStats($interval=180) { + public function fetchAllUserMiningStats($interval=180) { $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare(" SELECT a.id AS id, a.username AS account, + COUNT(DISTINCT t1.username) AS workers, IFNULL(SUM(t1.difficulty), 0) AS shares, ROUND(COUNT(t1.id) / ?, 2) AS sharerate, IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff @@ -489,12 +499,43 @@ class Statistics extends Base { $aData['data'][$row['id']] = $row; $aData['data'][$row['id']]['hashrate'] = $this->coin->calcHashrate($row['shares'], $interval); } + $this->allUserMiningStats = $aData; return $this->memcache->setStaticCache(STATISTICS_ALL_USER_HASHRATES, $aData, 600); } else { return $this->sqlError(); } } + /** + * Store our gathered data into our statistic table for users + * @param aData array Data created by fetchAllUserMiningStats + * @return bool true or false + **/ + public function storeAllUserMiningStatsSnapshot($aData) { + // initilize + $timestamp = time(); // Store all entries with the same timestamp to reduce cardinality + $ok = 0; + $failed = 0; + foreach ($aData['data'] as $key => $aUserData) { + $stmt = $this->mysqli->prepare(" + INSERT INTO " . $this->getUserStatsTableName() . " + ( account_id, hashrate, workers, sharerate, timestamp ) VALUES ( ?, ?, ?, ?, ?)"); + if ($this->checkStmt($stmt) && $stmt->bind_param("ididi", $aUserData['id'], $aUserData['hashrate'], $aUserData['workers'], $aUserData['sharerate'], $timestamp) && $stmt->execute() ) { + $ok++; + } else { + $failed++; + } + } + return array('ok' => $ok, 'failed' => $failed); + } + + /** + * Fetch unpaid PPS shares for an account + * @param username string Username + * @param account_id int User ID + * @param last_paid_pps_id int Last paid out share by pps_payout cron + * @return data int Sum of unpaid diff1 shares + **/ public function getUserUnpaidPPSShares($username, $account_id=NULL, $last_paid_pps_id) { $this->debug->append("STA " . __METHOD__, 4); if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; @@ -655,38 +696,26 @@ class Statistics extends Base { * @param $account_id int account id * @return data array NOT FINISHED YET **/ - public function getHourlyHashrateByAccount($username, $account_id=NULL) { + public function getHourlyHashrateByAccount($account_id) { $this->debug->append("STA " . __METHOD__, 4); if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - id, - IFNULL(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares, - HOUR(time) AS hour - FROM " . $this->share->getTableName() . " - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - AND username LIKE ? - GROUP BY HOUR(time) - UNION - SELECT - share_id, - IFNULL(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS shares, - HOUR(time) AS hour - FROM " . $this->share->getArchiveTableName() . " - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - AND username LIKE ? - GROUP BY HOUR(time)"); - $username = $username . ".%"; - if ($this->checkStmt($stmt) && $stmt->bind_param('ss', $username, $username) && $stmt->execute() && $result = $stmt->get_result()) { + account_id AS id, + AVG(hashrate) AS hashrate, + HOUR(FROM_UNIXTIME(timestamp)) AS hour + FROM " . $this->getUserStatsTableName() . " + WHERE + account_id = ? + AND timestamp <= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 HOUR)) + AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 24 HOUR)) + GROUP BY HOUR(FROM_UNIXTIME(timestamp))"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) { $iStartHour = date('G'); // Initilize array for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; - // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600); + // Fill data in proper hour order, result in SQL was ordered 0 - 23 + while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int)$row['hashrate']; return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData); } return $this->sqlError(); @@ -702,30 +731,24 @@ class Statistics extends Base { if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data; $stmt = $this->mysqli->prepare(" SELECT - id, - IFNULL(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares, - HOUR(s.time) AS hour - FROM " . $this->share->getTableName() . " AS s - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - GROUP BY HOUR(time) - UNION - SELECT - share_id, - IFNULL(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS shares, - HOUR(s.time) AS hour - FROM " . $this->share->getArchiveTableName() . " AS s - WHERE time <= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - AND time >= FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(NOW())/(60*60))*(60*60)) - INTERVAL 24 HOUR - AND our_result = 'Y' - GROUP BY HOUR(time)"); + SUM(hashrate) / ( + SELECT + COUNT(DISTINCT timestamp) + FROM " . $this->getUserStatsTableName() . " + WHERE timestamp <= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 HOUR)) + AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 24 HOUR)) + ) AS hashrate, + HOUR(FROM_UNIXTIME(timestamp)) AS hour + FROM " . $this->getUserStatsTableName() . " + WHERE timestamp <= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 HOUR)) + AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 24 HOUR)) + GROUP BY HOUR(FROM_UNIXTIME(timestamp))"); if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { $iStartHour = date('G'); // Initilize array for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600); + while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int)$row['hashrate']; return $this->memcache->setCache(__FUNCTION__, $aData); } return $this->sqlError(); diff --git a/include/pages/statistics/graphs.inc.php b/include/pages/statistics/graphs.inc.php index 0a19492d..291229cf 100644 --- a/include/pages/statistics/graphs.inc.php +++ b/include/pages/statistics/graphs.inc.php @@ -4,7 +4,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); if ($user->isAuthenticated()) { - $aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); + $aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']); $aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool(); } $smarty->assign("YOURHASHRATES", @$aHourlyHashRates); diff --git a/include/version.inc.php b/include/version.inc.php index a4e0d533..2b7ea18a 100644 --- a/include/version.inc.php +++ b/include/version.inc.php @@ -2,7 +2,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; define('MPOS_VERSION', '0.0.4'); -define('DB_VERSION', '0.0.12'); +define('DB_VERSION', '0.0.13'); define('CONFIG_VERSION', '0.0.8'); define('HASH_VERSION', 1); diff --git a/sql/000_base_structure.sql b/sql/000_base_structure.sql index a52829b5..b9887a51 100644 --- a/sql/000_base_structure.sql +++ b/sql/000_base_structure.sql @@ -144,7 +144,7 @@ CREATE TABLE IF NOT EXISTS `settings` ( UNIQUE KEY `setting` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -INSERT INTO `settings` (`name`, `value`) VALUES ('DB_VERSION', '0.0.12'); +INSERT INTO `settings` (`name`, `value`) VALUES ('DB_VERSION', '0.0.13'); CREATE TABLE IF NOT EXISTS `shares` ( `id` bigint(30) NOT NULL AUTO_INCREMENT, @@ -239,12 +239,15 @@ CREATE TABLE IF NOT EXISTS `transactions` ( KEY `account_id_archived` (`account_id`,`archived`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -CREATE TABLE IF NOT EXISTS `templates` ( - `template` varchar(255) NOT NULL, - `active` tinyint(1) NOT NULL DEFAULT 0, - `content` mediumtext, - `modified_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`template`) +CREATE TABLE `statistics_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `account_id` int(11) NOT NULL, + `hashrate` int(11) NOT NULL, + `workers` int(11) NOT NULL, + `sharerate` float NOT NULL, + `timestamp` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `account_id_timestamp` (`account_id`,`timestamp`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/upgrade/definitions/0.0.12_to_0.0.13.inc.php b/upgrade/definitions/0.0.12_to_0.0.13.inc.php new file mode 100644 index 00000000..e661c4d1 --- /dev/null +++ b/upgrade/definitions/0.0.12_to_0.0.13.inc.php @@ -0,0 +1,39 @@ +getValue('DB_VERSION'); // Our actual version installed + + // Upgrade specific variables + $aSql[] = "CREATE TABLE `statistics_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `account_id` int(11) NOT NULL, + `hashrate` int(11) NOT NULL, + `workers` int(11) NOT NULL, + `sharerate` float NOT NULL, + `timestamp` int(11) NOT NULL, + PRIMARY KEY (`id`), + KEY `account_id_timestamp` (`account_id`,`timestamp`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8"; + $aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.13' WHERE name = 'DB_VERSION'"; + + if ($db_version_now == $db_version_old && version_compare($db_version_now, DB_VERSION, '<')) { + // Run the upgrade + echo '- Starting database migration to version ' . $db_version_new . PHP_EOL; + foreach ($aSql as $sql) { + echo '- Preparing: ' . $sql . PHP_EOL; + $stmt = $mysqli->prepare($sql); + if ($stmt && $stmt->execute()) { + echo '- success' . PHP_EOL; + } else { + echo '- failed: ' . $mysqli->error . PHP_EOL; + exit(1); + } + } + } +} +?> From bf2429ab2f7a6f3ad306d3d85d8a3ab246950751 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 10 Jul 2014 13:26:03 +0200 Subject: [PATCH 20/38] [FIX] Skip stat storage on missing data --- include/classes/statistics.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index 51a63410..b7a65782 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -512,6 +512,8 @@ class Statistics extends Base { * @return bool true or false **/ public function storeAllUserMiningStatsSnapshot($aData) { + $this->debug->append("STA " . __METHOD__, 4); + if (!isset($aData['data'])) return false; // initilize $timestamp = time(); // Store all entries with the same timestamp to reduce cardinality $ok = 0; From 77c6abed05891a0553d0a00c253f7a3616006648 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Sun, 13 Jul 2014 13:55:37 +0200 Subject: [PATCH 21/38] [REFACTOR] Use raw statistical data --- .gitignore | 4 + include/classes/statistics.class.php | 53 ++++------- include/pages/api.inc.php | 2 +- include/pages/statistics/graphs.inc.php | 4 +- .../bootstrap/statistics/graphs/default.tpl | 88 ++++--------------- .../bootstrap/statistics/graphs/mine.tpl | 2 - .../bootstrap/statistics/graphs/pool.tpl | 2 - 7 files changed, 44 insertions(+), 111 deletions(-) diff --git a/.gitignore b/.gitignore index b4976dfc..6c1d5b6f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,10 @@ /include/config/global.inc.scrypt.php /include/config/global.inc.sha.php +# Test files +/scripts/test.php +/cronjobs/test.php + # IDE Settings /.idea/* .buildpath diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index b7a65782..c7b2c593 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -192,7 +192,7 @@ class Statistics extends Base { return $this->memcache->setCache(__FUNCTION__ . $account_id . $limit, $result->fetch_all(MYSQLI_ASSOC), 5); return $this->sqlError(); } - + /** * Currently the only function writing to the database * Stored per block user statistics of valid and invalid shares @@ -698,61 +698,44 @@ class Statistics extends Base { * @param $account_id int account id * @return data array NOT FINISHED YET **/ - public function getHourlyHashrateByAccount($account_id) { + public function getHashrateByAccount($account_id, $format='array') { $this->debug->append("STA " . __METHOD__, 4); if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - account_id AS id, - AVG(hashrate) AS hashrate, - HOUR(FROM_UNIXTIME(timestamp)) AS hour + timestamp, + hashrate FROM " . $this->getUserStatsTableName() . " WHERE - account_id = ? - AND timestamp <= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 HOUR)) - AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 24 HOUR)) - GROUP BY HOUR(FROM_UNIXTIME(timestamp))"); + account_id = ?"); if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) { - $iStartHour = date('G'); - // Initilize array - for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; - // Fill data in proper hour order, result in SQL was ordered 0 - 23 - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int)$row['hashrate']; - return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData); + $aData = $result->fetch_all(MYSQLI_ASSOC); + if ($format == 'json') $aData = json_encode($aData); + return $this->memcache->setCache(__FUNCTION__ . $account_id . $format, $aData); } return $this->sqlError(); } /** - * get Hourly hashrate for the pool + * get Hourly hashrate for the pool * @param none * @return data array NOT FINISHED YET **/ - public function getHourlyHashrateByPool() { + public function getHashrateForPool($format='array') { $this->debug->append("STA " . __METHOD__, 4); if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data; $stmt = $this->mysqli->prepare(" SELECT - SUM(hashrate) / ( - SELECT - COUNT(DISTINCT timestamp) - FROM " . $this->getUserStatsTableName() . " - WHERE timestamp <= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 HOUR)) - AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 24 HOUR)) - ) AS hashrate, - HOUR(FROM_UNIXTIME(timestamp)) AS hour - FROM " . $this->getUserStatsTableName() . " - WHERE timestamp <= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 1 HOUR)) - AND timestamp >= UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 24 HOUR)) - GROUP BY HOUR(FROM_UNIXTIME(timestamp))"); + timestamp, + SUM(hashrate) AS hashrate + FROM " . $this->getUserStatsTableName() . " + GROUP BY timestamp"); if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { - $iStartHour = date('G'); - // Initilize array - for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; - // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int)$row['hashrate']; - return $this->memcache->setCache(__FUNCTION__, $aData); + $aData = $result->fetch_all(MYSQLI_ASSOC); + if ($format == 'json') $aData = json_encode($aData); + return $this->memcache->setCache(__FUNCTION__ . $format, $aData); } + var_dump($this->mysqli->error); return $this->sqlError(); } diff --git a/include/pages/api.inc.php b/include/pages/api.inc.php index 01cd20f5..32fd0a34 100644 --- a/include/pages/api.inc.php +++ b/include/pages/api.inc.php @@ -5,7 +5,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; $api->isActive(); // Check for valid API key -$id = $user->checkApiKey($_REQUEST['api_key']); +$id = $user->checkApiKey(@$_REQUEST['api_key']); header('HTTP/1.1 400 Bad Request'); die('400 Bad Request'); diff --git a/include/pages/statistics/graphs.inc.php b/include/pages/statistics/graphs.inc.php index 291229cf..c970b8d8 100644 --- a/include/pages/statistics/graphs.inc.php +++ b/include/pages/statistics/graphs.inc.php @@ -4,8 +4,8 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); if ($user->isAuthenticated()) { - $aHourlyHashRates = $statistics->getHourlyHashrateByAccount($_SESSION['USERDATA']['id']); - $aPoolHourlyHashRates = $statistics->getHourlyHashrateByPool(); + $aHourlyHashRates = $statistics->getHashrateByAccount($_SESSION['USERDATA']['id'], 'json'); + $aPoolHourlyHashRates = $statistics->getHashrateForPool('json'); } $smarty->assign("YOURHASHRATES", @$aHourlyHashRates); $smarty->assign("POOLHASHRATES", @$aPoolHourlyHashRates); diff --git a/templates/bootstrap/statistics/graphs/default.tpl b/templates/bootstrap/statistics/graphs/default.tpl index 5de1b86b..65d03503 100644 --- a/templates/bootstrap/statistics/graphs/default.tpl +++ b/templates/bootstrap/statistics/graphs/default.tpl @@ -8,88 +8,38 @@ $(function () { // You can't draw here chart directly, because it's on hidden tab, instead let's do the workaround $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { - // this ain't pretty, but you should get the idea - if ($(e.target).attr('href') == '#pool' && $('#pool-area-chart').html().length == 0) { - Morris.Area({ - element: 'pool-area-chart', - data: [ - {foreach $POOLHASHRATES as $hour=>$hashrate} - { - period: '{$hour|default:"0"}:00', - Pool: '{$hashrate|default:"0"}', - }, - {/foreach} - ], - parseTime: false, - behaveLikeLine: true, - xkey: 'period', - ykeys: ['Pool'], + if ($(e.target).attr('href') == '#mine' && $('#mine-area-chart').html().length == 0) { + var chart = Morris.Line({ + // ID of the element in which to draw the chart. + element: 'mine-area-chart', + data: {$YOURHASHRATES}, + xkey: 'timestamp', + ykeys: ['hashrate'], labels: ['Hashrate'], pointSize: 2, hideHover: 'auto', - lineColors: ['#0b62a4'], - pointFillColors: ['#FFFFFF'], resize: true, fillOpacity: 1.00, - postUnits: ' KH/s' - }); - } - - if ($(e.target).attr('href') == '#mine' && $('#mine-area-chart').html().length == 0) { - Morris.Area({ - element: 'mine-area-chart', - data: [ - {foreach $YOURHASHRATES as $yourhour=>$yourhashrate} - { - period: '{$yourhour|default:"0"}:00', - Mine: '{$yourhashrate|default:"0"}', - }, - {/foreach} - ], - parseTime: false, - behaveLikeLine: true, - xkey: 'period', - ykeys: ['Mine'], - labels: ['Hashrate'], - pointSize: 2, - hideHover: 'auto', lineColors: ['#24A665'], pointFillColors: ['#FFFFFF'], - resize: true, - fillOpacity: 1.00, - postUnits: ' KH/s' }); } - - if ($(e.target).attr('href') == '#both' && $('#both-area-chart').html().length == 0) { - Morris.Area({ - element: 'both-area-chart', - data: [ - {foreach $YOURHASHRATES as $yourhour=>$yourhashrate} - { - period: '{$yourhour|default:"0"}:00', - Mine: '{$yourhashrate|default:"0"}', - {foreach $POOLHASHRATES as $poolhour=>$poolhashrate} - {if $yourhour eq $poolhour} - Pool: '{$poolhashrate|default:"0"}', - {/if} - {/foreach} - }, - {/foreach} - ], - parseTime: false, - behaveLikeLine: true, - xkey: 'period', - ykeys: ['Mine', 'Pool'], - labels: ['Your Hashrate', 'Pool Hashrate'], + if ($(e.target).attr('href') == '#pool' && $('#pool-area-chart').html().length == 0) { + var chart = Morris.Line({ + // ID of the element in which to draw the chart. + element: 'pool-area-chart', + data: {$POOLHASHRATES}, + xkey: 'timestamp', + ykeys: ['hashrate'], + labels: ['Hashrate'], pointSize: 2, hideHover: 'auto', resize: true, - fillOpacity: 0.1, - postUnits: ' KH/s' + fillOpacity: 1.00, + lineColors: ['#24A665'], + pointFillColors: ['#FFFFFF'], }); } - }); }); @@ -99,7 +49,7 @@ $(function () {
Stats -
+
From 226d2c8b54f2d233d90cdd9cbbef71f5d93cd1e2 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 17 Jul 2014 07:41:23 +0200 Subject: [PATCH 26/38] [ADDED] Flush statistics_users entries after 7 days default --- cronjobs/tables_cleanup.php | 15 ++++++++++++++- include/classes/statistics.class.php | 11 +++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cronjobs/tables_cleanup.php b/cronjobs/tables_cleanup.php index 04386133..231de9be 100755 --- a/cronjobs/tables_cleanup.php +++ b/cronjobs/tables_cleanup.php @@ -65,7 +65,7 @@ $status = 'OK'; $message = ''; $affected = $share->purgeArchive(); if ($affected === false) { - $message = 'Failed to delete notifications: ' . $oToken->getCronError(); + $message = 'Failed to delete shares: ' . $share->getCronError(); $status = 'ERROR'; $monitoring->endCronjob($cron_name, 'E0008', 0, false, false); } else { @@ -73,6 +73,19 @@ if ($affected === false) { } $log->logInfo(sprintf($strLogMask, 'purgeArchive', $affected, number_format(microtime(true) - $start, 3), $status, $message)); +// Clenaup shares archive +$start = microtime(true); +$status = 'OK'; +$message = ''; +$affected = $statistics->purgeUserStats(); +if ($affected === false) { + $message = 'Failed to delete entries: ' . $statistics->getCronError(); + $status = 'ERROR'; + $monitoring->endCronjob($cron_name, 'E0008', 0, false, false); +} else { + $affected == 0 ? $message = 'No entries deleted' : $message = 'Deleted old entries'; +} +$log->logInfo(sprintf($strLogMask, 'purgeUserStats', $affected, number_format(microtime(true) - $start, 3), $status, $message)); // Cron cleanup and monitoring require_once('cron_end.inc.php'); diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index dc4a7901..21623142 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -927,6 +927,17 @@ class Statistics extends Base { return $this->memcache->setCache(__FUNCTION__, $result->fetch_object()->total); return $this->sqlError(); } + + /** + * Purge older entries from our statistics_users table + **/ + public function purgeUserStats($days = 7) { + // Fallbacks if unset + $stmt = $this->mysqli->prepare("DELETE FROM " . $this->getUserStatsTableName() . " WHERE FROM_UNIXTIME(timestamp) <= DATE_SUB(NOW(), INTERVAL ? DAY)"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $days) && $stmt->execute()) + return $stmt->affected_rows; + return $this->sqlError(); + } } $statistics = new Statistics(); From 2c773fca4285e07c30a3eab0003512d31177fca6 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 17 Jul 2014 08:13:31 +0200 Subject: [PATCH 27/38] [UPDATE] Overhauled graphing stats * [REMOVED] Pool/Combined hashrate graph until we have a proper SQL to generate this data. Volunteers? * [ADDED] Worker and share rate statistics over time * [ADDED] Admin setting to change graphing days (default: 1 day) * [ADDED] Purge entries older than admin setting * [REMOVED] Template files that aren't used anymore --- cronjobs/tables_cleanup.php | 2 +- include/classes/statistics.class.php | 40 ++---- include/config/admin_settings.inc.php | 7 + include/pages/statistics/graphs.inc.php | 6 +- .../bootstrap/statistics/graphs/both.tpl | 10 -- .../bootstrap/statistics/graphs/default.tpl | 127 +++++++++++------- .../bootstrap/statistics/graphs/mine.tpl | 8 -- .../bootstrap/statistics/graphs/pool.tpl | 8 -- 8 files changed, 96 insertions(+), 112 deletions(-) delete mode 100644 templates/bootstrap/statistics/graphs/both.tpl delete mode 100644 templates/bootstrap/statistics/graphs/mine.tpl delete mode 100644 templates/bootstrap/statistics/graphs/pool.tpl diff --git a/cronjobs/tables_cleanup.php b/cronjobs/tables_cleanup.php index 231de9be..42189f2f 100755 --- a/cronjobs/tables_cleanup.php +++ b/cronjobs/tables_cleanup.php @@ -77,7 +77,7 @@ $log->logInfo(sprintf($strLogMask, 'purgeArchive', $affected, number_format(micr $start = microtime(true); $status = 'OK'; $message = ''; -$affected = $statistics->purgeUserStats(); +$affected = $statistics->purgeUserStats($setting->getValue('statistics_graphing_days', 1)); if ($affected === false) { $message = 'Failed to delete entries: ' . $statistics->getCronError(); $status = 'ERROR'; diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index 21623142..923d8cfa 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -698,19 +698,21 @@ class Statistics extends Base { * @param $account_id int account id * @return data array NOT FINISHED YET **/ - public function getHashrateByAccount($account_id, $format='array') { + public function getHourlyMiningStatsByAccount($account_id, $format='array', $days = 1) { $this->debug->append("STA " . __METHOD__, 4); if ($data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT timestamp, FROM_UNIXTIME(timestamp, '%Y-%m-%d %H:%i') AS time, - AVG(hashrate) AS hashrate + AVG(hashrate) AS hashrate, + AVG(workers) AS workers, + AVG(sharerate) AS sharerate FROM " . $this->getUserStatsTableName() . " - WHERE FROM_UNIXTIME(timestamp) >= DATE_SUB(NOW(), INTERVAL 24 HOUR) + WHERE FROM_UNIXTIME(timestamp) >= DATE_SUB(NOW(), INTERVAL $days DAY) AND account_id = ? - GROUP BY HOUR(FROM_UNIXTIME(timestamp))"); - if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id ) && $stmt->execute() && $result = $stmt->get_result()) { + GROUP BY DAY(FROM_UNIXTIME(timestamp)), HOUR(FROM_UNIXTIME(timestamp))"); + if ($this->checkStmt($stmt) && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) { $aData = $result->fetch_all(MYSQLI_ASSOC); if ($format == 'json') $aData = json_encode($aData); return $this->memcache->setCache(__FUNCTION__ . $account_id . $format, $aData); @@ -718,32 +720,6 @@ class Statistics extends Base { return $this->sqlError(); } - /** - * get Hourly hashrate for the pool - * @param none - * @return data array NOT FINISHED YET - **/ - public function getHashrateForPool($format='array') { - $this->debug->append("STA " . __METHOD__, 4); - if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__)) return $data; - $stmt = $this->mysqli->prepare(" - SELECT - timestamp, - FROM_UNIXTIME(timestamp, '%Y-%m-%d %T') AS time, - SUM(DISTINCT account_id) - FROM " . $this->getUserStatsTableName() . " - WHERE timestamp >= DATE_SUB(NOW(), INTERVAL 24 HOUR) - GROUP BY HOUR(FROM_UNIXTIME(timestamp))"); - if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { - // return json_encode(array(time() * 1000, 1000)); - $aData = $result->fetch_all(MYSQLI_ASSOC); - var_dump($aData); - if ($format == 'json') $aData = json_encode($aData); - return $this->memcache->setCache(__FUNCTION__ . $format, $aData); - } - return $this->sqlError(); - } - /** * get user estimated payouts based on share counts * @param value1 mixed Round shares OR share rate @@ -931,7 +907,7 @@ class Statistics extends Base { /** * Purge older entries from our statistics_users table **/ - public function purgeUserStats($days = 7) { + public function purgeUserStats($days = 1) { // Fallbacks if unset $stmt = $this->mysqli->prepare("DELETE FROM " . $this->getUserStatsTableName() . " WHERE FROM_UNIXTIME(timestamp) <= DATE_SUB(NOW(), INTERVAL ? DAY)"); if ($this->checkStmt($stmt) && $stmt->bind_param('i', $days) && $stmt->execute()) diff --git a/include/config/admin_settings.inc.php b/include/config/admin_settings.inc.php index 4f861830..2ae6716e 100644 --- a/include/config/admin_settings.inc.php +++ b/include/config/admin_settings.inc.php @@ -160,6 +160,13 @@ $aSettings['statistics'][] = array( 'name' => 'statistics_ajax_data_interval', 'value' => $setting->getValue('statistics_ajax_data_interval'), 'tooltip' => 'Time in minutes, interval for hashrate and sharerate calculations. Higher intervals allow for better accuracy at a higer server load.' ); +$aSettings['statistics'][] = array( + 'display' => 'Graphing Days', 'type' => 'text', + 'size' => 25, + 'default' => 1, + 'name' => 'statistics_graphing_days', 'value' => $setting->getValue('statistics_graphing_days'), + 'tooltip' => 'How many days to graph out on the statistics -> graphs page.' +); $aSettings['statistics'][] = array( 'display' => 'Block Statistics Count', 'type' => 'text', 'size' => 25, diff --git a/include/pages/statistics/graphs.inc.php b/include/pages/statistics/graphs.inc.php index c970b8d8..a212e941 100644 --- a/include/pages/statistics/graphs.inc.php +++ b/include/pages/statistics/graphs.inc.php @@ -4,11 +4,9 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); if ($user->isAuthenticated()) { - $aHourlyHashRates = $statistics->getHashrateByAccount($_SESSION['USERDATA']['id'], 'json'); - $aPoolHourlyHashRates = $statistics->getHashrateForPool('json'); + $aHourlyMiningStats = $statistics->getHourlyMiningStatsByAccount($_SESSION['USERDATA']['id'], 'json', $setting->getValue('statistics_graphing_days', 1)); } - $smarty->assign("YOURHASHRATES", @$aHourlyHashRates); - $smarty->assign("POOLHASHRATES", @$aPoolHourlyHashRates); + $smarty->assign('YOURMININGSTATS', @$aHourlyMiningStats); } else { $debug->append('Using cached page', 3); } diff --git a/templates/bootstrap/statistics/graphs/both.tpl b/templates/bootstrap/statistics/graphs/both.tpl deleted file mode 100644 index a4943f85..00000000 --- a/templates/bootstrap/statistics/graphs/both.tpl +++ /dev/null @@ -1,10 +0,0 @@ -{if is_array($YOURHASHRATES) && is_array($POOLHASHRATES)} -
-
- Your vs. Pool Hashrate -
-
-
-
-
-{/if} diff --git a/templates/bootstrap/statistics/graphs/default.tpl b/templates/bootstrap/statistics/graphs/default.tpl index 679b6885..b2007f71 100644 --- a/templates/bootstrap/statistics/graphs/default.tpl +++ b/templates/bootstrap/statistics/graphs/default.tpl @@ -1,47 +1,48 @@ @@ -50,17 +51,45 @@ $(function () {
- Stats + Average Hashrate past 24h
- -
- {include file="{$smarty.request.page|escape}/{$smarty.request.action|escape}/mine.tpl"} - {include file="{$smarty.request.page|escape}/{$smarty.request.action|escape}/pool.tpl"} -
+
+
+ +
+
+ + +
+
+
+
+ Average Workers past 24h +
+
+
+
+ +
+
+
+ +
+
+
+
+ Average Sharerate past 24h +
+
+
+
+
diff --git a/templates/bootstrap/statistics/graphs/mine.tpl b/templates/bootstrap/statistics/graphs/mine.tpl deleted file mode 100644 index 91c8c53a..00000000 --- a/templates/bootstrap/statistics/graphs/mine.tpl +++ /dev/null @@ -1,8 +0,0 @@ -
-
- Your Hashrate -
-
-
-
-
diff --git a/templates/bootstrap/statistics/graphs/pool.tpl b/templates/bootstrap/statistics/graphs/pool.tpl deleted file mode 100644 index 95450674..00000000 --- a/templates/bootstrap/statistics/graphs/pool.tpl +++ /dev/null @@ -1,8 +0,0 @@ -
-
- Pool Hashrate -
-
-
-
-
From feb958677455ba2af9c54aded821ecf1d70b058a Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Thu, 17 Jul 2014 09:37:40 +0200 Subject: [PATCH 28/38] [CHANGE] Shares/s to diff1 shares/s --- include/classes/statistics.class.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index 923d8cfa..e1005dad 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -261,12 +261,12 @@ class Statistics extends Base { SELECT ( ( - SELECT ROUND(COUNT(id) / ?, 2) AS sharerate + SELECT ROUND(SUM(difficulty) / ?, 2) AS sharerate FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) + ( - SELECT ROUND(COUNT(id) / ?, 2) AS sharerate + SELECT ROUND(SUM(difficulty) / ?, 2) AS sharerate FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' @@ -470,7 +470,7 @@ class Statistics extends Base { a.username AS account, COUNT(DISTINCT t1.username) AS workers, IFNULL(SUM(t1.difficulty), 0) AS shares, - ROUND(COUNT(t1.id) / ?, 2) AS sharerate, + ROUND(SUM(t1.difficulty) / ?, 2) AS sharerate, IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff FROM ( SELECT @@ -558,7 +558,7 @@ class Statistics extends Base { * Get Shares per x interval by user * @param username string username * @param $account_id int account id - * @return data integer Current Sharerate in shares/s + * @return data integer Current Sharerate in diff1 shares/s **/ public function getUserMiningStats($username, $account_id=NULL, $interval=180) { $this->debug->append("STA " . __METHOD__, 4); @@ -575,7 +575,7 @@ class Statistics extends Base { if ($this->getGetCache() && $data = $this->memcache->get(__FUNCTION__ . $account_id)) return $data; $stmt = $this->mysqli->prepare(" SELECT - IFNULL(COUNT(*) / ?, 0) AS sharerate, + IFNULL(SUM(difficulty) / ?, 0) AS sharerate, IFNULL(SUM(difficulty), 0) AS shares, IFNULL(AVG(difficulty), 0) AS avgsharediff FROM ( From 638b2c31f5a8e96deac6035b44a627d0244e4c87 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Sat, 19 Jul 2014 09:50:00 +0200 Subject: [PATCH 29/38] [FIX] Oversight --- include/classes/statistics.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/classes/statistics.class.php b/include/classes/statistics.class.php index 318a8bba..4a9c36f3 100644 --- a/include/classes/statistics.class.php +++ b/include/classes/statistics.class.php @@ -111,7 +111,7 @@ class Statistics extends Base { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0), 4) AS estshares + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares FROM " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id From ffe99faccc82597ded3e0b9e17a61ccc075fb69c Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Tue, 22 Jul 2014 10:33:01 +0200 Subject: [PATCH 30/38] [FIX] Disable API calls if not enabled --- include/pages/dashboard.inc.php | 1 + templates/bootstrap/dashboard/default.tpl | 2 ++ templates/bootstrap/dashboard/js/api.tpl | 10 ++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/pages/dashboard.inc.php b/include/pages/dashboard.inc.php index e813c834..b21b7b11 100644 --- a/include/pages/dashboard.inc.php +++ b/include/pages/dashboard.inc.php @@ -52,6 +52,7 @@ if ($user->isAuthenticated()) { $smarty->assign('BLOCKSFOUND', $aLastBlocks); $smarty->assign('DISABLED_DASHBOARD', $setting->getValue('disable_dashboard')); $smarty->assign('DISABLED_DASHBOARD_API', $setting->getValue('disable_dashboard_api')); + $smarty->assign('DISABLED_API', $setting->getValue('disable_api')); $smarty->assign('ESTIMATES', array('shares' => $iEstShares, 'percent' => $dEstPercent)); $smarty->assign('NETWORK', array('difficulty' => $dDifficulty, 'block' => $iBlock, 'EstNextDifficulty' => $dEstNextDifficulty, 'EstTimePerBlock' => $dExpectedTimePerBlock, 'BlocksUntilDiffChange' => $iBlocksUntilDiffChange)); $smarty->assign('INTERVAL', $interval / 60); diff --git a/templates/bootstrap/dashboard/default.tpl b/templates/bootstrap/dashboard/default.tpl index e042fa1e..98646c5e 100644 --- a/templates/bootstrap/dashboard/default.tpl +++ b/templates/bootstrap/dashboard/default.tpl @@ -16,7 +16,9 @@ {include file="dashboard/overview/default.tpl"} {include file="dashboard/round_statistics/$PAYOUT_SYSTEM/default.tpl"} {include file="dashboard/account_data/default.tpl"} + {if !$DISABLED_API} {include file="dashboard/worker_information/default.tpl"} + {/if} {include file="dashboard/blocks/default.tpl"}
diff --git a/templates/bootstrap/dashboard/js/api.tpl b/templates/bootstrap/dashboard/js/api.tpl index 731ee9a6..d47278f3 100644 --- a/templates/bootstrap/dashboard/js/api.tpl +++ b/templates/bootstrap/dashboard/js/api.tpl @@ -178,7 +178,7 @@ $(document).ready(function(){ return; } if (blocks[0].height > lastBlock) { - if(canCreateSoundJS) { + if(canCreateSoundJS) { createjs.Sound.play('ding'); } lastBlock = blocks[0].height; @@ -234,6 +234,7 @@ $(document).ready(function(){ }); })(); + {/literal}{if !$DISABLED_API}{literal} // Worker process to update active workers in the account details table (function worker2() { $.ajax({ @@ -250,7 +251,9 @@ $(document).ready(function(){ } }); })(); + {/literal}{/if}{literal} + {/literal}{if !$DISABLED_API}{literal} // Worker process to update user account balances // Our worker process to keep worker information updated (function worker3() { @@ -265,7 +268,8 @@ $(document).ready(function(){ } }); })(); - + {/literal}{/if}{literal} + // Mute Button $('#muteButton').click(function(){ if(muteFlag == 2) { @@ -280,8 +284,6 @@ $(document).ready(function(){ $(this).find($(".fa")).removeClass('fa-volume-up').addClass('fa-volume-off'); } }); - - }); {/literal} From c2b9eeac0689c5b44e41daa9b5318923614396e4 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Fri, 25 Jul 2014 09:49:48 +0200 Subject: [PATCH 31/38] [FIX] Allow higher hashrate values in statistcs table --- include/version.inc.php | 2 +- upgrade/definitions/0.0.13_to_0.0.14.inc.php | 30 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 upgrade/definitions/0.0.13_to_0.0.14.inc.php diff --git a/include/version.inc.php b/include/version.inc.php index 2b7ea18a..46e122fb 100644 --- a/include/version.inc.php +++ b/include/version.inc.php @@ -2,7 +2,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; define('MPOS_VERSION', '0.0.4'); -define('DB_VERSION', '0.0.13'); +define('DB_VERSION', '0.0.14'); define('CONFIG_VERSION', '0.0.8'); define('HASH_VERSION', 1); diff --git a/upgrade/definitions/0.0.13_to_0.0.14.inc.php b/upgrade/definitions/0.0.13_to_0.0.14.inc.php new file mode 100644 index 00000000..3db8f98d --- /dev/null +++ b/upgrade/definitions/0.0.13_to_0.0.14.inc.php @@ -0,0 +1,30 @@ +getValue('DB_VERSION'); // Our actual version installed + + // Upgrade specific variables + $aSql[] = "ALTER TABLE `statistics_users` CHANGE `hashrate` `hashrate` BIGINT UNSIGNED NOT NULL"; + $aSql[] = "UPDATE " . $setting->getTableName() . " SET value = '0.0.14' WHERE name = 'DB_VERSION'"; + + if ($db_version_now == $db_version_old && version_compare($db_version_now, DB_VERSION, '<')) { + // Run the upgrade + echo '- Starting database migration to version ' . $db_version_new . PHP_EOL; + foreach ($aSql as $sql) { + echo '- Preparing: ' . $sql . PHP_EOL; + $stmt = $mysqli->prepare($sql); + if ($stmt && $stmt->execute()) { + echo '- success' . PHP_EOL; + } else { + echo '- failed: ' . $mysqli->error . PHP_EOL; + exit(1); + } + } + } +} +?> From 8d5395de82e0b3cab4e21997fd2d01cd21ec82a1 Mon Sep 17 00:00:00 2001 From: Glen Date: Tue, 29 Jul 2014 14:22:13 +1000 Subject: [PATCH 32/38] Update default.tpl Correct small spelling mistake. --- templates/bootstrap/about/pool/default.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/bootstrap/about/pool/default.tpl b/templates/bootstrap/about/pool/default.tpl index 7c300f9f..b51a45a8 100644 --- a/templates/bootstrap/about/pool/default.tpl +++ b/templates/bootstrap/about/pool/default.tpl @@ -7,7 +7,7 @@
  • Q: When will I get paid?
  • -  A: This pool uses the follwing payout system.
    +  A: This pool uses the following payout system.
    {if $GLOBAL.config.payout_system == 'prop'}
    Proportional (Prop) - The block reward is distributed among miners in proportion to the number of shares they submitted in a round. The expected reward per share depends on the number of shares already submitted in the round. From 5cf37c8137ad99c416365d70f8560535f41cabc3 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Fri, 1 Aug 2014 09:08:37 +0200 Subject: [PATCH 33/38] [FIX] Maintenance popup on login --- include/pages/login.inc.php | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/include/pages/login.inc.php b/include/pages/login.inc.php index d58f9213..8d4a05df 100644 --- a/include/pages/login.inc.php +++ b/include/pages/login.inc.php @@ -18,28 +18,30 @@ if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_ena } } -if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail($_POST['username']))) { - $_SESSION['POPUP'][] = array('CONTENT' => 'You are not allowed to login during maintenace.', 'TYPE' => 'info'); -} else if (!empty($_POST['username']) && !empty($_POST['password'])) { - // Check if recaptcha is enabled, process form data if valid - if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) { - if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { - // check if login is correct - if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) { - $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); - $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; - $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; - $location.= '?page=dashboard'; - if (!headers_sent()) header('Location: ' . $location); - exit(''); +if (!empty($_POST['username']) && !empty($_POST['password'])) { + if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail($_POST['username']))) { + $_SESSION['POPUP'][] = array('CONTENT' => 'You are not allowed to login during maintenace.', 'TYPE' => 'alert alert-info'); + } else { + // Check if recaptcha is enabled, process form data if valid + if (!$setting->getValue('recaptcha_enabled') || !$setting->getValue('recaptcha_enabled_logins') || ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_logins') && $rsp->is_valid)) { + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + // check if login is correct + if ($user->checkLogin(@$_POST['username'], @$_POST['password']) ) { + $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); + $location = (@$_SERVER['HTTPS'] == "on") ? 'https://' : 'http://'; + $location .= $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME']; + $location.= '?page=dashboard'; + if (!headers_sent()) header('Location: ' . $location); + exit(''); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger'); + } } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); } - } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); } } // Load login template From caf90d9676ca31e3a759f1b83196636fcd069241 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Fri, 1 Aug 2014 09:23:22 +0200 Subject: [PATCH 34/38] [FIX] Password reset form layout --- .../bootstrap/password/change/default.tpl | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/templates/bootstrap/password/change/default.tpl b/templates/bootstrap/password/change/default.tpl index 33976e99..341abd70 100644 --- a/templates/bootstrap/password/change/default.tpl +++ b/templates/bootstrap/password/change/default.tpl @@ -1,39 +1,46 @@ -
    -
    +
    + - + -

    Password reset

    -
    -
    - - -
    -
    - - -
    -
    -
    -
    - {nocache} - - - {if $GLOBAL.twofactor.enabled && $GLOBAL.twofactor.options.changepw} - {if $CHANGEPASSSENT == 1 && $CHANGEPASSUNLOCKED == 1} - - {elseif $CHANGEPASSSENT == 0 && $CHANGEPASSUNLOCKED == 1 || $CHANGEPASSSENT == 1 && $CHANGEPASSUNLOCKED == 0} - - {elseif $CHANGEPASSSENT == 0 && $CHANGEPASSUNLOCKED == 0} - +
    +
    +

    Password reset

    +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    +
    + {/nocache} +
    +
- + From be8db649692efa3b39b8ca94b6e08b16a3261739 Mon Sep 17 00:00:00 2001 From: xisi Date: Mon, 4 Aug 2014 17:53:43 -0400 Subject: [PATCH 35/38] adds pool fee to public api --- include/pages/api/public.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/pages/api/public.inc.php b/include/pages/api/public.inc.php index c6b128d6..a37c80f5 100644 --- a/include/pages/api/public.inc.php +++ b/include/pages/api/public.inc.php @@ -19,7 +19,8 @@ echo json_encode( 'workers' => $worker->getCountAllActiveWorkers(), 'shares_this_round' => $aShares['valid'], 'last_block' => $aLastBlock['height'], - 'network_hashrate' => $dNetworkHashrate + 'network_hashrate' => $dNetworkHashrate, + 'fee' => $config['fees'] ) ); From 2d5d9518946a74921956ca2c165b0bb94e0f18e1 Mon Sep 17 00:00:00 2001 From: xisi Date: Tue, 5 Aug 2014 22:53:25 -0400 Subject: [PATCH 36/38] add payout to public api --- include/pages/api/public.inc.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/pages/api/public.inc.php b/include/pages/api/public.inc.php index a37c80f5..6446b5e5 100644 --- a/include/pages/api/public.inc.php +++ b/include/pages/api/public.inc.php @@ -20,7 +20,8 @@ echo json_encode( 'shares_this_round' => $aShares['valid'], 'last_block' => $aLastBlock['height'], 'network_hashrate' => $dNetworkHashrate, - 'fee' => $config['fees'] + 'fee' => $config['fees'], + 'payout' => $config['payout_system'] ) ); From 09d99b9f4842985d4fb6fd7f0dbb02f9b9957309 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Fri, 8 Aug 2014 20:27:10 +0200 Subject: [PATCH 37/38] [FIX] Skip newsletter to empty email accounts --- include/pages/admin/newsletter.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pages/admin/newsletter.inc.php b/include/pages/admin/newsletter.inc.php index 69204b01..a18955f4 100644 --- a/include/pages/admin/newsletter.inc.php +++ b/include/pages/admin/newsletter.inc.php @@ -20,7 +20,7 @@ if ($setting->getValue('notifications_disable_pool_newsletter', 0) == 1) { $iSuccess = 0; foreach ($user->getAllAssoc() as $aData) { $aUserNotificationSettings = $notification->getNotificationSettings($aData['id']); - if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1) continue; + if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1 || empty($aData['email']) continue; $aData['subject'] = $_REQUEST['data']['subject']; $aData['CONTENT'] = $_REQUEST['data']['content']; if (!$mail->sendMail('newsletter/body', $aData, true)) { From d85743f2cfce583b05a3e97befe4ebf012e69dd3 Mon Sep 17 00:00:00 2001 From: Sebastian Grewe Date: Mon, 18 Aug 2014 06:53:41 +0200 Subject: [PATCH 38/38] Fixed #2321 --- include/pages/admin/newsletter.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/pages/admin/newsletter.inc.php b/include/pages/admin/newsletter.inc.php index a18955f4..fed4f342 100644 --- a/include/pages/admin/newsletter.inc.php +++ b/include/pages/admin/newsletter.inc.php @@ -20,7 +20,7 @@ if ($setting->getValue('notifications_disable_pool_newsletter', 0) == 1) { $iSuccess = 0; foreach ($user->getAllAssoc() as $aData) { $aUserNotificationSettings = $notification->getNotificationSettings($aData['id']); - if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1 || empty($aData['email']) continue; + if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1 || empty($aData['email'])) continue; $aData['subject'] = $_REQUEST['data']['subject']; $aData['CONTENT'] = $_REQUEST['data']['content']; if (!$mail->sendMail('newsletter/body', $aData, true)) {