main_unlock(); exit; } debug_print($max_other_currencies_votes, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $total_count_currencies = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT count(`id`)\n\t\t\tFROM `" . DB_PREFIX . "currency`\n\t\t\t", 'fetch_one'); foreach ($max_other_currencies_votes as $currency_id => $count_and_votes) { $new_max_other_currencies[$currency_id] = get_max_vote($count_and_votes, 0, $total_count_currencies, 10); } if (get_community_users($db)) { $my_prefix = $testBlock->user_id . '_'; } else { $my_prefix = ''; } $node_private_key = get_node_private_key($db, $my_prefix); $json_data = json_encode($new_max_other_currencies); // подписываем нашим нод-ключем данные транзакции $data_for_sign = ParseData::findType('new_max_other_currencies') . ",{$time},{$my_user_id},{$json_data}"; $rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $rsa->sign($data_for_sign); debug_print('$data_for_sign=' . $data_for_sign . "\n", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // создаем тр-ию. пишем $block_id, на момент которого были актуальны голоса в табле 'pct' $data = dec_binary(ParseData::findType('new_max_other_currencies'), 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($my_user_id) . ParseData::encode_length_plus_data($json_data) . ParseData::encode_length_plus_data($signature); $hash = ParseData::dsha256($data); insert_tx($data, $db); $new_tx_data['data'] = $data; $new_tx_data['hash'] = hextobin(md5($data)); tx_parser($new_tx_data, true); } main_unlock();
} $need_tx .= hextobin($new_data['tx_hash']); } while ($binary_data); if (!$need_tx) { exit; } // получился список нужных нам тр-ий, теперь его пошлем тому ноду, у которого они есть $data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT `host`,\n\t\t\t\t\t\t `node_public_key`\n\t\t\tFROM `" . DB_PREFIX . "miners_data`\n\t\t\tWHERE `user_id` = {$new_data['user_id']}\n\t\t\t", 'fetch_array'); debug_print($data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $host = $data['host']; $node_public_key = $data['node_public_key']; debug_print($new_data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // шифруем данные. ключ $key будем использовать для расшифровки ответа $encrypted_data = encrypt_data($need_tx, $node_public_key, $db, $my_key); // user_id получателя (нужно для пулов) $encrypted_data = dec_binary($new_data['user_id'], 5) . $encrypted_data; debug_print('$encrypted_data=' . bin2hex($encrypted_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $url = "{$host}/get_tx.php"; debug_print($url, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // загружаем сами тр-ии $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, 'data=' . urlencode($encrypted_data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $encrypted_tx_set = curl_exec($ch); curl_close($ch); debug_print('$encrypted_tx_set=' . $encrypted_tx_set, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print('$my_key=' . $my_key, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__);
debug_print($max_promised_amount_votes, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $new_max_promised_amounts = array(); foreach ($max_promised_amount_votes as $currency_id => $amounts_and_votes) { //$valid_amounts_and_votes = ParseData::makeMaxPromisedAmount($amounts_and_votes); //$key = get_max_vote($valid_amounts_and_votes, 0, 1000, 100); //$new_max_promised_amounts[$currency_id] = ParseData::getPctValue($key); $new_max_promised_amounts[$currency_id] = get_max_vote($amounts_and_votes, 0, 165, 10); } if (get_community_users($db)) { $my_prefix = $testBlock->user_id . '_'; } else { $my_prefix = ''; } $node_private_key = get_node_private_key($db, $my_prefix); $json_data = json_encode($new_max_promised_amounts); // подписываем нашим нод-ключем данные транзакции $data_for_sign = ParseData::findType('new_max_promised_amounts') . ",{$time},{$my_user_id},{$json_data}"; $rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $rsa->sign($data_for_sign); debug_print('$data_for_sign=' . $data_for_sign . "\n", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // создаем тр-ию. пишем $block_id, на момент которого были актуальны голоса в табле 'pct' $data = dec_binary(ParseData::findType('new_max_promised_amounts'), 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($my_user_id) . ParseData::encode_length_plus_data($json_data) . ParseData::encode_length_plus_data($signature); $hash = ParseData::dsha256($data); insert_tx($data, $db); $new_tx_data['data'] = $data; $new_tx_data['hash'] = hextobin(md5($data)); tx_parser($new_tx_data, true); } main_unlock();
<?php /* * Получаем тр-ии, которые есть у юзера, в ответ выдаем те, что недостают и * их порядок следования, чтобы получить валидный блок */ define('DC', TRUE); define('ABSPATH', dirname(__FILE__) . '/'); set_time_limit(0); require_once ABSPATH . 'db_config.php'; require_once ABSPATH . 'includes/autoload.php'; require_once ABSPATH . 'includes/errors.php'; $db = new MySQLidb(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT); $data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT *\n\t\t\tFROM `" . DB_PREFIX . "testblock`\n\t\t\tLIMIT 1\n\t\t\t", 'fetch_array'); $response_binary_data = dec_binary($data['block_id'], 4) . dec_binary($data['time'], 4) . dec_binary($data['user_id'], 5) . encode_length(strlen($data['signature'])) . $data['signature']; // разбираем присланные данные $binary_data = $_POST['data']; $add_sql = ''; if ($binary_data) { $tr_array = array(); // получим хэши тр-ий, которые надо исключить do { list(, $tr) = unpack("H*", ParseData::string_shift($binary_data, 16)); // проверим if (!check_input_data($tr, 'md5')) { die('error md5 (' . $tr . ')'); } $add_sql .= $tr . ','; } while ($binary_data); $add_sql = substr($add_sql, 0, -1); $add_sql = "WHERE `id` NOT IN ({$add_sql})";
continue; } //print "id майнеров, которые на нашем уровне\n"; debug_print($nodes_ids, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $add_sql = ''; for ($i = 0; $i < sizeof($nodes_ids); $i++) { $add_sql .= "{$nodes_ids[$i]},"; } $add_sql = substr($add_sql, 0, strlen($add_sql) - 1); if (!$add_sql) { debug_print("continue", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); sleep(1); continue; } // получим хосты майнеров, которые на нашем уровне $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tSELECT `host`\n\t\t\t\t\tFROM `" . DB_PREFIX . "miners_data`\n\t\t\t\t\tWHERE `user_id` IN ({$add_sql})\n\t\t\t\t\t"); while ($row = $db->fetchArray($res)) { $urls[]['url'] = $row['host'] . 'gate_testblock.php'; } // шлем block_id, user_id, mrkl_root, signature $data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT `block_id`, `time`, `user_id`, `mrkl_root`, `signature`\n\t\t\tFROM `" . DB_PREFIX . "testblock`\n\t\t\tWHERE `status` = 'active'\n\t\t\t", 'fetch_array'); //print_r($data); //print_R($urls); if ($data) { $data_binary = dec_binary($data['block_id'], 4) . dec_binary($data['time'], 4) . dec_binary($data['user_id'], 5) . $data['mrkl_root'] . ParseData::encode_length_plus_data($data['signature']); m_curl($urls, $data_binary, '', 'data', 30); } //else debug_print("END", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); sleep(1); } while (true);
main_lock(); $my_user_id = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tSELECT `user_id`\n\t\t\t\t\tFROM `" . DB_PREFIX . MY_PREFIX . "my_table`\n\t\t\t\t\t", 'fetch_one'); $node_private_key = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tSELECT `private_key`\n\t\t\t\t\tFROM `" . DB_PREFIX . MY_PREFIX . "my_node_keys`\n\t\t\t\t\tWHERE `block_id` = (SELECT max(`block_id`) FROM `" . DB_PREFIX . MY_PREFIX . "my_node_keys` )\n\t\t\t\t\t", 'fetch_one'); if (!$my_user_id || !$node_private_key) { main_unlock(); exit; } require_once ABSPATH . 'phpseclib/Math/BigInteger.php'; require_once ABSPATH . 'phpseclib/Crypt/Random.php'; require_once ABSPATH . 'phpseclib/Crypt/Hash.php'; require_once ABSPATH . 'phpseclib/Crypt/RSA.php'; $rsa = new Crypt_RSA(); extract($rsa->createKey(1024)); $publickey = clear_public_key($publickey); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tINSERT INTO `" . DB_PREFIX . MY_PREFIX . "my_node_keys` (\n\t\t\t\t`public_key`,\n\t\t\t\t`private_key`\n\t\t\t)\n\t\t\tVALUES (\n\t\t\t\t0x{$publickey},\n\t\t\t\t'{$privatekey}'\n\t\t\t)"); $time = time(); // подписываем нашим нод-ключем данные транзакции $data_for_sign = ParseData::findType('change_node_key') . ",{$time},{$my_user_id},{$publickey}"; $rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $rsa->sign($data_for_sign); print '$node_private_key=' . $node_private_key . "\n"; print '$data_for_sign=' . $data_for_sign . "\n"; print 'strlen($signature)=' . strlen($signature) . "\n"; print 'strlen($publickey)=' . strlen($publickey) . "\n"; // создаем новую транзакцию $bin_public_key = hextobin($publickey); $data = dec_binary(ParseData::findType('change_node_key'), 1) . dec_binary($time, 4) . encode_length(strlen($my_user_id)) . $my_user_id . encode_length(strlen($bin_public_key)) . $bin_public_key . encode_length(strlen($signature)) . $signature; insert_tx($data, $db); main_unlock();
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']; $time_binary = dec_binary($new_testblock['time'], 4); $user_id_binary = dec_binary($new_testblock['user_id'], 5); $level_binary = dec_binary($testBlock->level, 1); $new_block_header = dec_binary(0, 1) . $new_block_id_binary . $time_binary . $user_id_binary . $level_binary . ParseData::encode_length_plus_data($new_testblock['signature']); $new_block = $new_block_header . $transactions; list(, $new_block_hex) = unpack("H*", $new_block); //testblock_lock(); // и передаем блок для обратотки через скрипт queue_parser_testblock.php // т.к. есть запросы к log_time_, а их можно выполнять только по очереди $file = save_tmp_644('FQT', "{$new_header_hash}\t{$new_block_hex}"); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\tLOAD DATA LOCAL INFILE '{$file}'\n\t\t\t\t\tREPLACE INTO TABLE `" . DB_PREFIX . "queue_testblock`\n\t\t\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t\t\t(@head_hash, @data)\n\t\t\t\t\tSET `head_hash` = UNHEX(@head_hash),\n\t\t\t\t\t\t `data` = UNHEX(@data)\n\t\t\t\t\t"); unlink($file); //debug_print($db->printsql()."\nAffectedRows=".$db->getAffectedRows() , __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); //main_unlock(); } else { //testblock_lock(); // если всё нормально, то пишем в таблу testblock новые данные $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tUPDATE `" . DB_PREFIX . "testblock`\n\t\t\tSET\n\t\t\t\t\t`time` = {$new_testblock['time']},\n\t\t\t\t\t`user_id` = {$new_testblock['user_id']},\n\t\t\t\t\t`header_hash`= 0x{$new_header_hash},\n\t\t\t\t\t`signature` = 0x{$new_testblock['signature_hex']}\n\t\t\t\t"); //debug_print($db->printsql()."\nAffectedRows=".$db->getAffectedRows() , __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__);
/** Обработка данных (блоков или транзакций), пришедших с гейта. Только проверка. */ public function ParseData_gate($only_tx = false) { $count_transactions = 0; $this->DataPre(); $this->global_variables = self::get_variables($this->db, array('max_tx_size', 'max_tx_count', 'error_time', 'max_block_user_transactions', 'max_user_transactions')); $transaction_binary_data = $this->binary_data; // если это транзакции (type>0), а не блок (type==0) if ($this->type > 0) { // проверим, есть ли такой тип тр-ий $error = $this->checkTxType($this->type); if ($error) { return $error; } debug_print('TX', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $transaction_binary_data = dec_binary($this->type, 1) . $transaction_binary_data; $transaction_binary_data_full = $transaction_binary_data; // нет ли хэша этой тр-ии у нас в БД? $error = $this->checkLogTx($transaction_binary_data_full); if ($error) { return $error; } $this->tx_hash = md5($transaction_binary_data); // преобразуем бинарные данные транзакции в массив $this->transaction_array = $this->parse_transaction($transaction_binary_data); if (!is_array($this->transaction_array)) { return $this->transaction_array; } debug_print($this->transaction_array, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // время транзакции может быть немного больше, чем время на ноде. // у нода может быть просто не настроено время. // время транзакции используется только для борьбы с атаками вчерашними транзакциями. // А т.к. мы храним хэши в log_transaction за 36 часов, то боятся нечего. $my_time = time(); if ($this->transaction_array[2] - MAX_TX_FORW > $my_time || $this->transaction_array[2] < $my_time - MAX_TX_BACK) { debug_print("tr_time={$this->transaction_array[2]}\nmy_time={$my_time}\nMAX_TX_FORW=" . MAX_TX_FORW . "\nMAX_TX_BACK=" . MAX_TX_BACK . "", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); return "error tx time ({$this->transaction_array[2]})"; } // $this->transaction_array[3] могут подсунуть пустой $user_id = @$this->transaction_array[3]; if (!check_input_data($user_id, 'bigint')) { return 'bad user_id'; } /*// от 1 юзера не может быть более X запросов за 1 минуту. Для борьбы с досами. $count = $this->db->query( __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, " SELECT `count` FROM `".DB_PREFIX."log_minute` WHERE `user_id` = {$user_id} ", 'fetch_one'); if (!$count) $this->db->query( __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, " INSERT INTO `".DB_PREFIX."log_minute` ( `user_id`, `count` ) VALUES ( {$user_id}, 1) "); else $this->db->query( __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, " UPDATE `".DB_PREFIX."log_minute` SET `count` = count+1 WHERE `user_id` = {$user_id} "); if ( $count > $this->global_variables['max_user_transactions'] ) return 'max_user_transactions'; */ } // если это блок if ($this->type == 0) { $count_transactions = array(); debug_print('BLOCK', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $rate = 1; // если есть $only_tx=true, то значит идет восстановление уже проверенного блока и заголовок не требуется if (!$only_tx) { $error = $this->ParseBlock(); if ($error) { debug_print("[error] " . $error, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); return $error; } // проверим данные, указанные в заголовке блока debug_print("CheckBlockHeader", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $error = $this->CheckBlockHeader(); if ($error) { return $error; } } else { debug_print('<$only_tx>', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); } // если в ходе проверки тр-ий возникает ошибка, то вызываем откатчик всех занесенных тр-ий. Эта переменная для него $this->full_tx_binary_data = $this->binary_data; $i = 0; $tx_for_RollbackTo = ''; if ($this->binary_data) { do { // обработка тр-ий может занять много времени, нужно отметиться upd_deamon_time($this->db); $transaction_size = $this->decode_length($this->binary_data); if (!$this->binary_data) { debug_print("transaction_size = {$transaction_size}\nthis->full_tx_binary_data = {$this->full_tx_binary_data}", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); return 'null $this->binary_data TX'; } // отчекрыжим одну транзакцию от списка транзакций $transaction_binary_data = $this->string_shift($this->binary_data, $transaction_size); $transaction_binary_data_full = $transaction_binary_data; // добавляем взятую тр-ию в набор тр-ий для RollbackTo, в котором пойдем в обратном порядке $tx_for_RollbackTo .= $this->encode_length_plus_data($transaction_binary_data); // нет ли хэша этой тр-ии у нас в БД? $error = $this->checkLogTx($transaction_binary_data); if ($error) { debug_print('[error]' . $error, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $this->RollbackTo($tx_for_RollbackTo, true, true); return $error; } $this->tx_hash = md5($transaction_binary_data); $this->transaction_array = $this->parse_transaction($transaction_binary_data); if (!is_array($this->transaction_array)) { return $this->transaction_array; } // $this->transaction_array[3] могут подсунуть пустой $user_id = @$this->transaction_array[3]; if (!check_input_data($user_id, 'bigint')) { return 'bad user_id'; } // считаем по каждому юзеру, сколько в блоке от него транзакций $count_transactions[$user_id]++; // чтобы 1 юзер не смог прислать дос-блок размером в 10гб, который заполнит своими же транзакциями if ($count_transactions[$user_id] > $this->global_variables['max_block_user_transactions']) { debug_print($count_transactions, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print($user_id, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print($this->global_variables, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $this->RollbackTo($tx_for_RollbackTo, true, true); return 'max_block_user_transactions'; } // проверим, есть ли такой тип тр-ий $error = $this->checkTxType($this->transaction_array[1]); if ($error) { return $error; } $fns_name = self::$MainArray[$this->transaction_array[1]]; //print '$fns_name='.$fns_name; $fns_name_init = $fns_name . '_init'; $fns_name_front = $fns_name . '_front'; debug_print('>>>>>>>>>>>>parsedatagate = ' . $fns_name_front, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); unset($this->tx_data); $error = $this->{$fns_name_init}(); if ($error) { return $error; } debug_print($this->tx_data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $error = $this->{$fns_name_front}(); if ($error) { debug_print('[error]=>' . $error, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); //if (substr_count($error, '[limit_requests]')>0) // $this->RollbackTo ($tx_for_RollbackTo, false, true); //else $this->RollbackTo($tx_for_RollbackTo, true, true); return $error; } // пишем хэш тр-ии в лог $this->insert_in_log_tx($transaction_binary_data_full, $this->tx_data['time']); // ===================>ради эксперимента /* $this->db->query( __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, " UPDATE `".DB_PREFIX."transactions` SET `verified` = 1 WHERE `hash` = 0x".md5($transaction_binary_data_full)." "); */ // ==================================== $i++; } while ($this->binary_data); } } else { debug_print('memory', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // / $rate = 10; // Оперативные транзакции $fns_name = self::$MainArray[$this->type]; $fns_name_init = $fns_name . '_init'; $fns_name_front = $fns_name . '_front'; unset($this->tx_data); $error = $this->{$fns_name_init}(); if ($error) { return $error; } debug_print($this->tx_data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $error = $this->{$fns_name_front}(); if ($error) { return $error; } $this->insert_in_log_tx($transaction_binary_data_full, $this->tx_data['time']); } }
// проверим блок, который получился с данными, которые прислал другой нод $parsedata = new ParseData($new_block, $db); $error = $parsedata->ParseData_gate(); debug_print("ParseData_gate OK", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); if ($error) { unset($parsedata); debug_print('------------------[error]' . $error . '-------------------', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // т.к. мы откатили наши тр-ии из transactions_testblock, то теперь нужно обработать их по новой // получим наши транзакции в 1 бинарнике, просто для удобства $my_testblock['block_body'] = ''; $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tSELECT `data`\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)) { $my_testblock['block_body'] .= ParseData::encode_length_plus_data($row['data']); } if ($my_testblock['block_body']) { $parsedata = new ParseData(dec_binary(0, 1) . $my_testblock['block_body'], $db); $parsedata->ParseData_gate(true); unset($parsedata); } /*if (substr_count($error, '[limit_requests]')>0) { debug_print('----------------[error]'.$error.'-------------------', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // если есть ошибки, то откатим фронтальные измненения от этого блока $parsedata = new ParseData($tx, $db); $parsedata->ParseDataRollbackFront(); } else { debug_print('error wo rollback----------------[error]'.$error.'-------------------', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); }*/ } else { //main_unlock(); // т.к. testblock_generator.php пишет в таблы testblock и transactions_testblock нужно локать эти таблы
function m_curl($urls, $_data, $db, $type = 'data', $timeout = 10, $answer = false, $post = true, $remote_node_host = '') { //создаем набор дескрипторов cURL $mh = curl_multi_init(); // при $remote_node_host будет всего 1 url - ip из локальной сети for ($i = 0; $i < sizeof($urls); $i++) { debug_print('$urls[' . $i . ']: ' . print_r_hex($urls[$i]), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); if ($db) { // т.к. на приеме может быть пул, то нужно дописать user_id, чьим нодовским ключем шифруем $data = encrypt_data($_data, $urls[$i]['node_public_key'], $db); $data = dec_binary($urls[$i]['user_id'], 5) . $data; } else { $data = $_data; } if ($remote_node_host) { $data = ParseData::encode_length_plus_data($remote_node_host) . $data; } // создаем ресурс cURL $ch[$i] = curl_init(); curl_setopt($ch[$i], CURLOPT_URL, $urls[$i]['url']); //curl_setopt($ch[$i], CURLOPT_FAILONERROR, 1); curl_setopt($ch[$i], CURLOPT_CONNECTTIMEOUT, 10); // timeout in seconds curl_setopt($ch[$i], CURLOPT_TIMEOUT, $timeout); if ($post) { curl_setopt($ch[$i], CURLOPT_POST, 1); curl_setopt($ch[$i], CURLOPT_POSTFIELDS, $type . '=' . urlencode($data)); } if ($answer) { curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, 1); } //$params[] = 'data='.urlencode($data); //curl_setopt($ch[$i], CURLOPT_POSTFIELDS, $params); //добавляем X дескрипторов curl_multi_add_handle($mh, $ch[$i]); } $active = null; //запускаем дескрипторы do { debug_print('curl_multi_exec', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); while ($active && $mrc == CURLM_OK) { if (curl_multi_select($mh) == -1) { usleep(100); } do { $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM); } $return = array(); if ($answer) { for ($i = 0; $i < sizeof($urls); $i++) { $return[$urls[$i]['user_id']] = curl_multi_getcontent($ch[$i]); } } for ($i = 0; $i < sizeof($urls); $i++) { // закрываем все дескрипторы curl_multi_remove_handle($mh, $ch[$i]); } curl_multi_close($mh); return $return; }
upd_deamon_time($db); // пишем свежие блоки в резервный блокчейн $end_block_id = get_end_block_id(); $cur_block_id = get_block_id($db); print $end_block_id . ' / ' . $cur_block_id; if ($cur_block_id - 30 > $end_block_id) { $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, ' SELECT `id`, `data` FROM `' . DB_PREFIX . 'block_chain` WHERE `id` > ' . $end_block_id . ' AND `id` <= ' . ($cur_block_id - 30) . ' ORDER BY `id` '); while ($row = $db->fetchArray($res)) { $data = dec_binary($row['id'], 5) . ParseData::encode_length_plus_data($row['data']); $size_and_data = dec_binary(strlen($data), 5) . $data; file_put_contents(ABSPATH . 'public/blockchain', $size_and_data . dec_binary(strlen($size_and_data), 5), FILE_APPEND | LOCK_EX); } } $auto_reload = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tSELECT `auto_reload`\n\t\tFROM `" . DB_PREFIX . "config`\n\t\t", 'fetch_one'); if ($auto_reload < 60) { exit; } // если main_lock висит более x минут, значит был какой-то сбой $main_lock = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tSELECT `lock_time`\n\t\tFROM `" . DB_PREFIX . "main_lock`\n\t\tWHERE `script_name` NOT IN ('my_lock', 'cleaning_db')\n\t\t", 'fetch_one'); if ($main_lock && time() - $auto_reload > $main_lock) { // на всякий случай пометим, что работаем $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tUPDATE `" . DB_PREFIX . "main_lock`\n\t\t\tSET `script_name` = 'cleaning_db'\n\t\t\t"); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tUPDATE `" . DB_PREFIX . "config`\n\t\t\tSET `pool_tech_works` = 1\n\t\t\t"); $tables_array = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSHOW TABLES\n\t\t\t", 'array'); foreach ($tables_array as $table) { //if (!in_array($table, $exceptions))
debug_print('VOTE = NO', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); } // проходимся по всем нашим майнерам, если это пул и по одному, если это сингл-мод foreach ($intersect_my_miners as $my_miner_id) { $my_user_id = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\t\tSELECT `user_id`\n\t\t\t\t\t\tFROM `" . DB_PREFIX . "miners_data`\n\t\t\t\t\t\tWHERE `miner_id` = {$my_miner_id}\n\t\t\t\t\t\t", 'fetch_one'); $community = get_community_users($db); if ($community) { $my_prefix = $my_user_id . '_'; } else { $my_prefix = ''; } $node_private_key = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\t\tSELECT `private_key`\n\t\t\t\t\t\tFROM `" . DB_PREFIX . "{$my_prefix}my_node_keys`\n\t\t\t\t\t\tWHERE `block_id` = (SELECT max(`block_id`) FROM `" . DB_PREFIX . "{$my_prefix}my_node_keys` )\n\t\t\t\t\t\t", 'fetch_one'); $time = time(); // подписываем нашим нод-ключем данные транзакции $data_for_sign = ParseData::findType('votes_node_new_miner') . ",{$time},{$my_user_id},{$row['vote_id']},{$vote}"; $rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $rsa->sign($data_for_sign); debug_print('$data_for_sign=' . $data_for_sign, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // создаем новую транзакцию - подверждение, что фото скопировано и проверено. $data = dec_binary(30, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($my_user_id) . ParseData::encode_length_plus_data($row['vote_id']) . ParseData::encode_length_plus_data($vote) . ParseData::encode_length_plus_data($signature); insert_tx($data, $db); } } // отмечаем, чтобы больше не брать эту строку $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tUPDATE `" . DB_PREFIX . "votes_miners`\n\t\t\t\tSET `cron_checked_time` = " . time() . "\n\t\t\t\tWHERE `id` = {$row['vote_id']}\n\t\t\t\t"); } main_unlock(); sleep(1); } while (true);
} if (!$new_admin) { main_unlock(); exit; } $testBlock = new testblock($db, true); if (get_community_users($db)) { $my_prefix = $testBlock->user_id . '_'; } else { $my_prefix = ''; } $node_private_key = get_node_private_key($db, $my_prefix); // подписываем нашим нод-ключем данные транзакции $data_for_sign = ParseData::findType('new_admin') . ",{$time},{$my_user_id},{$new_admin}"; $rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $rsa->sign($data_for_sign); debug_print('$data_for_sign=' . $data_for_sign . "\n", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // создаем тр-ию. пишем $block_id, на момент которого были актуальны голоса в табле 'pct' $data = dec_binary(ParseData::findType('new_admin'), 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($my_user_id) . ParseData::encode_length_plus_data($new_admin) . ParseData::encode_length_plus_data($signature); $hash = ParseData::dsha256($data); insert_tx($data, $db); // и не закрывая main_lock переводим нашу тр-ию в verified=1, откатив все несовместимые тр-ии // таким образом у нас будут в блоке только актуальные голоса. // а если придет другой блок и станет verified=0, то эта тр-ия просто удалится. $new_tx_data['data'] = $data; $new_tx_data['hash'] = hextobin(md5($data)); tx_parser($new_tx_data, true); } main_unlock();
// 5 байт = наш user_id. Но они будут не первые, т.к. m_curl допишет вперед user_id получателя (нужно для пулов) $to_be_sent = dec_binary($my_user_id, 5); if ($data) { // блок // если 5-й байт = 0, то на приемнике будем читать блок, если = 1 , то сразу хэши тр-ий $to_be_sent .= dec_binary(0, 1) . dec_binary($data['block_id'], 3) . $data['hash'] . $data['head_hash']; $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "UPDATE `" . DB_PREFIX . "info_block` SET `sent` = 1"); } else { // тр-ии без блока $to_be_sent .= dec_binary(1, 1); } // возьмем хэши тр-ий $res = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tSELECT `hash`, `high_rate`\n\t\t\t\tFROM `" . DB_PREFIX . "transactions`\n\t\t\t\tWHERE `sent` = 0 AND\n\t\t\t\t\t\t\t`for_self_use` = 0\n\t\t\t\t"); while ($row = $db->fetchArray($res)) { list(, $hex_hash) = unpack("H*", $row['hash']); $to_be_sent .= dec_binary($row['high_rate'], 1) . $row['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"); } //main_unlock(); debug_print('$to_be_sent=' . $to_be_sent, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // отправляем блок и хэши тр-ий, если есть что отправлять if (strlen($to_be_sent) > 10) { 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
$for_user_id = $_REQUEST['for_user_id']; $new_public_key = hextobin($_REQUEST['new_public_key']); $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($for_user_id) . ParseData::encode_length_plus_data($new_public_key) . $bin_signatures; break; case 'change_arbitrator_list': $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($_REQUEST['arbitration_trust_list']) . $bin_signatures; break; case 'money_back_request': $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($_REQUEST['order_id']) . ParseData::encode_length_plus_data(hextobin($_REQUEST['arbitrator_enc_text'][0])) . ParseData::encode_length_plus_data(hextobin($_REQUEST['arbitrator_enc_text'][1])) . ParseData::encode_length_plus_data(hextobin($_REQUEST['arbitrator_enc_text'][2])) . ParseData::encode_length_plus_data(hextobin($_REQUEST['arbitrator_enc_text'][3])) . ParseData::encode_length_plus_data(hextobin($_REQUEST['arbitrator_enc_text'][4])) . ParseData::encode_length_plus_data(hextobin($_REQUEST['seller_enc_text'])) . $bin_signatures; break; case 'change_seller_hold_back': $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($_REQUEST['arbitration_days_refund']) . ParseData::encode_length_plus_data($_REQUEST['hold_back_pct']) . $bin_signatures; break; case 'money_back': $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($_REQUEST['order_id']) . ParseData::encode_length_plus_data($_REQUEST['amount']) . $bin_signatures; break; case 'change_arbitrator_conditions': $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($_REQUEST['conditions']) . ParseData::encode_length_plus_data($_REQUEST['url']) . $bin_signatures; break; case 'change_money_back_time': $data = dec_binary($type, 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($user_id) . ParseData::encode_length_plus_data($_REQUEST['order_id']) . ParseData::encode_length_plus_data($_REQUEST['days']) . $bin_signatures; break; } $hash = md5($data); if (!in_array($_REQUEST['type'], array('new_pct', 'new_max_promised_amounts', 'new_reduction', 'votes_node_new_miner', 'new_max_other_currencies'))) { $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tINSERT INTO `" . DB_PREFIX . "transactions_status` (\n\t\t\t\t`hash`,\n\t\t\t\t`time`,\n\t\t\t\t`type`,\n\t\t\t\t`user_id`\n\t\t\t)\n\t\t\tVALUES (\n\t\t\t\t0x{$hash},\n\t\t\t\t" . time() . ",\n\t\t\t\t{$type},\n\t\t\t\t{$user_id}\n\t\t\t)"); } $data = bin2hex($data); $file = save_tmp_644('FSQ', "{$hash}\t{$data}"); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tLOAD DATA LOCAL INFILE '{$file}' IGNORE INTO TABLE `" . DB_PREFIX . "queue_tx`\n\t\tFIELDS TERMINATED BY '\t'\n\t\t(@hash, @data)\n\t\tSET `data` = UNHEX(@data),\n\t\t\t `hash` = UNHEX(@hash)\n\t\t"); unlink($file);
continue; } debug_print('Закончили спать, теперь генерим блок', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $block_id = $testBlock->prev_block['block_id']; if (!$block_id) { debug_print("continue", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); main_unlock(); unset($testBlock); sleep(1); continue; } $my_user_id = $testBlock->user_id; $new_block_id = $block_id + 1; $new_block_id_binary = dec_binary($new_block_id, 4); $user_id_binary = dec_binary($testBlock->cur_user_id, 5); $level_binary = dec_binary($testBlock->level, 1); if (get_community_users($db)) { $my_prefix = $testBlock->user_id . '_'; } else { $my_prefix = ''; } $node_private_key = get_node_private_key($db, $my_prefix); $prev_head_hash = $testBlock->prev_block['head_hash']; ##################################### ## Формируем блок ##################################### print '$new_block_id=' . $new_block_id . "\n"; print '$cur_user_id=' . $testBlock->cur_user_id . "\n"; if (!$testBlock->cur_user_id) { debug_print("continue", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); main_unlock();
//print $reduction_pct."\n"; //print $reduction_type."\n"; //print $reduction_currency_id."\n"; if (isset($reduction_currency_id) && isset($reduction_pct)) { if (get_community_users($db)) { $my_prefix = $testBlock->user_id . '_'; } else { $my_prefix = ''; } $node_private_key = get_node_private_key($db, $my_prefix); print $my_prefix . "\n"; // подписываем нашим нод-ключем данные транзакции $data_for_sign = ParseData::findType('new_reduction') . ",{$time},{$my_user_id},{$reduction_currency_id},{$reduction_pct},{$reduction_type}"; $rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); $signature = $rsa->sign($data_for_sign); debug_print('$data_for_sign=' . $data_for_sign . "\n", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); print $data_for_sign; print $node_private_key; // создаем тр-ию. пишем $block_id, на момент которого были актуальны голоса и статусы банкнот $reduction_tx_data = dec_binary(ParseData::findType('new_reduction'), 1) . dec_binary($time, 4) . ParseData::encode_length_plus_data($my_user_id) . ParseData::encode_length_plus_data($reduction_currency_id) . ParseData::encode_length_plus_data($reduction_pct) . ParseData::encode_length_plus_data($reduction_type) . ParseData::encode_length_plus_data($signature); insert_tx($reduction_tx_data, $db); // и не закрывая main_lock переводим нашу тр-ию в verified=1, откатив все несовместимые тр-ии // таким образом у нас будут в блоке только актуальные голоса. // а если придет другой блок и станет verified=0, то эта тр-ия просто удалится. $new_tx_data['data'] = $reduction_tx_data; $new_tx_data['hash'] = hextobin(md5($reduction_tx_data)); tx_parser($new_tx_data, true); } main_unlock();