current(); $id = $current['id']; } $data = $block->export($id); $id = san($id); if ($data === false || empty($data)) { die("Could not export block"); } $data = json_encode($data); // cache it to reduce the load $res = file_put_contents("tmp/$id", $data); if ($res === false) { die("Could not write the cache file"); } // broadcasting to all peers $ewhr = ""; // boradcasting to only certain peers if ($linear == true) { $ewhr = " ORDER by RAND() LIMIT 5"; } $r = $db->run("SELECT * FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 $ewhr"); foreach ($r as $x) { if($x['hostname']==$_config['hostname']) continue; // encode the hostname in base58 and sanitize the IP to avoid any second order shell injections $host = escapeshellcmd(base58_encode($x['hostname'])); $ip = escapeshellcmd(filter_var($x['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)); // fork a new process to send the blocks async $type=escapeshellcmd(san($type)); $id=escapeshellcmd(san($id)); if ($debug) { system("php propagate.php '$type' '$id' '$host' '$ip' debug"); } elseif ($linear) { system("php propagate.php '$type' '$id' '$host' '$ip' linear"); } else { system("php propagate.php '$type' '$id' '$host' 'ip' > /dev/null 2>&1 &"); } } exit; } // broadcast a block to a single peer (usually a forked process from above) if ($type == "block") { // current block or read cache if ($id == "current") { $current = $block->current(); $data = $block->export($current['id']); if (!$data) { echo "Invalid Block data"; exit; } } else { $data = file_get_contents("tmp/$id"); if (empty($data)) { echo "Invalid Block data"; exit; } $data = json_decode($data, true); } $hostname = base58_decode($peer); // send the block as POST to the peer echo "Block sent to $hostname:\n"; $response = peer_post($hostname."/peer.php?q=submitBlock", $data, 60, $debug); _log("Propagating block to $hostname - [result: $response] $data[height] - $data[id]",2); if ($response == "block-ok") { echo "Block $i accepted. Exiting.\n"; exit; } elseif ($response['request'] == "microsync") { // the peer requested us to send more blocks, as it's behind echo "Microsync request\n"; $height = intval($response['height']); $bl = san($response['block']); $current = $block->current(); // maximum microsync is 10 blocks, for more, the peer should sync by sanity if ($current['height'] - $height > 10) { echo "Height Differece too high\n"; exit; } $last_block = $block->get($height); // if their last block does not match our blockchain/fork, ignore the request if ($last_block['id'] != $bl) { echo "Last block does not match\n"; exit; } echo "Sending the requested blocks\n"; //start sending the requested block for ($i = $height + 1; $i <= $current['height']; $i++) { $data = $block->export("", $i); $response = peer_post($hostname."/peer.php?q=submitBlock", $data, 60, $debug); if ($response != "block-ok") { echo "Block $i not accepted. Exiting.\n"; exit; } echo "Block\t$i\t accepted\n"; } } elseif ($response == "reverse-microsanity") { // the peer informe us that we should run a microsanity echo "Running microsanity\n"; $ip = trim($argv[4]); $ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); if (empty($ip)) { die("Invalid IP"); } // fork a microsanity in a new process system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &"); } else { echo "Block not accepted!\n"; } } // broadcast a transaction to some peers if ($type == "transaction") { $trx = new Transaction(); // get the transaction data $data = $trx->export($id); if (!$data) { echo "Invalid transaction id\n"; exit; } // if the transaction was first sent locally, we will send it to all our peers, otherwise to just a few if ($data['peer'] == "local") { $r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP()"); } else { $r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 ORDER by RAND() LIMIT :limit",["limit"=>intval($_config['transaction_propagation_peers'])]); } foreach ($r as $x) { $res = peer_post($x['hostname']."/peer.php?q=submitTransaction", $data); if (!$res) { echo "Transaction not accepted\n"; } else { echo "Transaction accepted\n"; } } }