$binary_tx = $aes->decrypt($encrypted_tx_set); unset($aes); debug_print('$binary_tx=' . $binary_tx, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // разберем полученные тр-ии do { $tx_size = ParseData::decode_length($binary_tx); $tx_binary_data = ParseData::string_shift($binary_tx, $tx_size); debug_print('$tx_binary_data=' . $tx_binary_data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); list(, $tx_hex) = unpack("H*", $tx_binary_data); if (!$tx_binary_data) { continue; } // проверим размер if (strlen($tx_binary_data) > $variables['max_tx_size']) { debug_print('strlen($binary_tx) > $variables[max_tx_size]', __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); die("error tx size"); } // точно ли выдали то /*if ( md5($tx_binary_data) != $new_data['tx_hash'] ) { debug_print("error tx_hash (".md5($tx_binary_data)."!={$new_data['tx_hash']})", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); die ("error tx_hash (".md5($tx_binary_data)."!={$new_data['tx_hash']})"); }*/ // временно для тестов $new_data['high_rate'] = 0; $tx_hash = md5($tx_binary_data); // заливаем тр-ию в БД $file = save_tmp_644('FTB', "{$tx_hash}\t{$new_data['high_rate']}\t{$tx_hex}"); debug_print("hash={$tx_hash}\ndata={$tx_hex}", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tLOAD DATA LOCAL INFILE '{$file}'\n\t\t\tIGNORE INTO TABLE `" . DB_PREFIX . "queue_tx`\n\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t(@hash, `high_rate`, @data)\n\t\t\tSET `hash` = UNHEX(@hash),\n\t\t\t\t `data` = UNHEX(@data)\n\t\t\t"); unlink($file); } while ($binary_tx);
$rsa = new Crypt_RSA(); $rsa->loadKey($node_private_key); $rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); //$rsa->setHash('sha256'); $for_sign = "0,{$new_block_id},{$testBlock->prev_block['hash']},{$time},{$my_user_id},{$testBlock->level},{$mrkl_root}"; debug_print('$for_sign=' . $for_sign, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $signature = $rsa->sign($for_sign); unset($rsa); list(, $signature_hex) = unpack("H*", $signature); debug_print('$signature_hex = ' . $signature_hex, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // хэш шапки блока. нужен для сравнивания с другими и у кого будет меньше - у того блок круче $header_hash = ParseData::dsha256("{$my_user_id},{$new_block_id},{$prev_head_hash}"); debug_print("header_hash={$header_hash}", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $data = "{$new_block_id}\t{$time}\t{$testBlock->level}\t{$my_user_id}\t{$header_hash}\t{$signature_hex}\t{$mrkl_root}"; debug_print($data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $file = save_tmp_644('FTB', $data); // для тестов получим что там есть $tmp_testblock_data = $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tSELECT *\n\t\t\tFROM `" . DB_PREFIX . "testblock`\n\t\t\t", 'fetch_array'); debug_print($tmp_testblock_data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print("LOAD DATA LOCAL INFILE '{$file}' REPLACE INTO TABLE `" . DB_PREFIX . "testblock`", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // т.к. эти данные создали мы сами, то пишем их сразу в таблицу проверенных данных, которые будут отправлены другим нодам $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tLOAD DATA LOCAL INFILE '{$file}' REPLACE INTO TABLE `" . DB_PREFIX . "testblock`\n\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t(`block_id`,`time`,`level`,`user_id`, @header_hash, @signature, @mrkl_root)\n\t\t\tSET `header_hash` = UNHEX(@header_hash),\n\t\t\t\t `signature` = UNHEX(@signature),\n\t\t\t\t `mrkl_root` = UNHEX(@mrkl_root)\n\t\t\t"); unlink($file); // иногда не вставлялось, т.к. уже что-то было в testblock . добавил REPLACE debug_print('AffectedRows=' . $db->getAffectedRows(), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); /// ####################################### // Отмечаем транзакции, которые попали в transactions_testblock // Пока для эксперимента // если не отмечать, то получается, что и в transactions_testblock и в transactions будут провернные тр-ии, которые откатятся дважды if ($used_transactions) { $used_transactions = substr($used_transactions, 0, -1);
$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);
Далее - тело блока (Тр-ии) */ //$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__); //testblock_unlock(); } $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\tUPDATE `" . DB_PREFIX . "testblock`\n\t\tSET `status` = 'active'\n\t\t"); //debug_print($db->printsql(), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); main_unlock(); /*
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); } }
$db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tUPDATE `" . DB_PREFIX . "testblock`\n\t\t\t\tSET `time` = {$parsedata->block_data['time']},\n\t\t\t\t\t\t`user_id` = {$parsedata->block_data['user_id']},\n\t\t\t\t\t\t`header_hash` = 0x{$new_header_hash},\n\t\t\t\t\t\t`signature` = 0x" . bin2hex($parsedata->block_data['sign']) . ",\n\t\t\t\t\t\t`mrkl_root` = 0x{$parsedata->mrkl_root}\n\t\t\t\t"); ////debug_print($db->printsql()."\nAffectedRows=".$db->getAffectedRows() , __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // и сами тр-ии пишем в отдельную таблу if ($tx) { do { debug_print('$tx=' . $tx, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print('$tx hex=' . bin2hex($tx), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $tx_size = ParseData::decode_length($tx); // отчекрыжим одну транзакцию от списка транзакций $tx_binary_data = ParseData::string_shift($tx, $tx_size); // получим тип тр-ии и юзера // $type, $user_id, $to_user_id точно валидные, т.к. прошли фронт.проверку выше list($type, $user_id, $to_user_id) = get_tx_type_and_user_id($tx_binary_data); $md5 = md5($tx_binary_data); list(, $data_hex) = unpack("H*", $tx_binary_data); $file = save_tmp_644('FTT', "{$md5}\t{$data_hex}\t{$type}\t{$user_id}\t{$to_user_id}"); $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\t\tLOAD DATA LOCAL INFILE '{$file}'\n\t\t\t\t\t\tREPLACE INTO TABLE `" . DB_PREFIX . "transactions_testblock`\n\t\t\t\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t\t\t\t(@hash, @data, `type`, `user_id`, `third_var`)\n\t\t\t\t\t\tSET `hash` = UNHEX(@hash),\n\t\t\t\t\t\t\t `data` = UNHEX(@data)\n\t\t\t\t\t\t"); unlink($file); ////debug_print($db->printsql()."\nAffectedRows=".$db->getAffectedRows() , __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); } while ($tx); } // удаляем всё, где хэш больше нашего $db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\tDELETE FROM `" . DB_PREFIX . "queue_testblock`\n\t\t\t\tWHERE `head_hash` > 0x{$new_header_hash}\n\t\t"); ////debug_print($db->printsql()."\nAffectedRows=".$db->getAffectedRows() , __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); ############################################# // возможно нужно откатить и тр-ии с verified=1 и used=0 из transactions // т.к. в transactions может быть тр-ия на удаление банкноты // и в transactions_testblock только что была залита такая же тр-ия // выходит, что блок, который будет сгенерен на основе transactions будет ошибочным // или при откате transactions будет сделан вычет из log_time_.... // и выйдет что попавшая в блок тр-я из transactions_testblock попала минуя запись log_time_....
public function insert_into_blockchain() { debug_print("block_data=" . print_r_hex($this->block_data), __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // для локальных тестов if ($this->block_data['block_id'] == 1) { $ini_array = parse_ini_file(ABSPATH . "config.ini", true); if (isset($ini_array['local']['start_block_id'])) { $this->block_data['block_id'] = $ini_array['local']['start_block_id']; } } // пишем в цепочку блоков $data = "{$this->block_data['block_id']}\t{$this->block_data['hash']}\t{$this->block_data['head_hash']}\t{$this->block_hex}"; $file = save_tmp_644('FBC', $data); debug_print("file=" . $file, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); debug_print("data=" . $data, __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); // т.к. эти данные создали мы сами, то пишем их сразу в таблицу проверенных данных, которые будут отправлены другим нодам $this->db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tLOAD DATA LOCAL INFILE '{$file}' IGNORE INTO TABLE `" . DB_PREFIX . "block_chain`\n\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t(`id`, @hash, @head_hash, @data)\n\t\t\tSET `hash` = UNHEX(@hash),\n\t\t\t\t `head_hash` = UNHEX(@head_hash),\n\t\t\t\t `data` = UNHEX(@data)\n\t\t\t"); $AffectedRows = $this->db->getAffectedRows(); if ($AffectedRows < 1) { debug_print(">>>>>>>>>>> BUG LOAD DATA LOCAL INFILE '{$file}' IGNORE INTO TABLE block_chain", __FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__); $row = $this->db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\t\t\t\t\tSELECT *\n\t\t\t\t\t\t\tFROM `" . DB_PREFIX . "block_chain`\n\t\t\t\t\t\t\tWHERE `id` = {$this->block_data['block_id']}\n\t\t\t\t\t\t\t", 'fetch_array'); print_r_hex($row); // ========================= временно для поиска бага: ==================================== $this->db->query(__FILE__, __LINE__, __FUNCTION__, __CLASS__, __METHOD__, "\n\t\t\tLOAD DATA LOCAL INFILE '{$file}' REPLACE INTO TABLE `" . DB_PREFIX . "block_chain`\n\t\t\tFIELDS TERMINATED BY '\t'\n\t\t\t(`id`, @hash, @head_hash, @data)\n\t\t\tSET `hash` = UNHEX(@hash),\n\t\t\t\t `head_hash` = UNHEX(@head_hash),\n\t\t\t\t `data` = UNHEX(@data)\n\t\t\t"); //print 'getAffectedRows='.$this->db->getAffectedRows()."\n"; // ================================================================================= } unlink($file); }