Update peer file to PSR-2

This commit is contained in:
pxgamer
2018-05-29 15:46:52 +01:00
parent aa3459181e
commit ffd3a55144

488
peer.php
View File

@@ -1,228 +1,260 @@
<?php <?php
/* /*
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2018 AroDev Copyright (c) 2018 AroDev
www.arionum.com www.arionum.com
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE. OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
require_once("include/init.inc.php"); require_once("include/init.inc.php");
$trx = new Transaction; $trx = new Transaction();
$block=new Block; $block = new Block();
$q=$_GET['q']; $q = $_GET['q'];
// the data is sent as json, in $_POST['data'] // the data is sent as json, in $_POST['data']
if(!empty($_POST['data'])){ if (!empty($_POST['data'])) {
$data=json_decode(trim($_POST['data']),true); $data = json_decode(trim($_POST['data']), true);
} }
// make sure it's the same coin and not testnet // make sure it's the same coin and not testnet
if($_POST['coin']!=$_config['coin']) api_err("Invalid coin"); if ($_POST['coin'] != $_config['coin']) {
$ip=san_ip($_SERVER['REMOTE_ADDR']); api_err("Invalid coin");
$ip=filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); }
$ip = san_ip($_SERVER['REMOTE_ADDR']);
// peer with the current node $ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
if($q=="peer"){
// sanitize the hostname // peer with the current node
$hostname = filter_var($data['hostname'], FILTER_SANITIZE_URL); if ($q == "peer") {
// sanitize the hostname
if (!filter_var($hostname, FILTER_VALIDATE_URL)) api_err("invalid-hostname"); $hostname = filter_var($data['hostname'], FILTER_SANITIZE_URL);
$hostname=san_host($hostname);
// if it's already peered, only repeer on request if (!filter_var($hostname, FILTER_VALIDATE_URL)) {
$res=$db->single("SELECT COUNT(1) FROM peers WHERE hostname=:hostname AND ip=:ip",array(":hostname"=>$hostname,":ip"=>$ip)); api_err("invalid-hostname");
if($res==1){ }
if($data['repeer']==1){ $hostname = san_host($hostname);
$res=peer_post($hostname."/peer.php?q=peer",array("hostname"=>$_config['hostname'])); // if it's already peered, only repeer on request
if($res!==false) api_echo("re-peer-ok"); $res = $db->single("SELECT COUNT(1) FROM peers WHERE hostname=:hostname AND ip=:ip",
else api_err("re-peer failed - $result"); [":hostname" => $hostname, ":ip" => $ip]);
} if ($res == 1) {
api_echo("peer-ok-already"); if ($data['repeer'] == 1) {
} $res = peer_post($hostname."/peer.php?q=peer", ["hostname" => $_config['hostname']]);
// if we have enough peers, add it to DB as reserve if ($res !== false) {
$res=$db->single("SELECT COUNT(1) FROM peers WHERE blacklisted<UNIX_TIMESTAMP() AND ping >UNIX_TIMESTAMP()-86400 AND reserve=0"); api_echo("re-peer-ok");
$reserve=1; } else {
if($res<$_config['max_peers']) $reserve=0; api_err("re-peer failed - $result");
$db->run("INSERT ignore INTO peers SET hostname=:hostname, reserve=:reserve, ping=UNIX_TIMESTAMP(), ip=:ip ON DUPLICATE KEY UPDATE hostname=:hostname2",array(":ip"=>$ip, ":hostname2"=>$hostname,":hostname"=>$hostname, ":reserve"=>$reserve)); }
// re-peer to make sure the peer is valid }
$res=peer_post($hostname."/peer.php?q=peer",array("hostname"=>$_config['hostname'])); api_echo("peer-ok-already");
if($res!==false) api_echo("re-peer-ok"); }
else{ // if we have enough peers, add it to DB as reserve
$db->run("DELETE FROM peers WHERE ip=:ip",array(":ip"=>$ip)); $res = $db->single("SELECT COUNT(1) FROM peers WHERE blacklisted<UNIX_TIMESTAMP() AND ping >UNIX_TIMESTAMP()-86400 AND reserve=0");
api_err("re-peer failed - $result"); $reserve = 1;
} if ($res < $_config['max_peers']) {
} $reserve = 0;
elseif($q=="ping"){ }
// confirm peer is active $db->run("INSERT ignore INTO peers SET hostname=:hostname, reserve=:reserve, ping=UNIX_TIMESTAMP(), ip=:ip ON DUPLICATE KEY UPDATE hostname=:hostname2",
api_echo("pong"); [":ip" => $ip, ":hostname2" => $hostname, ":hostname" => $hostname, ":reserve" => $reserve]);
} elseif($q=="submitTransaction"){ // re-peer to make sure the peer is valid
// receive a new transaction from a peer $res = peer_post($hostname."/peer.php?q=peer", ["hostname" => $_config['hostname']]);
$current=$block->current(); if ($res !== false) {
api_echo("re-peer-ok");
} else {
// no transactions accepted if the sanity is syncing $db->run("DELETE FROM peers WHERE ip=:ip", [":ip" => $ip]);
if($_config['sanity_sync']==1) api_err("sanity-sync"); api_err("re-peer failed - $result");
}
$data['id']=san($data['id']); } elseif ($q == "ping") {
// validate transaction data // confirm peer is active
if(!$trx->check($data)) api_err("Invalid transaction"); api_echo("pong");
$hash=$data['id']; } elseif ($q == "submitTransaction") {
// make sure it's not already in mempool // receive a new transaction from a peer
$res=$db->single("SELECT COUNT(1) FROM mempool WHERE id=:id",array(":id"=>$hash)); $current = $block->current();
if($res!=0) api_err("The transaction is already in mempool");
// make sure the peer is not flooding us with transactions
$res=$db->single("SELECT COUNT(1) FROM mempool WHERE src=:src",array(":src"=>$data['src'])); // no transactions accepted if the sanity is syncing
if($res>25) api_err("Too many transactions from this address in mempool. Please rebroadcast later."); if ($_config['sanity_sync'] == 1) {
$res=$db->single("SELECT COUNT(1) FROM mempool WHERE peer=:peer",array(":peer"=>$ip)); api_err("sanity-sync");
if($res>$_config['peer_max_mempool']) api_error("Too many transactions broadcasted from this peer"); }
$data['id'] = san($data['id']);
// make sure the transaction is not already on the blockchain // validate transaction data
$res=$db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$hash)); if (!$trx->check($data)) {
if($res!=0) api_err("The transaction is already in a block"); api_err("Invalid transaction");
$acc=new Account; }
$src=$acc->get_address($data['public_key']); $hash = $data['id'];
// make sure the sender has enough balance // make sure it's not already in mempool
$balance=$db->single("SELECT balance FROM accounts WHERE id=:id",array(":id"=>$src)); $res = $db->single("SELECT COUNT(1) FROM mempool WHERE id=:id", [":id" => $hash]);
if($balance<$val+$fee) api_err("Not enough funds"); if ($res != 0) {
api_err("The transaction is already in mempool");
// make sure the sender has enough pending balance }
$memspent=$db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:src",array(":src"=>$src)); // make sure the peer is not flooding us with transactions
if($balance-$memspent<$val+$fee) api_err("Not enough funds (mempool)"); $res = $db->single("SELECT COUNT(1) FROM mempool WHERE src=:src", [":src" => $data['src']]);
if ($res > 25) {
// add to mempool api_err("Too many transactions from this address in mempool. Please rebroadcast later.");
$trx->add_mempool($data, $ip); }
$res = $db->single("SELECT COUNT(1) FROM mempool WHERE peer=:peer", [":peer" => $ip]);
// rebroadcast the transaction to some peers unless the transaction is smaller than the average size of transactions in mempool - protect against garbage data flooding if ($res > $_config['peer_max_mempool']) {
$res=$db->row("SELECT COUNT(1) as c, sum(val) as v FROM mempool ",array(":src"=>$data['src'])); api_error("Too many transactions broadcasted from this peer");
if($res['c']<$_config['max_mempool_rebroadcast']&&$res['v']/$res['c']<$data['val']) system("php propagate.php transaction '$data[id]' > /dev/null 2>&1 &"); }
api_echo("transaction-ok");
}
elseif($q=="submitBlock"){ // make sure the transaction is not already on the blockchain
// receive a new block from a peer $res = $db->single("SELECT COUNT(1) FROM transactions WHERE id=:id", [":id" => $hash]);
if ($res != 0) {
// if sanity sync, refuse all api_err("The transaction is already in a block");
if($_config['sanity_sync']==1){ _log('['.$ip."] Block rejected due to sanity sync"); api_err("sanity-sync"); } }
$data['id']=san($data['id']); $acc = new Account;
$current=$block->current(); $src = $acc->get_address($data['public_key']);
// block already in the blockchain // make sure the sender has enough balance
if($current['id']==$data['id']) api_echo("block-ok"); $balance = $db->single("SELECT balance FROM accounts WHERE id=:id", [":id" => $src]);
if($data['date']>time()+30) api_err("block in the future"); if ($balance < $val + $fee) {
api_err("Not enough funds");
if($current['height']==$data['height']&&$current['id']!=$data['id']){ }
// different forks, same height
$accept_new=false; // make sure the sender has enough pending balance
if($current['transactions']<$data['transactions']){ $memspent = $db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:src", [":src" => $src]);
// accept the one with most transactions if ($balance - $memspent < $val + $fee) {
$accept_new=true; api_err("Not enough funds (mempool)");
} elseif($current['transactions']==$data['transactions']) { }
// convert the first 12 characters from hex to decimal and the block with the largest number wins
$no1=hexdec(substr(coin2hex($current['id']),0,12)); // add to mempool
$no2=hexdec(substr(coin2hex($data['id']),0,12)); $trx->add_mempool($data, $ip);
if(gmp_cmp($no1,$no2)==1){
$accept_new=true; // rebroadcast the transaction to some peers unless the transaction is smaller than the average size of transactions in mempool - protect against garbage data flooding
} $res = $db->row("SELECT COUNT(1) as c, sum(val) as v FROM mempool ", [":src" => $data['src']]);
} if ($res['c'] < $_config['max_mempool_rebroadcast'] && $res['v'] / $res['c'] < $data['val']) {
if($accept_new){ system("php propagate.php transaction '$data[id]' > /dev/null 2>&1 &");
// if the new block is accepted, run a microsanity to sync it }
_log('['.$ip."] Starting microsanity - $data[height]"); api_echo("transaction-ok");
system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &"); } elseif ($q == "submitBlock") {
api_echo("microsanity"); // receive a new block from a peer
} else { // if sanity sync, refuse all
_log('['.$ip."] suggesting reverse-microsanity - $data[height]"); if ($_config['sanity_sync'] == 1) {
api_echo("reverse-microsanity"); // if it's not, suggest to the peer to get the block from us _log('['.$ip."] Block rejected due to sanity sync");
} api_err("sanity-sync");
} }
// if it's not the next block $data['id'] = san($data['id']);
if($current['height']!=$data['height']-1) { $current = $block->current();
// if the height of the block submitted is lower than our current height, send them our current block // block already in the blockchain
if($data['height']<$current['height']){ if ($current['id'] == $data['id']) {
$pr=$db->row("SELECT * FROM peers WHERE ip=:ip",array(":ip"=>$ip)); api_echo("block-ok");
if(!$pr) api_err("block-too-old"); }
$peer_host=base58_encode($pr['hostname']); if ($data['date'] > time() + 30) {
$pr['ip']=escapeshellcmd(san_ip($pr['ip'])); api_err("block in the future");
system("php propagate.php block current '$peer_host' '$pr[ip]' > /dev/null 2>&1 &"); }
_log('['.$ip."] block too old, sending our current block - $data[height]");
if ($current['height'] == $data['height'] && $current['id'] != $data['id']) {
api_err("block-too-old"); // different forks, same height
} $accept_new = false;
// if the block difference is bigger than 150, nothing should be done. They should sync via sanity if ($current['transactions'] < $data['transactions']) {
if($data['height']-$current['height']>150) { // accept the one with most transactions
_log('['.$ip."] block-out-of-sync - $data[height]"); $accept_new = true;
api_err("block-out-of-sync"); } elseif ($current['transactions'] == $data['transactions']) {
} // convert the first 12 characters from hex to decimal and the block with the largest number wins
// request them to send us a microsync with the latest blocks $no1 = hexdec(substr(coin2hex($current['id']), 0, 12));
_log('['.$ip."] requesting microsync - $current[height] - $data[height]"); $no2 = hexdec(substr(coin2hex($data['id']), 0, 12));
api_echo(array("request"=>"microsync","height"=>$current['height'], "block"=>$current['id'])); if (gmp_cmp($no1, $no2) == 1) {
$accept_new = true;
} }
// check block data }
if(!$block->check($data)){ if ($accept_new) {
_log('['.$ip."] invalid block - $data[height]"); // if the new block is accepted, run a microsanity to sync it
api_err("invalid-block"); _log('['.$ip."] Starting microsanity - $data[height]");
} system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &");
$b=$data; api_echo("microsanity");
// add the block to the blockchain } else {
$res=$block->add($b['height'], $b['public_key'], $b['nonce'], $b['data'], $b['date'], $b['signature'], $b['difficulty'], $b['reward_signature'], $b['argon']); _log('['.$ip."] suggesting reverse-microsanity - $data[height]");
api_echo("reverse-microsanity"); // if it's not, suggest to the peer to get the block from us
if(!$res) { }
_log('['.$ip."] invalid block data - $data[height]"); }
api_err("invalid-block-data"); // if it's not the next block
} if ($current['height'] != $data['height'] - 1) {
// if the height of the block submitted is lower than our current height, send them our current block
_log('['.$ip."] block ok, repropagating - $data[height]"); if ($data['height'] < $current['height']) {
$pr = $db->row("SELECT * FROM peers WHERE ip=:ip", [":ip" => $ip]);
// send it to all our peers if (!$pr) {
system("php propagate.php block '$data[id]' all all linear > /dev/null 2>&1 &"); api_err("block-too-old");
api_echo("block-ok"); }
} $peer_host = base58_encode($pr['hostname']);
// return the current block, used in syncing $pr['ip'] = escapeshellcmd(san_ip($pr['ip']));
elseif($q=="currentBlock"){ system("php propagate.php block current '$peer_host' '$pr[ip]' > /dev/null 2>&1 &");
$current=$block->current(); _log('['.$ip."] block too old, sending our current block - $data[height]");
api_echo($current);
} api_err("block-too-old");
// return a specific block, used in syncing }
elseif($q=="getBlock"){ // if the block difference is bigger than 150, nothing should be done. They should sync via sanity
$height=intval($data['height']); if ($data['height'] - $current['height'] > 150) {
_log('['.$ip."] block-out-of-sync - $data[height]");
$export=$block->export("",$height); api_err("block-out-of-sync");
if(!$export) api_err("invalid-block"); }
api_echo($export); // request them to send us a microsync with the latest blocks
} _log('['.$ip."] requesting microsync - $current[height] - $data[height]");
elseif($q=="getBlocks"){ api_echo(["request" => "microsync", "height" => $current['height'], "block" => $current['id']]);
// returns X block starting at height, used in syncing }
// check block data
$height=intval($data['height']); if (!$block->check($data)) {
_log('['.$ip."] invalid block - $data[height]");
$r=$db->run("SELECT id,height FROM blocks WHERE height>=:height ORDER by height ASC LIMIT 100",array(":height"=>$height)); api_err("invalid-block");
foreach($r as $x){ }
$blocks[$x['height']]=$block->export($x['id']); $b = $data;
} // add the block to the blockchain
api_echo($blocks); $res = $block->add($b['height'], $b['public_key'], $b['nonce'], $b['data'], $b['date'], $b['signature'],
$b['difficulty'], $b['reward_signature'], $b['argon']);
}
// returns a full list of unblacklisted peers in a random order if (!$res) {
elseif($q=="getPeers"){ _log('['.$ip."] invalid block data - $data[height]");
$peers=$db->run("SELECT ip,hostname FROM peers WHERE blacklisted<UNIX_TIMESTAMP() ORDER by RAND()"); api_err("invalid-block-data");
api_echo($peers); }
} else {
api_err("Invalid request"); _log('['.$ip."] block ok, repropagating - $data[height]");
}
// send it to all our peers
?> system("php propagate.php block '$data[id]' all all linear > /dev/null 2>&1 &");
api_echo("block-ok");
} // return the current block, used in syncing
elseif ($q == "currentBlock") {
$current = $block->current();
api_echo($current);
} // return a specific block, used in syncing
elseif ($q == "getBlock") {
$height = intval($data['height']);
$export = $block->export("", $height);
if (!$export) {
api_err("invalid-block");
}
api_echo($export);
} elseif ($q == "getBlocks") {
// returns X block starting at height, used in syncing
$height = intval($data['height']);
$r = $db->run("SELECT id,height FROM blocks WHERE height>=:height ORDER by height ASC LIMIT 100",
[":height" => $height]);
foreach ($r as $x) {
$blocks[$x['height']] = $block->export($x['id']);
}
api_echo($blocks);
} // returns a full list of unblacklisted peers in a random order
elseif ($q == "getPeers") {
$peers = $db->run("SELECT ip,hostname FROM peers WHERE blacklisted<UNIX_TIMESTAMP() ORDER by RAND()");
api_echo($peers);
} else {
api_err("Invalid request");
}