PageRenderTime 48ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/v1.9/queueclerk.php

https://bitbucket.org/rev22/timekoin
PHP | 541 lines | 374 code | 82 blank | 85 comment | 107 complexity | 5799761b30393a713caafbdda9823a7e MD5 | raw file
  1. <?PHP
  2. include 'configuration.php';
  3. include 'function.php';
  4. set_time_limit(90);
  5. //***********************************************************************************
  6. //***********************************************************************************
  7. if(QUEUECLERK_DISABLED == TRUE || TIMEKOIN_DISABLED == TRUE)
  8. {
  9. // This has been disabled
  10. exit;
  11. }
  12. //***********************************************************************************
  13. //***********************************************************************************
  14. // Open persistent connection to database
  15. mysql_connect(MYSQL_IP,MYSQL_USERNAME,MYSQL_PASSWORD);
  16. mysql_select_db(MYSQL_DATABASE);
  17. // Check for banned IP address
  18. $ip = mysql_result(mysql_query("SELECT * FROM `ip_banlist` WHERE `ip` = '" . $_SERVER['REMOTE_ADDR'] . "' LIMIT 1"),0,0);
  19. if(empty($ip) == FALSE)
  20. {
  21. // Sorry, your IP address has been banned :(
  22. exit;
  23. }
  24. //***********************************************************************************
  25. // Answer transaction hash poll
  26. if($_GET["action"] == "trans_hash")
  27. {
  28. $transaction_queue_hash = mysql_result(mysql_query("SELECT * FROM `options` WHERE `field_name` = 'transaction_queue_hash' LIMIT 1"),0,"field_data");
  29. echo $transaction_queue_hash;
  30. // Log inbound IP activity
  31. mysql_query("INSERT INTO `ip_activity` (`timestamp` ,`ip`, `attribute`)VALUES ('" . time() . "', '" . $_SERVER['REMOTE_ADDR'] . "', 'QU')");
  32. exit;
  33. }
  34. //***********************************************************************************
  35. //***********************************************************************************
  36. // Answer transaction queue poll
  37. if($_GET["action"] == "queue")
  38. {
  39. $sql = "SELECT * FROM `transaction_queue` ORDER BY RAND() LIMIT 100";
  40. $sql_result = mysql_query($sql);
  41. $sql_num_results = mysql_num_rows($sql_result);
  42. $queue_number = 1;
  43. if($sql_num_results > 0)
  44. {
  45. for ($i = 0; $i < $sql_num_results; $i++)
  46. {
  47. $sql_row = mysql_fetch_array($sql_result);
  48. echo "---queue$queue_number=" , $sql_row["hash"] , "---end$queue_number";
  49. $queue_number++;
  50. }
  51. }
  52. // Log inbound IP activity
  53. mysql_query("INSERT INTO `ip_activity` (`timestamp` ,`ip`, `attribute`)VALUES ('" . time() . "', '" . $_SERVER['REMOTE_ADDR'] . "', 'QU')");
  54. exit;
  55. }
  56. //***********************************************************************************
  57. //***********************************************************************************
  58. // Answer public key balance request that match our hash code
  59. if($_GET["action"] == "key_balance")
  60. {
  61. $hash_code = substr($_GET["hash"], 0, 256);
  62. $server_hash_code = mysql_result(mysql_query("SELECT * FROM `options` WHERE `field_name` = 'server_hash_code' LIMIT 1"),0,"field_data");
  63. if($hash_code == $server_hash_code && $server_hash_code != "0")
  64. {
  65. // Grab balance for public key and return back
  66. $public_key = substr($_POST["public_key"], 0, 500);
  67. $public_key = filter_sql($public_key);
  68. $public_key = base64_decode($public_key);
  69. echo check_crypt_balance($public_key);
  70. }
  71. // Log inbound IP activity
  72. mysql_query("INSERT INTO `ip_activity` (`timestamp` ,`ip`, `attribute`)VALUES ('" . time() . "', '" . $_SERVER['REMOTE_ADDR'] . "', 'QU')");
  73. exit;
  74. }
  75. //***********************************************************************************
  76. //***********************************************************************************
  77. // Answer transaction details that match our hash number
  78. if($_GET["action"] == "transaction" && empty($_GET["number"]) == FALSE)
  79. {
  80. $current_hash = filter_sql($_GET["number"]);
  81. $sql = "SELECT * FROM `transaction_queue` WHERE `hash` = '$current_hash' LIMIT 1";
  82. $sql_result = mysql_query($sql);
  83. $sql_num_results = mysql_num_rows($sql_result);
  84. if($sql_num_results > 0)
  85. {
  86. $sql_row = mysql_fetch_array($sql_result);
  87. $qhash = $sql_row["timestamp"] . base64_encode($sql_row["public_key"]) . $sql_row["crypt_data1"] . $sql_row["crypt_data2"] . $sql_row["crypt_data3"] . $sql_row["hash"] . $sql_row["attribute"];
  88. $qhash = hash('md5', $qhash);
  89. echo "-----timestamp=" , $sql_row["timestamp"] , "-----public_key=" , base64_encode($sql_row["public_key"]) , "-----crypt1=" , $sql_row["crypt_data1"];
  90. echo "-----crypt2=" , $sql_row["crypt_data2"] , "-----crypt3=" , $sql_row["crypt_data3"] , "-----hash=" , $sql_row["hash"];
  91. echo "-----attribute=" , $sql_row["attribute"] , "-----end---qhash=$qhash---endqhash";
  92. }
  93. // Log inbound IP activity
  94. mysql_query("INSERT INTO `ip_activity` (`timestamp` ,`ip`, `attribute`)VALUES ('" . time() . "', '" . $_SERVER['REMOTE_ADDR'] . "', 'QU')");
  95. exit;
  96. }
  97. //***********************************************************************************
  98. //***********************************************************************************
  99. // Accept a transaction from a firewalled peer (behind a firewall with no inbound communication port open)
  100. if($_GET["action"] == "input_transaction")
  101. {
  102. $next_generation_cycle = transaction_cycle(1);
  103. $current_generation_cycle = transaction_cycle(0);
  104. // Can we work on the transactions in the database?
  105. // Not allowed 120 seconds before and 30 seconds after generation cycle.
  106. if(($next_generation_cycle - time()) > 120 && (time() - $current_generation_cycle) > 30)
  107. {
  108. $transaction_timestamp = intval($_POST["timestamp"]);
  109. $transaction_public_key = filter_sql($_POST["public_key"]);
  110. $transaction_crypt1 = filter_sql($_POST["crypt_data1"]);
  111. $transaction_crypt2 = filter_sql($_POST["crypt_data2"]);
  112. $transaction_crypt3 = filter_sql($_POST["crypt_data3"]);
  113. $transaction_hash = filter_sql($_POST["hash"]);
  114. $transaction_attribute = filter_sql($_POST["attribute"]);
  115. $transaction_qhash = filter_sql($_POST["qhash"]);
  116. // If a qhash is included, use this to verify the data
  117. if(empty($transaction_qhash) == FALSE)
  118. {
  119. $qhash = $transaction_timestamp . $transaction_public_key . $transaction_crypt1 . $transaction_crypt2 . $transaction_crypt3 . $transaction_hash . $transaction_attribute;
  120. $qhash = hash('md5', $qhash);
  121. // Compare hashes to make sure data is intact
  122. if($transaction_qhash != $qhash)
  123. {
  124. write_log("Queue Hash Data MisMatch from IP: " . $_SERVER['REMOTE_ADDR'] . " for Public Key: " . base64_encode($transaction_public_key), "QC");
  125. $hash_match = "mismatch";
  126. }
  127. else
  128. {
  129. $hash_match = mysql_result(mysql_query("SELECT * FROM `transaction_queue` WHERE `hash` = '$transaction_hash' LIMIT 1"),0,0);
  130. }
  131. }
  132. else
  133. {
  134. // A qhash is required to verify the transaction now
  135. write_log("Queue Hash Data MisMatch from IP: " . $_SERVER['REMOTE_ADDR'] . " for Public Key: " . base64_encode($transaction_public_key), "QC");
  136. $hash_match = "mismatch";
  137. }
  138. $transaction_public_key = base64_decode($transaction_public_key);
  139. if(empty($hash_match) == TRUE)
  140. {
  141. // No duplicate found, continue processing
  142. if($transaction_attribute == "R")
  143. {
  144. // Check to make sure this public key isn't forged or made up to win the list
  145. openssl_public_decrypt(base64_decode($transaction_crypt1), $inside_transaction_hash, $transaction_public_key);
  146. $final_hash_compare = $transaction_crypt2;
  147. $crypt_hash_check = $transaction_hash;
  148. }
  149. else
  150. {
  151. // Check to make sure attribute is valid
  152. if($transaction_attribute == "G" || $transaction_attribute == "T")
  153. {
  154. // Decrypt transaction information for regular transaction data
  155. // and check to make sure the public key that is being sent to
  156. // has not been tampered with.
  157. openssl_public_decrypt(base64_decode($transaction_crypt3), $transaction_info, $transaction_public_key);
  158. $inside_transaction_hash = find_string("HASH=", "", $transaction_info, TRUE);
  159. // Check if a message is encoded in this data as well
  160. if(strlen($inside_transaction_hash) != 64)
  161. {
  162. // A message is also encoded
  163. $inside_transaction_hash = find_string("HASH=", "---MSG", $transaction_info);
  164. }
  165. // Check Hash against 3 crypt fields
  166. $crypt_hash_check = hash('sha256', $transaction_crypt1 . $transaction_crypt2 . $transaction_crypt3);
  167. }
  168. $final_hash_compare = hash('sha256', $transaction_crypt1 . $transaction_crypt2);
  169. }
  170. // Check to make sure this transaction is even valid
  171. if($transaction_hash == $crypt_hash_check
  172. && $inside_transaction_hash == $final_hash_compare
  173. && strlen($transaction_public_key) > 300
  174. && $transaction_timestamp >= $current_generation_cycle
  175. && $transaction_timestamp < $next_generation_cycle)
  176. {
  177. // Check for 100 public key limit in the transaction queue
  178. $sql = "SELECT * FROM `transaction_queue` WHERE `public_key` = '$transaction_public_key'";
  179. $sql_result = mysql_query($sql);
  180. $sql_num_results = mysql_num_rows($sql_result);
  181. if($sql_num_results < 100)
  182. {
  183. // Transaction hash and real hash match
  184. $sql = "INSERT INTO `transaction_queue` (`timestamp`,`public_key`,`crypt_data1`,`crypt_data2`,`crypt_data3`, `hash`, `attribute`)
  185. VALUES ('$transaction_timestamp', '$transaction_public_key', '$transaction_crypt1', '$transaction_crypt2' , '$transaction_crypt3', '$transaction_hash' , '$transaction_attribute')";
  186. if(mysql_query($sql) == TRUE)
  187. {
  188. // Give confirmation of transaction insert accept
  189. echo "OK";
  190. write_log("Accepted Inbound Transaction from IP: " . $_SERVER['REMOTE_ADDR'], "QC");
  191. }
  192. }
  193. else
  194. {
  195. write_log("More Than 100 Transactions Trying to Queue from IP: " . $_SERVER['REMOTE_ADDR'] . " for Public Key: " . base64_encode($transaction_public_key), "QC");
  196. }
  197. }
  198. else
  199. {
  200. write_log("Invalid Transactin Queue Data Discarded from IP: " . $_SERVER['REMOTE_ADDR'] . " for Public Key: " . base64_encode($transaction_public_key), "QC");
  201. }
  202. } // End Duplicate & Timestamp check
  203. } // End time allowed check
  204. // Log inbound IP activity
  205. mysql_query("INSERT INTO `ip_activity` (`timestamp` ,`ip`, `attribute`)VALUES ('" . time() . "', '" . $_SERVER['REMOTE_ADDR'] . "', 'QU')");
  206. exit;
  207. }
  208. //***********************************************************************************
  209. //***********************************************************************************
  210. $loop_active = mysql_result(mysql_query("SELECT * FROM `main_loop_status` WHERE `field_name` = 'queueclerk_heartbeat_active' LIMIT 1"),0,"field_data");
  211. // Check if loop is already running
  212. if($loop_active == 0)
  213. {
  214. // Set the working status of 1
  215. $sql = "UPDATE `main_loop_status` SET `field_data` = '1' WHERE `main_loop_status`.`field_name` = 'queueclerk_heartbeat_active' LIMIT 1";
  216. mysql_query($sql);
  217. }
  218. else if($loop_active == 1)
  219. {
  220. // Allow another instance to start
  221. // Set the working status of 2
  222. $sql = "UPDATE `main_loop_status` SET `field_data` = '2' WHERE `main_loop_status`.`field_name` = 'queueclerk_heartbeat_active' LIMIT 1";
  223. mysql_query($sql);
  224. }
  225. else
  226. {
  227. // Loop called while still working
  228. exit;
  229. }
  230. //***********************************************************************************
  231. //***********************************************************************************
  232. $next_generation_cycle = transaction_cycle(1);
  233. $current_generation_cycle = transaction_cycle(0);
  234. // Can we work on the transactions in the database?
  235. // Not allowed 30 seconds before and 30 seconds after generation cycle.
  236. if(($next_generation_cycle - time()) > 30 && (time() - $current_generation_cycle) > 30)
  237. {
  238. // Create a hash of my own transaction queue
  239. $sql = "SELECT * FROM `transaction_queue` ORDER BY `hash`";
  240. $sql_result = mysql_query($sql);
  241. $sql_num_results = mysql_num_rows($sql_result);
  242. $transaction_queue_hash = 0;
  243. if($sql_num_results > 0)
  244. {
  245. for ($i = 0; $i < $sql_num_results; $i++)
  246. {
  247. $sql_row = mysql_fetch_array($sql_result);
  248. $transaction_queue_hash .= $sql_row["public_key"] . $sql_row["crypt_data1"] .
  249. $sql_row["crypt_data2"] . $sql_row["crypt_data3"] . $sql_row["hash"] . $sql_row["attribute"];
  250. }
  251. $transaction_queue_hash = hash('md5', $transaction_queue_hash);
  252. }
  253. // Store in database for quick reference from database
  254. $sql = "UPDATE `options` SET `field_data` = '$transaction_queue_hash' WHERE `options`.`field_name` = 'transaction_queue_hash' LIMIT 1";
  255. mysql_query($sql);
  256. // How does my transaction queue compare to others?
  257. // Ask all of my active peers
  258. ini_set('user_agent', 'Timekoin Server (Queueclerk) v' . TIMEKOIN_VERSION);
  259. ini_set('default_socket_timeout', 3); // Timeout for request in seconds
  260. $context = stream_context_create(array('http' => array('header'=>'Connection: close'))); // Force close socket after complete
  261. $sql = "SELECT * FROM `active_peer_list` ORDER BY RAND()";
  262. $sql_result = mysql_query($sql);
  263. $sql_num_results = mysql_num_rows($sql_result);
  264. $transaction_queue_hash_match = 0;
  265. $transaction_queue_hash_different = 0;
  266. $site_address;
  267. if($sql_num_results > 0)
  268. {
  269. $hash_different = array();
  270. for ($i = 0; $i < $sql_num_results; $i++)
  271. {
  272. $sql_row = mysql_fetch_array($sql_result);
  273. $ip_address = $sql_row["IP_Address"];
  274. $domain = $sql_row["domain"];
  275. $subfolder = $sql_row["subfolder"];
  276. $port_number = $sql_row["port_number"];
  277. if(empty($domain) == TRUE)
  278. {
  279. $site_address = $ip_address;
  280. }
  281. else
  282. {
  283. $site_address = $domain;
  284. }
  285. if($port_number == 443)
  286. {
  287. $ssl = "s";
  288. }
  289. else
  290. {
  291. $ssl = NULL;
  292. }
  293. $poll_peer = filter_sql(file_get_contents("http$ssl://$site_address:$port_number/$subfolder/queueclerk.php?action=trans_hash", FALSE, $context, NULL, 40));
  294. if($transaction_queue_hash === $poll_peer)
  295. {
  296. $transaction_queue_hash_match++;
  297. }
  298. else
  299. {
  300. if(empty($poll_peer) == FALSE)
  301. {
  302. $transaction_queue_hash_different++;
  303. $hash_different["ip_address$transaction_queue_hash_different"] = $ip_address;
  304. $hash_different["domain$transaction_queue_hash_different"] = $domain;
  305. $hash_different["subfolder$transaction_queue_hash_different"] = $subfolder;
  306. $hash_different["port_number$transaction_queue_hash_different"] = $port_number;
  307. }
  308. }
  309. } // End for Loop
  310. } // End number of results check
  311. // Compare tallies
  312. if($transaction_queue_hash_different > 0)
  313. {
  314. // Transaction Queue still not in sync with all peers
  315. $hash_array = array();
  316. for ($i = 1; $i < $transaction_queue_hash_different + 1; $i++)
  317. {
  318. $ip_address = $hash_different["ip_address$i"];
  319. $domain = $hash_different["domain$i"];
  320. $subfolder = $hash_different["subfolder$i"];
  321. $port_number = $hash_different["port_number$i"];
  322. if(empty($domain) == TRUE)
  323. {
  324. $site_address = $ip_address;
  325. }
  326. else
  327. {
  328. $site_address = $domain;
  329. }
  330. if($port_number == 443)
  331. {
  332. $ssl = "s";
  333. }
  334. else
  335. {
  336. $ssl = NULL;
  337. }
  338. $poll_peer = filter_sql(file_get_contents("http$ssl://$site_address:$port_number/$subfolder/queueclerk.php?action=queue", FALSE, $context, NULL, 8200));
  339. // Bring up first match (if any) to compare agaist our database
  340. $match_number = 1;
  341. $current_hash = find_string("---queue$match_number=", "---end$match_number", $poll_peer);
  342. while(empty($current_hash) == FALSE)
  343. {
  344. //Check if this transaction is already in our queue
  345. $hash_match = mysql_result(mysql_query("SELECT * FROM `transaction_queue` WHERE `hash` = '$current_hash' LIMIT 1"),0,0);
  346. if(empty($hash_match) == TRUE)
  347. {
  348. // This peer has a different transaction, ask for the full details of it
  349. $poll_hash = filter_sql(file_get_contents("http$ssl://$site_address:$port_number/$subfolder/queueclerk.php?action=transaction&number=$current_hash", FALSE, $context, NULL, 1500));
  350. $transaction_timestamp = find_string("-----timestamp=", "-----public_key", $poll_hash);
  351. $transaction_public_key = find_string("-----public_key=", "-----crypt1", $poll_hash);
  352. $transaction_crypt1 = find_string("-----crypt1=", "-----crypt2", $poll_hash);
  353. $transaction_crypt2 = find_string("-----crypt2=", "-----crypt3", $poll_hash);
  354. $transaction_crypt3 = find_string("-----crypt3=", "-----hash", $poll_hash);
  355. $transaction_hash = find_string("-----hash=", "-----attribute", $poll_hash);
  356. $transaction_attribute = find_string("-----attribute=", "-----end", $poll_hash);
  357. $transaction_qhash = find_string("---qhash=", "---endqhash", $poll_hash);
  358. // If a qhash is included, use this to verify the data
  359. if(empty($transaction_qhash) == FALSE)
  360. {
  361. $qhash = $transaction_timestamp . $transaction_public_key . $transaction_crypt1 . $transaction_crypt2 . $transaction_crypt3 . $transaction_hash . $transaction_attribute;
  362. $qhash = hash('md5', $qhash);
  363. // Compare hashes to make sure data is intact
  364. if($transaction_qhash != $qhash)
  365. {
  366. write_log("Queue Hash Data MisMatch for Public Key: " . $transaction_public_key, "QC");
  367. $transaction_attribute = "mismatch";
  368. }
  369. }
  370. else
  371. {
  372. // Qhash is required to match hash now
  373. write_log("Queue Hash Data MisMatch for Public Key: " . $transaction_public_key, "QC");
  374. $transaction_attribute = "mismatch";
  375. }
  376. $transaction_public_key = base64_decode($transaction_public_key);
  377. if($transaction_attribute == "R")
  378. {
  379. // Check to make sure this public key isn't forged or made up to win the list
  380. openssl_public_decrypt(base64_decode($transaction_crypt1), $inside_transaction_hash, $transaction_public_key);
  381. $final_hash_compare = $transaction_crypt2;
  382. $crypt_hash_check = $transaction_hash;
  383. }
  384. else
  385. {
  386. if($transaction_attribute == "T" || $transaction_attribute == "G")
  387. {
  388. // Decrypt transaction information for regular transaction data
  389. // and check to make sure the public key that is being sent to
  390. // has not been tampered with.
  391. openssl_public_decrypt(base64_decode($transaction_crypt3), $transaction_info, $transaction_public_key);
  392. $inside_transaction_hash = find_string("HASH=", "", $transaction_info, TRUE);
  393. // Check if a message is encoded in this data as well
  394. if(strlen($inside_transaction_hash) != 64)
  395. {
  396. // A message is also encoded
  397. $inside_transaction_hash = find_string("HASH=", "---MSG", $transaction_info);
  398. }
  399. // Check Hash against 3 crypt fields
  400. $crypt_hash_check = hash('sha256', $transaction_crypt1 . $transaction_crypt2 . $transaction_crypt3);
  401. }
  402. $final_hash_compare = hash('sha256', $transaction_crypt1 . $transaction_crypt2);
  403. }
  404. // Check to make sure this transaction is even valid (hash check, length check, & timestamp)
  405. if($transaction_hash == $crypt_hash_check
  406. && $inside_transaction_hash == $final_hash_compare
  407. && strlen($transaction_public_key) > 300
  408. && $transaction_timestamp >= $current_generation_cycle
  409. && $transaction_timestamp < $next_generation_cycle)
  410. {
  411. // Check for 100 public key limit in the transaction queue
  412. $sql = "SELECT * FROM `transaction_queue` WHERE `public_key` = '$transaction_public_key'";
  413. $sql_result = mysql_query($sql);
  414. $sql_num_results = mysql_num_rows($sql_result);
  415. if($sql_num_results < 100)
  416. {
  417. // Transaction hash and real hash match
  418. $sql = "INSERT INTO `transaction_queue` (`timestamp`,`public_key`,`crypt_data1`,`crypt_data2`,`crypt_data3`, `hash`, `attribute`)
  419. VALUES ('$transaction_timestamp', '$transaction_public_key', '$transaction_crypt1', '$transaction_crypt2' , '$transaction_crypt3', '$transaction_hash' , '$transaction_attribute')";
  420. mysql_query($sql);
  421. }
  422. else
  423. {
  424. write_log("More Than 100 Transactions Trying to Queue for Key: " . base64_encode($transaction_public_key), "QC");
  425. }
  426. }
  427. }
  428. $match_number++;
  429. $current_hash = find_string("---queue$match_number=", "---end$match_number", $poll_peer);
  430. } // End While Loop
  431. } // End For Loop
  432. // Build queue hash after completion
  433. $sql = "SELECT * FROM `transaction_queue` ORDER BY `hash`";
  434. $sql_result = mysql_query($sql);
  435. $sql_num_results = mysql_num_rows($sql_result);
  436. $transaction_queue_hash = 0;
  437. if($sql_num_results > 0)
  438. {
  439. for ($i = 0; $i < $sql_num_results; $i++)
  440. {
  441. $sql_row = mysql_fetch_array($sql_result);
  442. $transaction_queue_hash .= $sql_row["public_key"] . $sql_row["crypt_data1"] .
  443. $sql_row["crypt_data2"] . $sql_row["crypt_data3"] . $sql_row["hash"] . $sql_row["attribute"];
  444. }
  445. $transaction_queue_hash = hash('md5', $transaction_queue_hash);
  446. }
  447. // Store in database for quick reference from database
  448. mysql_query("UPDATE `options` SET `field_data` = '$transaction_queue_hash' WHERE `options`.`field_name` = 'transaction_queue_hash' LIMIT 1");
  449. } // End Compare Tallies
  450. } // If/then Check for valid times
  451. //***********************************************************************************
  452. //***********************************************************************************
  453. // Script finished, set status to 0
  454. $sql = "UPDATE `main_loop_status` SET `field_data` = '0' WHERE `main_loop_status`.`field_name` = 'queueclerk_heartbeat_active' LIMIT 1";
  455. mysql_query($sql);
  456. // Record when this script finished
  457. $sql = "UPDATE `main_loop_status` SET `field_data` = '" . time() . "' WHERE `main_loop_status`.`field_name` = 'queueclerk_last_heartbeat' LIMIT 1";
  458. mysql_query($sql);
  459. ?>