diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php index 7baf5bf1d..ffbc69431 100755 --- a/cronjobs/notifications.php +++ b/cronjobs/notifications.php @@ -29,47 +29,49 @@ $monitoring->endCronjob($cron_name, 'E0009', 0, true, false); } -$log->logDebug(" IDLE Worker Notifications ..."); -// Find all IDLE workers -$aWorkers = $worker->getAllIdleWorkers(); -if (empty($aWorkers)) { - $log->logDebug(" no idle workers found"); -} else { - $log->logInfo(" found " . count($aWorkers) . " IDLE workers"); - foreach ($aWorkers as $aWorker) { - $aData = $aWorker; - $aData['username'] = $user->getUserName($aWorker['account_id']); - $aData['subject'] = 'IDLE Worker : ' . $aWorker['username']; - $aData['worker'] = $aWorker['username']; - $aData['email'] = $user->getUserEmail($aData['username']); - $log->logDebug(" " . $aWorker['username'] . "..."); - if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData)) - $log->logDebug(" Failed sending notifications: " . $notification->getCronError()); +if ($setting->getValue('notifications_disable_idle_worker') != 1) { + $log->logDebug(" IDLE Worker Notifications ..."); + // Find all IDLE workers + $aWorkers = $worker->getAllIdleWorkers(); + if (empty($aWorkers)) { + $log->logDebug(" no idle workers found"); + } else { + $log->logInfo(" found " . count($aWorkers) . " IDLE workers"); + foreach ($aWorkers as $aWorker) { + $aData = $aWorker; + $aData['username'] = $user->getUserName($aWorker['account_id']); + $aData['subject'] = 'IDLE Worker : ' . $aWorker['username']; + $aData['worker'] = $aWorker['username']; + $aData['email'] = $user->getUserEmail($aData['username']); + $log->logDebug(" " . $aWorker['username'] . "..."); + if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData)) + $log->logDebug(" Failed sending notifications: " . $notification->getCronError()); + } } -} -$log->logDebug(" Reset IDLE Worker Notifications ..."); -// We notified, lets check which recovered -$aNotifications = $notification->getAllActive('idle_worker'); -if (!empty($aNotifications)) { - $log->logInfo(" found " . count($aNotifications) . " active notification(s)"); - foreach ($aNotifications as $aNotification) { - $aData = json_decode($aNotification['data'], true); - $aWorker = $worker->getWorker($aData['id']); - $log->logDebug(" " . $aWorker['username'] . " ..."); - if ($aWorker['hashrate'] > 0) { - if ($notification->setInactive($aNotification['id'])) { - $log->logDebug(" updated #" . $aNotification['id'] . " for " . $aWorker['username'] . " as inactive"); + $log->logDebug(" Reset IDLE Worker Notifications ..."); + // We notified, lets check which recovered + $aNotifications = $notification->getAllActive('idle_worker'); + if (!empty($aNotifications)) { + $log->logInfo(" found " . count($aNotifications) . " active notification(s)"); + foreach ($aNotifications as $aNotification) { + $aData = json_decode($aNotification['data'], true); + $aWorker = $worker->getWorker($aData['id']); + $log->logDebug(" " . $aWorker['username'] . " ..."); + if ($aWorker['hashrate'] > 0) { + if ($notification->setInactive($aNotification['id'])) { + $log->logDebug(" updated #" . $aNotification['id'] . " for " . $aWorker['username'] . " as inactive"); + } else { + $log->logError(" failed to update #" . $aNotification['id'] . " for " . $aWorker['username']); + } } else { - $log->logError(" failed to update #" . $aNotification['id'] . " for " . $aWorker['username']); + $log->logDebug(" still inactive"); } - } else { - $log->logDebug(" still inactive"); } + } else { + $log->logDebug(" no active IDLE worker notifications"); } -} else { - $log->logDebug(" no active IDLE worker notifications"); } require_once('cron_end.inc.php'); diff --git a/cronjobs/pplns_payout.php b/cronjobs/pplns_payout.php index 08656ed7e..c256b2792 100755 --- a/cronjobs/pplns_payout.php +++ b/cronjobs/pplns_payout.php @@ -181,8 +181,8 @@ } // Table header for account shares - $strLogMask = "| %5.5s | %-15.15s | %15.15s | %15.15s | %12.12s | %20.20s | %20.20s | %20.20s |"; - $log->logInfo(sprintf($strLogMask, 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee')); + $strLogMask = "| %5.5s | %-15.15s | %15.15s | %15.15s | %12.12s | %15.15s | %15.15s | %15.15s | %15.15s |"; + $log->logInfo(sprintf($strLogMask, 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee', 'Bonus')); // Loop through all accounts that have found shares for this round foreach ($aTotalAccountShares as $key => $aData) { @@ -201,16 +201,28 @@ // Defaults $aData['fee' ] = 0; $aData['donation'] = 0; + $aData['pool_bonus'] = 0; + // Calculate pool fees if ($config['fees'] > 0 && $aData['no_fees'] == 0) $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 8); + + // Calculate pool bonus if it applies, will be paid from liquid assets! + if ($config['pool_bonus'] > 0) { + if ($config['pool_bonus_type'] == 'block') { + $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $dReward, 8); + } else { + $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $aData['payout'], 8); + } + } + // Calculate donation amount, fees not included $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8); // Verbose output of this users calculations $log->logInfo( sprintf($strLogMask, $aData['id'], $aData['username'], $aData['pplns_valid'], $aData['pplns_invalid'], - number_format($aData['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8) + number_format($aData['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8), number_format($aData['pool_bonus'], 8) ) ); @@ -225,6 +237,10 @@ if ($aData['donation'] > 0) if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation', $aBlock['id'])) $log->logFatal('Failed to insert new Donation transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError() . 'on block ' . $aBlock['id']); + // Add new bonus credit + if ($aData['pool_bonus'] > 0) + if (!$transaction->addTransaction($aData['id'], $aData['pool_bonus'], 'Bonus', $aBlock['id'])) + $log->logFatal('Failed to insert new Bonus transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError()); } // Add full round share statistics diff --git a/cronjobs/proportional_payout.php b/cronjobs/proportional_payout.php index a91ba7a4d..58f47ee9b 100755 --- a/cronjobs/proportional_payout.php +++ b/cronjobs/proportional_payout.php @@ -40,8 +40,8 @@ $count = 0; // Table header for account shares -$strLogMask = "| %10.10s | %-5.5s | %15.15s | %15.15s | %12.12s | %20.20s | %20.20s | %20.20s |"; -$log->logInfo(sprintf($strLogMask, 'Block', 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee')); +$strLogMask = "| %10.10s | %-5.5s | %15.15s | %15.15s | %12.12s | %12.12s | %15.15s | %15.15s | %15.15s | %15.15s |"; +$log->logInfo(sprintf($strLogMask, 'Block', 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee', 'Bonus')); foreach ($aAllBlocks as $iIndex => $aBlock) { // If we have unaccounted blocks without share_ids, they might not have been inserted yet if (!$aBlock['share_id']) { @@ -86,18 +86,30 @@ // Defaults $aData['fee' ] = 0; $aData['donation'] = 0; + $aData['pool_bonus'] = 0; $aData['percentage'] = round(( 100 / $iRoundShares ) * $aData['valid'], 8); $aData['payout'] = round(( $aData['percentage'] / 100 ) * $dReward, 8); + // Calculate pool fees if they apply if ($config['fees'] > 0 && $aData['no_fees'] == 0) $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 8); + + // Calculate pool bonus if it applies, will be paid from liquid assets! + if ($config['pool_bonus'] > 0) { + if ($config['pool_bonus_type'] == 'block') { + $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $dReward, 8); + } else { + $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $aData['payout'], 8); + } + } + // Calculate donation amount, fees not included $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8); // Verbose output of this users calculations $log->logInfo( sprintf($strLogMask, $aBlock['height'], $aData['id'], $aData['username'], $aData['valid'], $aData['invalid'], - number_format($aData['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8)) + number_format($aData['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8), number_format($aData['pool_bonus'], 8)) ); // Update user share statistics @@ -114,6 +126,10 @@ if ($aData['donation'] > 0) if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation', $aBlock['id'])) $log->logFatal('Failed to insert new Donation transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError()); + // Add new bonus credit + if ($aData['pool_bonus'] > 0) + if (!$transaction->addTransaction($aData['id'], $aData['pool_bonus'], 'Bonus', $aBlock['id'])) + $log->logFatal('Failed to insert new Bonus transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError()); } // Add block as accounted for into settings table diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index 98ecbbb26..f112efb4a 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -6,25 +6,27 @@ $notice = array(); $enotice = array(); $error = array(); - + // setup some basic stuff for checking - getuid/getpwuid not available on mac/windows $apache_user = 'unknown'; if (substr_count(strtolower(PHP_OS), 'nix') > 0 || substr_count(strtolower(PHP_OS), 'linux') > 0) { $apache_user = (function_exists('posix_getuid')) ? posix_getuid() : 'unknown'; $apache_user = (function_exists('posix_getpwuid')) ? posix_getpwuid($apache_user) : $apache_user; } - + // setup checks // logging if ($config['logging']['enabled']) { if (!is_writable($config['logging']['path'])) { - $error[] = "Logging is enabled but we can't write in the logging path"; + $error[] = "Logging is enabled but we can't write in the logfile path"; } } + // check if memcache isn't available but enabled in config -> error if (!class_exists('Memcached') && $config['memcache']['enabled']) { - $error[] = "You have memcache enabled in your config and it's not available. Install the package on your system."; + $error[] = "You have memcached enabled in your config and it's not available as a PHP module. Install the package on your system."; } + // if it's not enabled, test it if it exists, if it works -> error tell them to enable, -> otherwise notice it's disabled if (!$config['memcache']['enabled']) { if (PHP_OS == 'WINNT') { @@ -38,16 +40,18 @@ $memcache_test_get = @$memcache_test->get('test_mpos_setval'); } if (class_exists('Memcached') && $memcache_test_get == $randmctv) { - $error[] = "You have memcache disabled in the config and it's available & works! Enable it."; + $error[] = "You have memcache disabled in the config but it's available and works! Enable it for best performance."; } else { $notice[] = "Memcache is disabled; Almost every linux distro has packages for it, you should be using it if you can."; } } + // check if htaccess exists if (!file_exists(BASEPATH.".htaccess")) { $htaccess_link = ".htaccess"; - $notice[] = "You don't seem to have a .htaccess in your public folder, if you're using apache set it up $htaccess_link"; + $notice[] = "You don't seem to have a .htaccess in your public folder, if you're using Apache set it up: $htaccess_link"; } + // check if we can write templates/cache and templates/compile -> error if (!is_writable(THEME_DIR.'/cache')) { $error[] = "templates/cache folder is not writable for uid {$apache_user['name']}"; @@ -55,11 +59,13 @@ if (!is_writable(THEME_DIR.'/compile')) { $error[] = "templates/compile folder is not writable for uid {$apache_user['name']}"; } + // check if we can write the config files, we should NOT be able to -> error if (is_writable(INCLUDE_DIR.'/config/global.inc.php') || is_writable(INCLUDE_DIR.'/config/global.inc.dist.php') || is_writable(INCLUDE_DIR.'/config/security.inc.php') || is_writable(INCLUDE_DIR.'/config/security.inc.dist.php')) { $error[] = "Your config files SHOULD NOT be writable to this user!"; } + // check if daemon can connect -> error try { if ($bitcoin->can_connect() !== true) { @@ -76,7 +82,7 @@ if (!$bitcoin->validateaddress($config['coldwallet']['address'])) $error[] = "Your cold wallet address is SET and INVALID"; } - + // check if there is more than one account set on wallet $accounts = $bitcoin->listaccounts(); if (count($accounts) > 1 && $accounts[''] <= 0) { @@ -85,34 +91,30 @@ } } catch (Exception $e) { } - // if database connection fails -> error - $db_connect = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); - if (mysqli_connect_errno() || !array_key_exists('client_info', $db_connect)) { - $error[] = "Unable to connect to mysql using provided credentials"; - } + // check anti DOS protection, we need memcache for that if ($config['mc_antidos'] && !$config['memcache']['enabled']) { $error[] = "mc_antidos is enabled and memcache is not, memcache is required to use this"; } + // poke stratum using gettingstarted details -> enotice - if (substr_count(strtolower(PHP_OS), 'nix') > 0) { - // unix *poke* - $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + if (function_exists('socket_create')) { + $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($socket !== false) { $address = @gethostbyname($config['gettingstarted']['stratumurl']); $result = @socket_connect($socket, $address, $config['gettingstarted']['stratumport']); if ($result !== true) { - $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; + $enotice[] = 'We tried to poke your Stratum server using your $config[\'gettingstarted\'] settings but it didn\'t respond'; } $close = @socket_close($socket); } } else { - // mac/windows *poke* - if (! $fp = @fsockopen($config['gettingstarted']['stratumurl'],$config['gettingstarted']['stratumport'],$errCode,$errStr,1)) { - $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; + // Connect via fsockopen as fallback + if (! $fp = @fsockopen($config['gettingstarted']['stratumurl'], $config['gettingstarted']['stratumport'], $errCode, $errStr, 1)) { + $enotice[] = 'We tried to poke your Stratum server using your $config[\'gettingstarted\'] settings but it didn\'t respond'; } @fclose($fp); } - + // security checks // salts too short -> notice, salts default -> error if ((strlen($config['SALT']) < 24) || (strlen($config['SALTY']) < 24) || $config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { @@ -122,7 +124,7 @@ $notice[] = "SALT or SALTY is too short, they should be more than 24 characters and changing them will require registering again"; } } - + // display the errors foreach ($enotice as $en) { $_SESSION['POPUP'][] = array('CONTENT' => $en, 'TYPE' => 'info'); diff --git a/public/include/classes/setting.class.php b/public/include/classes/setting.class.php index 3da3ccb9b..1f92eb7ad 100644 --- a/public/include/classes/setting.class.php +++ b/public/include/classes/setting.class.php @@ -3,6 +3,21 @@ class Setting extends Base { protected $table = 'settings'; + private $cache = array(); + + /** + * Fetch all values available and cache them in this class + * That way we don't fetch them from DB for each call + */ + public function createCache() { + if ($aSettings = $this->getAllAssoc()) { + foreach ($aSettings as $key => $aData) { + $this->cache[$aData['name']] = $aData['value']; + } + return true; + } + return false; + } /** * Fetch a value from our table @@ -10,6 +25,8 @@ class Setting extends Base { * @return value string Value **/ public function getValue($name, $default="") { + // Try our class cache first + if (isset($this->cache[$name])) return $this->cache[$name]; $stmt = $this->mysqli->prepare("SELECT value FROM $this->table WHERE name = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('s', $name) && $stmt->execute() && $result = $stmt->get_result()) { if ($result->num_rows > 0) { @@ -30,6 +47,8 @@ public function getValue($name, $default="") { * @return bool **/ public function setValue($name, $value) { + // Update local cache too + $this->cache[$name] = $value; $stmt = $this->mysqli->prepare(" INSERT INTO $this->table (name, value) VALUES (?, ?) @@ -44,3 +63,5 @@ public function setValue($name, $value) { $setting->setDebug($debug); $setting->setMysql($mysqli); $setting->setErrorCodes($aErrorCodes); +// Fill our class cache with data so we don't have to run SQL queries all the time +$setting->createCache(); diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php index 5b2eeacf6..1a9e1b3c0 100644 --- a/public/include/classes/statistics.class.php +++ b/public/include/classes/statistics.class.php @@ -469,7 +469,7 @@ public function getAllUserMiningStats($interval=180) { share_id, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty, username - FROM shares_archive + FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) AS t1 LEFT JOIN " . $this->user->getTableName() . " AS a diff --git a/public/include/classes/tools.class.php b/public/include/classes/tools.class.php index 8778a2004..a272761ef 100644 --- a/public/include/classes/tools.class.php +++ b/public/include/classes/tools.class.php @@ -55,6 +55,8 @@ private function getApiType($url) { return 'btce'; } else if (preg_match('/cryptsy.com/', $url)) { return 'cryptsy'; + } else if (preg_match('/cryptorush.in/', $url)) { + return 'cryptorush'; } $this->setErrorMessage("API URL unknown"); return false; @@ -84,6 +86,9 @@ public function getPrice() { case 'cryptsy': return @$aData['return']['markets'][$strCurrency]['lasttradeprice']; break; + case 'cryptorush': + return @$aData["$strCurrency/" . $this->config['price']['target']]['last_trade']; + break; } } else { $this->setErrorMessage("Got an invalid response from ticker API"); diff --git a/public/include/config/admin_settings.inc.php b/public/include/config/admin_settings.inc.php index 593d03b8b..0a2284820 100644 --- a/public/include/config/admin_settings.inc.php +++ b/public/include/config/admin_settings.inc.php @@ -425,3 +425,10 @@ 'name' => 'notifications_disable_block', 'value' => $setting->getValue('notifications_disable_block'), 'tooltip' => 'Enable/Disable block notifications globally. Will remove the user option too.' ); +$aSettings['notifications'][] = array( + 'display' => 'Disable IDLE Worker Notifications', 'type' => 'select', + 'options' => array( 0 => 'No', 1 => 'Yes'), + 'default' => 0, + 'name' => 'notifications_disable_idle_worker', 'value' => $setting->getValue('notifications_disable_idle_worker'), + 'tooltip' => 'Enable/Disable IDLE worker notifications globally. Will remove the user option too.' +); diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 2da7464ec..b1a2d7a7e 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -128,12 +128,14 @@ $config['txfee_manual'] = 0.1; /** - * Block Bonus - * Bonus in coins of block bonus + * Block & Pool Bonus + * Bonus coins for blockfinder or a pool bonus for everyone * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-block-bonus + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-pool-bonus */ $config['block_bonus'] = 0; - +$config['pool_bonus'] = 0; +$config['pool_bonus_type'] = 'payout'; /** * Payout System diff --git a/public/include/pages/account/notifications.inc.php b/public/include/pages/account/notifications.inc.php index 5fbf03551..1411b804a 100644 --- a/public/include/pages/account/notifications.inc.php +++ b/public/include/pages/account/notifications.inc.php @@ -24,6 +24,7 @@ // Fetch global settings $smarty->assign('DISABLE_BLOCKNOTIFICATIONS', $setting->getValue('notifications_disable_block')); + $smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); // Fetch user notification settings $aSettings = $notification->getNotificationSettings($_SESSION['USERDATA']['id']); diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php index e85623f15..5e5c7d08a 100644 --- a/public/include/pages/account/workers.inc.php +++ b/public/include/pages/account/workers.inc.php @@ -40,6 +40,7 @@ break; } + $smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); $aWorkers = $worker->getWorkers($_SESSION['USERDATA']['id']); if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'errormsg'); diff --git a/public/include/pages/admin/poolworkers.inc.php b/public/include/pages/admin/poolworkers.inc.php index 24cb675c0..8d80314ad 100644 --- a/public/include/pages/admin/poolworkers.inc.php +++ b/public/include/pages/admin/poolworkers.inc.php @@ -15,6 +15,7 @@ $aWorkers = $worker->getAllWorkers($iLimit, $interval, $start); +$smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); $smarty->assign('LIMIT', $iLimit); $smarty->assign('WORKERS', $aWorkers); $smarty->assign('CONTENT', 'default.tpl'); diff --git a/public/templates/mpos/account/notifications/default.tpl b/public/templates/mpos/account/notifications/default.tpl index a112147d6..23e77667c 100644 --- a/public/templates/mpos/account/notifications/default.tpl +++ b/public/templates/mpos/account/notifications/default.tpl @@ -13,6 +13,7 @@