// наш последний блок-1 $block_id = get_block_id($db) - 1; if ($block_id < 1) { exit; } $hash = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tSELECT `hash`\n\t\tFROM `" . DB_PREFIX . "block_chain`\n\t\tWHERE `id`= {$block_id}\n\t\t", 'fetch_one'); $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tSELECT `host`,\n\t\t\t\t\t `user_id`\n\t\tFROM `" . DB_PREFIX . "miners_data`\n\t\tWHERE `miner_id`> 0\n\t\tGROUP BY `host`\n\t\tORDER BY RAND()\n\t\tLIMIT " . COUNT_CONFIRMED_NODES . "\n\t\t"); $i = 0; $urls = array(); while ($row = $db->fetchArray($res)) { $urls[$i]['url'] = $row['host'] . 'tools/check_node.php?block_id=' . $block_id; $urls[$i]['user_id'] = $row['user_id']; $i++; } if (empty($urls)) { exit; } print_R($urls); $result = m_curl($urls, '', '', '', 10, true, false); debug_print("result=" . print_r_hex($result), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); print_R($result); $status[0] = 0; $status[1] = 0; foreach ($result as $user_id => $answer) { if ($answer != $hash) { $status[0]++; } else { $status[1]++; } } $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tINSERT INTO `" . DB_PREFIX . "confirmations` (\n\t\t\t`block_id`,\n\t\t\t`good`,\n\t\t\t`bad`,\n\t\t\t`time`\n\t\t)\n\t\tVALUES (\n\t\t\t{$block_id},\n\t\t\t" . intval($status[1]) . ",\n\t\t\t" . intval($status[0]) . ",\n\t\t\t" . time() . "\n\t\t)\n\t\tON DUPLICATE KEY UPDATE `good` = {$status[1]}, `bad` = {$status[0]}, `time` = " . time() . "\n\t\t");
debug_print($urls, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $rez = m_curl($urls, $to_be_sent, $db, 'data', 20, true); debug_print($rez, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); } } else { // если просто юзер или работаю в защищенном режиме, то шлю тр-ии целиком. слать блоки не имею права. if ($my_config['local_gate_ip']) { $gate = 'protected_gate_tx.php'; // Чтобы protected_gate_tx.php мог понять, какому ноду слать эту тр-ию, пишем в первые 100 байт host $remote_node_host = $node_data['host']; } else { $gate = 'gate_tx.php'; $remote_node_host = ''; } for ($i = 0; $i < sizeof($hosts); $i++) { $urls[$i] = array('url' => $hosts[$i]['host'] . $gate, 'node_public_key' => $hosts[$i]['node_public_key'], 'user_id' => $hosts[$i]['user_id']); } debug_print($urls, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // возьмем хэши и сами тр-ии $tx_data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tSELECT `hash`, `data`\n\t\t\t\tFROM `" . DB_PREFIX . "transactions`\n\t\t\t\tWHERE `sent` = 0\n\t\t\t\t", 'fetch_array'); debug_print('$tx_data: ' . print_r_hex($tx_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); if ($tx_data['hash']) { $hex_hash = bin2hex($tx_data['hash']); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tUPDATE `" . DB_PREFIX . "transactions`\n\t\t\t\t\tSET `sent` = 1\n\t\t\t\t\tWHERE `hash` = 0x{$hex_hash}\n\t\t\t\t\t"); // в первые 5 байт tx_data['data'] m_curl допишет user_id получателя, если вдруг там пул $rez = m_curl($urls, $tx_data['data'], $db, 'data', 20, true, true, $remote_node_host); debug_print($rez, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); } } sleep(1); }
// откатываем по фронту все свежие тр-ии $parsedata = new ParseData($transactions, $db); $parsedata->ParseDataRollbackFront(); unset($parsedata); } $LOG_MARKER = "Вилка на {$block_id}"; rollback_transactions_testblock($db, true); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tTRUNCATE TABLE `" . DB_PREFIX . "testblock`\n\t\t\t\t\t"); } //print '$binary_block_full='.$binary_block_full."\n"; // теперь у нас в таблицах всё тоже самое, что у нода, у которого качаем блок // и можем этот блок проверить и занести в нашу БД $LOG_MARKER = "new block_id = " . $block_id; $parsedata = new ParseData($binary_block_full, $db); $error = $parsedata->ParseDataFull(); debug_print("parsedata->block_data " . print_r_hex($parsedata->block_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); if (!$error) { $parsedata->insert_into_blockchain(); } unset($parsedata); //main_unlock(); // начинаем всё с начала уже с другими нодами. Но у нас уже могут быть новые блоки до $block_id, взятые от нода, которого с в итоге мы баним if ($error) { //$block_id--; nodes_ban($db, $max_block_id_user_id, '$block_id=' . $block_id . "\n" . $error . "\n" . __FILE__ . ', ' . __LINE__ . ', ' . __FUNCTION__ . ', ' . __CLASS__ . ', ' . __METHOD__); debug_print("[[error]] ## пробуем взять этот же блок у другого нода ParseDataFull error={$error}", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); //ob_save(); main_unlock(); sleep(1); continue 2; }
while ($row = $db->fetchArray($res)) { if (array_key_exists($row['host'], $nodes_ban)) { if ($nodes_ban[$row['host']] > time() - NODE_BAN_TIME) { continue; } } $hosts[] = $row['host']; $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\t\tINSERT IGNORE INTO `" . DB_PREFIX . "nodes_connection` (\n\t\t\t\t\t\t\t`host`,\n\t\t\t\t\t\t\t`user_id`\n\t\t\t\t\t\t)\n\t\t\t\t\t\tVALUES (\n\t\t\t\t\t\t\t'{$row['host']}',\n\t\t\t\t\t\t\t{$row['user_id']}\n\t\t\t\t\t\t)"); } } } debug_print($hosts, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // если хосты не набрались из miner_data, то берем из файла if (!$hosts) { $hosts = file(ABSPATH . 'nodes.inc'); debug_print(ABSPATH . 'nodes.inc ' . print_r_hex($hosts), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $r = array_rand($hosts, sizeof($hosts) > $max_hosts - 1 ? $max_hosts : sizeof($hosts)); $r = is_array($r) ? $r : array($r); for ($i = 0; $i < sizeof($r); $i++) { list($host, $user_id) = explode(';', $hosts[$r[$i]]); if (in_array($user_id, $collective)) { continue; } if (array_key_exists($host, $nodes_ban)) { if ($nodes_ban[$host] > time() - NODE_BAN_TIME) { continue; } } $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tINSERT IGNORE INTO `" . DB_PREFIX . "nodes_connection` (\n\t\t\t\t\t\t`host`,\n\t\t\t\t\t\t`user_id`\n\t\t\t\t\t)\n\t\t\t\t\tVALUES (\n\t\t\t\t\t\t'{$host}',\n\t\t\t\t\t\t{$user_id}\n\t\t\t\t\t)"); } }
$order_array[] = bin2hex(ParseData::string_shift($binary_data, 16)); } } while ($binary_data); $order_array = array_flip($order_array); debug_print('$tr_array:' . print_r_hex($tr_array), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print('$order_array:' . print_r_hex($order_array), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // сортируем и наши и полученные транзакции $transactions = ''; //$merkle_array = array(); foreach ($order_array as $md5 => $id) { $ordered_transactions[$id] = $tr_array[$md5]; $transactions .= ParseData::encode_length_plus_data($tr_array[$md5]); //$merkle_array[] = hash('sha256', hash('sha256', $tr_array[$md5])); } debug_print('strlen($transactions)=' . strlen($transactions), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print('$ordered_transactions:' . print_r_hex($ordered_transactions), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // формируем блок, который далее будем тщательно проверять /* Заголовок (от 143 до 527 байт ) TYPE (0-блок, 1-тр-я) 1 BLOCK_ID 4 TIME 4 USER_ID 5 LEVEL 1 SIGN от 128 до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT Далее - тело блока (Тр-ии) */ //$merkle_root = $testBlock->merkle_tree_root($merkle_array); //$merkle_root_binary = pack( "H*", $merkle_root); $new_block_id_binary = dec_binary($new_testblock['block_id'], 4); //$prev_block_hash_binary = $testBlock->block_info['hash'];
private function query_($query, $self = false) { global $global_current_block_id; $this->query = $query; $mysql_error = ''; $i1 = 0; do { if (!($this->result = $this->_mysqli->query($this->query))) { if (substr_count($this->_mysqli->error, 'Deadlock') == 0) { $mysql_error = $this->_mysqli->error; if (preg_match('/(has gone away)/i', $mysql_error)) { sleep(300); $i1++; } else { trigger_error('Error performing query ' . $query . ' - Error message : ' . $mysql_error, E_USER_ERROR); } } else { usleep(10); file_put_contents(ABSPATH . 'log/error_deadlock.log', date('H:i:s') . " : " . $query . "\n", FILE_APPEND); } } } while (preg_match('/(has gone away)/i', $mysql_error) && $i1 < 10); $ini_array = parse_ini_file(ABSPATH . "config.ini", true); $this->logging = false; //debug_print( "{$global_current_block_id} >= {$ini_array['main']['log_block_id_begin']} && {$global_current_block_id} <= {$ini_array['main']['log_block_id_end']}", $this->file, $this->line, $this->fns, $this->class, $this->method); //if (!$self) //debug_print( '!$self', $this->file, $this->line, $this->fns, $this->class, $this->method); if (!$self && ($ini_array['main']['log'] == 1 || $global_current_block_id >= $ini_array['main']['log_block_id_begin'] && $global_current_block_id <= $ini_array['main']['log_block_id_end'] && $ini_array['main']['log_block_id_begin'] && $ini_array['main']['log_block_id_end'])) { $this->logging = true; $this->AffectedRows = $this->getAffectedRows(true); debug_print("AffectedRows= {$this->AffectedRows}", $this->file, $this->line, $this->fns, $this->class, $this->method); if ($ini_array['main']['log_tables']) { $table = $this->parse_table($query); $rexp = '/\\`(' . $ini_array['main']['log_tables'] . ')\\`\\s/i'; //$rexp = '/sssss/'; if (preg_match($rexp, $query) && $table) { $result00 = $this->result; $res = $this->_mysqli->query("SELECT * FROM `{$table}`"); $data = array(); $i = 0; while ($row = $res->fetch_array(MYSQLI_ASSOC)) { foreach ($row as $name => $value) { $data[$i][$name] = $value; } $i++; } debug_print('$table:' . $table . "\n" . print_r_hex($data), $this->file, $this->line, $this->fns, $this->class, $this->method); $this->result = $result00; } } } return $this->result; }
function tx_parser($new_tx_data, $my_tx = false) { global $db; $error = ''; $binary_tx = $new_tx_data['data']; debug_print('$new_tx_data=' . print_r_hex($new_tx_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // проверим, нет ли несовместимых тр-ий // $wait_error - значит просто откладываем обработку тр-ии на после того, как сформируются блок // $fatal_error - удаляем тр-ию, т.к. она некорректная list($fatal_error, $wait_error, $for_self_use, $type, $user_id, $third_var) = clear_incompatible_tx($binary_tx, $db, $my_tx); if (!$fatal_error && !$wait_error) { $parsedata = new ParseData($binary_tx, $db); $error = $parsedata->ParseData_gate(); unset($parsedata); } if ($error || $fatal_error) { delete_queue_tx($new_tx_data); } // удалим тр-ию из очереди if (!$error) { $error = $fatal_error; } if (!$error) { $error = $wait_error; } if ($error) { /* не актуально * if (substr_count($error, '[limit_requests]')>0) { debug_print('----------------[error]'.$error.'-------------------', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $parsedata = new ParseData(ParseData::encode_length_plus_data($binary_tx), $db); $parsedata->ParseDataRollbackFront(); unset($parsedata); } else {*/ debug_print('error wo rollback----------------[error]' . $error . '-------------------', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // пишем в отдельный лог невалидных тр-ий $ini_array = parse_ini_file(ABSPATH . "config.ini", true); if ($ini_array['main']['bad_tx_log'] == 1) { $file = ABSPATH . 'log/bad_tx.log'; $text = "time: " . date('d-m-Y H:i:s') . "\n"; $text .= "script: " . get_script_name() . "\n"; $text .= "error: {$error}\n"; $text .= "md5_hash: " . md5($binary_tx) . "\n"; $text .= "data: {$binary_tx}\n"; @file_put_contents($file, $text, FILE_APPEND); } $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tUPDATE `" . DB_PREFIX . "transactions_status`\n\t\t\t\t\tSET `error` = '" . $db->escape($error) . "'\n\t\t\t\t\tWHERE `hash` = 0x" . md5($binary_tx) . "\n\t\t\t\t\t"); /*}*/ //delete_queue_tx(); //main_unlock(); //ob_save(); //sleep(1); //return 'continue'; } else { list(, $data_hex) = unpack("H*", $binary_tx); list(, $hash_hex) = unpack("H*", $new_tx_data['hash']); // счтечик, чтобы не было зацикливания $counter = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tSELECT `counter`\n\t\t\t\tFROM `" . DB_PREFIX . "transactions`\n\t\t\t\tWHERE `hash` = 0x{$hash_hex}\n\t\t\t\t", 'fetch_one'); $counter = intval($counter); $counter++; $data = "{$hash_hex}\t{$data_hex}\t{$for_self_use}\t{$type}\t{$user_id}\t{$third_var}\t{$counter}"; $file = save_tmp_644('FTX', $data); debug_print($data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // используем REPLACE т.к. тр-ия уже может быть в transactions с verified=0 $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tLOAD DATA LOCAL INFILE '{$file}'\n\t\t\t\tREPLACE INTO TABLE `" . DB_PREFIX . "transactions`\n\t\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t\t(@hash, @data, `for_self_use`, `type`, `user_id`, `third_var`, `counter`)\n\t\t\t\tSET `hash` = UNHEX(@hash),\n\t\t\t\t\t `data` = UNHEX(@data)\n\t\t\t\t"); unlink($file); // удалим тр-ию из очереди delete_queue_tx($new_tx_data); } }
* * */ do { debug_print("START", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // отметимся в БД, что мы живы. upd_deamon_time($db); // проверим, не нужно нам выйти, т.к. обновилась версия скрипта if (check_deamon_restart($db)) { exit; } $blocks = array(); //print 'memory='.memory_get_usage()."\n---------------------------------\n"; // ждем, пока разлочится и лочим сами, чтобы не попасть в тот момент, когда данные из блока уже занесены в БД, а info_block еще не успел обновиться main_lock(); $prev_block_data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT *\n\t\t\tFROM `" . DB_PREFIX . "info_block`\n\t\t\t", 'fetch_array'); debug_print('info_block:' . print_r_hex($prev_block_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $new_block_data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT *\n\t\t\tFROM `" . DB_PREFIX . "queue_blocks`\n\t\t\tLIMIT 1\n\t\t\t", 'fetch_array'); //print '$new_block_data:'; //print_r($new_block_data); if (!$new_block_data) { main_unlock(); debug_print("continue", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); sleep(1); continue; } $new_block_data['head_hash_hex'] = bin2hex($new_block_data['head_hash']); $prev_block_data['head_hash_hex'] = bin2hex($prev_block_data['head_hash']); $new_block_data['hash_hex'] = bin2hex($new_block_data['hash']); $prev_block_data['hash_hex'] = bin2hex($prev_block_data['hash']); $variables = ParseData::get_variables($db, array('rollback_blocks_1', 'max_block_size', 'max_tx_size', 'max_tx_count')); /*
// также, нужно блокировать main, т.к. изменение в info_block и block_chain ведут к изменению подписи в testblock //main_lock(); testblock_lock(); // за промежуток в main_unlock и main_lock мог прийти новый блок $testBlock = new testblock($db, true); // на всякий случай убедимся, что блок не изменился if ($testBlock->prev_block['head_hash'] != $prev_head_hash) { main_unlock(); unset($testBlock); debug_print("continue", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); sleep(1); continue; } // составим блок. заголовок + тело + подпись $testblock_data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT *\n\t\t\tFROM `" . DB_PREFIX . "testblock`\n\t\t\tWHERE `status` = 'active'\n\t\t\t", 'fetch_array'); debug_print(print_r_hex($testblock_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print("testBlock->prev_block['block_id']={$testBlock->prev_block['block_id']} // testblock_data['block_id'] = {$testblock_data['block_id']} ", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); if (!$testblock_data) { //main_unlock(); testblock_unlock(); print 'null $testblock_data' . "\n"; unset($testBlock); sleep(1); print ">>continue\n"; //ob_save(); continue; } // получим транзакции $testblock_data['tx'] = ''; $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tSELECT *\n\t\t\t\tFROM `" . DB_PREFIX . "transactions_testblock`\n\t\t\t\tORDER BY `id` ASC\n\t\t\t\t"); while ($row = $db->fetchArray($res)) {
function CheckBlockHeader() { // инфа о предыдущем блоке (т.е. последнем занесенном) if (!$this->prev_block) { // инфа может быть передана прямо в массиве $this->get_prev_block($this->block_data['block_id'] - 1); } //$this->get_info_block(); убрано, т.к. CheckBlockHeader используется и при сборе новых блоков при вилке // для локальных тестов if ($this->prev_block['block_id'] == 1) { $ini_array = parse_ini_file(ABSPATH . "config.ini", true); if (isset($ini_array['local']['start_block_id'])) { $this->prev_block['block_id'] = $ini_array['local']['start_block_id']; } } debug_print("this->prev_block: " . print_r_hex($this->prev_block), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print("this->block_data: " . print_r_hex($this->block_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // меркель рут нужен для проверки подписи блока, а также проверки лимитов MAX_TX_SIZE и MAX_TX_COUNT if ($this->block_data['block_id'] == 1) { $this->global_variables['max_tx_size'] = 1024 * 1024; $first = true; } else { $first = false; } $this->mrkl_root = self::getMrklroot($this->binary_data, $this->global_variables, $first); // проверим время if (!check_input_data($this->block_data['time'], 'int')) { return 'error time'; } // проверим уровень if (!check_input_data($this->block_data['level'], 'level')) { return 'error level'; } // получим значения для сна $sleep_data = $this->db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tSELECT `value`\n\t\t\t\t\tFROM `" . DB_PREFIX . "variables`\n\t\t\t\t\tWHERE `name` = 'sleep'\n\t\t\t\t\t", 'fetch_one'); $sleep_data = json_decode($sleep_data, true); debug_print("sleep_data:", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); //print_R($sleep_data); // узнаем время, которые было затрачено в ожидании is_ready предыдущим блоком $is_ready_sleep = testblock::get_is_ready_sleep($this->prev_block['level'], $sleep_data['is_ready']); // сколько сек должен ждать нод, перед тем, как начать генерить блок, если нашел себя в одном из уровней. $generator_sleep = testblock::get_generator_sleep($this->block_data['level'], $sleep_data['generator']); // сумма is_ready всех предыдущих уровней, которые не успели сгенерить блок $is_ready_sleep2 = testblock::get_is_ready_sleep_sum($this->block_data['level'], $sleep_data['is_ready']); debug_print("is_ready_sleep={$is_ready_sleep}\ngenerator_sleep={$generator_sleep}\nis_ready_sleep2={$is_ready_sleep2}", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print('prev_block:' . print_r_hex($this->prev_block), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print('block_data:' . print_r_hex($this->block_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // не слишком ли рано прислан этот блок. допустима погрешность = error_time if (!$first) { if ($this->prev_block['time'] + $is_ready_sleep + $generator_sleep + $is_ready_sleep2 - $this->block_data['time'] > $this->global_variables['error_time']) { return "error block time {$this->prev_block['time']} + {$is_ready_sleep} + {$generator_sleep} + {$is_ready_sleep2} - {$this->block_data['time']} > {$this->global_variables['error_time']}\n"; } } // исключим тех, кто сгенерил блок с бегущими часами if ($this->block_data['time'] > time()) { return "error block time"; } // проверим ID блока if (!check_input_data($this->block_data['block_id'], 'int')) { return 'block_id'; } // проверим, верный ли ID блока if (!$first) { if ($this->block_data['block_id'] != $this->prev_block['block_id'] + 1) { return "error block_id ({$this->block_data['block_id']}!=" . ($this->prev_block['block_id'] + 1) . ")"; } } // проверим, есть ли такой майнер и заодно получим public_key // ================================== my_table заменить =============================================== $this->node_public_key = $this->db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tSELECT `node_public_key`\n\t\t\t\t\tFROM `" . DB_PREFIX . "miners_data`\n\t\t\t\t\tWHERE `user_id` = {$this->block_data['user_id']}\n\t\t\t\t\tLIMIT 1\n\t\t\t\t\t", 'fetch_one'); if (!$first) { if (!$this->node_public_key) { return 'user_id'; } } // SIGN от 128 байта до 512 байт. Подпись от TYPE, BLOCK_ID, PREV_BLOCK_HASH, TIME, USER_ID, LEVEL, MRKL_ROOT $for_sign = "0,{$this->block_data['block_id']},{$this->prev_block['hash']},{$this->block_data['time']},{$this->block_data['user_id']},{$this->block_data['level']},{$this->mrkl_root}"; debug_print("checkSign", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // проверяем подпись if (!$first) { $error = self::checkSign($this->node_public_key, $for_sign, $this->block_data['sign'], true); if ($error) { return $error; } } }
unset($testBlock); die('!$my_miner_id'); } $variables = ParseData::get_all_variables($db); $time = time(); $reduction_tx_data = ''; $promised_amount = array(); $reduction_currency_id = false; $reduction_type = ''; // ===== ручное урезание денежной массы // получаем кол-во обещанных сумм у разных юзеров по каждой валюте. start_time есть только у тех, у кого статус mining/repaid $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tSELECT `currency_id`, count(`user_id`) as `count`\n\t\tFROM (\n\t\t\t\tSELECT `currency_id`, `user_id`\n\t\t\t\tFROM `" . DB_PREFIX . "promised_amount`\n\t\t\t\tWHERE `start_time` < " . ($time - $variables['min_hold_time_promise_amount']) . " AND\n\t\t\t\t\t\t\t `del_block_id` = 0 AND\n\t\t\t\t\t\t\t `status` IN ('mining', 'repaid')\n\t\t\t\tGROUP BY `user_id`, `currency_id`\n\t\t\t\t) as t1\n\t\tGROUP BY `currency_id`\n\t\t"); while ($row = $db->fetchArray($res)) { $promised_amount[$row['currency_id']] = $row['count']; } debug_print('$promised_amount_:' . print_r_hex($promised_amount), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // берем все голоса юзеров $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT `currency_id`,\n\t\t\t\t\t\t `pct`,\n\t\t\t\t\t\t count(`currency_id`) as `votes`\n\t\t\tFROM `" . DB_PREFIX . "votes_reduction`\n\t\t\tWHERE `time` > " . ($time - $variables['reduction_period']) . "\n\t\t\tGROUP BY `currency_id`, `pct`\n\t\t\t"); while ($row = $db->fetchArray($res)) { debug_print($row, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); if (!isset($promised_amount[$row['currency_id']])) { continue; } // если голосов за урезание > 50% от числа всех держателей данной валюты if ($row['votes'] >= $promised_amount[$row['currency_id']] / 2) { // проверим, прошло ли 2 недели с последнего урезания $reduction_time = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tSELECT max(`time`)\n\t\t\t\t\tFROM `" . DB_PREFIX . "reduction`\n\t\t\t\t\tWHERE `currency_id` = {$row['currency_id']} AND\n\t\t\t\t\t\t\t\t `type` = 'manual'\n\t\t\t\t\t", 'fetch_one'); $reduction_time = intval($reduction_time); if ($time - $reduction_time > $variables['reduction_period']) { $reduction_currency_id = $row['currency_id']; $reduction_pct = $row['pct'];