Compare commits
	
		
			62 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 984aedc940 | ||
|   | e59bb416b4 | ||
|   | 57d2257c43 | ||
|   | 8c32d1c71b | ||
|   | b5110bf01f | ||
|   | 0567899edd | ||
|   | 66b1221e22 | ||
|   | 9e9c12fbbb | ||
|   | c5002508d6 | ||
|   | fbc48921f3 | ||
|   | 07dcebd895 | ||
|   | 6651ff54fc | ||
|   | 38745111ef | ||
|   | c83895d384 | ||
|   | 62cc290b50 | ||
|   | dab6648ae8 | ||
|   | 5c476be954 | ||
|   | 0d5f79fc20 | ||
|   | 5fc167cfbf | ||
|   | 5f4b6d9d51 | ||
|   | e707f8daa4 | ||
|   | a09279d091 | ||
|   | d9e5ad94de | ||
|   | 8b006fc26a | ||
|   | 066211b2c0 | ||
|   | 06960e64e7 | ||
|   | b276fde6da | ||
|   | 7ebf3e0e8a | ||
|   | 3a4aaf973c | ||
|   | 81bd36d2c5 | ||
|   | 85cf950fca | ||
|   | 2f4e95f22d | ||
|   | c6393d7e8d | ||
|   | aae845548f | ||
|   | b68f316029 | ||
|   | ffd3a55144 | ||
|   | aa3459181e | ||
|   | 28807ef9ca | ||
|   | 2fded5d4eb | ||
|   | f95d94f205 | ||
|   | c82e68c9b2 | ||
|   | bff8025b15 | ||
|   | 636f4013dc | ||
|   | d8f1f4ea57 | ||
|   | 44c9eb5ce6 | ||
|   | 425bdcb504 | ||
|   | af98de2e86 | ||
|   | 5d5e4d1f3c | ||
|   | e1d52c0e31 | ||
|   | 58a815e068 | ||
|   | 6bf10c408c | ||
|   | 128241a3d9 | ||
|   | 0a5be52570 | ||
|   | 4ee780578b | ||
|   | 0e561e5407 | ||
|   | 82ef1e9d10 | ||
|   | f2dbc02e93 | ||
|   | a5a1ff7f7a | ||
|   | 1115e02e5d | ||
|   | 54aea30232 | ||
|   | 3898b7c7e0 | ||
|   | 70966df297 | 
							
								
								
									
										77
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,55 +1,54 @@ | |||||||
| # node | # node | ||||||
| Arionum (ARO) cryptocurrency node |  | ||||||
|  |  | ||||||
| ----------------------------------------------------- | The Arionum (ARO) cryptocurrency node. | ||||||
| Block 10800 Hard fork - Code name: Resistance |  | ||||||
|  |  | ||||||
| In order to increase the fairness of Arionum and stay true to the inital claim of being a cpu coin, we will be changing the mining algorithm starting the block 10800. | ## Install | ||||||
|  |  | ||||||
| The new mining alghoritm uses: | **Hardware Requirements:** | ||||||
|  | ``` | ||||||
|  | 2GB RAM | ||||||
|  | 1 CPU Core | ||||||
|  | 50GB DISK | ||||||
|  | ``` | ||||||
|  | **Requirements:** | ||||||
|  |  | ||||||
| threads=1 | - PHP 7.2 | ||||||
|  |   - PDO extension | ||||||
|  |   - GMP extension | ||||||
|  |   - BCMath extension | ||||||
|  | - MySQL/MariaDB | ||||||
|  |  | ||||||
| memory=524288 | 1. Install MySQL or MariaDB and create a database and a user. | ||||||
|  | 2. Rename `include/config-sample.inc.php` to  `include/config.inc.php` and set the DB login data | ||||||
|  | 3. Change permissions to tmp and `tmp/db-update` to 777 (`chmod 777 tmp -R`) | ||||||
|  | 4. Access the http://ip-or-domain and refresh once | ||||||
|  |  | ||||||
| time=1 | ## Usage | ||||||
|  |  | ||||||
| Also, starting block 10800, the maximum transaction fee will be 10 ARO. | This app should only be run in the main directory of the domain/subdomain, ex: http://111.111.111.111 | ||||||
|  |  | ||||||
| ----------------------------------------------------- |  | ||||||
|  |  | ||||||
| Requires php 7.2, mysql/mariadb, php-pdo, php-bcmath and php-gmp |  | ||||||
|  |  | ||||||
| This app should only be run in the main directory of the domain/subdomain, ex: http://111.111.111.111/ |  | ||||||
|  |  | ||||||
| The node should have a public IP and be accessible over internet. | The node should have a public IP and be accessible over internet. | ||||||
|  |  | ||||||
| Installation: | ## Links | ||||||
| 1. Install MySQL or MariaDB and create a database and a user. |  | ||||||
|  |  | ||||||
| 2. Edit include/config.inc.php and set the DB login data | - Official website: https://www.arionum.com | ||||||
|  | - Block explorer: https://arionum.info | ||||||
|  | - Forums: https://forum.arionum.com | ||||||
|  |  | ||||||
| 3. Change permissions to tmp and tmp/db-update to 777 (chmod 777 tmp -R) | ## Development Fund | ||||||
|  |  | ||||||
| 4. Access the http://ip-or-domain and refresh once | Coin | Address | ||||||
|  | ---- | -------- | ||||||
| Official website: https://www.arionum.com | [ARO]: | 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr | ||||||
|  | [LTC]: | LWgqzbXGeucKaMmJEvwaAWPFrAgKiJ4Y4m | ||||||
| Block explorer: https://arionum.info | [BTC]: | 1LdoMmYitb4C3pXoGNLL1VRj7xk3smGXoU | ||||||
|  | [ETH]: | 0x4B904bDf071E9b98441d25316c824D7b7E447527 | ||||||
| Forums: https://forum.arionum.com | [BCH]: | qrtkqrl3mxzdzl66nchkgdv73uu3rf7jdy7el2vduw | ||||||
|  |  | ||||||
|  |  | ||||||
| Development Fund |  | ||||||
|  |  | ||||||
| ARO: 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr |  | ||||||
|  |  | ||||||
| LTC: LWgqzbXGeucKaMmJEvwaAWPFrAgKiJ4Y4m |  | ||||||
|  |  | ||||||
| BTC: 1LdoMmYitb4C3pXoGNLL1VRj7xk3smGXoU |  | ||||||
|  |  | ||||||
| ETH: 0x4B904bDf071E9b98441d25316c824D7b7E447527 |  | ||||||
|  |  | ||||||
| BCH: qrtkqrl3mxzdzl66nchkgdv73uu3rf7jdy7el2vduw |  | ||||||
|  |  | ||||||
| If you'd like to support the Arionum development, you can donate to the addresses listed above. | If you'd like to support the Arionum development, you can donate to the addresses listed above. | ||||||
|  |  | ||||||
|  | [aro]: https://arionum.com | ||||||
|  | [ltc]: https://litecoin.org | ||||||
|  | [btc]: https://bitcoin.org | ||||||
|  | [eth]: https://ethereum.org | ||||||
|  | [bch]: https://www.bitcoincash.org | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								UPGRADE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								UPGRADE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | In order to upgrade your Arionum Node, follow the next steps: | ||||||
|  | 1. Download the source code from https://github.com/arionum/node | ||||||
|  | 2. Edit the include/config.inc.php with the DB details | ||||||
|  | 3. Replace your old node folder with the new one. | ||||||
|  | 4. chmod 777 tmp -R | ||||||
|  | 5. Load the node's address in your browser. | ||||||
							
								
								
									
										520
									
								
								api.php
									
									
									
									
									
								
							
							
						
						
									
										520
									
								
								api.php
									
									
									
									
									
								
							| @@ -24,7 +24,6 @@ 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. | ||||||
| */ | */ | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @api {get} /api.php 01. Basic Information |  * @api {get} /api.php 01. Basic Information | ||||||
|  * @apiName Info |  * @apiName Info | ||||||
| @@ -66,30 +65,26 @@ OR OTHER DEALINGS IN THE SOFTWARE. | |||||||
|  *     } |  *     } | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| require_once("include/init.inc.php"); | require_once("include/init.inc.php"); | ||||||
| error_reporting(0); | error_reporting(0); | ||||||
| $ip=$_SERVER['REMOTE_ADDR']; | $ip = san_ip($_SERVER['REMOTE_ADDR']); | ||||||
| $ip=filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); | $ip = filter_var($ip, FILTER_VALIDATE_IP); | ||||||
|  |  | ||||||
| if($_config['public_api']==false&&!in_array($ip,$_config['allowed_hosts'])){ | if ($_config['public_api'] == false && !in_array($ip, $_config['allowed_hosts'])) { | ||||||
|     api_err("private-api"); |     api_err("private-api"); | ||||||
| } | } | ||||||
|  |  | ||||||
| $acc = new Account; | $acc = new Account(); | ||||||
| $block = new Block; | $block = new Block(); | ||||||
|  |  | ||||||
| $trx = new Transaction; | $trx = new Transaction(); | ||||||
| $q=$_GET['q']; | $q = $_GET['q']; | ||||||
| if(!empty($_POST['data'])){ | if (!empty($_POST['data'])) { | ||||||
|     $data=json_decode($_POST['data'],true); |     $data = json_decode($_POST['data'], true); | ||||||
| } else { | } else { | ||||||
|     $data=$_GET; |     $data = $_GET; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @api {get} /api.php?q=getAddress  02. getAddress |  * @api {get} /api.php?q=getAddress  02. getAddress | ||||||
|  * @apiName getAddress |  * @apiName getAddress | ||||||
| @@ -101,13 +96,14 @@ if(!empty($_POST['data'])){ | |||||||
|  * @apiSuccess {string} data Contains the address |  * @apiSuccess {string} data Contains the address | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| if($q=="getAddress"){ | if ($q == "getAddress") { | ||||||
|     $public_key=$data['public_key']; |     $public_key = $data['public_key']; | ||||||
|     if(strlen($public_key)<32) api_err("Invalid public key"); |     if (strlen($public_key) < 32) { | ||||||
|  |         api_err("Invalid public key"); | ||||||
|  |     } | ||||||
|     api_echo($acc->get_address($public_key)); |     api_echo($acc->get_address($public_key)); | ||||||
| } | } elseif ($q == "base58") { | ||||||
| elseif($q=="base58"){		 |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=base58  03. base58 |      * @api {get} /api.php?q=base58  03. base58 | ||||||
|      * @apiName base58 |      * @apiName base58 | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -119,9 +115,8 @@ elseif($q=="base58"){ | |||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     api_echo(base58_encode($data['data'])); |     api_echo(base58_encode($data['data'])); | ||||||
| } | } elseif ($q == "getBalance") { | ||||||
| elseif($q=="getBalance"){ |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=getBalance  04. getBalance |      * @api {get} /api.php?q=getBalance  04. getBalance | ||||||
|      * @apiName getBalance |      * @apiName getBalance | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -129,20 +124,30 @@ elseif($q=="getBalance"){ | |||||||
|      * |      * | ||||||
|      * @apiParam {string} [public_key] Public key |      * @apiParam {string} [public_key] Public key | ||||||
|      * @apiParam {string} [account] Account id / address |      * @apiParam {string} [account] Account id / address | ||||||
|  |      * @apiParam {string} [alias] alias | ||||||
|      * |      * | ||||||
|      * @apiSuccess {string} data The ARO balance |      * @apiSuccess {string} data The ARO balance | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $public_key=$data['public_key']; |     $public_key = $data['public_key']; | ||||||
|     $account=$data['account']; |     $account = $data['account']; | ||||||
|     if(!empty($public_key)&&strlen($public_key)<32) api_err("Invalid public key"); |     $alias = $data['alias']; | ||||||
|     if(!empty($public_key)) $account=$acc->get_address($public_key); |     if (!empty($public_key) && strlen($public_key) < 32) { | ||||||
|     if(empty($account)) api_err("Invalid account id"); |         api_err("Invalid public key"); | ||||||
|     $account=san($account); |     } | ||||||
|  |     if (!empty($public_key)) { | ||||||
|  |         $account = $acc->get_address($public_key); | ||||||
|  |     } | ||||||
|  |     if (!empty($alias)) { | ||||||
|  |         $account = $acc->alias2account($alias); | ||||||
|  |     } | ||||||
|  |     if (empty($account)) { | ||||||
|  |         api_err("Invalid account id"); | ||||||
|  |     } | ||||||
|  |     $account = san($account); | ||||||
|     api_echo($acc->balance($account)); |     api_echo($acc->balance($account)); | ||||||
| } | } elseif ($q == "getPendingBalance") { | ||||||
| elseif($q=="getPendingBalance"){ |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=getPendingBalance  05. getPendingBalance |      * @api {get} /api.php?q=getPendingBalance  05. getPendingBalance | ||||||
|      * @apiName getPendingBalance |      * @apiName getPendingBalance | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -154,15 +159,20 @@ elseif($q=="getPendingBalance"){ | |||||||
|      * @apiSuccess {string} data The ARO balance |      * @apiSuccess {string} data The ARO balance | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $account=$data['account']; |     $account = $data['account']; | ||||||
|     if(!empty($public_key)&&strlen($public_key)<32) api_err("Invalid public key"); |     if (!empty($public_key) && strlen($public_key) < 32) { | ||||||
|     if(!empty($public_key)) $account=$acc->get_address($public_key); |         api_err("Invalid public key"); | ||||||
|     if(empty($account)) api_err("Invalid account id"); |     } | ||||||
|     $account=san($account); |     if (!empty($public_key)) { | ||||||
|  |         $account = $acc->get_address($public_key); | ||||||
|  |     } | ||||||
|  |     if (empty($account)) { | ||||||
|  |         api_err("Invalid account id"); | ||||||
|  |     } | ||||||
|  |     $account = san($account); | ||||||
|     api_echo($acc->pending_balance($account)); |     api_echo($acc->pending_balance($account)); | ||||||
| } | } elseif ($q == "getTransactions") { | ||||||
| elseif($q=="getTransactions"){ |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=getTransactions  06. getTransactions |      * @api {get} /api.php?q=getTransactions  06. getTransactions | ||||||
|      * @apiName getTransactions |      * @apiName getTransactions | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -188,18 +198,23 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {numeric} version Transaction version |      * @apiSuccess {numeric} version Transaction version | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $account=san($data['account']); |     $account = san($data['account']); | ||||||
|     if(!empty($public_key)&&strlen($public_key)<32) api_err("Invalid public key"); |     if (!empty($public_key) && strlen($public_key) < 32) { | ||||||
|     if(!empty($public_key)) $account=$acc->get_address($public_key); |         api_err("Invalid public key"); | ||||||
|     if(empty($account)) api_err("Invalid account id"); |     } | ||||||
|  |     if (!empty($public_key)) { | ||||||
|  |         $account = $acc->get_address($public_key); | ||||||
|  |     } | ||||||
|  |     if (empty($account)) { | ||||||
|  |         api_err("Invalid account id"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $limit=intval($data['limit']); |     $limit = intval($data['limit']); | ||||||
|     $transactions=$acc->get_mempool_transactions($account); |     $transactions = $acc->get_mempool_transactions($account); | ||||||
|     $transactions=array_merge($transactions, $acc->get_transactions($account,$limit)); |     $transactions = array_merge($transactions, $acc->get_transactions($account, $limit)); | ||||||
|     api_echo($transactions); |     api_echo($transactions); | ||||||
|  | } elseif ($q == "getTransaction") { | ||||||
| } elseif($q=="getTransaction"){ |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=getTransaction  07. getTransaction |      * @api {get} /api.php?q=getTransaction  07. getTransaction | ||||||
|      * @apiName getTransaction |      * @apiName getTransaction | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -223,15 +238,17 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {numeric} version Transaction version |      * @apiSuccess {numeric} version Transaction version | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $id=san($data['transaction']); |     $id = san($data['transaction']); | ||||||
|     $res=$trx->get_transaction($id); |     $res = $trx->get_transaction($id); | ||||||
|     if($res===false) { |     if ($res === false) { | ||||||
|         $res=$trx->get_mempool_transaction($id); |         $res = $trx->get_mempool_transaction($id); | ||||||
|         if($res===false) api_err("invalid transaction"); |         if ($res === false) { | ||||||
|  |             api_err("invalid transaction"); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     api_Echo($res); |     api_Echo($res); | ||||||
| } elseif($q=="getPublicKey"){ | } elseif ($q == "getPublicKey") { | ||||||
| /** |     /** | ||||||
|      * @api {get} /api.php?q=getPublicKey  08. getPublicKey |      * @api {get} /api.php?q=getPublicKey  08. getPublicKey | ||||||
|      * @apiName getPublicKey |      * @apiName getPublicKey | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -242,15 +259,18 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {string} data The public key |      * @apiSuccess {string} data The public key | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $account=san($data['account']); |     $account = san($data['account']); | ||||||
|     if(empty($account)) api_err("Invalid account id"); |     if (empty($account)) { | ||||||
|     $public_key=$acc->public_key($account); |         api_err("Invalid account id"); | ||||||
|     if($public_key===false) api_err("No public key found for this account"); |     } | ||||||
|     else api_echo($public_key); |     $public_key = $acc->public_key($account); | ||||||
|  |     if ($public_key === false) { | ||||||
|      |         api_err("No public key found for this account"); | ||||||
| } elseif($q=="generateAccount"){ |     } else { | ||||||
| /** |         api_echo($public_key); | ||||||
|  |     } | ||||||
|  | } elseif ($q == "generateAccount") { | ||||||
|  |     /** | ||||||
|      * @api {get} /api.php?q=generateAccount  09. generateAccount |      * @api {get} /api.php?q=generateAccount  09. generateAccount | ||||||
|      * @apiName generateAccount |      * @apiName generateAccount | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -261,11 +281,11 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {string} private_key Private key |      * @apiSuccess {string} private_key Private key | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
| 	$acc=new Account; |     $acc = new Account(); | ||||||
| 	$res=$acc->generate_account(); |     $res = $acc->generate_account(); | ||||||
|     api_echo($res); |     api_echo($res); | ||||||
| } elseif($q=="currentBlock"){ | } elseif ($q == "currentBlock") { | ||||||
| /** |     /** | ||||||
|      * @api {get} /api.php?q=currentBlock  10. currentBlock |      * @api {get} /api.php?q=currentBlock  10. currentBlock | ||||||
|      * @apiName currentBlock |      * @apiName currentBlock | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -279,15 +299,12 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {string} signature Signature signed by the generator |      * @apiSuccess {string} signature Signature signed by the generator | ||||||
|      * @apiSuccess {numeric} difficulty The base target / difficulty |      * @apiSuccess {numeric} difficulty The base target / difficulty | ||||||
|      * @apiSuccess {string} argon Mining argon hash |      * @apiSuccess {string} argon Mining argon hash | ||||||
|  |  | ||||||
|  |  | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $current=$block->current(); |     $current = $block->current(); | ||||||
|     api_echo($current); |     api_echo($current); | ||||||
|  | } elseif ($q == "getBlock") { | ||||||
| } elseif($q=="getBlock"){ |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=getBlock  11. getBlock |      * @api {get} /api.php?q=getBlock  11. getBlock | ||||||
|      * @apiName getBlock |      * @apiName getBlock | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -304,12 +321,15 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {numeric} difficulty The base target / difficulty |      * @apiSuccess {numeric} difficulty The base target / difficulty | ||||||
|      * @apiSuccess {string} argon Mining argon hash |      * @apiSuccess {string} argon Mining argon hash | ||||||
|      */ |      */ | ||||||
| 	$height=san($data['height']); |     $height = san($data['height']); | ||||||
| 	$ret=$block->get($height); |     $ret = $block->get($height); | ||||||
| 	if($ret==false) api_err("Invalid block"); |     if ($ret == false) { | ||||||
| 	else api_echo($ret); |         api_err("Invalid block"); | ||||||
| } elseif($q=="getBlockTransactions"){ |     } else { | ||||||
| /** |         api_echo($ret); | ||||||
|  |     } | ||||||
|  | } elseif ($q == "getBlockTransactions") { | ||||||
|  |     /** | ||||||
|      * @api {get} /api.php?q=getBlockTransactions  12. getBlockTransactions |      * @api {get} /api.php?q=getBlockTransactions  12. getBlockTransactions | ||||||
|      * @apiName getBlockTransactions |      * @apiName getBlockTransactions | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -319,7 +339,7 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiParam {string} [block] Block id |      * @apiParam {string} [block] Block id | ||||||
|      * |      * | ||||||
|      * @apiSuccess {string} block  Block ID |      * @apiSuccess {string} block  Block ID | ||||||
|  * @apiSuccess {numeric} confirmation Number of confirmations |      * @apiSuccess {numeric} confirmations Number of confirmations | ||||||
|      * @apiSuccess {numeric} date  Transaction's date in UNIX TIMESTAMP format |      * @apiSuccess {numeric} date  Transaction's date in UNIX TIMESTAMP format | ||||||
|      * @apiSuccess {string} dst  Transaction destination |      * @apiSuccess {string} dst  Transaction destination | ||||||
|      * @apiSuccess {numeric} fee  The transaction's fee |      * @apiSuccess {numeric} fee  The transaction's fee | ||||||
| @@ -333,14 +353,16 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {numeric} val Transaction value |      * @apiSuccess {numeric} val Transaction value | ||||||
|      * @apiSuccess {numeric} version Transaction version |      * @apiSuccess {numeric} version Transaction version | ||||||
|      */ |      */ | ||||||
|         $height=san($data['height']); |     $height = san($data['height']); | ||||||
| 	$block=san($data['block']); |     $block = san($data['block']); | ||||||
|         $ret=$trx->get_transactions($height, $block); |     $ret = $trx->get_transactions($height, $block); | ||||||
|         if($ret===false) api_err("Invalid block"); |     if ($ret === false) { | ||||||
|         else api_echo($ret); |         api_err("Invalid block"); | ||||||
|  |     } else { | ||||||
| } elseif($q=="version"){  |         api_echo($ret); | ||||||
| /** |     } | ||||||
|  | } elseif ($q == "version") { | ||||||
|  |     /** | ||||||
|      * @api {get} /api.php?q=version  13. version |      * @api {get} /api.php?q=version  13. version | ||||||
|      * @apiName version |      * @apiName version | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -348,11 +370,10 @@ elseif($q=="getTransactions"){ | |||||||
|      * |      * | ||||||
|      * |      * | ||||||
|      * @apiSuccess {string} data  Version |      * @apiSuccess {string} data  Version | ||||||
| */ |      */ | ||||||
|     api_echo(VERSION); |     api_echo(VERSION); | ||||||
|  | } elseif ($q == "send") { | ||||||
| } elseif($q=="send"){ |     /** | ||||||
| /** |  | ||||||
|      * @api {get} /api.php?q=send  14. send |      * @api {get} /api.php?q=send  14. send | ||||||
|      * @apiName send |      * @apiName send | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -369,108 +390,179 @@ elseif($q=="getTransactions"){ | |||||||
|      * |      * | ||||||
|      * @apiSuccess {string} data  Transaction id |      * @apiSuccess {string} data  Transaction id | ||||||
|      */ |      */ | ||||||
|     $current=$block->current(); |     $current = $block->current(); | ||||||
|  |  | ||||||
|     if($current['height']>10790&&$current['height']<10810) api_err("Hard fork in progress. Please retry the transaction later!"); //10800 |     if ($current['height'] > 10790 && $current['height'] < 10810) { | ||||||
|  |         api_err("Hard fork in progress. Please retry the transaction later!"); //10800 | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $acc = new Account; |     $acc = new Account(); | ||||||
|     $block = new Block; |     $block = new Block(); | ||||||
|  |  | ||||||
|     $trx = new Transaction; |     $trx = new Transaction(); | ||||||
|  |     $version = intval($data['version']); | ||||||
|  |     $dst = san($data['dst']); | ||||||
|  |     if ($version < 1) { | ||||||
|  |         $version = 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $dst=san($data['dst']); |     if ($version==1) { | ||||||
|  |         if (!$acc->valid($dst)) { | ||||||
|     if(!$acc->valid($dst)) api_err("Invalid destination address"); |             api_err("Invalid destination address"); | ||||||
|     $dst_b=base58_decode($dst); |         } | ||||||
|     if(strlen($dst_b)!=64)  api_err("Invalid destination address"); |         $dst_b = base58_decode($dst); | ||||||
|  |         if (strlen($dst_b) != 64) { | ||||||
|  |             api_err("Invalid destination address"); | ||||||
|  |         } | ||||||
|  |     } elseif ($version==2) { | ||||||
|  |         $dst=strtoupper($dst); | ||||||
|  |         $dst = san($dst); | ||||||
|  |         if (!$acc->valid_alias($dst)) { | ||||||
|  |             api_err("Invalid destination alias"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|      |      | ||||||
|  |  | ||||||
|     $public_key=san($data['public_key']); |  | ||||||
|     if(!$acc->valid_key($public_key)) api_err("Invalid public key"); |  | ||||||
|     $private_key=san($data['private_key']); |  | ||||||
|     if(!$acc->valid_key($private_key)) api_err("Invalid private key"); |  | ||||||
|     $signature=san($data['signature']); |  | ||||||
|     if(!$acc->valid_key($signature)) api_err("Invalid signature"); |  | ||||||
|     $date=$data['date']+0; |  | ||||||
|  |  | ||||||
|     if($date==0) $date=time(); |     $public_key = san($data['public_key']); | ||||||
|     if($date<time()-(3600*24*48)) api_err("The date is too old"); |     if (!$acc->valid_key($public_key)) { | ||||||
|     if($date>time()+86400) api_err("Invalid Date"); |         api_err("Invalid public key"); | ||||||
|     $version=intval($data['version']); |     } | ||||||
|  |     $private_key = san($data['private_key']); | ||||||
|  |     if (!$acc->valid_key($private_key)) { | ||||||
|  |         api_err("Invalid private key"); | ||||||
|  |     } | ||||||
|  |     $signature = san($data['signature']); | ||||||
|  |     if (!$acc->valid_key($signature)) { | ||||||
|  |         api_err("Invalid signature"); | ||||||
|  |     } | ||||||
|  |     $date = $data['date'] + 0; | ||||||
|  |  | ||||||
|  |     if ($date == 0) { | ||||||
|  |         $date = time(); | ||||||
|  |     } | ||||||
|  |     if ($date < time() - (3600 * 24 * 48)) { | ||||||
|  |         api_err("The date is too old"); | ||||||
|  |     } | ||||||
|  |     if ($date > time() + 86400) { | ||||||
|  |         api_err("Invalid Date"); | ||||||
|  |     } | ||||||
|  |     | ||||||
|     $message=$data['message']; |     $message=$data['message']; | ||||||
|     if(strlen($message)>128) api_err("The message must be less than 128 chars"); |     if (strlen($message) > 128) { | ||||||
|     $val=$data['val']+0; |         api_err("The message must be less than 128 chars"); | ||||||
|     $fee=$val*0.0025; |     } | ||||||
|     if($fee<0.00000001) $fee=0.00000001; |     $val = $data['val'] + 0; | ||||||
|  |     $fee = $val * 0.0025; | ||||||
|  |     if ($fee < 0.00000001) { | ||||||
|  |         $fee = 0.00000001; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     if($fee>10&&$current['height']>10800) $fee=10; //10800 |     if ($fee > 10 && $current['height'] > 10800) { | ||||||
|     if($val<0.00000001) api_err("Invalid value"); |         $fee = 10; //10800 | ||||||
|  |     } | ||||||
|  |     if ($val < 0.00000001) { | ||||||
|  |         api_err("Invalid value"); | ||||||
|  |     } | ||||||
|      |      | ||||||
|     if($version<1) $version=1; |     // set alias | ||||||
|  |     if ($version==3) { | ||||||
|  |         $fee=10; | ||||||
|  |         $message = san($message); | ||||||
|  |         $message=strtoupper($message); | ||||||
|  |         if (!$acc->free_alias($message)) { | ||||||
|  |             api_err("Invalid alias"); | ||||||
|  |         } | ||||||
|  |         if ($acc->has_alias($public_key)) { | ||||||
|  |             api_err("This account already has an alias"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $val=number_format($val,8,'.',''); |     if ($version>=100&&$version<110) { | ||||||
|     $fee=number_format($fee,8,'.',''); |         if ($version==100) { | ||||||
|  |             $message=preg_replace("/[^0-9\.]/", "", $message); | ||||||
|  |             if (!filter_var($message, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { | ||||||
|  |                 api_err("Invalid Node IP - $message !"); | ||||||
|  |             } | ||||||
|  |             $val=100000; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $val = number_format($val, 8, '.', ''); | ||||||
|  |     $fee = number_format($fee, 8, '.', ''); | ||||||
|  |  | ||||||
|  |  | ||||||
|     if(empty($public_key)&&empty($private_key)) api_err("Either the private key or the public key must be sent"); |     if (empty($public_key) && empty($private_key)) { | ||||||
|  |         api_err("Either the private key or the public key must be sent"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|      |     if (empty($private_key) && empty($signature)) { | ||||||
|     if(empty($private_key)&&empty($signature)) api_err("Either the private_key or the signature must be sent"); |         api_err("Either the private_key or the signature must be sent"); | ||||||
|     if(empty($public_key)) |     } | ||||||
|     { |     if (empty($public_key)) { | ||||||
|      |         $pk = coin2pem($private_key, true); | ||||||
|         $pk=coin2pem($private_key,true); |         $pkey = openssl_pkey_get_private($pk); | ||||||
|         $pkey=openssl_pkey_get_private($pk); |  | ||||||
|         $pub = openssl_pkey_get_details($pkey); |         $pub = openssl_pkey_get_details($pkey); | ||||||
|         $public_key= pem2coin($pub['key']); |         $public_key = pem2coin($pub['key']); | ||||||
|      |  | ||||||
|     } |     } | ||||||
|     $transaction=array("val"=>$val, "fee"=>$fee, "dst"=>$dst, "public_key"=>$public_key,"date"=>$date, "version"=>$version,"message"=>$message, "signature"=>$signature); |     $transaction = [ | ||||||
|      |         "val"        => $val, | ||||||
|     if(!empty($private_key)){ |         "fee"        => $fee, | ||||||
|          |         "dst"        => $dst, | ||||||
|             $signature=$trx->sign($transaction, $private_key); |         "public_key" => $public_key, | ||||||
|             $transaction['signature']=$signature; |         "date"       => $date, | ||||||
|  |         "version"    => $version, | ||||||
|  |         "message"    => $message, | ||||||
|  |         "signature"  => $signature, | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     if (!empty($private_key)) { | ||||||
|  |         $signature = $trx->sign($transaction, $private_key); | ||||||
|  |         $transaction['signature'] = $signature; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     $hash=$trx->hash($transaction); |     $hash = $trx->hash($transaction); | ||||||
|     $transaction['id']=$hash; |     $transaction['id'] = $hash; | ||||||
|  |  | ||||||
|  |  | ||||||
|     |     if (!$trx->check($transaction)) { | ||||||
|     if(!$trx->check($transaction)) api_err("Transaction signature failed"); |         api_err("Transaction signature failed"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $res = $db->single("SELECT COUNT(1) FROM mempool WHERE id=:id", [":id" => $hash]); | ||||||
|  |     if ($res != 0) { | ||||||
|  |         api_err("The transaction is already in mempool"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $res = $db->single("SELECT COUNT(1) FROM transactions WHERE id=:id", [":id" => $hash]); | ||||||
|  |     if ($res != 0) { | ||||||
|  |         api_err("The transaction is already in a block"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM mempool WHERE id=:id",array(":id"=>$hash)); |     $src = $acc->get_address($public_key); | ||||||
|     if($res!=0) api_err("The transaction is already in mempool"); |     $transaction['src'] = $src; | ||||||
|      |     $balance = $db->single("SELECT balance FROM accounts WHERE id=:id", [":id" => $src]); | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$hash)); |     if ($balance < $val + $fee) { | ||||||
|     if($res!=0) api_err("The transaction is already in a block"); |         api_err("Not enough funds"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|      |     $memspent = $db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:src", [":src" => $src]); | ||||||
|     $src=$acc->get_address($public_key); |     if ($balance - $memspent < $val + $fee) { | ||||||
|     $transaction['src']=$src; |         api_err("Not enough funds (mempool)"); | ||||||
|     $balance=$db->single("SELECT balance FROM accounts WHERE id=:id",array(":id"=>$src)); |     } | ||||||
|     if($balance<$val+$fee) api_err("Not enough funds"); |  | ||||||
|      |  | ||||||
|      |  | ||||||
|     $memspent=$db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:src",array(":src"=>$src)); |  | ||||||
|     if($balance-$memspent<$val+$fee) api_err("Not enough funds (mempool)"); |  | ||||||
|      |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     $trx->add_mempool($transaction, "local"); |     $trx->add_mempool($transaction, "local"); | ||||||
|     system("php propagate.php transaction $hash &>/dev/null &"); |     system("php propagate.php transaction $hash > /dev/null 2>&1  &"); | ||||||
|     api_echo($hash); |     api_echo($hash); | ||||||
| } elseif($q=="mempoolSize"){ | } elseif ($q == "mempoolSize") { | ||||||
| /** |     /** | ||||||
|      * @api {get} /api.php?q=mempoolSize  15. mempoolSize |      * @api {get} /api.php?q=mempoolSize  15. mempoolSize | ||||||
|      * @apiName mempoolSize |      * @apiName mempoolSize | ||||||
|      * @apiGroup API |      * @apiGroup API | ||||||
| @@ -479,10 +571,104 @@ elseif($q=="getTransactions"){ | |||||||
|      * @apiSuccess {numeric} data  Number of mempool transactions |      * @apiSuccess {numeric} data  Number of mempool transactions | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM mempool"); |     $res = $db->single("SELECT COUNT(1) FROM mempool"); | ||||||
|     api_echo($res); |     api_echo($res); | ||||||
|  | } elseif ($q == 'randomNumber') { | ||||||
|  |     /** | ||||||
|  |      * @api {get} /api.php?q=randomNumber 16. randomNumber | ||||||
|  |      * @apiName randomNumber | ||||||
|  |      * @apiGroup API | ||||||
|  |      * @apiDescription Returns a random number based on an ARO block id. | ||||||
|  |      * | ||||||
|  |      * @apiParam {numeric} height The height of the block on which the random number will be based on (should be a future block when starting) | ||||||
|  |      * @apiParam {numeric} min Minimum number (default 1) | ||||||
|  |      * @apiParam {numeric} max Maximum number | ||||||
|  |      * @apiParam {string} seed A seed to generate different numbers for each use cases. | ||||||
|  |      * @apiSuccess {numeric} data  The random number | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     $height = san($_GET['height']); | ||||||
|  |     $max = intval($_GET['max']); | ||||||
|  |     if (empty($_GET['min'])) { | ||||||
|  |         $min = 1; | ||||||
|  |     } else { | ||||||
|  |         $min = intval($_GET['min']); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $blk = $db->single("SELECT id FROM blocks WHERE height=:h", [":h" => $height]); | ||||||
|  |     if ($blk === false) { | ||||||
|  |         api_err("Unknown block. Future?"); | ||||||
|  |     } | ||||||
|  |     $base = hash("sha256", $blk.$_GET['seed']); | ||||||
|  |  | ||||||
|  |     $seed1 = hexdec(substr($base, 0, 12)); | ||||||
|  |     // generate random numbers based on the seed | ||||||
|  |     mt_srand($seed1, MT_RAND_MT19937); | ||||||
|  |     $res = mt_rand($min, $max); | ||||||
|  |     api_echo($res); | ||||||
|  | } elseif ($q == "checkSignature") { | ||||||
|  |     /** | ||||||
|  |      * @api {get} /api.php?q=checkSignature  17. checkSignature | ||||||
|  |      * @apiName checkSignature | ||||||
|  |      * @apiGroup API | ||||||
|  |      * @apiDescription Checks a signature against a public key | ||||||
|  |      * | ||||||
|  |      * @apiParam {string} [public_key] Public key | ||||||
|  |      * @apiParam {string} [signature] signature | ||||||
|  |      * @apiParam {string} [data] signed data | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @apiSuccess {boolean} data true or false | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     $public_key=san($data['public_key']); | ||||||
|  |     $signature=san($data['signature']); | ||||||
|  |     $data=$data['data']; | ||||||
|  |      | ||||||
|  |     api_echo(ec_verify($data, $signature, $public_key)); | ||||||
|  | } elseif ($q == "masternodes") { | ||||||
|  |     /** | ||||||
|  |      * @api {get} /api.php?q=masternodes  18. masternodes | ||||||
|  |      * @apiName masternodes | ||||||
|  |      * @apiGroup API | ||||||
|  |      * @apiDescription Returns all the masternode data | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @apiSuccess {boolean} data masternode date | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     $res=$db->run("SELECT * FROM masternode"); | ||||||
|  |     api_echo($res); | ||||||
|  | } elseif ($q == "getAlias") { | ||||||
|  |     /** | ||||||
|  |      * @api {get} /api.php?q=getAlias  189. getAlias | ||||||
|  |      * @apiName getAlias | ||||||
|  |      * @apiGroup API | ||||||
|  |      * @apiDescription Returns the alias of an account | ||||||
|  |      * | ||||||
|  |      * @apiParam {string} [public_key] Public key | ||||||
|  |      * @apiParam {string} [account] Account id / address | ||||||
|  |      * | ||||||
|  |      * | ||||||
|  |      * @apiSuccess {string} data alias | ||||||
|  |      */ | ||||||
|  |      | ||||||
|  |     $public_key = $data['public_key']; | ||||||
|  |     $account = $data['account']; | ||||||
|  |     if (!empty($public_key) && strlen($public_key) < 32) { | ||||||
|  |         api_err("Invalid public key"); | ||||||
|  |     } | ||||||
|  |     if (!empty($public_key)) { | ||||||
|  |         $account = $acc->get_address($public_key); | ||||||
|  |     } | ||||||
|  |    | ||||||
|  |     if (empty($account)) { | ||||||
|  |         api_err("Invalid account id"); | ||||||
|  |     } | ||||||
|  |     $account = san($account); | ||||||
|  |      | ||||||
|  |     api_echo($acc->account2alias($account)); | ||||||
| } else { | } else { | ||||||
|     api_err("Invalid request"); |     api_err("Invalid request"); | ||||||
|  } | } | ||||||
| ?> |  | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | { | ||||||
|  |     "name": "arionum/node", | ||||||
|  |     "description": "The Arionum (ARO) cryptocurrency node.", | ||||||
|  |     "license": "MIT", | ||||||
|  |     "require": { | ||||||
|  |         "php": "^7.2", | ||||||
|  |         "ext-bcmath": "*", | ||||||
|  |         "ext-gmp": "*", | ||||||
|  |         "ext-openssl": "*", | ||||||
|  |         "ext-pdo": "*" | ||||||
|  |     }, | ||||||
|  |     "require-dev": { | ||||||
|  |         "squizlabs/php_codesniffer": "^3.2" | ||||||
|  |     }, | ||||||
|  |     "scripts": { | ||||||
|  |         "check-style": "phpcs -p -l --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 . include", | ||||||
|  |         "fix-style": "phpcbf -p -l --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 . include" | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										204
									
								
								doc/api_data.js
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								doc/api_data.js
									
									
									
									
									
								
							| @@ -101,6 +101,57 @@ define({ "api": [ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=checkSignature", | ||||||
|  |     "title": "17. checkSignature", | ||||||
|  |     "name": "checkSignature", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Checks a signature against a public key</p>", | ||||||
|  |     "parameter": { | ||||||
|  |       "fields": { | ||||||
|  |         "Parameter": [ | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "public_key", | ||||||
|  |             "description": "<p>Public key</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "signature", | ||||||
|  |             "description": "<p>signature</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>signed data</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "boolean", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>true or false</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=currentBlock", |     "url": "/api.php?q=currentBlock", | ||||||
| @@ -249,6 +300,50 @@ define({ "api": [ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=getAlias", | ||||||
|  |     "title": "189. getAlias", | ||||||
|  |     "name": "getAlias", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Returns the alias of an account</p>", | ||||||
|  |     "parameter": { | ||||||
|  |       "fields": { | ||||||
|  |         "Parameter": [ | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "public_key", | ||||||
|  |             "description": "<p>Public key</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "account", | ||||||
|  |             "description": "<p>Account id / address</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>alias</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=getBalance", |     "url": "/api.php?q=getBalance", | ||||||
| @@ -272,6 +367,13 @@ define({ "api": [ | |||||||
|             "optional": true, |             "optional": true, | ||||||
|             "field": "account", |             "field": "account", | ||||||
|             "description": "<p>Account id / address</p>" |             "description": "<p>Account id / address</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "alias", | ||||||
|  |             "description": "<p>alias</p>" | ||||||
|           } |           } | ||||||
|         ] |         ] | ||||||
|       } |       } | ||||||
| @@ -420,7 +522,7 @@ define({ "api": [ | |||||||
|             "group": "Success 200", |             "group": "Success 200", | ||||||
|             "type": "numeric", |             "type": "numeric", | ||||||
|             "optional": false, |             "optional": false, | ||||||
|             "field": "confirmation", |             "field": "confirmations", | ||||||
|             "description": "<p>Number of confirmations</p>" |             "description": "<p>Number of confirmations</p>" | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
| @@ -865,6 +967,30 @@ define({ "api": [ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=masternodes", | ||||||
|  |     "title": "18. masternodes", | ||||||
|  |     "name": "masternodes", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Returns all the masternode data</p>", | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "boolean", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>masternode date</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=mempoolSize", |     "url": "/api.php?q=mempoolSize", | ||||||
| @@ -889,6 +1015,64 @@ define({ "api": [ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=randomNumber", | ||||||
|  |     "title": "16. randomNumber", | ||||||
|  |     "name": "randomNumber", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Returns a random number based on an ARO block id.</p>", | ||||||
|  |     "parameter": { | ||||||
|  |       "fields": { | ||||||
|  |         "Parameter": [ | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "height", | ||||||
|  |             "description": "<p>The height of the block on which the random number will be based on (should be a future block when starting)</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "min", | ||||||
|  |             "description": "<p>Minimum number (default 1)</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "max", | ||||||
|  |             "description": "<p>Maximum number</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "seed", | ||||||
|  |             "description": "<p>A seed to generate different numbers for each use cases.</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>The random number</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=send", |     "url": "/api.php?q=send", | ||||||
| @@ -1211,6 +1395,24 @@ define({ "api": [ | |||||||
|     "filename": "./util.php", |     "filename": "./util.php", | ||||||
|     "groupTitle": "UTIL" |     "groupTitle": "UTIL" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "php util.php", | ||||||
|  |     "url": "clean-blacklist", | ||||||
|  |     "title": "Clean-Blacklist", | ||||||
|  |     "name": "clean_blacklist", | ||||||
|  |     "group": "UTIL", | ||||||
|  |     "description": "<p>Removes all the peers from blacklist</p>", | ||||||
|  |     "examples": [ | ||||||
|  |       { | ||||||
|  |         "title": "Example usage:", | ||||||
|  |         "content": "php util.php clean-blacklist", | ||||||
|  |         "type": "cli" | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./util.php", | ||||||
|  |     "groupTitle": "UTIL" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "php util.php", |     "type": "php util.php", | ||||||
|     "url": "current", |     "url": "current", | ||||||
|   | |||||||
| @@ -101,6 +101,57 @@ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=checkSignature", | ||||||
|  |     "title": "17. checkSignature", | ||||||
|  |     "name": "checkSignature", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Checks a signature against a public key</p>", | ||||||
|  |     "parameter": { | ||||||
|  |       "fields": { | ||||||
|  |         "Parameter": [ | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "public_key", | ||||||
|  |             "description": "<p>Public key</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "signature", | ||||||
|  |             "description": "<p>signature</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>signed data</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "boolean", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>true or false</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=currentBlock", |     "url": "/api.php?q=currentBlock", | ||||||
| @@ -249,6 +300,50 @@ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=getAlias", | ||||||
|  |     "title": "189. getAlias", | ||||||
|  |     "name": "getAlias", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Returns the alias of an account</p>", | ||||||
|  |     "parameter": { | ||||||
|  |       "fields": { | ||||||
|  |         "Parameter": [ | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "public_key", | ||||||
|  |             "description": "<p>Public key</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "account", | ||||||
|  |             "description": "<p>Account id / address</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>alias</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=getBalance", |     "url": "/api.php?q=getBalance", | ||||||
| @@ -272,6 +367,13 @@ | |||||||
|             "optional": true, |             "optional": true, | ||||||
|             "field": "account", |             "field": "account", | ||||||
|             "description": "<p>Account id / address</p>" |             "description": "<p>Account id / address</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": true, | ||||||
|  |             "field": "alias", | ||||||
|  |             "description": "<p>alias</p>" | ||||||
|           } |           } | ||||||
|         ] |         ] | ||||||
|       } |       } | ||||||
| @@ -420,7 +522,7 @@ | |||||||
|             "group": "Success 200", |             "group": "Success 200", | ||||||
|             "type": "numeric", |             "type": "numeric", | ||||||
|             "optional": false, |             "optional": false, | ||||||
|             "field": "confirmation", |             "field": "confirmations", | ||||||
|             "description": "<p>Number of confirmations</p>" |             "description": "<p>Number of confirmations</p>" | ||||||
|           }, |           }, | ||||||
|           { |           { | ||||||
| @@ -865,6 +967,30 @@ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=masternodes", | ||||||
|  |     "title": "18. masternodes", | ||||||
|  |     "name": "masternodes", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Returns all the masternode data</p>", | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "boolean", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>masternode date</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=mempoolSize", |     "url": "/api.php?q=mempoolSize", | ||||||
| @@ -889,6 +1015,64 @@ | |||||||
|     "filename": "./api.php", |     "filename": "./api.php", | ||||||
|     "groupTitle": "API" |     "groupTitle": "API" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "get", | ||||||
|  |     "url": "/api.php?q=randomNumber", | ||||||
|  |     "title": "16. randomNumber", | ||||||
|  |     "name": "randomNumber", | ||||||
|  |     "group": "API", | ||||||
|  |     "description": "<p>Returns a random number based on an ARO block id.</p>", | ||||||
|  |     "parameter": { | ||||||
|  |       "fields": { | ||||||
|  |         "Parameter": [ | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "height", | ||||||
|  |             "description": "<p>The height of the block on which the random number will be based on (should be a future block when starting)</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "min", | ||||||
|  |             "description": "<p>Minimum number (default 1)</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "max", | ||||||
|  |             "description": "<p>Maximum number</p>" | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             "group": "Parameter", | ||||||
|  |             "type": "string", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "seed", | ||||||
|  |             "description": "<p>A seed to generate different numbers for each use cases.</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "success": { | ||||||
|  |       "fields": { | ||||||
|  |         "Success 200": [ | ||||||
|  |           { | ||||||
|  |             "group": "Success 200", | ||||||
|  |             "type": "numeric", | ||||||
|  |             "optional": false, | ||||||
|  |             "field": "data", | ||||||
|  |             "description": "<p>The random number</p>" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./api.php", | ||||||
|  |     "groupTitle": "API" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "get", |     "type": "get", | ||||||
|     "url": "/api.php?q=send", |     "url": "/api.php?q=send", | ||||||
| @@ -1211,6 +1395,24 @@ | |||||||
|     "filename": "./util.php", |     "filename": "./util.php", | ||||||
|     "groupTitle": "UTIL" |     "groupTitle": "UTIL" | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "type": "php util.php", | ||||||
|  |     "url": "clean-blacklist", | ||||||
|  |     "title": "Clean-Blacklist", | ||||||
|  |     "name": "clean_blacklist", | ||||||
|  |     "group": "UTIL", | ||||||
|  |     "description": "<p>Removes all the peers from blacklist</p>", | ||||||
|  |     "examples": [ | ||||||
|  |       { | ||||||
|  |         "title": "Example usage:", | ||||||
|  |         "content": "php util.php clean-blacklist", | ||||||
|  |         "type": "cli" | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     "version": "0.0.0", | ||||||
|  |     "filename": "./util.php", | ||||||
|  |     "groupTitle": "UTIL" | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "type": "php util.php", |     "type": "php util.php", | ||||||
|     "url": "current", |     "url": "current", | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ define({ | |||||||
|   "apidoc": "0.3.0", |   "apidoc": "0.3.0", | ||||||
|   "generator": { |   "generator": { | ||||||
|     "name": "apidoc", |     "name": "apidoc", | ||||||
|     "time": "2018-02-22T16:13:41.713Z", |     "time": "2018-08-05T21:17:14.214Z", | ||||||
|     "url": "http://apidocjs.com", |     "url": "http://apidocjs.com", | ||||||
|     "version": "0.17.6" |     "version": "0.17.6" | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
|   "apidoc": "0.3.0", |   "apidoc": "0.3.0", | ||||||
|   "generator": { |   "generator": { | ||||||
|     "name": "apidoc", |     "name": "apidoc", | ||||||
|     "time": "2018-02-22T16:13:41.713Z", |     "time": "2018-08-05T21:17:14.214Z", | ||||||
|     "url": "http://apidocjs.com", |     "url": "http://apidocjs.com", | ||||||
|     "version": "0.17.6" |     "version": "0.17.6" | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,51 +1,64 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| class Account { | class Account | ||||||
| 	 | { | ||||||
| 	 |  | ||||||
|     // inserts the account in the DB and updates the public key if empty |     // inserts the account in the DB and updates the public key if empty | ||||||
| 	public function add($public_key, $block){ |     public function add($public_key, $block) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
| 		$id=$this->get_address($public_key); |         $id = $this->get_address($public_key); | ||||||
| 		$bind=array(":id"=>$id, ":public_key"=>$public_key, ":block"=>$block,":public_key2"=>$public_key ); |         $bind = [":id" => $id, ":public_key" => $public_key, ":block" => $block, ":public_key2" => $public_key]; | ||||||
|  |  | ||||||
| 		$db->run("INSERT INTO accounts SET id=:id, public_key=:public_key, block=:block, balance=0 ON DUPLICATE KEY UPDATE public_key=if(public_key='',:public_key2,public_key)",$bind); |         $db->run( | ||||||
|  |             "INSERT INTO accounts SET id=:id, public_key=:public_key, block=:block, balance=0 ON DUPLICATE KEY UPDATE public_key=if(public_key='',:public_key2,public_key)", | ||||||
|  |             $bind | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // inserts just the account without public key |     // inserts just the account without public key | ||||||
| 	public function add_id($id, $block){ |     public function add_id($id, $block) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
| 		$bind=array(":id"=>$id, ":block"=>$block); |         $bind = [":id" => $id, ":block" => $block]; | ||||||
| 		$db->run("INSERT ignore INTO accounts SET id=:id, public_key='', block=:block, balance=0",$bind); |         $db->run("INSERT ignore INTO accounts SET id=:id, public_key='', block=:block, balance=0", $bind); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // generates Account's address from the public key |     // generates Account's address from the public key | ||||||
| 	public function get_address($hash){ |     public function get_address($hash) | ||||||
|  |     { | ||||||
|         //broken base58 addresses, which are block winners, missing the first 0 bytes from the address. |         //broken base58 addresses, which are block winners, missing the first 0 bytes from the address. | ||||||
|                 if($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwCpspGFGQSaF9yVGLamBgymdf8M7FafghmP3oPzQb3W4PZsZApVa41uQrrHRVBH5p9bdoz7c6XeRQHK2TkzWR45e') return '22SoB29oyq2JhMxtBbesL7JioEYytyC6VeFmzvBH6fRQrueSvyZfEXR5oR7ajSQ9mLERn6JKU85EAbVDNChke32'; |         if ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwCpspGFGQSaF9yVGLamBgymdf8M7FafghmP3oPzQb3W4PZsZApVa41uQrrHRVBH5p9bdoz7c6XeRQHK2TkzWR45e') { | ||||||
|                 elseif($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCzbRyyz5oDNDKhk5jyjg4caRjkbqegMZMrUkuBjVMuYcVfPyc3aKuLmPHS4QEDjCrNGks7Z5oPxwv4yXSv7WJnkbL') return 'AoFnv3SLujrJSa2J7FDTADGD7Eb9kv3KtNAp7YVYQEUPcLE6cC6nLvvhVqcVnRLYF5BFF38C1DyunUtmfJBhyU'; |             return '22SoB29oyq2JhMxtBbesL7JioEYytyC6VeFmzvBH6fRQrueSvyZfEXR5oR7ajSQ9mLERn6JKU85EAbVDNChke32'; | ||||||
|                 elseif($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyradtFFJoaYB4QdcXyBGSXjiASMMnofsT4f5ZNaxTnNDJt91ubemn3LzgKrfQh8CBpqaphkVNoRLub2ctdMnrzG1') return 'RncXQuc7S7aWkvTUJSHEFvYoV3ntAf7bfxEHjSiZNBvQV37MzZtg44L7GAV7szZ3uV8qWqikBewa3piZMqzBqm'; |         } elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCzbRyyz5oDNDKhk5jyjg4caRjkbqegMZMrUkuBjVMuYcVfPyc3aKuLmPHS4QEDjCrNGks7Z5oPxwv4yXSv7WJnkbL') { | ||||||
|                 elseif($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyjKMBY4ihhJ2G25EVezg7KnoCBVbhdvWfqzNA4LC5R7wgu3VNfJgvqkCq9sKKZcCoCpX6Qr9cN882MoXsfGTvZoj') return 'Rq53oLzpCrb4BdJZ1jqQ2zsixV2ukxVdM4H9uvUhCGJCz1q2wagvuXV4hC6UVwK7HqAt1FenukzhVXgzyG1y32'; |             return 'AoFnv3SLujrJSa2J7FDTADGD7Eb9kv3KtNAp7YVYQEUPcLE6cC6nLvvhVqcVnRLYF5BFF38C1DyunUtmfJBhyU'; | ||||||
|  |         } elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyradtFFJoaYB4QdcXyBGSXjiASMMnofsT4f5ZNaxTnNDJt91ubemn3LzgKrfQh8CBpqaphkVNoRLub2ctdMnrzG1') { | ||||||
|  |             return 'RncXQuc7S7aWkvTUJSHEFvYoV3ntAf7bfxEHjSiZNBvQV37MzZtg44L7GAV7szZ3uV8qWqikBewa3piZMqzBqm'; | ||||||
|  |         } elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyjKMBY4ihhJ2G25EVezg7KnoCBVbhdvWfqzNA4LC5R7wgu3VNfJgvqkCq9sKKZcCoCpX6Qr9cN882MoXsfGTvZoj') { | ||||||
|  |             return 'Rq53oLzpCrb4BdJZ1jqQ2zsixV2ukxVdM4H9uvUhCGJCz1q2wagvuXV4hC6UVwK7HqAt1FenukzhVXgzyG1y32'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // hashes 9 times in sha512 (binary) and encodes in base58 |         // hashes 9 times in sha512 (binary) and encodes in base58 | ||||||
| 	        for($i=0;$i<9;$i++) $hash=hash('sha512',$hash, true);					 |         for ($i = 0; $i < 9; | ||||||
| 		return base58_encode($hash); |              $i++) { | ||||||
|         	 |             $hash = hash('sha512', $hash, true); | ||||||
|  |         } | ||||||
|  |         return base58_encode($hash); | ||||||
|     } |     } | ||||||
| 	// checks the ecdsa secp256k1 signature for a specific public key |  | ||||||
| 	public function check_signature($data, $signature, $public_key){ |  | ||||||
|  |  | ||||||
| 		return ec_verify($data ,$signature, $public_key); |     // checks the ecdsa secp256k1 signature for a specific public key | ||||||
|  |     public function check_signature($data, $signature, $public_key) | ||||||
|  |     { | ||||||
|  |         return ec_verify($data, $signature, $public_key); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // generates a new account and a public/private key pair |     // generates a new account and a public/private key pair | ||||||
| 	public function generate_account(){ |     public function generate_account() | ||||||
|  |     { | ||||||
|         // using secp256k1 curve for ECDSA |         // using secp256k1 curve for ECDSA | ||||||
| 		$args = array( |         $args = [ | ||||||
|             "curve_name"       => "secp256k1", |             "curve_name"       => "secp256k1", | ||||||
|             "private_key_type" => OPENSSL_KEYTYPE_EC, |             "private_key_type" => OPENSSL_KEYTYPE_EC, | ||||||
| 		); |         ]; | ||||||
|  |  | ||||||
|         // generates a new key pair |         // generates a new key pair | ||||||
|         $key1 = openssl_pkey_new($args); |         $key1 = openssl_pkey_new($args); | ||||||
| @@ -54,109 +67,243 @@ class Account { | |||||||
|         openssl_pkey_export($key1, $pvkey); |         openssl_pkey_export($key1, $pvkey); | ||||||
|  |  | ||||||
|         // converts the PEM to a base58 format |         // converts the PEM to a base58 format | ||||||
| 		$private_key= pem2coin($pvkey); |         $private_key = pem2coin($pvkey); | ||||||
|  |  | ||||||
|         // exports the private key encoded as PEM |         // exports the private key encoded as PEM | ||||||
|         $pub = openssl_pkey_get_details($key1); |         $pub = openssl_pkey_get_details($key1); | ||||||
|  |  | ||||||
|         // converts the PEM to a base58 format |         // converts the PEM to a base58 format | ||||||
| 		$public_key= pem2coin($pub['key']); |         $public_key = pem2coin($pub['key']); | ||||||
|  |  | ||||||
|         // generates the account's address based on the public key |         // generates the account's address based on the public key | ||||||
| 		$address=$this->get_address($public_key); |         $address = $this->get_address($public_key); | ||||||
| 		return array("address"=>$address, "public_key"=>$public_key,"private_key"=>$private_key); |         return ["address" => $address, "public_key" => $public_key, "private_key" => $private_key]; | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // check the validity of a base58 encoded key. At the moment, it checks only the characters to be base58. |     // check the validity of a base58 encoded key. At the moment, it checks only the characters to be base58. | ||||||
| 	public function valid_key($id){ |     public function valid_key($id) | ||||||
|  |     { | ||||||
|         $chars = str_split("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); |         $chars = str_split("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); | ||||||
| 		for($i=0;$i<strlen($id);$i++) if(!in_array($id[$i],$chars)) return false; |         for ($i = 0; $i < strlen($id); | ||||||
|  |              $i++) { | ||||||
|  |             if (!in_array($id[$i], $chars)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|  |  | ||||||
|     } |     } | ||||||
| 	// check the validity of an address. At the moment, it checks only the characters to be base58 and the length to be >=70 and <=128. |     //check alias validity | ||||||
| 	public function valid($id){ |     public function free_alias($id) | ||||||
| 		if(strlen($id)<70||strlen($id)>128) return false; |     { | ||||||
| 		$chars = str_split("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); |         global $db; | ||||||
| 		for($i=0;$i<strlen($id);$i++) if(!in_array($id[$i],$chars)) return false; |         $orig=$id; | ||||||
|  |         $id=strtoupper($id); | ||||||
|  |         $id = san($id); | ||||||
|  |         if (strlen($id)<4||strlen($id)>25) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if($orig!=$id){ | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|          |          | ||||||
|  |         if ($db->single("SELECT COUNT(1) FROM accounts WHERE alias=:alias", [":alias"=>$id])==0) { | ||||||
|             return true; |             return true; | ||||||
|  |  | ||||||
| 	} |  | ||||||
| 	// returns the current account balance |  | ||||||
| 	public function balance($id){ |  | ||||||
| 		global $db; |  | ||||||
| 		$res=$db->single("SELECT balance FROM accounts WHERE id=:id",array(":id"=>$id)); |  | ||||||
| 		if($res===false) $res="0.00000000"; |  | ||||||
| 		return number_format($res,8,".",""); |  | ||||||
| 	} |  | ||||||
| 	// returns the account balance - any pending debits from the mempool |  | ||||||
| 	public function pending_balance($id){ |  | ||||||
| 		global $db; |  | ||||||
| 		$res=$db->single("SELECT balance FROM accounts WHERE id=:id",array(":id"=>$id)); |  | ||||||
| 		if($res===false) $res="0.00000000"; |  | ||||||
|  |  | ||||||
| 		// if the original balance is 0, no mempool transactions are possible |  | ||||||
| 		if($res=="0.00000000") return $res; |  | ||||||
| 		$mem=$db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:id",array(":id"=>$id)); |  | ||||||
| 		$rez=$res-$mem; |  | ||||||
| 		return number_format($rez,8,".",""); |  | ||||||
| 		 |  | ||||||
| 	} |  | ||||||
| 	// returns all the transactions of a specific address |  | ||||||
| 	public function get_transactions($id,$limit=100){ |  | ||||||
| 		global $db; |  | ||||||
| 		$block=new Block; |  | ||||||
|         	$current=$block->current(); |  | ||||||
| 		$public_key=$this->public_key($id); |  | ||||||
| 		$limit=intval($limit); |  | ||||||
| 		if($limit>100||$limit<1) $limit=100; |  | ||||||
| 		$res=$db->run("SELECT * FROM transactions WHERE dst=:dst or public_key=:src ORDER by height DESC LIMIT :limit",array(":src"=>$public_key, ":dst"=>$id, ":limit"=>$limit)); |  | ||||||
| 		 |  | ||||||
| 		$transactions=array(); |  | ||||||
| 		foreach($res as $x){ |  | ||||||
| 			$trans=array("block"=>$x['block'],"height"=>$x['height'], "id"=>$x['id'],"dst"=>$x['dst'],"val"=>$x['val'],"fee"=>$x['fee'],"signature"=>$x['signature'], "message"=>$x['message'],"version"=>$x['version'],"date"=>$x['date'], "public_key"=>$x['public_key']); |  | ||||||
| 			$trans['src']=$this->get_address($x['public_key']); |  | ||||||
| 			$trans['confirmations']=$current['height']-$x['height']; |  | ||||||
| 			 |  | ||||||
| 			// version 0 -> reward transaction, version 1 -> normal transaction |  | ||||||
| 			if($x['version']==0) $trans['type']="mining"; |  | ||||||
| 			elseif($x['version']==1){ |  | ||||||
| 				if($x['dst']==$id) $trans['type']="credit"; |  | ||||||
| 				else $trans['type']="debit"; |  | ||||||
|         } else { |         } else { | ||||||
| 				$trans['type']="other"; |             return false; | ||||||
|         } |         } | ||||||
| 			ksort($trans); |  | ||||||
| 			$transactions[]=$trans; |  | ||||||
|     } |     } | ||||||
| 		return $transactions; |  | ||||||
| 	} |     //check if an account already has an alias | ||||||
| 	// returns the transactions from the mempool |     public function has_alias($public_key){ | ||||||
| 	public function get_mempool_transactions($id){ |  | ||||||
|         global $db; |         global $db; | ||||||
| 		$transactions=array(); |         $public_key=san($public_key); | ||||||
| 		$res=$db->run("SELECT * FROM mempool WHERE src=:src ORDER by height DESC LIMIT 100",array(":src"=>$id, ":dst"=>$id)); |         $res=$db->single("SELECT COUNT(1) FROM accounts WHERE public_key=:public_key AND alias IS NOT NULL",[":public_key"=>$public_key]); | ||||||
| 		foreach($res as $x){ |         if($res!=0) return true; | ||||||
| 			$trans=array("block"=>$x['block'],"height"=>$x['height'], "id"=>$x['id'],"src"=>$x['src'],"dst"=>$x['dst'],"val"=>$x['val'],"fee"=>$x['fee'],"signature"=>$x['signature'], "message"=>$x['message'],"version"=>$x['version'],"date"=>$x['date'], "public_key"=>$x['public_key']); |         else return false; | ||||||
| 			$trans['type']="mempool"; |  | ||||||
| 			// they are unconfirmed, so they will have -1 confirmations. |  | ||||||
| 			$trans['confirmations']=-1; |  | ||||||
| 			ksort($trans); |  | ||||||
| 			$transactions[]=$trans; |  | ||||||
|     } |     } | ||||||
| 		return $transactions; |  | ||||||
| 	} |     //check alias validity | ||||||
| 	// returns the public key for a specific account |     public function valid_alias($id) | ||||||
| 	public function public_key($id){ |     { | ||||||
|         global $db; |         global $db; | ||||||
| 		$res=$db->single("SELECT public_key FROM accounts WHERE id=:id",array(":id"=>$id)); |         $orig=$id; | ||||||
|  |         $banned=["MERCURY","DEVS","DEVELOPMENT", "MARKETING", "MERCURY80","DEVARO", "DEVELOPER","DEVELOPERS","ARODEV", "DONATION","MERCATOX", "OCTAEX", "MERCURY", "ARIONUM", "ESCROW","OKEX","BINANCE","CRYPTOPIA","HUOBI","ITFINEX","HITBTC","UPBIT","COINBASE","KRAKEN","BITSTAMP","BITTREX","POLONIEX"]; | ||||||
|  |         $id=strtoupper($id); | ||||||
|  |         $id = san($id); | ||||||
|  |         if (in_array($id, $banned)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if (strlen($id)<4||strlen($id)>25) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if($orig!=$id){ | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         return $db->single("SELECT COUNT(1) FROM accounts WHERE alias=:alias", [":alias"=>$id]); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //returns the account of an alias | ||||||
|  |     public function alias2account($alias){ | ||||||
|  |         global $db; | ||||||
|  |         $alias=strtoupper($alias); | ||||||
|  |         $res=$db->single("SELECT id FROM accounts WHERE alias=:alias LIMIT 1",[":alias"=>$alias]); | ||||||
|         return $res; |         return $res; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     //returns the alias of an account | ||||||
|  |     public function account2alias($id){ | ||||||
|  |         global $db; | ||||||
|  |         $id=san($id); | ||||||
|  |         $res=$db->single("SELECT alias FROM accounts WHERE id=:id LIMIT 1",[":id"=>$id]); | ||||||
|  |         return $res; | ||||||
|  |     } | ||||||
|  |     // check the validity of an address. At the moment, it checks only the characters to be base58 and the length to be >=70 and <=128. | ||||||
|  |     public function valid($id) | ||||||
|  |     { | ||||||
|  |         if (strlen($id) < 70 || strlen($id) > 128) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         $chars = str_split("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); | ||||||
|  |         for ($i = 0; $i < strlen($id); | ||||||
|  |              $i++) { | ||||||
|  |             if (!in_array($id[$i], $chars)) { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // returns the current account balance | ||||||
|  |     public function balance($id) | ||||||
|  |     { | ||||||
|  |         global $db; | ||||||
|  |         $res = $db->single("SELECT balance FROM accounts WHERE id=:id", [":id" => $id]); | ||||||
|  |         if ($res === false) { | ||||||
|  |             $res = "0.00000000"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return number_format($res, 8, ".", ""); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // returns the account balance - any pending debits from the mempool | ||||||
|  |     public function pending_balance($id) | ||||||
|  |     { | ||||||
|  |         global $db; | ||||||
|  |         $res = $db->single("SELECT balance FROM accounts WHERE id=:id", [":id" => $id]); | ||||||
|  |         if ($res === false) { | ||||||
|  |             $res = "0.00000000"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // if the original balance is 0, no mempool transactions are possible | ||||||
|  |         if ($res == "0.00000000") { | ||||||
|  |             return $res; | ||||||
|  |         } | ||||||
|  |         $mem = $db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:id", [":id" => $id]); | ||||||
|  |         $rez = $res - $mem; | ||||||
|  |         return number_format($rez, 8, ".", ""); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // returns all the transactions of a specific address | ||||||
|  |     public function get_transactions($id, $limit = 100) | ||||||
|  |     { | ||||||
|  |         global $db; | ||||||
|  |         $block = new Block(); | ||||||
|  |         $current = $block->current(); | ||||||
|  |         $public_key = $this->public_key($id); | ||||||
|  |         $limit = intval($limit); | ||||||
|  |         if ($limit > 100 || $limit < 1) { | ||||||
|  |             $limit = 100; | ||||||
|  |         } | ||||||
|  |         $res = $db->run( | ||||||
|  |             "SELECT * FROM transactions WHERE dst=:dst or public_key=:src ORDER by height DESC LIMIT :limit", | ||||||
|  |             [":src" => $public_key, ":dst" => $id, ":limit" => $limit] | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         $transactions = []; | ||||||
|  |         foreach ($res as $x) { | ||||||
|  |             $trans = [ | ||||||
|  |                 "block"      => $x['block'], | ||||||
|  |                 "height"     => $x['height'], | ||||||
|  |                 "id"         => $x['id'], | ||||||
|  |                 "dst"        => $x['dst'], | ||||||
|  |                 "val"        => $x['val'], | ||||||
|  |                 "fee"        => $x['fee'], | ||||||
|  |                 "signature"  => $x['signature'], | ||||||
|  |                 "message"    => $x['message'], | ||||||
|  |                 "version"    => $x['version'], | ||||||
|  |                 "date"       => $x['date'], | ||||||
|  |                 "public_key" => $x['public_key'], | ||||||
|  |             ]; | ||||||
|  |             $trans['src'] = $this->get_address($x['public_key']); | ||||||
|  |             $trans['confirmations'] = $current['height'] - $x['height']; | ||||||
|  |  | ||||||
|  |             // version 0 -> reward transaction, version 1 -> normal transaction | ||||||
|  |             if ($x['version'] == 0) { | ||||||
|  |                 $trans['type'] = "mining"; | ||||||
|  |             } elseif ($x['version'] == 1) { | ||||||
|  |                 if ($x['dst'] == $id) { | ||||||
|  |                     $trans['type'] = "credit"; | ||||||
|  |                 } else { | ||||||
|  |                     $trans['type'] = "debit"; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 $trans['type'] = "other"; | ||||||
|  |             } | ||||||
|  |             ksort($trans); | ||||||
|  |             $transactions[] = $trans; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return $transactions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // returns the transactions from the mempool | ||||||
|  |     public function get_mempool_transactions($id) | ||||||
|  |     { | ||||||
|  |         global $db; | ||||||
|  |         $transactions = []; | ||||||
|  |         $res = $db->run( | ||||||
|  |             "SELECT * FROM mempool WHERE src=:src ORDER by height DESC LIMIT 100", | ||||||
|  |             [":src" => $id, ":dst" => $id] | ||||||
|  |         ); | ||||||
|  |         foreach ($res as $x) { | ||||||
|  |             $trans = [ | ||||||
|  |                 "block"      => $x['block'], | ||||||
|  |                 "height"     => $x['height'], | ||||||
|  |                 "id"         => $x['id'], | ||||||
|  |                 "src"        => $x['src'], | ||||||
|  |                 "dst"        => $x['dst'], | ||||||
|  |                 "val"        => $x['val'], | ||||||
|  |                 "fee"        => $x['fee'], | ||||||
|  |                 "signature"  => $x['signature'], | ||||||
|  |                 "message"    => $x['message'], | ||||||
|  |                 "version"    => $x['version'], | ||||||
|  |                 "date"       => $x['date'], | ||||||
|  |                 "public_key" => $x['public_key'], | ||||||
|  |             ]; | ||||||
|  |             $trans['type'] = "mempool"; | ||||||
|  |             // they are unconfirmed, so they will have -1 confirmations. | ||||||
|  |             $trans['confirmations'] = -1; | ||||||
|  |             ksort($trans); | ||||||
|  |             $transactions[] = $trans; | ||||||
|  |         } | ||||||
|  |         return $transactions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // returns the public key for a specific account | ||||||
|  |     public function public_key($id) | ||||||
|  |     { | ||||||
|  |         global $db; | ||||||
|  |         $res = $db->single("SELECT public_key FROM accounts WHERE id=:id", [":id" => $id]); | ||||||
|  |         return $res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function get_masternode($public_key){ | ||||||
|  |         global $db; | ||||||
|  |         $res = $db->row("SELECT * FROM masternode WHERE public_key=:public_key", [":public_key" => $public_key]); | ||||||
|  |         if(empty($res['public_key'])) return false; | ||||||
|  |         return $res; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										114
									
								
								include/config-sample.inc.php
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										114
									
								
								include/config-sample.inc.php
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,114 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | Database Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // The database DSN | ||||||
|  | $_config['db_connect'] = 'mysql:host=localhost;dbname=ENTER-DB-NAME'; | ||||||
|  |  | ||||||
|  | // The database username | ||||||
|  | $_config['db_user'] = 'ENTER-DB-USER'; | ||||||
|  |  | ||||||
|  | // The database password | ||||||
|  | $_config['db_pass'] = 'ENTER-DB-PASS'; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | General Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Maximum number of connected peers | ||||||
|  | $_config['max_peers'] = 30; | ||||||
|  |  | ||||||
|  | // Enable testnet mode for development | ||||||
|  | $_config['testnet'] = false; | ||||||
|  |  | ||||||
|  | // To avoid any problems if other clones are made | ||||||
|  | $_config['coin'] = 'arionum'; | ||||||
|  |  | ||||||
|  | // Allow others to connect to the node api (if set to false, only the below 'allowed_hosts' are allowed) | ||||||
|  | $_config['public_api'] = true; | ||||||
|  |  | ||||||
|  | // Hosts that are allowed to mine on this node | ||||||
|  | $_config['allowed_hosts'] = [ | ||||||
|  |     '127.0.0.1', | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | Peer Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // The number of peers to send each new transaction to | ||||||
|  | $_config['transaction_propagation_peers'] = 5; | ||||||
|  |  | ||||||
|  | // How many new peers to check from each peer | ||||||
|  | $_config['max_test_peers'] = 5; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | Mempool Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // The maximum transactions to accept from a single peer | ||||||
|  | $_config['peer_max_mempool'] = 100; | ||||||
|  |  | ||||||
|  | // The maximum number of mempool transactions to be rebroadcasted | ||||||
|  | $_config['max_mempool_rebroadcast'] = 5000; | ||||||
|  |  | ||||||
|  | // The number of blocks between rebroadcasting transactions | ||||||
|  | $_config['sanity_rebroadcast_height'] = 30; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | Sanity Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Recheck the last blocks on sanity | ||||||
|  | $_config['sanity_recheck_blocks'] = 10; | ||||||
|  |  | ||||||
|  | // The interval to run the sanity in seconds | ||||||
|  | $_config['sanity_interval'] = 900; | ||||||
|  |  | ||||||
|  | // Enable setting a new hostname (should be used only if you want to change the hostname) | ||||||
|  | $_config['allow_hostname_change'] = false; | ||||||
|  |  | ||||||
|  | // Rebroadcast local transactions when running sanity | ||||||
|  | $_config['sanity_rebroadcast_locals'] = true; | ||||||
|  |  | ||||||
|  | // Get more peers? | ||||||
|  | $_config['get_more_peers']=true; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | Logging Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Enable log output to the specified file | ||||||
|  | $_config['enable_logging'] = false; | ||||||
|  |  | ||||||
|  | // The specified file to write to (this should not be publicly visible) | ||||||
|  | $_config['log_file'] = '/var/log/aro.log'; | ||||||
|  |  | ||||||
|  | // Log verbosity (default 0, maximum 3) | ||||||
|  | $_config['log_verbosity'] = 0; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | | Masternode Configuration | ||||||
|  | |-------------------------------------------------------------------------- | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | // Enable this node as a masternode | ||||||
|  | $_config['masternode'] = false; | ||||||
|  |  | ||||||
|  | // The public key for the masternode | ||||||
|  | $_config['masternode_public_key'] = ''; | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| <?php |  | ||||||
| // Database connection |  | ||||||
| $_config['db_connect']="mysql:host=localhost;dbname=ENTER-DB-NAME"; |  | ||||||
| $_config['db_user']="ENTER-DB-USER"; |  | ||||||
| $_config['db_pass']="ENTER-DB-PASS"; |  | ||||||
|  |  | ||||||
| // Maximum number of connected peers  |  | ||||||
| $_config['max_peers']=30; |  | ||||||
| // Testnet, used for development |  | ||||||
| $_config['testnet']=false; |  | ||||||
| // To avoid any problems if other clones are made |  | ||||||
| $_config['coin']="arionum"; |  | ||||||
| // maximum transactions accepted from a single peer |  | ||||||
| $_config['peer_max_mempool']=100; |  | ||||||
| // maximum mempool transactions to be rebroadcasted |  | ||||||
| $_config['max_mempool_rebroadcast']=5000; |  | ||||||
| // after how many blocks should the transactions be rebroadcasted |  | ||||||
| $_config['sanity_rebroadcast_height']=30; |  | ||||||
| // each new received transaction is sent to X peers |  | ||||||
| $_config['transaction_propagation_peers']=5; |  | ||||||
| // how many new peers to check from each peer. |  | ||||||
| $_config['max_test_peers']=5; |  | ||||||
| // recheck the last blocks on sanity |  | ||||||
| $_config['sanity_recheck_blocks']=10; |  | ||||||
| // allow others to connect to node api. If set to false, only allowed_hosts are allowed |  | ||||||
| $_config['public_api']=true; |  | ||||||
| // hosts allowed to mine on this node |  | ||||||
| $_config['allowed_hosts']=array("127.0.0.1"); |  | ||||||
| // sanity is run every X seconds |  | ||||||
| $_config['sanity_interval']=900; |  | ||||||
| // accept the setting of new hostnames / should be used only if you want to change the hostname |  | ||||||
| $_config['allow_hostname_change']=false; |  | ||||||
| // rebroadcast local transactions on each sanity |  | ||||||
| $_config['sanity_rebroadcast_locals']=true; |  | ||||||
| // write logs to file |  | ||||||
| $_config['enable_logging']=false; |  | ||||||
| // log file, should not be publicly viewable |  | ||||||
| $_config['log_file']="/var/log/aro.log"; |  | ||||||
|  |  | ||||||
| ?> |  | ||||||
| @@ -1,21 +1,26 @@ | |||||||
| <?php | <?php | ||||||
| // a simple wrapper for pdo |  | ||||||
| class db extends PDO { |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Class DB | ||||||
|  |  * | ||||||
|  |  * A simple wrapper for PDO. | ||||||
|  |  */ | ||||||
|  | class DB extends PDO | ||||||
|  | { | ||||||
|     private $error; |     private $error; | ||||||
|     private $sql; |     private $sql; | ||||||
|     private $bind; |     private $bind; | ||||||
|         private $debugger=0; |     private $debugger = 0; | ||||||
|         public $working="yes"; |     public $working = "yes"; | ||||||
|  |  | ||||||
|         public function __construct($dsn, $user="", $passwd="",$debug_level=0) { |     public function __construct($dsn, $user = "", $passwd = "", $debug_level = 0) | ||||||
|                 $options = array( |     { | ||||||
|  |         $options = [ | ||||||
|             PDO::ATTR_PERSISTENT       => true, |             PDO::ATTR_PERSISTENT       => true, | ||||||
|             PDO::ATTR_EMULATE_PREPARES => false, |             PDO::ATTR_EMULATE_PREPARES => false, | ||||||
|                         PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION |             PDO::ATTR_ERRMODE          => PDO::ERRMODE_EXCEPTION, | ||||||
|                 ); |         ]; | ||||||
|                 $this->debugger=$debug_level; |         $this->debugger = $debug_level; | ||||||
|         try { |         try { | ||||||
|             parent::__construct($dsn, $user, $passwd, $options); |             parent::__construct($dsn, $user, $passwd, $options); | ||||||
|         } catch (PDOException $e) { |         } catch (PDOException $e) { | ||||||
| @@ -24,57 +29,65 @@ class db extends PDO { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         private function debug() { |     private function debug() | ||||||
|                         if(!$this->debugger) return; |     { | ||||||
|                         $error = array("Error" => $this->error); |         global $_config; | ||||||
|                         if(!empty($this->sql)) |         if (!$this->debugger) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         $error = ["Error" => $this->error]; | ||||||
|  |         if (!empty($this->sql)) { | ||||||
|             $error["SQL Statement"] = $this->sql; |             $error["SQL Statement"] = $this->sql; | ||||||
|                         if(!empty($this->bind)) |         } | ||||||
|  |         if (!empty($this->bind)) { | ||||||
|             $error["Bind Parameters"] = trim(print_r($this->bind, true)); |             $error["Bind Parameters"] = trim(print_r($this->bind, true)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $backtrace = debug_backtrace(); |         $backtrace = debug_backtrace(); | ||||||
|                         if(!empty($backtrace)) { |         if (!empty($backtrace)) { | ||||||
|                                 foreach($backtrace as $info) { |             foreach ($backtrace as $info) { | ||||||
|                                         if($info["file"] != __FILE__) |                 if ($info["file"] != __FILE__) { | ||||||
|                                                 $error["Backtrace"] = $info["file"] . " at line " . $info["line"]; |                     $error["Backtrace"] = $info["file"]." at line ".$info["line"]; | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         $msg = ""; |         $msg = ""; | ||||||
|                                 $msg .= "SQL Error\n" . str_repeat("-", 50); |         $msg .= "SQL Error\n".str_repeat("-", 50); | ||||||
|                                 foreach($error as $key => $val) |         foreach ($error as $key => $val) { | ||||||
|             $msg .= "\n\n$key:\n$val"; |             $msg .= "\n\n$key:\n$val"; | ||||||
|  |         } | ||||||
|  |  | ||||||
|                         if($this->debugger){  |  | ||||||
|          |          | ||||||
|                                 echo nl2br($msg); |             _log($msg); | ||||||
|          |          | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private function cleanup($bind, $sql = "") | ||||||
|  |     { | ||||||
|  |         if (!is_array($bind)) { | ||||||
|  |             if (!empty($bind)) { | ||||||
|  |                 $bind = [$bind]; | ||||||
|  |             } else { | ||||||
|  |                 $bind = []; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private function cleanup($bind,$sql="") { |         foreach ($bind as $key => $val) { | ||||||
|                         if(!is_array($bind)) { |             if (str_replace($key, "", $sql) == $sql) { | ||||||
|                                 if(!empty($bind)) |                 unset($bind[$key]); | ||||||
|                                         $bind = array($bind); |  | ||||||
|                                 else |  | ||||||
|                                         $bind = array(); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|                         foreach($bind as $key=>$val){ |  | ||||||
|                         if(str_replace($key,"",$sql)==$sql) unset($bind[$key]); |  | ||||||
|         } |         } | ||||||
|         return $bind; |         return $bind; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function single($sql, $bind = "") | ||||||
|  |     { | ||||||
|  |  | ||||||
|         public function single($sql,$bind="")   { |  | ||||||
|         $this->sql = trim($sql); |         $this->sql = trim($sql); | ||||||
|                         $this->bind = $this->cleanup($bind,$sql); |         $this->bind = $this->cleanup($bind, $sql); | ||||||
|         $this->error = ""; |         $this->error = ""; | ||||||
|         try { |         try { | ||||||
|             $pdostmt = $this->prepare($this->sql); |             $pdostmt = $this->prepare($this->sql); | ||||||
|                                 if($pdostmt->execute($this->bind) !== false) { |             if ($pdostmt->execute($this->bind) !== false) { | ||||||
|                 return $pdostmt->fetchColumn(); |                 return $pdostmt->fetchColumn(); | ||||||
|             } |             } | ||||||
|         } catch (PDOException $e) { |         } catch (PDOException $e) { | ||||||
| @@ -84,20 +97,21 @@ class db extends PDO { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public function run($sql, $bind = "") | ||||||
|         public function run($sql, $bind="") { |     { | ||||||
|         $this->sql = trim($sql); |         $this->sql = trim($sql); | ||||||
|                 $this->bind = $this->cleanup($bind,$sql); |         $this->bind = $this->cleanup($bind, $sql); | ||||||
|         $this->error = ""; |         $this->error = ""; | ||||||
|  |  | ||||||
|         try { |         try { | ||||||
|             $pdostmt = $this->prepare($this->sql); |             $pdostmt = $this->prepare($this->sql); | ||||||
|                         if($pdostmt->execute($this->bind) !== false) { |             if ($pdostmt->execute($this->bind) !== false) { | ||||||
|                                 if(preg_match("/^(" . implode("|", array("select", "describe", "pragma")) . ") /i", $this->sql)) |                 if (preg_match("/^(".implode("|", ["select", "describe", "pragma"]).") /i", $this->sql)) { | ||||||
|                     return $pdostmt->fetchAll(PDO::FETCH_ASSOC); |                     return $pdostmt->fetchAll(PDO::FETCH_ASSOC); | ||||||
|                                 elseif(preg_match("/^(" . implode("|", array("delete", "insert", "update")) . ") /i", $this->sql)) |                 } elseif (preg_match("/^(".implode("|", ["delete", "insert", "update"]).") /i", $this->sql)) { | ||||||
|                     return $pdostmt->rowCount(); |                     return $pdostmt->rowCount(); | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
|         } catch (PDOException $e) { |         } catch (PDOException $e) { | ||||||
|             $this->error = $e->getMessage(); |             $this->error = $e->getMessage(); | ||||||
|             $this->debug(); |             $this->debug(); | ||||||
| @@ -105,18 +119,20 @@ class db extends PDO { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         public function row($sql,$bind=""){ |     public function row($sql, $bind = "") | ||||||
|         	$query=$this->run($sql,$bind); |     { | ||||||
|         	if(count($query)==0) return false; |         $query = $this->run($sql, $bind); | ||||||
|         	if(count($query)>1) return $query; |         if (count($query) == 0) { | ||||||
|         	if(count($query)==1){ |             return false; | ||||||
|         		foreach($query as $row) $result=$row; |         } | ||||||
|  |         if (count($query) > 1) { | ||||||
|  |             return $query; | ||||||
|  |         } | ||||||
|  |         if (count($query) == 1) { | ||||||
|  |             foreach ($query as $row) { | ||||||
|  |                 $result = $row; | ||||||
|  |             } | ||||||
|             return $result; |             return $result; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
| @@ -1,71 +1,97 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
|  |  | ||||||
| // simple santization function to accept only alphanumeric characters | // simple santization function to accept only alphanumeric characters | ||||||
| function san($a,$b=""){ | function san($a, $b = "") | ||||||
|  | { | ||||||
|     $a = preg_replace("/[^a-zA-Z0-9".$b."]/", "", $a); |     $a = preg_replace("/[^a-zA-Z0-9".$b."]/", "", $a); | ||||||
|  |  | ||||||
|     return $a; |     return $a; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function san_ip($a) | ||||||
|  | { | ||||||
|  |     $a = preg_replace("/[^a-fA-F0-9\[\]\.\:]/", "", $a); | ||||||
|  |     return $a; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function san_host($a) | ||||||
|  | { | ||||||
|  |     $a = preg_replace("/[^a-zA-Z0-9\.\-\:\/]/", "", $a); | ||||||
|  |     return $a; | ||||||
|  | } | ||||||
|  |  | ||||||
| // api  error and exit | // api  error and exit | ||||||
| function api_err($data){ | function api_err($data) | ||||||
|  | { | ||||||
|     global $_config; |     global $_config; | ||||||
| 	echo json_encode(array("status"=>"error","data"=>$data, "coin"=>$_config['coin'])); |     echo json_encode(["status" => "error", "data" => $data, "coin" => $_config['coin']]); | ||||||
|     exit; |     exit; | ||||||
| } | } | ||||||
|  |  | ||||||
| // api print ok and exit | // api print ok and exit | ||||||
| function api_echo($data){ | function api_echo($data) | ||||||
|  | { | ||||||
|     global $_config; |     global $_config; | ||||||
| 	echo json_encode(array("status"=>"ok","data"=>$data, "coin"=>$_config['coin'])); |     echo json_encode(["status" => "ok", "data" => $data, "coin" => $_config['coin']]); | ||||||
|     exit; |     exit; | ||||||
| } | } | ||||||
|  |  | ||||||
| // log function, shows only in cli atm | // log function, shows only in cli atm | ||||||
| function _log($data){ | function _log($data, $verbosity = 0) | ||||||
| 	$date=date("[Y-m-d H:i:s]"); | { | ||||||
| 	$trace=debug_backtrace();  |     $date = date("[Y-m-d H:i:s]"); | ||||||
| 	$loc=count($trace)-1; |     $trace = debug_backtrace(); | ||||||
| 	$file=substr($trace[$loc]['file'],strrpos($trace[$loc]['file'],"/")+1); |     $loc = count($trace) - 1; | ||||||
|  |     $file = substr($trace[$loc]['file'], strrpos($trace[$loc]['file'], "/") + 1); | ||||||
|  |  | ||||||
| 	$res="$date ".$file.":".$trace[$loc]['line']; |     $res = "$date ".$file.":".$trace[$loc]['line']; | ||||||
|  |  | ||||||
| 	if(!empty($trace[$loc]['class'])) $res.="---".$trace[$loc]['class']; |     if (!empty($trace[$loc]['class'])) { | ||||||
| 	if(!empty($trace[$loc]['function'])&&$trace[$loc]['function']!='_log') $res.='->'.$trace[$loc]['function'].'()'; |         $res .= "---".$trace[$loc]['class']; | ||||||
| 	$res.=" $data \n"; |     } | ||||||
| 	if(php_sapi_name() === 'cli') echo $res; |     if (!empty($trace[$loc]['function']) && $trace[$loc]['function'] != '_log') { | ||||||
|  |         $res .= '->'.$trace[$loc]['function'].'()'; | ||||||
|  |     } | ||||||
|  |     $res .= " $data \n"; | ||||||
|  |     if (php_sapi_name() === 'cli') { | ||||||
|  |         echo $res; | ||||||
|  |     } | ||||||
|     global $_config; |     global $_config; | ||||||
| 	if($_config['enable_logging']==true){ |     if ($_config['enable_logging'] == true && $_config['log_verbosity'] >= $verbosity) { | ||||||
| 		@file_put_contents($_config['log_file'],$res, FILE_APPEND); |         @file_put_contents($_config['log_file'], $res, FILE_APPEND); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| // converts PEM key to hex | // converts PEM key to hex | ||||||
| function pem2hex ($data) { | function pem2hex($data) | ||||||
|     $data=str_replace("-----BEGIN PUBLIC KEY-----","",$data); | { | ||||||
|     $data=str_replace("-----END PUBLIC KEY-----","",$data); |     $data = str_replace("-----BEGIN PUBLIC KEY-----", "", $data); | ||||||
|     $data=str_replace("-----BEGIN EC PRIVATE KEY-----","",$data); |     $data = str_replace("-----END PUBLIC KEY-----", "", $data); | ||||||
|     $data=str_replace("-----END EC PRIVATE KEY-----","",$data); |     $data = str_replace("-----BEGIN EC PRIVATE KEY-----", "", $data); | ||||||
|     $data=str_replace("\n","",$data); |     $data = str_replace("-----END EC PRIVATE KEY-----", "", $data); | ||||||
|     $data=base64_decode($data); |     $data = str_replace("\n", "", $data); | ||||||
|     $data=bin2hex($data); |     $data = base64_decode($data); | ||||||
|  |     $data = bin2hex($data); | ||||||
|     return $data; |     return $data; | ||||||
| } | } | ||||||
|  |  | ||||||
| // converts hex key to PEM | // converts hex key to PEM | ||||||
| function hex2pem ($data, $is_private_key=false) { | function hex2pem($data, $is_private_key = false) | ||||||
|     $data=hex2bin($data); | { | ||||||
|     $data=base64_encode($data); |     $data = hex2bin($data); | ||||||
|     if($is_private_key) return "-----BEGIN EC PRIVATE KEY-----\n".$data."\n-----END EC PRIVATE KEY-----"; |     $data = base64_encode($data); | ||||||
|  |     if ($is_private_key) { | ||||||
|  |         return "-----BEGIN EC PRIVATE KEY-----\n".$data."\n-----END EC PRIVATE KEY-----"; | ||||||
|  |     } | ||||||
|     return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----"; |     return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----"; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Base58 encoding/decoding functions - all credits go to https://github.com/stephen-hill/base58php | ||||||
|  | function base58_encode($string) | ||||||
|     // Base58 encoding/decoding functions - all credits go to https://github.com/stephen-hill/base58php | { | ||||||
|     function base58_encode($string) |     $alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; | ||||||
|     { |     $base = strlen($alphabet); | ||||||
| 	$alphabet='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; |  | ||||||
| 	$base=strlen($alphabet); |  | ||||||
|     // Type validation |     // Type validation | ||||||
|     if (is_string($string) === false) { |     if (is_string($string) === false) { | ||||||
|         return false; |         return false; | ||||||
| @@ -96,17 +122,18 @@ function hex2pem ($data, $is_private_key=false) { | |||||||
|     $bytes = str_split($string); |     $bytes = str_split($string); | ||||||
|     foreach ($bytes as $byte) { |     foreach ($bytes as $byte) { | ||||||
|         if ($byte === "\x00") { |         if ($byte === "\x00") { | ||||||
|                 $output = $alphabet[0] . $output; |             $output = $alphabet[0].$output; | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|         return (string) $output; |     return (string)$output; | ||||||
|     } | } | ||||||
|     function base58_decode($base58) |  | ||||||
|     { | function base58_decode($base58) | ||||||
|         $alphabet='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; | { | ||||||
|         $base=strlen($alphabet); |     $alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; | ||||||
|  |     $base = strlen($alphabet); | ||||||
|  |  | ||||||
|     // Type Validation |     // Type Validation | ||||||
|     if (is_string($base58) === false) { |     if (is_string($base58) === false) { | ||||||
| @@ -134,124 +161,134 @@ function hex2pem ($data, $is_private_key=false) { | |||||||
|     $output = ''; |     $output = ''; | ||||||
|     while (gmp_cmp($decimal, 0) > 0) { |     while (gmp_cmp($decimal, 0) > 0) { | ||||||
|         list($decimal, $byte) = gmp_div_qr($decimal, 256); |         list($decimal, $byte) = gmp_div_qr($decimal, 256); | ||||||
|             $output = pack('C', gmp_intval($byte)) . $output; |         $output = pack('C', gmp_intval($byte)).$output; | ||||||
|     } |     } | ||||||
|     // Now we need to add leading zeros |     // Now we need to add leading zeros | ||||||
|     foreach ($chars as $char) { |     foreach ($chars as $char) { | ||||||
|         if ($indexes[$char] === 0) { |         if ($indexes[$char] === 0) { | ||||||
|                 $output = "\x00" . $output; |             $output = "\x00".$output; | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     return $output; |     return $output; | ||||||
|     } | } | ||||||
|  |  | ||||||
| // converts PEM key to the base58 version used by ARO | // converts PEM key to the base58 version used by ARO | ||||||
| function pem2coin ($data) { | function pem2coin($data) | ||||||
|     $data=str_replace("-----BEGIN PUBLIC KEY-----","",$data); | { | ||||||
|     $data=str_replace("-----END PUBLIC KEY-----","",$data); |     $data = str_replace("-----BEGIN PUBLIC KEY-----", "", $data); | ||||||
|     $data=str_replace("-----BEGIN EC PRIVATE KEY-----","",$data); |     $data = str_replace("-----END PUBLIC KEY-----", "", $data); | ||||||
|     $data=str_replace("-----END EC PRIVATE KEY-----","",$data); |     $data = str_replace("-----BEGIN EC PRIVATE KEY-----", "", $data); | ||||||
|     $data=str_replace("\n","",$data); |     $data = str_replace("-----END EC PRIVATE KEY-----", "", $data); | ||||||
|     $data=base64_decode($data); |     $data = str_replace("\n", "", $data); | ||||||
|  |     $data = base64_decode($data); | ||||||
|  |  | ||||||
|  |  | ||||||
|     return base58_encode($data); |     return base58_encode($data); | ||||||
|      |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // converts the key in base58 to PEM | // converts the key in base58 to PEM | ||||||
| function coin2pem ($data, $is_private_key=false) { | function coin2pem($data, $is_private_key = false) | ||||||
|  | { | ||||||
|  |     $data = base58_decode($data); | ||||||
|  |     $data = base64_encode($data); | ||||||
|  |  | ||||||
|  |     $dat = str_split($data, 64); | ||||||
|  |     $data = implode("\n", $dat); | ||||||
|  |  | ||||||
|      |     if ($is_private_key) { | ||||||
|        $data=base58_decode($data); |         return "-----BEGIN EC PRIVATE KEY-----\n".$data."\n-----END EC PRIVATE KEY-----\n"; | ||||||
|        $data=base64_encode($data); |     } | ||||||
|  |  | ||||||
|         $dat=str_split($data,64); |  | ||||||
|         $data=implode("\n",$dat); |  | ||||||
|  |  | ||||||
|     if($is_private_key) return "-----BEGIN EC PRIVATE KEY-----\n".$data."\n-----END EC PRIVATE KEY-----\n"; |  | ||||||
|     return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----\n"; |     return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----\n"; | ||||||
| } | } | ||||||
|  |  | ||||||
| // sign data with private key | // sign data with private key | ||||||
| function ec_sign($data, $key){ | function ec_sign($data, $key) | ||||||
|  | { | ||||||
|     // transform the base58 key format to PEM |     // transform the base58 key format to PEM | ||||||
|     $private_key=coin2pem($key,true); |     $private_key = coin2pem($key, true); | ||||||
|  |  | ||||||
|  |  | ||||||
|     $pkey=openssl_pkey_get_private($private_key); |     $pkey = openssl_pkey_get_private($private_key); | ||||||
|  |  | ||||||
|     $k=openssl_pkey_get_details($pkey); |     $k = openssl_pkey_get_details($pkey); | ||||||
|  |  | ||||||
|  |  | ||||||
|     openssl_sign($data,$signature,$pkey,OPENSSL_ALGO_SHA256); |     openssl_sign($data, $signature, $pkey, OPENSSL_ALGO_SHA256); | ||||||
|  |  | ||||||
|     // the signature will be base58 encoded |     // the signature will be base58 encoded | ||||||
|     return base58_encode($signature); |     return base58_encode($signature); | ||||||
|      |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| function ec_verify($data, $signature, $key){ | function ec_verify($data, $signature, $key) | ||||||
|  | { | ||||||
|      |  | ||||||
|     // transform the base58 key to PEM |     // transform the base58 key to PEM | ||||||
|     $public_key=coin2pem($key); |     $public_key = coin2pem($key); | ||||||
|  |  | ||||||
|     $signature=base58_decode($signature); |     $signature = base58_decode($signature); | ||||||
|  |  | ||||||
|     $pkey=openssl_pkey_get_public($public_key); |     $pkey = openssl_pkey_get_public($public_key); | ||||||
|  |  | ||||||
|     $res=openssl_verify($data,$signature,$pkey,OPENSSL_ALGO_SHA256); |     $res = openssl_verify($data, $signature, $pkey, OPENSSL_ALGO_SHA256); | ||||||
|  |  | ||||||
|  |  | ||||||
|     if($res===1) return true; |     if ($res === 1) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| // POST data to an URL (usualy peer). The data is an array, json encoded with is sent as $_POST['data'] | // POST data to an URL (usualy peer). The data is an array, json encoded with is sent as $_POST['data'] | ||||||
| function peer_post($url, $data=array(),$timeout=60,$debug=false){ | function peer_post($url, $data = [], $timeout = 60, $debug = false) | ||||||
|  | { | ||||||
|     global $_config; |     global $_config; | ||||||
|     if($debug) echo "\nPeer post: $url\n"; |     if ($debug) { | ||||||
|  |         echo "\nPeer post: $url\n"; | ||||||
|  |     } | ||||||
|     $postdata = http_build_query( |     $postdata = http_build_query( | ||||||
|         array( |         [ | ||||||
|             'data' => json_encode($data), |             'data' => json_encode($data), | ||||||
|             "coin"=>$_config['coin'] |             "coin" => $_config['coin'], | ||||||
|             ) |         ] | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|     $opts = array('http' => |     $opts = [ | ||||||
|         array( |         'http' => | ||||||
|  |             [ | ||||||
|                 'timeout' => $timeout, |                 'timeout' => $timeout, | ||||||
|                 'method'  => 'POST', |                 'method'  => 'POST', | ||||||
|                 'header'  => 'Content-type: application/x-www-form-urlencoded', |                 'header'  => 'Content-type: application/x-www-form-urlencoded', | ||||||
|             'content' => $postdata |                 'content' => $postdata, | ||||||
|         ) |             ], | ||||||
|     ); |     ]; | ||||||
|  |  | ||||||
|     $context = stream_context_create($opts); |     $context = stream_context_create($opts); | ||||||
|  |  | ||||||
|     $result = file_get_contents($url, false, $context); |     $result = file_get_contents($url, false, $context); | ||||||
|     if($debug) echo "\nPeer response: $result\n"; |     if ($debug) { | ||||||
|     $res=json_decode($result,true); |         echo "\nPeer response: $result\n"; | ||||||
|  |     } | ||||||
|  |     $res = json_decode($result, true); | ||||||
|  |  | ||||||
|     // the function will return false if something goes wrong |     // the function will return false if something goes wrong | ||||||
|     if($res['status']!="ok"||$res['coin']!=$_config['coin']) return false; |     if ($res['status'] != "ok" || $res['coin'] != $_config['coin']) { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|     return $res['data']; |     return $res['data']; | ||||||
| } | } | ||||||
|  |  | ||||||
| // convers hex to base58 | // convers hex to base58 | ||||||
| function hex2coin($hex){ | function hex2coin($hex) | ||||||
|     | { | ||||||
|     $data=hex2bin($hex); |     $data = hex2bin($hex); | ||||||
|     return base58_encode($data); |     return base58_encode($data); | ||||||
| } | } | ||||||
| // converts base58 to hex |  | ||||||
| function coin2hex($data){ |  | ||||||
|  |  | ||||||
|     $bin= base58_decode($data); | // converts base58 to hex | ||||||
|  | function coin2hex($data) | ||||||
|  | { | ||||||
|  |     $bin = base58_decode($data); | ||||||
|     return bin2hex($bin); |     return bin2hex($bin); | ||||||
| } | } | ||||||
| ?> |  | ||||||
|   | |||||||
| @@ -1,21 +1,18 @@ | |||||||
| <?php | <?php | ||||||
| // ARO version | // ARO version | ||||||
| define("VERSION", "0.2b"); | define("VERSION", "0.4.2"); | ||||||
| // Amsterdam timezone by default, should probably be moved to config | // Amsterdam timezone by default, should probably be moved to config | ||||||
| date_default_timezone_set("Europe/Amsterdam"); | date_default_timezone_set("UTC"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| //error_reporting(E_ALL & ~E_NOTICE); | //error_reporting(E_ALL & ~E_NOTICE); | ||||||
| error_reporting(0); | error_reporting(0); | ||||||
| ini_set('display_errors',"off"); | ini_set('display_errors', "off"); | ||||||
|  |  | ||||||
| // not accessible directly | // not accessible directly | ||||||
| if(php_sapi_name() !== 'cli'&&substr_count($_SERVER['PHP_SELF'],"/")>1){ | if (php_sapi_name() !== 'cli' && substr_count($_SERVER['PHP_SELF'], "/") > 1) { | ||||||
|     die("This application should only be run in the main directory /"); |     die("This application should only be run in the main directory /"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| require_once("include/config.inc.php"); | require_once("include/config.inc.php"); | ||||||
| require_once("include/db.inc.php"); | require_once("include/db.inc.php"); | ||||||
| require_once("include/functions.inc.php"); | require_once("include/functions.inc.php"); | ||||||
| @@ -23,42 +20,59 @@ require_once("include/block.inc.php"); | |||||||
| require_once("include/account.inc.php"); | require_once("include/account.inc.php"); | ||||||
| require_once("include/transaction.inc.php"); | require_once("include/transaction.inc.php"); | ||||||
|  |  | ||||||
| if($_config['db_pass']=="ENTER-DB-PASS") die("Please update your config file and set your db password"); | if ($_config['db_pass'] == "ENTER-DB-PASS") { | ||||||
|  |     die("Please update your config file and set your db password"); | ||||||
|  | } | ||||||
| // initial DB connection | // initial DB connection | ||||||
| $db=new DB($_config['db_connect'],$_config['db_user'],$_config['db_pass'],0); | $db = new DB($_config['db_connect'], $_config['db_user'], $_config['db_pass'], $_config['enable_logging']); | ||||||
| if(!$db) die("Could not connect to the DB backend."); | if (!$db) { | ||||||
|  |     die("Could not connect to the DB backend."); | ||||||
| // checks for php version and extensions |  | ||||||
| if (!extension_loaded("openssl") && !defined("OPENSSL_KEYTYPE_EC")) api_err("Openssl php extension missing"); |  | ||||||
| if (!extension_loaded("gmp")) api_err("gmp php extension missing"); |  | ||||||
| if (!extension_loaded('PDO')) api_err("pdo php extension missing"); |  | ||||||
| if (!extension_loaded("bcmath")) api_err("bcmath php extension missing"); |  | ||||||
| if (!defined("PASSWORD_ARGON2I")) api_err("The php version is not compiled with argon2i support"); |  | ||||||
|  |  | ||||||
| if(floatval(phpversion())<7.2) api_err("The minimum php version required is 7.2"); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // Getting extra configs from the database |  | ||||||
| $query=$db->run("SELECT cfg, val FROM config"); |  | ||||||
| foreach($query as $res){ |  | ||||||
| 	$_config[$res['cfg']]=trim($res['val']); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // checks for php version and extensions | ||||||
|  | if (!extension_loaded("openssl") && !defined("OPENSSL_KEYTYPE_EC")) { | ||||||
|  |     api_err("Openssl php extension missing"); | ||||||
|  | } | ||||||
|  | if (!extension_loaded("gmp")) { | ||||||
|  |     api_err("gmp php extension missing"); | ||||||
|  | } | ||||||
|  | if (!extension_loaded('PDO')) { | ||||||
|  |     api_err("pdo php extension missing"); | ||||||
|  | } | ||||||
|  | if (!extension_loaded("bcmath")) { | ||||||
|  |     api_err("bcmath php extension missing"); | ||||||
|  | } | ||||||
|  | if (!defined("PASSWORD_ARGON2I")) { | ||||||
|  |     api_err("The php version is not compiled with argon2i support"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | if (floatval(phpversion()) < 7.2) { | ||||||
|  |     api_err("The minimum php version required is 7.2"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Getting extra configs from the database | ||||||
|  | $query = $db->run("SELECT cfg, val FROM config"); | ||||||
|  | foreach ($query as $res) { | ||||||
|  |     $_config[$res['cfg']] = trim($res['val']); | ||||||
|  | } | ||||||
|  |  | ||||||
| // nothing is allowed while in maintenance | // nothing is allowed while in maintenance | ||||||
| if($_config['maintenance']==1) api_err("under-maintenance"); | if ($_config['maintenance'] == 1) { | ||||||
|  |     api_err("under-maintenance"); | ||||||
|  | } | ||||||
|  |  | ||||||
| // update the db schema, on every git pull or initial install | // update the db schema, on every git pull or initial install | ||||||
| if(file_exists("tmp/db-update")){ | if (file_exists("tmp/db-update")) { | ||||||
| 	 |     //checking if the server has at least 2GB of ram | ||||||
| 	$res=unlink("tmp/db-update"); |     $ram=file_get_contents("/proc/meminfo"); | ||||||
| 	if($res){ |     $ramz=explode("MemTotal:",$ram); | ||||||
|  |     $ramb=explode("kB",$ramz[1]); | ||||||
|  |     $ram=intval(trim($ramb[0])); | ||||||
|  |     if($ram<1700000) { | ||||||
|  |         die("The node requires at least 2 GB of RAM"); | ||||||
|  |     } | ||||||
|  |     $res = unlink("tmp/db-update"); | ||||||
|  |     if ($res) { | ||||||
|         echo "Updating db schema! Please refresh!\n"; |         echo "Updating db schema! Please refresh!\n"; | ||||||
|         require_once("include/schema.inc.php"); |         require_once("include/schema.inc.php"); | ||||||
|         exit; |         exit; | ||||||
| @@ -67,23 +81,28 @@ if(file_exists("tmp/db-update")){ | |||||||
| } | } | ||||||
|  |  | ||||||
| // something went wront with the db schema | // something went wront with the db schema | ||||||
| if($_config['dbversion']<2) exit; | if ($_config['dbversion'] < 2) { | ||||||
|  |     exit; | ||||||
|  | } | ||||||
|  |  | ||||||
| // separate blockchain for testnet | // separate blockchain for testnet | ||||||
| if($_config['testnet']==true) $_config['coin'].="-testnet";  | if ($_config['testnet'] == true) { | ||||||
|  |     $_config['coin'] .= "-testnet"; | ||||||
|  | } | ||||||
|  |  | ||||||
| // current hostname | // current hostname | ||||||
| $hostname=(!empty($_SERVER['HTTPS'])?'https':'http')."://".$_SERVER['HTTP_HOST']; | $hostname = (!empty($_SERVER['HTTPS']) ? 'https' : 'http')."://".san_host($_SERVER['HTTP_HOST']); | ||||||
| // set the hostname to the current one | // set the hostname to the current one | ||||||
| if($hostname!=$_config['hostname']&&$_SERVER['HTTP_HOST']!="localhost"&&$_SERVER['HTTP_HOST']!="127.0.0.1"&&$_SERVER['hostname']!='::1'&&php_sapi_name() !== 'cli' && ($_config['allow_hostname_change']!=false||empty($_config['hostname']))){ | if ($hostname != $_config['hostname'] && $_SERVER['HTTP_HOST'] != "localhost" && $_SERVER['HTTP_HOST'] != "127.0.0.1" && $_SERVER['hostname'] != '::1' && php_sapi_name() !== 'cli' && ($_config['allow_hostname_change'] != false || empty($_config['hostname']))) { | ||||||
| 	$db->run("UPDATE config SET val=:hostname WHERE cfg='hostname' LIMIT 1",array(":hostname"=>$hostname)); |     $db->run("UPDATE config SET val=:hostname WHERE cfg='hostname' LIMIT 1", [":hostname" => $hostname]); | ||||||
| 	$_config['hostname']=$hostname; |     $_config['hostname'] = $hostname; | ||||||
|  | } | ||||||
|  | if (empty($_config['hostname']) || $_config['hostname'] == "http://" || $_config['hostname'] == "https://") { | ||||||
|  |     api_err("Invalid hostname"); | ||||||
| } | } | ||||||
| if(empty($_config['hostname'])||$_config['hostname']=="http://"||$_config['hostname']=="https://") api_err("Invalid hostname"); |  | ||||||
|  |  | ||||||
| // run sanity | // run sanity | ||||||
| 	$t=time(); | $t = time(); | ||||||
| 	if($t-$_config['sanity_last']>$_config['sanity_interval']&& php_sapi_name() !== 'cli') system("php sanity.php  > /dev/null 2>&1  &"); | if ($t - $_config['sanity_last'] > $_config['sanity_interval'] && php_sapi_name() !== 'cli') { | ||||||
|  |     system("php sanity.php  > /dev/null 2>&1  &"); | ||||||
|  | } | ||||||
| ?> |  | ||||||
|   | |||||||
| @@ -1,10 +1,9 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| // when db schema modifications are done, this function is run. | // when db schema modifications are done, this function is run. | ||||||
|  | $dbversion = intval($_config['dbversion']); | ||||||
| $dbversion=intval($_config['dbversion']); |  | ||||||
| $db->beginTransaction(); | $db->beginTransaction(); | ||||||
| if($dbversion==0){ | if ($dbversion == 0) { | ||||||
|     $db->run(" |     $db->run(" | ||||||
|     CREATE TABLE `accounts` ( |     CREATE TABLE `accounts` ( | ||||||
|       `id` varbinary(128) NOT NULL, |       `id` varbinary(128) NOT NULL, | ||||||
| @@ -114,36 +113,62 @@ if($dbversion==0){ | |||||||
|  |  | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
| if($dbversion==1){ | if ($dbversion == 1) { | ||||||
|     $db->run("INSERT INTO `config` (`cfg`, `val`) VALUES ('sanity_last', '0');"); |     $db->run("INSERT INTO `config` (`cfg`, `val`) VALUES ('sanity_last', '0');"); | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
| if($dbversion==2){ | if ($dbversion == 2) { | ||||||
|     $db->run("INSERT INTO `config` (`cfg`, `val`) VALUES ('sanity_sync', '0');"); |     $db->run("INSERT INTO `config` (`cfg`, `val`) VALUES ('sanity_sync', '0');"); | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
| if($dbversion==3){ | if ($dbversion == 3) { | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
|  |  | ||||||
| if($dbversion==4){ | if ($dbversion == 4) { | ||||||
|     $db->run("ALTER TABLE `mempool` ADD INDEX(`src`);"); |     $db->run("ALTER TABLE `mempool` ADD INDEX(`src`);"); | ||||||
|     $db->run("ALTER TABLE `mempool` ADD INDEX(`peer`); "); |     $db->run("ALTER TABLE `mempool` ADD INDEX(`peer`); "); | ||||||
|     $db->run("ALTER TABLE `mempool` ADD INDEX(`val`); "); |     $db->run("ALTER TABLE `mempool` ADD INDEX(`val`); "); | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
| if($dbversion==5){ | if ($dbversion == 5) { | ||||||
|     $db->run("ALTER TABLE `peers` ADD `fails` TINYINT NOT NULL DEFAULT '0' AFTER `ip`; "); |     $db->run("ALTER TABLE `peers` ADD `fails` TINYINT NOT NULL DEFAULT '0' AFTER `ip`; "); | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
| if($dbversion==6){ | if ($dbversion == 6) { | ||||||
|     $db->run("ALTER TABLE `peers` ADD `stuckfail` TINYINT(4) NOT NULL DEFAULT '0' AFTER `fails`, ADD INDEX (`stuckfail`); "); |     $db->run("ALTER TABLE `peers` ADD `stuckfail` TINYINT(4) NOT NULL DEFAULT '0' AFTER `fails`, ADD INDEX (`stuckfail`); "); | ||||||
|     $db->run("ALTER TABLE `accounts` ADD `alias` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL AFTER `balance`; "); |     $db->run("ALTER TABLE `accounts` ADD `alias` VARCHAR(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL AFTER `balance`; "); | ||||||
|     $dbversion++; |     $dbversion++; | ||||||
| } | } | ||||||
|  | if ($dbversion == 7) { | ||||||
|  |     $db->run("ALTER TABLE `accounts` ADD INDEX(`alias`); "); | ||||||
|  |     $db->run("ALTER TABLE `transactions` ADD KEY `dst` (`dst`), ADD KEY `height` (`height`),  ADD KEY `public_key` (`public_key`);"); | ||||||
|  |     $dbversion++; | ||||||
|  | } | ||||||
|  | if ($dbversion == 8) { | ||||||
|  |   $db->run("CREATE TABLE `masternode` ( | ||||||
|  |     `public_key` varchar(128) COLLATE utf8mb4_bin NOT NULL, | ||||||
|  |     `height` int(11) NOT NULL, | ||||||
|  |     `ip` varchar(16) COLLATE utf8mb4_bin NOT NULL, | ||||||
|  |     `last_won` int(11) NOT NULL DEFAULT '0', | ||||||
|  |     `blacklist` int(11) NOT NULL DEFAULT '0', | ||||||
|  |     `fails` int(11) NOT NULL DEFAULT '0', | ||||||
|  |     `status` tinyint(4) NOT NULL DEFAULT '1' | ||||||
|  |   ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;"); | ||||||
|  |  | ||||||
|  |   $db->run("ALTER TABLE `masternode` | ||||||
|  |   ADD PRIMARY KEY (`public_key`), | ||||||
|  |   ADD KEY `last_won` (`last_won`), | ||||||
|  |   ADD KEY `status` (`status`), | ||||||
|  |   ADD KEY `blacklist` (`blacklist`), | ||||||
|  |   ADD KEY `height` (`height`);"); | ||||||
|  |   $dbversion++; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // update the db version to the latest one | // update the db version to the latest one | ||||||
| if($dbversion!=$_config['dbversion']) $db->run("UPDATE config SET val=:val WHERE cfg='dbversion'",array(":val"=>$dbversion)); | if ($dbversion != $_config['dbversion']) { | ||||||
|  |     $db->run("UPDATE config SET val=:val WHERE cfg='dbversion'", [":val" => $dbversion]); | ||||||
|  | } | ||||||
| $db->commit(); | $db->commit(); | ||||||
|  |  | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
| @@ -1,79 +1,175 @@ | |||||||
| <?php | <?php | ||||||
|  |  | ||||||
| class Transaction { | class Transaction | ||||||
|  | { | ||||||
|     // reverse and remove all transactions from a block |     // reverse and remove all transactions from a block | ||||||
|     public function reverse($block){ |     public function reverse($block) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $acc=new Account; |         $acc = new Account(); | ||||||
|         $r=$db->run("SELECT * FROM transactions WHERE block=:block",array(":block"=>$block)); |         $r = $db->run("SELECT * FROM transactions WHERE block=:block ORDER by `version` ASC", [":block" => $block]); | ||||||
|         foreach($r as $x){ |         foreach ($r as $x) { | ||||||
|             if(empty($x['src'])) $x['src']=$acc->get_address($x['public_key']); |             if (empty($x['src'])) { | ||||||
|             $db->run("UPDATE accounts SET balance=balance-:val WHERE id=:id",array(":id"=>$x['dst'], ":val"=>$x['val'])); |                 $x['src'] = $acc->get_address($x['public_key']); | ||||||
|  |             } | ||||||
|  |             if ($x['version'] == 2) { | ||||||
|  |                 // payment sent to alias | ||||||
|  |                 $db->run( | ||||||
|  |                     "UPDATE accounts SET balance=balance-:val WHERE alias=:alias", | ||||||
|  |                     [":alias" => $x['dst'], ":val" => $x['val']] | ||||||
|  |                     ); | ||||||
|  |             } else { | ||||||
|  |                 // other type of transactions | ||||||
|         |         | ||||||
|  | 	        if($x['version']!=100) { $db->run( | ||||||
|  |                     "UPDATE accounts SET balance=balance-:val WHERE id=:id", | ||||||
|  |                     [":id" => $x['dst'], ":val" => $x['val']] | ||||||
|  |                     ); | ||||||
|  | 		} | ||||||
|  |          | ||||||
|  |     		}	 | ||||||
|             // on version 0 / reward transaction, don't credit anyone |             // on version 0 / reward transaction, don't credit anyone | ||||||
|             if($x['version']>0) $db->run("UPDATE accounts SET balance=balance+:val WHERE id=:id",array(":id"=>$x['src'], ":val"=>$x['val']+$x['fee'])); |             if ($x['version'] > 0) { | ||||||
|  |                 $db->run( | ||||||
|  |                     "UPDATE accounts SET balance=balance+:val WHERE id=:id", | ||||||
|  |                     [":id" => $x['src'], ":val" => $x['val'] + $x['fee']] | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |             // removing the alias if the alias transaction is reversed | ||||||
|  |             if ($x['version']==3) { | ||||||
|  |                 $db->run( | ||||||
|  |                     "UPDATE accounts SET alias=NULL WHERE id=:id", | ||||||
|  |                     [":id" => $x['src']] | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             if ($x['version']>=100&&$x['version']<110&&$x['height']>=80000) { | ||||||
|  |                 if ($x['version']==100) { | ||||||
|  |                     $db->run("DELETE FROM masternode WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                 } elseif ($x['version']==101) { | ||||||
|  |                     $db->run( | ||||||
|  |                         "UPDATE masternode SET status=1 WHERE public_key=:public_key", | ||||||
|  |                     [':public_key'=>$x['public_key']] | ||||||
|  |                     ); | ||||||
|  |                 } elseif ($x['version']==102) { | ||||||
|  |                     $db->run("UPDATE masternode SET status=0 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                 } elseif ($x['version']==103) { | ||||||
|  |                     $mnt=$db->row("SELECT height, `message` FROM transactions WHERE version=100 AND public_key=:public_key ORDER by height DESC LIMIT 1", [":public_key"=>$x['public_key']]); | ||||||
|  |                     $vers=$db->single( | ||||||
|  |                         "SELECT `version` FROM transactions WHERE (version=101 or version=102) AND public_key=:public_key AND height>:height ORDER by height DESC LIMIT 1", | ||||||
|  |                     [":public_key"=>$x['public_key'],":height"=>$mnt['height']] | ||||||
|  |                     ); | ||||||
|  |                         | ||||||
|  |                     $status=1; | ||||||
|  |                          | ||||||
|  |                     if ($vers==101) { | ||||||
|  |                         $status=0; | ||||||
|  |                     } | ||||||
|  |                      | ||||||
|  |                     $db->run( | ||||||
|  |                         "INSERT into masternode SET `public_key`=:public_key, `height`=:height, `ip`=:ip, `status`=:status", | ||||||
|  |                     [":public_key"=>$x['public_key'], ":height"=>$mnt['height'], ":ip"=>$mnt['message'], ":status"=>$status] | ||||||
|  |                     ); | ||||||
|  |                     $db->run("UPDATE accounts SET balance=balance-100000 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             // internal masternode history | ||||||
|  |             if ($x['version']==111) { | ||||||
|  |                 $m=explode(",", $x['message']); | ||||||
|  |  | ||||||
|  |                 $db->run( | ||||||
|  |                     "UPDATE masternode SET fails=:fails, blacklist=:blacklist, last_won=:last_won WHERE public_key=:public_key", | ||||||
|  |                 [":public_key"=>$x['public_key'], ":blacklist"=> $m[0], ":fails"=>$m[2], ":last_won"=>$m[1]] | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|      |      | ||||||
|             // add the transactions to mempool |             // add the transactions to mempool | ||||||
|            if($x['version']>0) $this->add_mempool($x); |             if ($x['version'] > 0 && $x['version']<=110) { | ||||||
|            $res= $db->run("DELETE FROM transactions WHERE id=:id",array(":id"=>$x['id'])); |                 $this->add_mempool($x); | ||||||
|            if($res!=1) return false; |             } | ||||||
|  |             $res = $db->run("DELETE FROM transactions WHERE id=:id", [":id" => $x['id']]); | ||||||
|  |             if ($res != 1) { | ||||||
|  |                 return false; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // clears the mempool |     // clears the mempool | ||||||
|     public function clean_mempool(){ |     public function clean_mempool() | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $block= new Block; |         $block = new Block(); | ||||||
| 	    $current=$block->current(); |         $current = $block->current(); | ||||||
|         $height=$current['height']; |         $height = $current['height']; | ||||||
|         $limit=$height-1000; |         $limit = $height - 1000; | ||||||
|         $db->run("DELETE FROM mempool WHERE height<:limit",array(":limit"=>$limit)); |         $db->run("DELETE FROM mempool WHERE height<:limit", [":limit" => $limit]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // returns X  transactions from mempool |     // returns X  transactions from mempool | ||||||
|     public function mempool($max){ |     public function mempool($max) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $block=new Block; |         $block = new Block(); | ||||||
|         $current=$block->current(); |         $current = $block->current(); | ||||||
|         $height=$current['height']+1; |         $height = $current['height'] + 1; | ||||||
|         // only get the transactions that are not locked with a future height |         // only get the transactions that are not locked with a future height | ||||||
|         $r=$db->run("SELECT * FROM mempool WHERE height<=:height ORDER by val/fee DESC LIMIT :max",array(":height"=>$height, ":max"=>$max+50)); |         $r = $db->run( | ||||||
|         $transactions=array(); |             "SELECT * FROM mempool WHERE height<=:height ORDER by val/fee DESC LIMIT :max", | ||||||
|         if(count($r)>0){ |             [":height" => $height, ":max" => $max + 50] | ||||||
|             $i=0; |         ); | ||||||
|             $balance=array(); |         $transactions = []; | ||||||
|             foreach($r as $x){ |         if (count($r) > 0) { | ||||||
|                     $trans=array("id"=>$x['id'],"dst"=>$x['dst'],"val"=>$x['val'],"fee"=>$x['fee'],"signature"=>$x['signature'], "message"=>$x['message'],"version"=>$x['version'],"date"=>$x['date'], "public_key"=>$x['public_key']); |             $i = 0; | ||||||
|  |             $balance = []; | ||||||
|  |             foreach ($r as $x) { | ||||||
|  |                 $trans = [ | ||||||
|  |                     "id"         => $x['id'], | ||||||
|  |                     "dst"        => $x['dst'], | ||||||
|  |                     "val"        => $x['val'], | ||||||
|  |                     "fee"        => $x['fee'], | ||||||
|  |                     "signature"  => $x['signature'], | ||||||
|  |                     "message"    => $x['message'], | ||||||
|  |                     "version"    => $x['version'], | ||||||
|  |                     "date"       => $x['date'], | ||||||
|  |                     "public_key" => $x['public_key'], | ||||||
|  |                 ]; | ||||||
|  |  | ||||||
|                     if($i>=$max) break; |                 if ($i >= $max) { | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                     if(empty($x['public_key'])){ |                 if (empty($x['public_key'])) { | ||||||
|                     _log("$x[id] - Transaction has empty public_key"); |                     _log("$x[id] - Transaction has empty public_key"); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                     if(empty($x['src'])){ |                 if (empty($x['src'])) { | ||||||
|                     _log("$x[id] - Transaction has empty src"); |                     _log("$x[id] - Transaction has empty src"); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|                     if(!$this->check($trans, $current['height'])){ |                 if (!$this->check($trans, $current['height'])) { | ||||||
|                     _log("$x[id] - Transaction Check Failed"); |                     _log("$x[id] - Transaction Check Failed"); | ||||||
|                     continue; |                     continue; | ||||||
|                 } |                 } | ||||||
|    |    | ||||||
|                     $balance[$x['src']]+=$x['val']+$x['fee']; |                 $balance[$x['src']] += $x['val'] + $x['fee']; | ||||||
|                     if($db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$x['id']))>0) { |                 if ($db->single("SELECT COUNT(1) FROM transactions WHERE id=:id", [":id" => $x['id']]) > 0) { | ||||||
|                     _log("$x[id] - Duplicate transaction"); |                     _log("$x[id] - Duplicate transaction"); | ||||||
|                     continue; //duplicate transaction |                     continue; //duplicate transaction | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                     $res=$db->single("SELECT COUNT(1) FROM accounts WHERE id=:id AND balance>=:balance",array(":id"=>$x['src'], ":balance"=>$balance[$x['src']])); |                 $res = $db->single( | ||||||
|  |                     "SELECT COUNT(1) FROM accounts WHERE id=:id AND balance>=:balance", | ||||||
|  |                     [":id" => $x['src'], ":balance" => $balance[$x['src']]] | ||||||
|  |                 ); | ||||||
|  |  | ||||||
|                     if($res==0) { |                 if ($res == 0) { | ||||||
|                     _log("$x[id] - Not enough funds in balance"); |                     _log("$x[id] - Not enough funds in balance"); | ||||||
|                     continue; // not enough balance for the transactions |                     continue; // not enough balance for the transactions | ||||||
|                 } |                 } | ||||||
|                 $i++; |                 $i++; | ||||||
|                 ksort($trans); |                 ksort($trans); | ||||||
|                     $transactions[$x['id']]=$trans; |                 $transactions[$x['id']] = $trans; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         // always sort the array |         // always sort the array | ||||||
| @@ -83,193 +179,458 @@ class Transaction { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // add a new transaction to mempool and lock it with the current height |     // add a new transaction to mempool and lock it with the current height | ||||||
|     public function add_mempool($x, $peer=""){ |     public function add_mempool($x, $peer = "") | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $block= new Block; |         $block = new Block(); | ||||||
| 	    $current=$block->current(); |         if ($x['version']>110) { | ||||||
|         $height=$current['height']; |  | ||||||
|         $x['id']=san($x['id']); |  | ||||||
|         $bind=array(":peer"=>$peer, ":id"=>$x['id'],"public_key"=>$x['public_key'], ":height"=>$height, ":src"=>$x['src'],":dst"=>$x['dst'],":val"=>$x['val'], ":fee"=>$x['fee'],":signature"=>$x['signature'], ":version"=>$x['version'],":date"=>$x['date'], ":message"=>$x['message']); |  | ||||||
|         $db->run("INSERT into mempool  SET peer=:peer, id=:id, public_key=:public_key, height=:height, src=:src, dst=:dst, val=:val, fee=:fee, signature=:signature, version=:version, message=:message, `date`=:date",$bind); |  | ||||||
|             return true; |             return true; | ||||||
|  |         } | ||||||
|  |         $current = $block->current(); | ||||||
|  |         $height = $current['height']; | ||||||
|  |         $x['id'] = san($x['id']); | ||||||
|  |         $bind = [ | ||||||
|  |             ":peer"      => $peer, | ||||||
|  |             ":id"        => $x['id'], | ||||||
|  |             "public_key" => $x['public_key'], | ||||||
|  |             ":height"    => $height, | ||||||
|  |             ":src"       => $x['src'], | ||||||
|  |             ":dst"       => $x['dst'], | ||||||
|  |             ":val"       => $x['val'], | ||||||
|  |             ":fee"       => $x['fee'], | ||||||
|  |             ":signature" => $x['signature'], | ||||||
|  |             ":version"   => $x['version'], | ||||||
|  |             ":date"      => $x['date'], | ||||||
|  |             ":message"   => $x['message'], | ||||||
|  |         ]; | ||||||
|  |  | ||||||
|  |         //only a single masternode command of same type, per block | ||||||
|  |         if ($x['version']>=100&&$x['version']<110) { | ||||||
|  |             $check=$db->single("SELECT COUNT(1) FROM mempool WHERE public_key=:public_key", [":public_key"=>$x['public_key']]); | ||||||
|  |             if ($check!=0) { | ||||||
|  |                 _log("Masternode transaction already in mempool", 3); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $db->run( | ||||||
|  |             "INSERT into mempool  SET peer=:peer, id=:id, public_key=:public_key, height=:height, src=:src, dst=:dst, val=:val, fee=:fee, signature=:signature, version=:version, message=:message, `date`=:date", | ||||||
|  |             $bind | ||||||
|  |         ); | ||||||
|  |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // add a new transaction to the blockchain |     // add a new transaction to the blockchain | ||||||
|     public function add($block,$height, $x){ |     public function add($block, $height, $x) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $acc= new Account; |         $acc = new Account(); | ||||||
|         $acc->add($x['public_key'], $block); |         $acc->add($x['public_key'], $block); | ||||||
|         $acc->add_id($x['dst'],$block); |         if ($x['version']==1) { | ||||||
|         $x['id']=san($x['id']); |             $acc->add_id($x['dst'], $block); | ||||||
|         $bind=array(":id"=>$x['id'], ":public_key"=>$x['public_key'],":height"=>$height, ":block"=>$block, ":dst"=>$x['dst'],":val"=>$x['val'], ":fee"=>$x['fee'],":signature"=>$x['signature'], ":version"=>$x['version'],":date"=>$x['date'], ":message"=>$x['message']); |         } | ||||||
|         $res=$db->run("INSERT into transactions SET id=:id, public_key=:public_key, block=:block,  height=:height, dst=:dst, val=:val, fee=:fee, signature=:signature, version=:version, message=:message, `date`=:date",$bind); |         $x['id'] = san($x['id']); | ||||||
|         if($res!=1) return false; |         $bind = [ | ||||||
|         $db->run("UPDATE accounts SET balance=balance+:val WHERE id=:id",array(":id"=>$x['dst'], ":val"=>$x['val'])); |             ":id"         => $x['id'], | ||||||
|  |             ":public_key" => $x['public_key'], | ||||||
|  |             ":height"     => $height, | ||||||
|  |             ":block"      => $block, | ||||||
|  |             ":dst"        => $x['dst'], | ||||||
|  |             ":val"        => $x['val'], | ||||||
|  |             ":fee"        => $x['fee'], | ||||||
|  |             ":signature"  => $x['signature'], | ||||||
|  |             ":version"    => $x['version'], | ||||||
|  |             ":date"       => $x['date'], | ||||||
|  |             ":message"    => $x['message'], | ||||||
|  |         ]; | ||||||
|  |         $res = $db->run( | ||||||
|  |             "INSERT into transactions SET id=:id, public_key=:public_key, block=:block,  height=:height, dst=:dst, val=:val, fee=:fee, signature=:signature, version=:version, message=:message, `date`=:date", | ||||||
|  |             $bind | ||||||
|  |         ); | ||||||
|  |         if ($res != 1) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if ($x['version'] == 2&&$height>=80000) { | ||||||
|  |             $db->run("UPDATE accounts SET balance=balance+:val WHERE alias=:alias", [":alias" => $x['dst'], ":val" => $x['val']]); | ||||||
|  |         } elseif ($x['version']==100&&$height>=80000) { | ||||||
|  |             //master node deposit | ||||||
|  |         } elseif ($x['version']==103&&$height>=80000) { | ||||||
|  |             $blk=new Block(); | ||||||
|  |             $blk->masternode_log($x['public_key'],$height,$block); | ||||||
|  |  | ||||||
|  |             //master node withdrawal | ||||||
|  |         } else { | ||||||
|  |             $db->run("UPDATE accounts SET balance=balance+:val WHERE id=:id", [":id" => $x['dst'], ":val" => $x['val']]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|         // no debit when the transaction is reward |         // no debit when the transaction is reward | ||||||
| 	if($x['version']>0) $db->run("UPDATE accounts SET balance=(balance-:val)-:fee WHERE id=:id",array(":id"=>$x['src'], ":val"=>$x['val'], ":fee"=>$x['fee'])); |         if ($x['version'] > 0) { | ||||||
|         $db->run("DELETE FROM mempool WHERE id=:id",array(":id"=>$x['id'])); |             $db->run( | ||||||
|  |                 "UPDATE accounts SET balance=(balance-:val)-:fee WHERE id=:id", | ||||||
|  |                 [":id" => $x['src'], ":val" => $x['val'], ":fee" => $x['fee']] | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // set the alias | ||||||
|  |         if ($x['version']==3&&$height>=80000) { | ||||||
|  |             $db->run( | ||||||
|  |                     "UPDATE accounts SET alias=:alias WHERE id=:id", | ||||||
|  |                     [":id" => $x['src'], ":alias"=>$x['message']] | ||||||
|  |                 ); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if ($x['version']>=100&&$x['version']<110&&$height>=80000) { | ||||||
|  |             $message=$x['message']; | ||||||
|  |             $message=preg_replace("/[^0-9\.]/", "", $message); | ||||||
|  |             if ($x['version']==100) { | ||||||
|  |                 $db->run("INSERT into masternode SET `public_key`=:public_key, `height`=:height, `ip`=:ip, `status`=1", [":public_key"=>$x['public_key'], ":height"=>$height, ":ip"=>$message]); | ||||||
|  |             } else { | ||||||
|  |                 if ($x['version']==101) { | ||||||
|  |                     $db->run("UPDATE masternode SET status=0 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                 } elseif ($x['version']==102) { | ||||||
|  |                     $db->run("UPDATE masternode SET status=1 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                 } elseif ($x['version']==103) { | ||||||
|  |                     $db->run("DELETE FROM masternode WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                     $db->run("UPDATE accounts SET balance=balance+100000 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         $db->run("DELETE FROM mempool WHERE id=:id", [":id" => $x['id']]); | ||||||
|         return true; |         return true; | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // hash the transaction's most important fields and create the transaction ID |     // hash the transaction's most important fields and create the transaction ID | ||||||
|     public function hash($x){ |     public function hash($x) | ||||||
|         $info=$x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date']."-".$x['signature']; |     { | ||||||
|         $hash= hash("sha512",$info); |         $info = $x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date']."-".$x['signature']; | ||||||
|  |         $hash = hash("sha512", $info); | ||||||
|         return hex2coin($hash); |         return hex2coin($hash); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // check the transaction for validity |     // check the transaction for validity | ||||||
|     public function check($x, $height=0){ |     public function check($x, $height = 0) | ||||||
|  |     { | ||||||
|         // if no specific block, use current |         // if no specific block, use current | ||||||
| 		if($height===0){ |         if ($height === 0) { | ||||||
| 			$block=new Block; |             $block = new Block(); | ||||||
| 			$current=$block->current(); |             $current = $block->current(); | ||||||
| 			$height=$current['height']; |             $height = $current['height']; | ||||||
|         } |         } | ||||||
|                 $acc= new Account; |         $acc = new Account(); | ||||||
|                 $info=$x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date']; |         $info = $x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date']; | ||||||
|  |  | ||||||
| 		// the value must be >=0 |         // hard fork at 80000 to implement alias, new mining system, assets | ||||||
|                 if($x['val']<0){ _log("$x[id] - Value below 0"); return false; } |         // if($x['version']>1 && $height<80000){ | ||||||
|  |         //     return false; | ||||||
|  |         // } | ||||||
|              |              | ||||||
| 		// the fee must be >=0 |         // internal transactions | ||||||
| 	        if($x['fee']<0) { _log("$x[id] - Fee below 0"); return false; } |         if($x['version']>110){ | ||||||
|              |  | ||||||
| 		// the fee is 0.25%, hardcoded |  | ||||||
|                 $fee=$x['val']*0.0025; |  | ||||||
| 		$fee=number_format($fee,8,".",""); |  | ||||||
|                 if($fee<0.00000001) $fee=0.00000001; |  | ||||||
| 		// max fee after block 10800 is 10 |  | ||||||
| 		if($height>10800&&$fee>10) $fee=10; //10800 |  | ||||||
| 		// added fee does not match |  | ||||||
|                 if($fee!=$x['fee']) { _log("$x[id] - Fee not 0.25%"); return false; } |  | ||||||
|  |  | ||||||
| 		// invalid destination address |  | ||||||
|                 if(!$acc->valid($x['dst'])) { _log("$x[id] - Invalid destination address"); return false; } |  | ||||||
|               |  | ||||||
| 		// reward transactions are not added via this function |  | ||||||
|                 if($x['version']<1) { _log("$x[id] - Invalid version <1"); return false; } |  | ||||||
|                 //if($x['version']>1) { _log("$x[id] - Invalid version >1"); return false; } |  | ||||||
|          |  | ||||||
| 		// public key must be at least 15 chars / probably should be replaced with the validator function         |  | ||||||
| 	        if(strlen($x['public_key'])<15) { _log("$x[id] - Invalid public key size"); return false; } |  | ||||||
|  		// no transactions before the genesis |  | ||||||
|                 if($x['date']<1511725068) { _log("$x[id] - Date before genesis"); return false; } |  | ||||||
| 		// no future transactions |  | ||||||
|                 if($x['date']>time()+86400) { _log("$x[id] - Date in the future"); return false; } |  | ||||||
|                 // prevent the resending of broken base58 transactions |  | ||||||
| 		if($height>16900&&$x['date']<1519327780) return false; |  | ||||||
|                 $id=$this->hash($x);	 |  | ||||||
|         	// the hash does not match our regenerated hash |  | ||||||
| 	        if($x['id']!=$id) {  |  | ||||||
| 			// fix for broken base58 library which was used until block 16900, accepts hashes without the first 1 or 2 bytes |  | ||||||
| 			$xs=base58_decode($x['id']); |  | ||||||
|                         if(((strlen($xs)!=63||substr($id,1)!=$x['id'])&&(strlen($xs)!=62||substr($id,2)!=$x['id']))||$height>16900){ |  | ||||||
|                                  _log("$x[id] - $id - Invalid hash"); |  | ||||||
|             return false; |             return false; | ||||||
|         }     |         }     | ||||||
|  |  | ||||||
|  |         // the value must be >=0 | ||||||
|  |         if ($x['val'] < 0) { | ||||||
|  |             _log("$x[id] - Value below 0", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // the fee must be >=0 | ||||||
|  |         if ($x['fee'] < 0) { | ||||||
|  |             _log("$x[id] - Fee below 0", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // the fee is 0.25%, hardcoded | ||||||
|  |         $fee = $x['val'] * 0.0025; | ||||||
|  |         $fee = number_format($fee, 8, ".", ""); | ||||||
|  |         if ($fee < 0.00000001) { | ||||||
|  |             $fee = 0.00000001; | ||||||
|  |         } | ||||||
|  |         //alias fee | ||||||
|  |         if ($x['version']==3&&$height>=80000) { | ||||||
|  |             $fee=10; | ||||||
|  |             if (!$acc->free_alias($x['message'])) { | ||||||
|  |                 _log("Alias not free", 3); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |             // alias can only be set once per account | ||||||
|  |             if ($acc->has_alias($x['public_key'])) { | ||||||
|  |                 _log("The account already has an alias", 3); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         //masternode transactions | ||||||
|  |          | ||||||
|  |         if ($x['version']>=100&&$x['version']<110&&$height>=80000) { | ||||||
|  |             if ($x['version']==100) { | ||||||
|  |                 $message=$x['message']; | ||||||
|  |                 $message=preg_replace("/[^0-9\.]/", "", $message); | ||||||
|  |                 if (!filter_var($message, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { | ||||||
|  |                     _log("The Masternode IP is invalid", 3); | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             | ||||||
|  |          | ||||||
|  |             if ($x['version']==100&&$x['val']!=100000) { | ||||||
|  |                 _log("The masternode transaction is not 100k", 3); | ||||||
|  |                 return false; | ||||||
|  |             } elseif ($x['version']!=100) { | ||||||
|  |                 $mn=$acc->get_masternode($x['public_key']); | ||||||
|  |                  | ||||||
|  |                 if (!$mn) { | ||||||
|  |                     _log("The masternode does not exist", 3); | ||||||
|  |                     return false; | ||||||
|  |                 } | ||||||
|  |                 if ($x['version']==101&&$mn['status']!=1) { | ||||||
|  |                     _log("The masternode does is not running", 3); | ||||||
|  |                     return false; | ||||||
|  |                 } elseif ($x['version']==102 && $mn['status']!=0) { | ||||||
|  |                     _log("The masternode is not paused", 3); | ||||||
|  |                     return false; | ||||||
|  |                 } elseif ($x['version']==103) { | ||||||
|  |                     if ($mn['status']!=0) { | ||||||
|  |                         _log("The masternode is not paused", 3); | ||||||
|  |                         return false; | ||||||
|  |                     } elseif ($height-$mn['last_won']<10800) { //10800 | ||||||
|  |                         _log("The masternode last won block is less than 10800 blocks", 3); | ||||||
|  |                         return false; | ||||||
|  |                     } elseif ($height-$mn['height']<32400) { //32400 | ||||||
|  |                         _log("The masternode start height is less than 32400 blocks! $height - $mn[height]", 3); | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |  | ||||||
|  |         // max fee after block 10800 is 10 | ||||||
|  |         if ($height > 10800 && $fee > 10) { | ||||||
|  |             $fee = 10; //10800 | ||||||
|  |         } | ||||||
|  |         // added fee does not match | ||||||
|  |         if ($fee != $x['fee']) { | ||||||
|  |             _log("$x[id] - Fee not 0.25%", 3); | ||||||
|  |             _log(json_encode($x), 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($x['version']==1) { | ||||||
|  |             // invalid destination address | ||||||
|  |             if (!$acc->valid($x['dst'])) { | ||||||
|  |                 _log("$x[id] - Invalid destination address", 3); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } elseif ($x['version']==2&&$height>=80000) { | ||||||
|  |             if (!$acc->valid_alias($x['dst'])) { | ||||||
|  |                 _log("$x[id] - Invalid destination alias", 3); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         // reward transactions are not added via this function | ||||||
|  |         if ($x['version'] < 1) { | ||||||
|  |             _log("$x[id] - Invalid version <1", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         //if($x['version']>1) { _log("$x[id] - Invalid version >1"); return false; } | ||||||
|  |  | ||||||
|  |         // public key must be at least 15 chars / probably should be replaced with the validator function | ||||||
|  |         if (strlen($x['public_key']) < 15) { | ||||||
|  |             _log("$x[id] - Invalid public key size", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // no transactions before the genesis | ||||||
|  |         if ($x['date'] < 1511725068) { | ||||||
|  |             _log("$x[id] - Date before genesis", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // no future transactions | ||||||
|  |         if ($x['date'] > time() + 86400) { | ||||||
|  |             _log("$x[id] - Date in the future", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         // prevent the resending of broken base58 transactions | ||||||
|  |         if ($height > 16900 && $x['date'] < 1519327780) { | ||||||
|  |             _log("$x[id] - Broken base58 transaction", 3); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         $id = $this->hash($x); | ||||||
|  |         // the hash does not match our regenerated hash | ||||||
|  |         if ($x['id'] != $id) { | ||||||
|  |             // fix for broken base58 library which was used until block 16900, accepts hashes without the first 1 or 2 bytes | ||||||
|  |             $xs = base58_decode($x['id']); | ||||||
|  |             if (((strlen($xs) != 63 || substr($id, 1) != $x['id']) && (strlen($xs) != 62 || substr( | ||||||
|  |                 $id, | ||||||
|  |                 2 | ||||||
|  |             ) != $x['id'])) || $height > 16900) { | ||||||
|  |                 _log("$x[id] - $id - Invalid hash"); | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         //verify the ecdsa signature |         //verify the ecdsa signature | ||||||
|     		if(!$acc->check_signature($info, $x['signature'], $x['public_key'])) { _log("$x[id] - Invalid signature"); return false; } |         if (!$acc->check_signature($info, $x['signature'], $x['public_key'])) { | ||||||
|  |             _log("$x[id] - Invalid signature - $info"); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // sign a transaction |     // sign a transaction | ||||||
|     public function sign($x, $private_key){ |     public function sign($x, $private_key) | ||||||
|         $info=$x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date']; |     { | ||||||
|         $signature=ec_sign($info,$private_key); |         $info = $x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date']; | ||||||
|  |          | ||||||
|  |         $signature = ec_sign($info, $private_key); | ||||||
|  |  | ||||||
|         return $signature; |         return $signature; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     //export a mempool transaction |     //export a mempool transaction | ||||||
|     public function export($id){ |     public function export($id) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $r=$db->row("SELECT * FROM mempool WHERE id=:id",array(":id"=>$id)); |         $r = $db->row("SELECT * FROM mempool WHERE id=:id", [":id" => $id]); | ||||||
|         return $r; |         return $r; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // get the transaction data as array |     // get the transaction data as array | ||||||
|     public function get_transaction($id){ |     public function get_transaction($id) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $acc=new Account; |         $acc = new Account(); | ||||||
|         $block=new Block; |         $block = new Block(); | ||||||
|         $current=$block->current(); |         $current = $block->current(); | ||||||
|  |  | ||||||
|         $x=$db->row("SELECT * FROM transactions WHERE id=:id",array(":id"=>$id)); |         $x = $db->row("SELECT * FROM transactions WHERE id=:id", [":id" => $id]); | ||||||
|  |  | ||||||
| 	    if(!$x) return false; |         if (!$x) { | ||||||
| 	    $trans=array("block"=>$x['block'],"height"=>$x['height'], "id"=>$x['id'],"dst"=>$x['dst'],"val"=>$x['val'],"fee"=>$x['fee'],"signature"=>$x['signature'], "message"=>$x['message'],"version"=>$x['version'],"date"=>$x['date'], "public_key"=>$x['public_key']); |             return false; | ||||||
|             $trans['src']=$acc->get_address($x['public_key']); |         } | ||||||
|             $trans['confirmations']=$current['height']-$x['height']; |         $trans = [ | ||||||
|  |             "block"      => $x['block'], | ||||||
|  |             "height"     => $x['height'], | ||||||
|  |             "id"         => $x['id'], | ||||||
|  |             "dst"        => $x['dst'], | ||||||
|  |             "val"        => $x['val'], | ||||||
|  |             "fee"        => $x['fee'], | ||||||
|  |             "signature"  => $x['signature'], | ||||||
|  |             "message"    => $x['message'], | ||||||
|  |             "version"    => $x['version'], | ||||||
|  |             "date"       => $x['date'], | ||||||
|  |             "public_key" => $x['public_key'], | ||||||
|  |         ]; | ||||||
|  |         $trans['src'] = $acc->get_address($x['public_key']); | ||||||
|  |         $trans['confirmations'] = $current['height'] - $x['height']; | ||||||
|  |  | ||||||
| 			if($x['version']==0) $trans['type']="mining"; |         if ($x['version'] == 0) { | ||||||
| 			elseif($x['version']==1){ |             $trans['type'] = "mining"; | ||||||
| 				if($x['dst']==$id) $trans['type']="credit"; |         } elseif ($x['version'] == 1 || $x['version'] == 2) { | ||||||
| 				else $trans['type']="debit"; |             if ($x['dst'] == $id) { | ||||||
|  |                 $trans['type'] = "credit"; | ||||||
|             } else { |             } else { | ||||||
| 				$trans['type']="other"; |                 $trans['type'] = "debit"; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             $trans['type'] = "other"; | ||||||
|         } |         } | ||||||
|         ksort($trans); |         ksort($trans); | ||||||
|         return $trans; |         return $trans; | ||||||
|              |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // return the transactions for a specific block id or height |     // return the transactions for a specific block id or height | ||||||
|    public function get_transactions($height="", $id=""){ |     public function get_transactions($height = "", $id = "") | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $block=new Block; |         $block = new Block(); | ||||||
|         $current=$block->current(); |         $current = $block->current(); | ||||||
|         $acc=new Account; |         $acc = new Account(); | ||||||
| 	$height=san($height); |         $height = san($height); | ||||||
| 	$id=san($id); |         $id = san($id); | ||||||
| 	if(empty($id)&&empty($height)) return false; |         if (empty($id) && empty($height)) { | ||||||
| 	if(!empty($id)) $r=$db->run("SELECT * FROM transactions WHERE block=:id AND version>0",array(":id"=>$id)); |             return false; | ||||||
| 	else $r=$db->run("SELECT * FROM transactions WHERE height=:height AND version>0",array(":height"=>$height)); |         } | ||||||
| 	$res=array(); |         if (!empty($id)) { | ||||||
| 	foreach($r as $x){ |             $r = $db->run("SELECT * FROM transactions WHERE block=:id AND version>0", [":id" => $id]); | ||||||
|             $trans=array("block"=>$x['block'],"height"=>$x['height'], "id"=>$x['id'],"dst"=>$x['dst'],"val"=>$x['val'],"fee"=>$x['fee'],"signature"=>$x['signature'], "message"=>$x['message'],"version"=>$x['version'],"date"=>$x['date'], "public_key"=>$x['public_key']); |  | ||||||
|             $trans['src']=$acc->get_address($x['public_key']); |  | ||||||
|             $trans['confirmations']=$current['height']-$x['height']; |  | ||||||
|  |  | ||||||
|                         if($x['version']==0) $trans['type']="mining"; |  | ||||||
|                         elseif($x['version']==1){ |  | ||||||
|                                 if($x['dst']==$id) $trans['type']="credit"; |  | ||||||
|                                 else $trans['type']="debit"; |  | ||||||
|         } else { |         } else { | ||||||
|                                 $trans['type']="other"; |             $r = $db->run("SELECT * FROM transactions WHERE height=:height AND version>0", [":height" => $height]); | ||||||
|  |         } | ||||||
|  |         $res = []; | ||||||
|  |         foreach ($r as $x) { | ||||||
|  |             if ($x['version']>110) { | ||||||
|  |                 continue; //internal transactions | ||||||
|  |             } | ||||||
|  |             $trans = [ | ||||||
|  |                 "block"      => $x['block'], | ||||||
|  |                 "height"     => $x['height'], | ||||||
|  |                 "id"         => $x['id'], | ||||||
|  |                 "dst"        => $x['dst'], | ||||||
|  |                 "val"        => $x['val'], | ||||||
|  |                 "fee"        => $x['fee'], | ||||||
|  |                 "signature"  => $x['signature'], | ||||||
|  |                 "message"    => $x['message'], | ||||||
|  |                 "version"    => $x['version'], | ||||||
|  |                 "date"       => $x['date'], | ||||||
|  |                 "public_key" => $x['public_key'], | ||||||
|  |             ]; | ||||||
|  |             $trans['src'] = $acc->get_address($x['public_key']); | ||||||
|  |             $trans['confirmations'] = $current['height'] - $x['height']; | ||||||
|  |  | ||||||
|  |             if ($x['version'] == 0) { | ||||||
|  |                 $trans['type'] = "mining"; | ||||||
|  |             } elseif ($x['version'] == 1||$x['version'] == 2) { | ||||||
|  |                 if ($x['dst'] == $id) { | ||||||
|  |                     $trans['type'] = "credit"; | ||||||
|  |                 } else { | ||||||
|  |                     $trans['type'] = "debit"; | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 $trans['type'] = "other"; | ||||||
|             } |             } | ||||||
|             ksort($trans); |             ksort($trans); | ||||||
| 			$res[]=$trans; |             $res[] = $trans; | ||||||
|         } |         } | ||||||
|         return $res; |         return $res; | ||||||
|  |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // get a specific mempool transaction as array |     // get a specific mempool transaction as array | ||||||
|     public function get_mempool_transaction($id){ |     public function get_mempool_transaction($id) | ||||||
|  |     { | ||||||
|         global $db; |         global $db; | ||||||
|         $x=$db->row("SELECT * FROM mempool WHERE id=:id",array(":id"=>$id)); |         $x = $db->row("SELECT * FROM mempool WHERE id=:id", [":id" => $id]); | ||||||
| 		if(!$x) return false; |         if (!$x) { | ||||||
| 			$trans=array("block"=>$x['block'],"height"=>$x['height'], "id"=>$x['id'],"dst"=>$x['dst'],"val"=>$x['val'],"fee"=>$x['fee'],"signature"=>$x['signature'], "message"=>$x['message'],"version"=>$x['version'],"date"=>$x['date'], "public_key"=>$x['public_key']); |             return false; | ||||||
| 			$trans['src']=$x['src']; |         } | ||||||
|  |         $trans = [ | ||||||
|  |             "block"      => $x['block'], | ||||||
|  |             "height"     => $x['height'], | ||||||
|  |             "id"         => $x['id'], | ||||||
|  |             "dst"        => $x['dst'], | ||||||
|  |             "val"        => $x['val'], | ||||||
|  |             "fee"        => $x['fee'], | ||||||
|  |             "signature"  => $x['signature'], | ||||||
|  |             "message"    => $x['message'], | ||||||
|  |             "version"    => $x['version'], | ||||||
|  |             "date"       => $x['date'], | ||||||
|  |             "public_key" => $x['public_key'], | ||||||
|  |         ]; | ||||||
|  |         $trans['src'] = $x['src']; | ||||||
|  |  | ||||||
| 			$trans['type']="mempool"; |         $trans['type'] = "mempool"; | ||||||
|             $trans['confirmations']=-1; |         $trans['confirmations'] = -1; | ||||||
|         ksort($trans); |         ksort($trans); | ||||||
|         return $trans; |         return $trans; | ||||||
|              |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
							
								
								
									
										306
									
								
								index.php
									
									
									
									
									
								
							
							
						
						
									
										306
									
								
								index.php
									
									
									
									
									
								
							| @@ -24,14 +24,300 @@ 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 __DIR__.'/include/init.inc.php'; | ||||||
| require_once("include/init.inc.php"); | $block = new Block(); | ||||||
| $block=new Block; | $current = $block->current(); | ||||||
| $current=$block->current(); |  | ||||||
|  |  | ||||||
| echo "<h3>Arionum Node</h3>"; |  | ||||||
| echo "System check complete.<br><br> Current block: $current[height]"; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ?> | ?> | ||||||
|  | <!DOCTYPE html> | ||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|  |     <title>Arionum Node</title> | ||||||
|  |     <style> | ||||||
|  |         .title:not(:last-child) { | ||||||
|  |             margin-bottom: 1.5rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         body, h1, html { | ||||||
|  |             margin: 0; | ||||||
|  |             padding: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         h1 { | ||||||
|  |             font-size: 100%; | ||||||
|  |             font-weight: 400; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         html { | ||||||
|  |             box-sizing: border-box; | ||||||
|  |             background-color: #fff; | ||||||
|  |             font-size: 16px; | ||||||
|  |             -moz-osx-font-smoothing: grayscale; | ||||||
|  |             -webkit-font-smoothing: antialiased; | ||||||
|  |             min-width: 300px; | ||||||
|  |             overflow-x: hidden; | ||||||
|  |             overflow-y: scroll; | ||||||
|  |             text-rendering: optimizeLegibility; | ||||||
|  |             -webkit-text-size-adjust: 100%; | ||||||
|  |             -moz-text-size-adjust: 100%; | ||||||
|  |             -ms-text-size-adjust: 100%; | ||||||
|  |             text-size-adjust: 100%; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         *, ::after, ::before { | ||||||
|  |             box-sizing: inherit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         section { | ||||||
|  |             display: block; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         body { | ||||||
|  |             font-family: "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; | ||||||
|  |             color: #4a4a4a; | ||||||
|  |             font-size: 1rem; | ||||||
|  |             font-weight: 400; | ||||||
|  |             line-height: 1.5; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |             font-style: inherit; | ||||||
|  |             font-weight: inherit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         strong { | ||||||
|  |             color: #363636; | ||||||
|  |             font-weight: 700; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .container { | ||||||
|  |             position: relative; | ||||||
|  |             margin: 0 auto; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .field.is-grouped { | ||||||
|  |             display: flex; | ||||||
|  |             justify-content: flex-start; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .field.is-grouped > .control { | ||||||
|  |             flex-shrink: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .field.is-grouped > .control:not(:last-child) { | ||||||
|  |             margin-bottom: 0; | ||||||
|  |             margin-right: .75rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .field.is-grouped.is-grouped-multiline { | ||||||
|  |             flex-wrap: wrap; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .field.is-grouped.is-grouped-multiline > .control:last-child, .field.is-grouped.is-grouped-multiline > .control:not(:last-child) { | ||||||
|  |             margin-bottom: .75rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .field.is-grouped.is-grouped-multiline:last-child { | ||||||
|  |             margin-bottom: -.75rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .control { | ||||||
|  |             font-size: 1rem; | ||||||
|  |             position: relative; | ||||||
|  |             text-align: left; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags { | ||||||
|  |             align-items: center; | ||||||
|  |             display: flex; | ||||||
|  |             flex-wrap: wrap; | ||||||
|  |             justify-content: flex-start; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags .tag { | ||||||
|  |             margin-bottom: .5rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags .tag:not(:last-child) { | ||||||
|  |             margin-right: .5rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags:last-child { | ||||||
|  |             margin-bottom: -.5rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags.has-addons .tag { | ||||||
|  |             margin-right: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags.has-addons .tag:not(:first-child) { | ||||||
|  |             border-bottom-left-radius: 0; | ||||||
|  |             border-top-left-radius: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tags.has-addons .tag:not(:last-child) { | ||||||
|  |             border-bottom-right-radius: 0; | ||||||
|  |             border-top-right-radius: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tag:not(body) { | ||||||
|  |             align-items: center; | ||||||
|  |             background-color: #f5f5f5; | ||||||
|  |             border-radius: 4px; | ||||||
|  |             color: #4a4a4a; | ||||||
|  |             display: inline-flex; | ||||||
|  |             font-size: .75rem; | ||||||
|  |             height: 2em; | ||||||
|  |             justify-content: center; | ||||||
|  |             line-height: 1.5; | ||||||
|  |             padding-left: .75em; | ||||||
|  |             padding-right: .75em; | ||||||
|  |             white-space: nowrap; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tag:not(body).is-light { | ||||||
|  |             background-color: #f5f5f5; | ||||||
|  |             color: #363636; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tag:not(body).is-info { | ||||||
|  |             background-color: #209cee; | ||||||
|  |             color: #fff; | ||||||
|  |         } | ||||||
|  |         .tag:not(body).is-danger { | ||||||
|  |             background-color: #f48f42; | ||||||
|  |             color: #fff; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .tag:not(body).is-success { | ||||||
|  |             background-color: #23d160; | ||||||
|  |             color: #fff; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .title { | ||||||
|  |             word-break: break-word; | ||||||
|  |             color: #363636; | ||||||
|  |             font-size: 2rem; | ||||||
|  |             font-weight: 600; | ||||||
|  |             line-height: 1.125; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero { | ||||||
|  |             align-items: stretch; | ||||||
|  |             display: flex; | ||||||
|  |             flex-direction: column; | ||||||
|  |             justify-content: space-between; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero.is-dark { | ||||||
|  |             background-color: #363636; | ||||||
|  |             color: #f5f5f5; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero.is-dark strong { | ||||||
|  |             color: inherit; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero.is-dark .title { | ||||||
|  |             color: #f5f5f5; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero.is-fullheight .hero-body { | ||||||
|  |             align-items: center; | ||||||
|  |             display: flex; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero.is-fullheight .hero-body > .container { | ||||||
|  |             flex-grow: 1; | ||||||
|  |             flex-shrink: 1; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero.is-fullheight { | ||||||
|  |             min-height: 100vh; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .hero-body { | ||||||
|  |             flex-grow: 1; | ||||||
|  |             flex-shrink: 0; | ||||||
|  |             padding: 3rem 1.5rem; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         a { | ||||||
|  |             color: #3273dc; | ||||||
|  |             cursor: pointer; | ||||||
|  |             text-decoration: none; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         a:hover { | ||||||
|  |             color: #363636; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         a.is-dark { | ||||||
|  |             color: #fff; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @media screen and (min-width: 1088px) { | ||||||
|  |  | ||||||
|  |             .container { | ||||||
|  |                 max-width: 960px; | ||||||
|  |                 width: 960px; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @media screen and (min-width: 1280px) { | ||||||
|  |  | ||||||
|  |             .container { | ||||||
|  |                 max-width: 1152px; | ||||||
|  |                 width: 1152px; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @media screen and (min-width: 1472px) { | ||||||
|  |  | ||||||
|  |             .container { | ||||||
|  |                 max-width: 1344px; | ||||||
|  |                 width: 1344px; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     </style> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  | <section class="hero is-dark is-fullheight"> | ||||||
|  |     <div class="hero-body"> | ||||||
|  |         <div class="container"> | ||||||
|  |             <h1 class="title">Arionum Node</h1> | ||||||
|  |  | ||||||
|  |             <div class="field is-grouped is-grouped-multiline"> | ||||||
|  |                 <div class="control"> | ||||||
|  |                     <div class="tags has-addons"> | ||||||
|  |                         <strong class="tag is-success">Current Block</strong> | ||||||
|  |                         <span class="tag is-light"><?= $current['height']; ?></span> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="control"> | ||||||
|  |                     <div class="tags has-addons"> | ||||||
|  |                         <strong class="tag is-danger">Version</strong> | ||||||
|  |                         <span class="tag is-light"><?= VERSION; ?></span> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |  | ||||||
|  |                 <div class="control"> | ||||||
|  |                     <div class="tags has-addons"> | ||||||
|  |                         <strong class="tag is-info">Public API</strong> | ||||||
|  |                         <span class="tag is-light"><?= ($_config['public_api']) ? 'yes' : 'no'; ?></span> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |  | ||||||
|  |                 <div class="control"> | ||||||
|  |                     <a class="tags is-dark" href="./doc/" target="_blank"> | ||||||
|  |                         <strong class="tag is-info">Documentation</strong> | ||||||
|  |                     </a> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </section> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
|   | |||||||
							
								
								
									
										195
									
								
								mine.php
									
									
									
									
									
								
							
							
						
						
									
										195
									
								
								mine.php
									
									
									
									
									
								
							| @@ -24,51 +24,196 @@ 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"); | ||||||
| $block=new Block(); | $block = new Block(); | ||||||
| $acc=new Account(); | $acc = new Account(); | ||||||
| set_time_limit(360); | set_time_limit(360); | ||||||
| $q=$_GET['q']; | $q = $_GET['q']; | ||||||
|  |  | ||||||
| $ip=$_SERVER['REMOTE_ADDR']; | $ip = san_ip($_SERVER['REMOTE_ADDR']); | ||||||
| $ip=filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); | $ip = filter_var($ip, FILTER_VALIDATE_IP); | ||||||
|  |  | ||||||
| // in case of testnet, all IPs are accepted for mining | // in case of testnet, all IPs are accepted for mining | ||||||
| if($_config['testnet']==false&&!in_array($ip,$_config['allowed_hosts'])) api_err("unauthorized"); | if ($_config['testnet'] == false && !in_array($ip, $_config['allowed_hosts']) && !empty($ip) && !in_array( | ||||||
|  |     '*', | ||||||
|  |     $_config['allowed_hosts'] | ||||||
|  | )) { | ||||||
|  |     api_err("unauthorized"); | ||||||
|  | } | ||||||
|  |  | ||||||
| if($q=="info"){ | if ($q == "info") { | ||||||
|     // provides the mining info to the miner |     // provides the mining info to the miner | ||||||
| 	$diff=$block->difficulty(); |     $diff = $block->difficulty(); | ||||||
| 	$current=$block->current(); |     $current = $block->current(); | ||||||
| 	api_echo(array("difficulty"=>$diff, "block"=>$current['id'], "height"=>$current['height'])); |  | ||||||
|  |     $current_height=$current['height']; | ||||||
|  |     $recommendation="mine"; | ||||||
|  |     $argon_mem=16384; | ||||||
|  |     $argon_threads=4; | ||||||
|  |     $argon_time=4; | ||||||
|  |     if ($current_height<80000) { | ||||||
|  |         if ($current_height > 10800) { | ||||||
|  |             $argon_mem=524288; | ||||||
|  |             $argon_threads=1; | ||||||
|  |             $argon_time=1; | ||||||
|  |         } | ||||||
|  |      } elseif($current_height>=80460&&$current_height%2==0){ | ||||||
|  | 	          $argon_mem=524288; | ||||||
|  |             $argon_threads=1; | ||||||
|  |             $argon_time=1; | ||||||
|  |  | ||||||
|  | 	 | ||||||
|  |     } else { | ||||||
|  |         if ($current_height%3==0) { | ||||||
|  |             $argon_mem=524288; | ||||||
|  |             $argon_threads=1; | ||||||
|  |             $argon_time=1; | ||||||
|  |         } elseif ($current_height%3==2) { | ||||||
|  |             global $db; | ||||||
|  |             $winner=$db->single( | ||||||
|  |                 "SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 1", | ||||||
|  |                 [":current"=>$current_height, ":start"=>$current_height-360] | ||||||
|  |             ); | ||||||
|  |             $recommendation="pause"; | ||||||
|  |             if ($winner===false) { | ||||||
|  |                 $recommendation="mine"; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     $res = [ | ||||||
|  |         "difficulty" => $diff, | ||||||
|  |         "block"      => $current['id'], | ||||||
|  |         "height"     => $current['height'], | ||||||
|  |         "testnet"    => $_config['testnet'], | ||||||
|  |         "recommendation"=> $recommendation, | ||||||
|  |         "argon_mem"  => $argon_mem, | ||||||
|  |         "argon_threads"  => $argon_threads, | ||||||
|  |         "argon_time"  => $argon_time, | ||||||
|  |     ]; | ||||||
|  |     api_echo($res); | ||||||
|     exit; |     exit; | ||||||
| } elseif($q=="submitNonce"){ | } elseif ($q == "submitNonce") { | ||||||
|     // in case the blocks are syncing, reject all |     // in case the blocks are syncing, reject all | ||||||
| 	if($_config['sanity_sync']==1) api_err("sanity-sync"); |     if ($_config['sanity_sync'] == 1) { | ||||||
|  |         api_err("sanity-sync"); | ||||||
|  |     } | ||||||
|     $nonce = san($_POST['nonce']); |     $nonce = san($_POST['nonce']); | ||||||
| 	$argon=$_POST['argon']; |     $argon = $_POST['argon']; | ||||||
| 	$public_key=san($_POST['public_key']); |     $public_key = san($_POST['public_key']); | ||||||
| 	$private_key=san($_POST['private_key']); |     $private_key = san($_POST['private_key']); | ||||||
|     // check if the miner won the block |     // check if the miner won the block | ||||||
| 	$result=$block->mine($public_key, $nonce, $argon); |     $result = $block->mine($public_key, $nonce, $argon); | ||||||
|  |  | ||||||
| 	if($result) { |     if ($result) { | ||||||
|         // generate the new block |         // generate the new block | ||||||
| 			$res=$block->forge($nonce,$argon, $public_key, $private_key); |         $res = $block->forge($nonce, $argon, $public_key, $private_key); | ||||||
|  |  | ||||||
|  |  | ||||||
| 			 |         if ($res) { | ||||||
|  |  | ||||||
| 		 |  | ||||||
| 		if($res){ |  | ||||||
|             //if the new block is generated, propagate it to all peers in background |             //if the new block is generated, propagate it to all peers in background | ||||||
| 			$current=$block->current(); |             $current = $block->current(); | ||||||
|             system("php propagate.php block $current[id]  > /dev/null 2>&1  &"); |             system("php propagate.php block $current[id]  > /dev/null 2>&1  &"); | ||||||
|             api_echo("accepted"); |             api_echo("accepted"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     api_err("rejected"); |     api_err("rejected"); | ||||||
|  | } elseif ($q == "submitBlock") { | ||||||
|  |     // in case the blocks are syncing, reject all | ||||||
|  |     if ($_config['sanity_sync'] == 1) { | ||||||
|  |         api_err("sanity-sync"); | ||||||
|  |     } | ||||||
|  |     $nonce = san($_POST['nonce']); | ||||||
|  |     $argon = $_POST['argon']; | ||||||
|  |     $public_key = san($_POST['public_key']); | ||||||
|  |     // check if the miner won the block | ||||||
|  |      | ||||||
|  |     $result = $block->mine($public_key, $nonce, $argon); | ||||||
|  |      | ||||||
|  |     if ($result) { | ||||||
|  |         // generate the new block | ||||||
|  |         $date = intval($_POST['date']); | ||||||
|  |         if ($date <= $current['date']) { | ||||||
|  |             api_err("rejected - date"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // get the mempool transactions | ||||||
|  |         $txn = new Transaction(); | ||||||
|  |         $current = $block->current(); | ||||||
|  |         $height = $current['height'] += 1; | ||||||
|  |    | ||||||
|  |         // get the mempool transactions | ||||||
|  |         $txn = new Transaction(); | ||||||
|  |          | ||||||
|  |  | ||||||
|  |         $difficulty = $block->difficulty(); | ||||||
|  |         $acc = new Account(); | ||||||
|  |         $generator = $acc->get_address($public_key); | ||||||
|  |  | ||||||
|  |         $data=json_decode($_POST['data'], true); | ||||||
|  |             | ||||||
|  |         // sign the block | ||||||
|  |         $signature = san($_POST['signature']); | ||||||
|  |  | ||||||
|  |         // reward transaction and signature | ||||||
|  |         $reward = $block->reward($height, $data); | ||||||
|  |         $msg = ''; | ||||||
|  |         $transaction = [ | ||||||
|  |             "src"        => $generator, | ||||||
|  |             "dst"        => $generator, | ||||||
|  |             "val"        => $reward, | ||||||
|  |             "version"    => 0, | ||||||
|  |             "date"       => $date, | ||||||
|  |             "message"    => $msg, | ||||||
|  |             "fee"        => "0.00000000", | ||||||
|  |             "public_key" => $public_key, | ||||||
|  |         ]; | ||||||
|  |         ksort($transaction); | ||||||
|  |         $reward_signature = san($_POST['reward_signature']); | ||||||
|  |  | ||||||
|  |         // add the block to the blockchain | ||||||
|  |         $res = $block->add( | ||||||
|  |             $height, | ||||||
|  |             $public_key, | ||||||
|  |             $nonce, | ||||||
|  |             $data, | ||||||
|  |             $date, | ||||||
|  |             $signature, | ||||||
|  |             $difficulty, | ||||||
|  |             $reward_signature, | ||||||
|  |             $argon | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         if ($res) { | ||||||
|  |             //if the new block is generated, propagate it to all peers in background | ||||||
|  |             $current = $block->current(); | ||||||
|  |             system("php propagate.php block $current[id]  > /dev/null 2>&1  &"); | ||||||
|  |             api_echo("accepted"); | ||||||
|  |         } else { | ||||||
|  |             api_err("rejected - add"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     api_err("rejected"); | ||||||
|  | } elseif ($q == "getWork") { | ||||||
|  |     if ($_config['sanity_sync'] == 1) { | ||||||
|  |         api_err("sanity-sync"); | ||||||
|  |     } | ||||||
|  |     $block = new Block(); | ||||||
|  |     $current = $block->current(); | ||||||
|  |     $height = $current['height'] += 1; | ||||||
|  |     $date = time(); | ||||||
|  |     // get the mempool transactions | ||||||
|  |     $txn = new Transaction(); | ||||||
|  |     $data = $txn->mempool($block->max_transactions()); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $difficulty = $block->difficulty(); | ||||||
|  |     // always sort  the transactions in the same way | ||||||
|  |     ksort($data); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // reward transaction and signature | ||||||
|  |     $reward = $block->reward($height, $data); | ||||||
|  |     api_echo(["height"=>$height, "data"=>$data, "reward"=>$reward, "block"=>$current['id'], "difficulty"=>$difficulty]); | ||||||
| } else { | } else { | ||||||
|     api_err("invalid command"); |     api_err("invalid command"); | ||||||
| } | } | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
							
								
								
									
										265
									
								
								peer.php
									
									
									
									
									
								
							
							
						
						
									
										265
									
								
								peer.php
									
									
									
									
									
								
							| @@ -24,164 +24,218 @@ 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=$_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']); | ||||||
|  | $ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); | ||||||
|  |  | ||||||
| // peer with the current node | // peer with the current node | ||||||
| if($q=="peer"){ | if ($q == "peer") { | ||||||
|     // sanitize the hostname |     // sanitize the hostname | ||||||
|     $hostname = filter_var($data['hostname'], FILTER_SANITIZE_URL); |     $hostname = filter_var($data['hostname'], FILTER_SANITIZE_URL); | ||||||
|  |  | ||||||
|     if (!filter_var($hostname, FILTER_VALIDATE_URL)) api_err("invalid-hostname"); |     $bad_peers = ["127.", "localhost", "10.", "192.168.","172.16.","172.17.","172.18.","172.19.","172.20.","172.21.","172.22.","172.23.","172.24.","172.25.","172.26.","172.27.","172.28.","172.29.","172.30.","172.31."]; | ||||||
|  |     $tpeer=str_replace(["https://","http://","//"], "", $hostname); | ||||||
|  |     foreach ($bad_peers as $bp) { | ||||||
|  |         if (strpos($tpeer, $bp)===0) { | ||||||
|  |             api_err("invalid-hostname"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!filter_var($hostname, FILTER_VALIDATE_URL)) { | ||||||
|  |         api_err("invalid-hostname"); | ||||||
|  |     } | ||||||
|  |     $hostname = san_host($hostname); | ||||||
|     // if it's already peered, only repeer on request |     // if it's already peered, only repeer on request | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM peers WHERE hostname=:hostname AND ip=:ip",array(":hostname"=>$hostname,":ip"=>$ip)); |     $res = $db->single( | ||||||
|     if($res==1){ |         "SELECT COUNT(1) FROM peers WHERE hostname=:hostname AND ip=:ip", | ||||||
|          if($data['repeer']==1){ |         [":hostname" => $hostname, ":ip" => $ip] | ||||||
|             $res=peer_post($hostname."/peer.php?q=peer",array("hostname"=>$_config['hostname'])); |     ); | ||||||
|             if($res!==false) api_echo("re-peer-ok"); |     if ($res == 1) { | ||||||
|             else api_err("re-peer failed - $result"); |         if ($data['repeer'] == 1) { | ||||||
|  |             $res = peer_post($hostname."/peer.php?q=peer", ["hostname" => $_config['hostname']]); | ||||||
|  |             if ($res !== false) { | ||||||
|  |                 api_echo("re-peer-ok"); | ||||||
|  |             } else { | ||||||
|  |                 api_err("re-peer failed - $result"); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         api_echo("peer-ok-already"); |         api_echo("peer-ok-already"); | ||||||
|     } |     } | ||||||
|     // if we have enough peers, add it to DB as reserve |     // if we have enough peers, add it to DB as reserve | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM peers WHERE blacklisted<UNIX_TIMESTAMP() AND ping >UNIX_TIMESTAMP()-86400 AND reserve=0"); |     $res = $db->single("SELECT COUNT(1) FROM peers WHERE blacklisted<UNIX_TIMESTAMP() AND ping >UNIX_TIMESTAMP()-86400 AND reserve=0"); | ||||||
|     $reserve=1; |     $reserve = 1; | ||||||
|     if($res<$_config['max_peers']) $reserve=0; |     if ($res < $_config['max_peers']) { | ||||||
|     $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)); |         $reserve = 0; | ||||||
|  |     } | ||||||
|  |     $db->run( | ||||||
|  |         "INSERT ignore INTO peers SET hostname=:hostname, reserve=:reserve, ping=UNIX_TIMESTAMP(), ip=:ip ON DUPLICATE KEY UPDATE hostname=:hostname2", | ||||||
|  |         [":ip" => $ip, ":hostname2" => $hostname, ":hostname" => $hostname, ":reserve" => $reserve] | ||||||
|  |     ); | ||||||
|     // re-peer to make sure the peer is valid |     // re-peer to make sure the peer is valid | ||||||
|     $res=peer_post($hostname."/peer.php?q=peer",array("hostname"=>$_config['hostname'])); |     $res = peer_post($hostname."/peer.php?q=peer", ["hostname" => $_config['hostname']]); | ||||||
|     if($res!==false) api_echo("re-peer-ok"); |     if ($res !== false) { | ||||||
|     else{  |         api_echo("re-peer-ok"); | ||||||
|         $db->run("DELETE FROM peers WHERE ip=:ip",array(":ip"=>$ip)); |     } else { | ||||||
|  |         $db->run("DELETE FROM peers WHERE ip=:ip", [":ip" => $ip]); | ||||||
|         api_err("re-peer failed - $result"); |         api_err("re-peer failed - $result"); | ||||||
|     } |     } | ||||||
| } | } elseif ($q == "ping") { | ||||||
| elseif($q=="ping"){ |  | ||||||
|     // confirm peer is active |     // confirm peer is active | ||||||
|     api_echo("pong"); |     api_echo("pong"); | ||||||
| } elseif($q=="submitTransaction"){ | } elseif ($q == "submitTransaction") { | ||||||
|     // receive a new transaction from a peer |     // receive a new transaction from a peer | ||||||
|     $current=$block->current(); |     $current = $block->current(); | ||||||
|  |  | ||||||
|  |  | ||||||
|     // no transactions accepted if the sanity is syncing |     // no transactions accepted if the sanity is syncing | ||||||
|     if($_config['sanity_sync']==1) api_err("sanity-sync"); |     if ($_config['sanity_sync'] == 1) { | ||||||
|  |         api_err("sanity-sync"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $data['id']=san($data['id']); |     $data['id'] = san($data['id']); | ||||||
|     // validate transaction data |     // validate transaction data | ||||||
|     if(!$trx->check($data)) api_err("Invalid transaction"); |     if (!$trx->check($data)) { | ||||||
|     $hash=$data['id'];  |         api_err("Invalid transaction"); | ||||||
|  |     } | ||||||
|  |     $hash = $data['id']; | ||||||
|     // make sure it's not already in mempool |     // make sure it's not already in mempool | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM mempool WHERE id=:id",array(":id"=>$hash)); |     $res = $db->single("SELECT COUNT(1) FROM mempool WHERE id=:id", [":id" => $hash]); | ||||||
|     if($res!=0) api_err("The transaction is already in mempool"); |     if ($res != 0) { | ||||||
|  |         api_err("The transaction is already in mempool"); | ||||||
|  |     } | ||||||
|     // make sure the peer is not flooding us with transactions |     // 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'])); |     $res = $db->single("SELECT COUNT(1) FROM mempool WHERE src=:src", [":src" => $data['src']]); | ||||||
|     if($res>25) api_err("Too many transactions from this address in mempool. Please rebroadcast later."); |     if ($res > 25) { | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM mempool WHERE peer=:peer",array(":peer"=>$ip)); |         api_err("Too many transactions from this address in mempool. Please rebroadcast later."); | ||||||
|     if($res>$_config['peer_max_mempool']) api_error("Too many transactions broadcasted from this peer"); |     } | ||||||
|  |     $res = $db->single("SELECT COUNT(1) FROM mempool WHERE peer=:peer", [":peer" => $ip]); | ||||||
|  |     if ($res > $_config['peer_max_mempool']) { | ||||||
|  |         api_error("Too many transactions broadcasted from this peer"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     // make sure the transaction is not already on the blockchain |     // make sure the transaction is not already on the blockchain | ||||||
|     $res=$db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$hash)); |     $res = $db->single("SELECT COUNT(1) FROM transactions WHERE id=:id", [":id" => $hash]); | ||||||
|     if($res!=0) api_err("The transaction is already in a block"); |     if ($res != 0) { | ||||||
|     $acc=new Account; |         api_err("The transaction is already in a block"); | ||||||
|     $src=$acc->get_address($data['public_key']); |     } | ||||||
|  |     $acc = new Account(); | ||||||
|  |     $src = $acc->get_address($data['public_key']); | ||||||
|     // make sure the sender has enough balance |     // make sure the sender has enough balance | ||||||
|     $balance=$db->single("SELECT balance FROM accounts WHERE id=:id",array(":id"=>$src)); |     $balance = $db->single("SELECT balance FROM accounts WHERE id=:id", [":id" => $src]); | ||||||
|     if($balance<$val+$fee) api_err("Not enough funds"); |     if ($balance < $val + $fee) { | ||||||
|  |         api_err("Not enough funds"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // make sure the sender has enough pending balance |     // make sure the sender has enough pending balance | ||||||
|     $memspent=$db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:src",array(":src"=>$src)); |     $memspent = $db->single("SELECT SUM(val+fee) FROM mempool WHERE src=:src", [":src" => $src]); | ||||||
|     if($balance-$memspent<$val+$fee) api_err("Not enough funds (mempool)"); |     if ($balance - $memspent < $val + $fee) { | ||||||
|  |         api_err("Not enough funds (mempool)"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // add to mempool |     // add to mempool | ||||||
|     $trx->add_mempool($data, $ip); |     $trx->add_mempool($data, $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 |     // 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 ",array(":src"=>$data['src'])); |     $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']) system("php propagate.php transaction '$data[id]'  > /dev/null 2>&1  &"); |     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"); |     api_echo("transaction-ok"); | ||||||
| } | } elseif ($q == "submitBlock") { | ||||||
| elseif($q=="submitBlock"){ |  | ||||||
|     // receive a  new block from a peer |     // receive a  new block from a peer | ||||||
|  |  | ||||||
|     // if sanity sync, refuse all |     // if sanity sync, refuse all | ||||||
|     if($_config['sanity_sync']==1){ _log('['.$ip."] Block rejected due to sanity sync"); api_err("sanity-sync"); } |     if ($_config['sanity_sync'] == 1) { | ||||||
|     $data['id']=san($data['id']); |         _log('['.$ip."] Block rejected due to sanity sync"); | ||||||
|     $current=$block->current(); |         api_err("sanity-sync"); | ||||||
|  |     } | ||||||
|  |     $data['id'] = san($data['id']); | ||||||
|  |     $current = $block->current(); | ||||||
|     // block already in the blockchain |     // block already in the blockchain | ||||||
|     if($current['id']==$data['id']) api_echo("block-ok"); |     if ($current['id'] == $data['id']) { | ||||||
|     if($data['date']>time()+30) api_err("block in the future"); |         api_echo("block-ok"); | ||||||
|  |     } | ||||||
|  |     if ($data['date'] > time() + 30) { | ||||||
|  |         api_err("block in the future"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if($current['height']==$data['height']&&$current['id']!=$data['id']){ |     if ($current['height'] == $data['height'] && $current['id'] != $data['id']) { | ||||||
|         // different forks, same height |         // different forks, same height | ||||||
|         $accept_new=false; |         $accept_new = false; | ||||||
|         if($current['transactions']<$data['transactions']){ |  | ||||||
|     	    // accept the one with most transactions |  | ||||||
|             $accept_new=true; |  | ||||||
|         } elseif($current['transactions']==$data['transactions']) { |  | ||||||
|             // convert the first 12 characters from hex to decimal and the block with the largest number wins |             // 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)); |             $no1 = hexdec(substr(coin2hex($current['id']), 0, 12)); | ||||||
|             $no2=hexdec(substr(coin2hex($data['id']),0,12)); |             $no2 = hexdec(substr(coin2hex($data['id']), 0, 12)); | ||||||
|             if(gmp_cmp($no1,$no2)==1){ |             if (gmp_cmp($no1, $no2) == 1) { | ||||||
|                 $accept_new=true; |                 $accept_new = true; | ||||||
|             } |             } | ||||||
|         } |          | ||||||
|         if($accept_new){ |         if ($accept_new) { | ||||||
|             // if the new block is accepted, run a microsanity to sync it |             // if the new block is accepted, run a microsanity to sync it | ||||||
|             _log('['.$ip."] Starting microsanity - $data[height]"); |             _log('['.$ip."] Starting microsanity - $data[height]"); | ||||||
|             system("php sanity.php microsanity '$ip'  > /dev/null 2>&1  &"); |             system("php sanity.php microsanity '$ip'  > /dev/null 2>&1  &"); | ||||||
|             api_echo("microsanity"); |             api_echo("microsanity"); | ||||||
| 	 |  | ||||||
|         } else { |         } else { | ||||||
|             _log('['.$ip."] suggesting reverse-microsanity - $data[height]"); |             _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 |             api_echo("reverse-microsanity"); // if it's not, suggest to the peer to get the block from us | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     // if it's not the next block |     // if it's not the next block | ||||||
|     if($current['height']!=$data['height']-1) { |     if ($current['height'] != $data['height'] - 1) { | ||||||
|         // if the height of the block submitted is lower than our current height, send them our current block |         // if the height of the block submitted is lower than our current height, send them our current block | ||||||
|         if($data['height']<$current['height']){  |         if ($data['height'] < $current['height']) { | ||||||
| 		$pr=$db->row("SELECT * FROM peers WHERE ip=:ip",array(":ip"=>$ip)); |             $pr = $db->row("SELECT * FROM peers WHERE ip=:ip", [":ip" => $ip]); | ||||||
| 		if(!$pr) api_err("block-too-old"); |             if (!$pr) { | ||||||
| 		$peer_host=base58_encode($pr['hostname']); |                 api_err("block-too-old"); | ||||||
| 		$pr['ip']=escapeshellcmd($pr['ip']); |             } | ||||||
|  |             $peer_host = base58_encode($pr['hostname']); | ||||||
|  |             $pr['ip'] = escapeshellcmd(san_ip($pr['ip'])); | ||||||
|             system("php propagate.php block current '$peer_host' '$pr[ip]'   > /dev/null 2>&1  &"); |             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]"); |             _log('['.$ip."] block too old, sending our current block - $data[height]"); | ||||||
|  |  | ||||||
|             api_err("block-too-old"); |             api_err("block-too-old"); | ||||||
|         } |         } | ||||||
|         // if the block difference is bigger than 150, nothing should be done. They should sync via sanity |         // if the block difference is bigger than 150, nothing should be done. They should sync via sanity | ||||||
|         if($data['height']-$current['height']>150) {  |         if ($data['height'] - $current['height'] > 150) { | ||||||
|             _log('['.$ip."] block-out-of-sync - $data[height]"); |             _log('['.$ip."] block-out-of-sync - $data[height]"); | ||||||
|             api_err("block-out-of-sync"); |             api_err("block-out-of-sync"); | ||||||
|         } |         } | ||||||
|         // request them to send us a microsync with the latest blocks |         // request them to send us a microsync with the latest blocks | ||||||
|         _log('['.$ip."] requesting microsync - $current[height] - $data[height]"); |         _log('['.$ip."] requesting microsync - $current[height] - $data[height]"); | ||||||
|         api_echo(array("request"=>"microsync","height"=>$current['height'], "block"=>$current['id'])); |         api_echo(["request" => "microsync", "height" => $current['height'], "block" => $current['id']]); | ||||||
|          |  | ||||||
|     } |     } | ||||||
|     // check block data |     // check block data | ||||||
|     if(!$block->check($data)){ |     if (!$block->check($data)) { | ||||||
|         _log('['.$ip."] invalid block - $data[height]"); |         _log('['.$ip."] invalid block - $data[height]"); | ||||||
|         api_err("invalid-block"); |         api_err("invalid-block"); | ||||||
|     } |     } | ||||||
|     $b=$data; |     $b = $data; | ||||||
|     // add the block to the blockchain |     // add the block to the blockchain | ||||||
|     $res=$block->add($b['height'], $b['public_key'], $b['nonce'], $b['data'], $b['date'], $b['signature'], $b['difficulty'], $b['reward_signature'], $b['argon']);	 |     $res = $block->add( | ||||||
|  |         $b['height'], | ||||||
|  |         $b['public_key'], | ||||||
|  |         $b['nonce'], | ||||||
|  |         $b['data'], | ||||||
|  |         $b['date'], | ||||||
|  |         $b['signature'], | ||||||
|  |         $b['difficulty'], | ||||||
|  |         $b['reward_signature'], | ||||||
|  |         $b['argon'] | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     if(!$res) { |     if (!$res) { | ||||||
|         _log('['.$ip."] invalid block data - $data[height]"); |         _log('['.$ip."] invalid block data - $data[height]"); | ||||||
|         api_err("invalid-block-data"); |         api_err("invalid-block-data"); | ||||||
|     } |     } | ||||||
| @@ -191,38 +245,35 @@ elseif($q=="submitBlock"){ | |||||||
|     // send it to all our peers |     // send it to all our peers | ||||||
|     system("php propagate.php block '$data[id]' all all linear > /dev/null 2>&1  &"); |     system("php propagate.php block '$data[id]' all all linear > /dev/null 2>&1  &"); | ||||||
|     api_echo("block-ok"); |     api_echo("block-ok"); | ||||||
| } | } // return the current block, used in syncing | ||||||
| // return the current block, used in syncing | elseif ($q == "currentBlock") { | ||||||
| elseif($q=="currentBlock"){ |     $current = $block->current(); | ||||||
|    $current=$block->current(); |  | ||||||
|     api_echo($current); |     api_echo($current); | ||||||
| } | } // return a specific block, used in syncing | ||||||
| // return a specific block, used in syncing | elseif ($q == "getBlock") { | ||||||
| elseif($q=="getBlock"){ |     $height = intval($data['height']); | ||||||
|     $height=intval($data['height']); |     $export = $block->export("", $height); | ||||||
|      |     if (!$export) { | ||||||
|     $export=$block->export("",$height); |         api_err("invalid-block"); | ||||||
|     if(!$export) api_err("invalid-block"); |  | ||||||
|      api_echo($export); |  | ||||||
|     } |     } | ||||||
|  elseif($q=="getBlocks"){ |     api_echo($export); | ||||||
|  | } elseif ($q == "getBlocks") { | ||||||
| // returns X block starting at height,  used in syncing | // returns X block starting at height,  used in syncing | ||||||
|  |  | ||||||
|     $height=intval($data['height']); |     $height = intval($data['height']); | ||||||
|  |  | ||||||
|     $r=$db->run("SELECT id,height FROM blocks WHERE height>=:height ORDER by height ASC LIMIT 100",array(":height"=>$height)); |     $r = $db->run( | ||||||
|     foreach($r as $x){ |         "SELECT id,height FROM blocks WHERE height>=:height ORDER by height ASC LIMIT 100", | ||||||
|         $blocks[$x['height']]=$block->export($x['id']); |         [":height" => $height] | ||||||
|  |     ); | ||||||
|  |     foreach ($r as $x) { | ||||||
|  |         $blocks[$x['height']] = $block->export($x['id']); | ||||||
|     } |     } | ||||||
|     api_echo($blocks); |     api_echo($blocks); | ||||||
|  | } // returns a full list of unblacklisted peers in a random order | ||||||
|  } | elseif ($q == "getPeers") { | ||||||
|  // returns a full list of unblacklisted peers in a random order |     $peers = $db->run("SELECT ip,hostname FROM peers WHERE blacklisted<UNIX_TIMESTAMP() ORDER by RAND()"); | ||||||
|  elseif($q=="getPeers"){ |  | ||||||
|     $peers=$db->run("SELECT ip,hostname FROM peers WHERE blacklisted<UNIX_TIMESTAMP() ORDER by RAND()"); |  | ||||||
|     api_echo($peers); |     api_echo($peers); | ||||||
|  } else { | } else { | ||||||
|     api_err("Invalid request"); |     api_err("Invalid request"); | ||||||
|  } | } | ||||||
|   |  | ||||||
| ?> |  | ||||||
|   | |||||||
							
								
								
									
										183
									
								
								propagate.php
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								propagate.php
									
									
									
									
									
								
							| @@ -25,116 +25,155 @@ OR OTHER DEALINGS IN THE SOFTWARE. | |||||||
| */ | */ | ||||||
| set_time_limit(360); | set_time_limit(360); | ||||||
| require_once("include/init.inc.php"); | require_once("include/init.inc.php"); | ||||||
| $block= new Block(); | $block = new Block(); | ||||||
|  |  | ||||||
| $type=san($argv[1]); | $type = san($argv[1]); | ||||||
| $id=san($argv[2]); | $id = san($argv[2]); | ||||||
| $debug=false; | $debug = false; | ||||||
| $linear=false; | $linear = false; | ||||||
| // if debug mode, all data is printed to console, no background processes | // if debug mode, all data is printed to console, no background processes | ||||||
| if(trim($argv[5])=='debug') $debug=true; | if (trim($argv[5]) == 'debug') { | ||||||
| if(trim($argv[5])=='linear') $linear=true; |     $debug = true; | ||||||
| $peer=san(trim($argv[3])); | } | ||||||
|  | if (trim($argv[5]) == 'linear') { | ||||||
|  |     $linear = true; | ||||||
|  | } | ||||||
|  | $peer = san(trim($argv[3])); | ||||||
|  |  | ||||||
|  |  | ||||||
| // broadcasting a block to all peers | // broadcasting a block to all peers | ||||||
| if((empty($peer)||$peer=='all')&&$type=="block"){ | if ((empty($peer) || $peer == 'all') && $type == "block") { | ||||||
| 	$whr=""; |     $whr = ""; | ||||||
| 	if($id=="current") { |     if ($id == "current") { | ||||||
| 		$current=$block->current(); |         $current = $block->current(); | ||||||
| 		$id=$current['id']; |         $id = $current['id']; | ||||||
|     } |     } | ||||||
| 	$data=$block->export($id); |     $data = $block->export($id); | ||||||
| 	$id=san($id); |     $id = san($id); | ||||||
| 	if($data===false||empty($data)) die("Could not export block");   |     if ($data === false || empty($data)) { | ||||||
| 	$data=json_encode($data); |         die("Could not export block"); | ||||||
|  |     } | ||||||
|  |     $data = json_encode($data); | ||||||
|     // cache it to reduce the load |     // cache it to reduce the load | ||||||
| 	$res=file_put_contents("tmp/$id",$data); |     $res = file_put_contents("tmp/$id", $data); | ||||||
| 	if($res===false) die("Could not write the cache file"); |     if ($res === false) { | ||||||
|  |         die("Could not write the cache file"); | ||||||
|  |     } | ||||||
|     // broadcasting to all peers |     // broadcasting to all peers | ||||||
| 	$ewhr=""; |     $ewhr = ""; | ||||||
|     // boradcasting to only certain peers |     // boradcasting to only certain peers | ||||||
| 	if($linear==true) $ewhr=" ORDER by RAND() LIMIT 5"; |     if ($linear == true) { | ||||||
| 	$r=$db->run("SELECT * FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 $ewhr"); |         $ewhr = " ORDER by RAND() LIMIT 5"; | ||||||
| 	foreach($r as $x) { |     } | ||||||
|  |     $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 |         // encode the hostname in base58 and sanitize the IP to avoid any second order shell injections | ||||||
| 		$host=base58_encode($x['hostname']); |         $host = base58_encode($x['hostname']); | ||||||
| 		$ip=filter_var($x['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); |         $ip = 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 |         // fork a new process to send the blocks async | ||||||
| 		if($debug) system("php propagate.php '$type' '$id' '$host' '$ip' debug"); |         if ($debug) { | ||||||
| 		elseif($linear)  system("php propagate.php '$type' '$id' '$host' '$ip' linear"); |             system("php propagate.php '$type' '$id' '$host' '$ip' debug"); | ||||||
| 		else system("php propagate.php '$type' '$id' '$host' 'ip'  > /dev/null 2>&1  &"); |         } 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; |     exit; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // broadcast a block to a single peer (usually a forked process from above) | // broadcast a block to a single peer (usually a forked process from above) | ||||||
| if($type=="block"){ | if ($type == "block") { | ||||||
|     // current block or read cache |     // current block or read cache | ||||||
| 	if($id=="current"){ |     if ($id == "current") { | ||||||
| 		$current=$block->current(); |         $current = $block->current(); | ||||||
| 		$data=$block->export($current['id']); |         $data = $block->export($current['id']); | ||||||
| 		if(!$data)  { echo "Invalid Block data"; exit; } |         if (!$data) { | ||||||
| 	} else { |             echo "Invalid Block data"; | ||||||
| 		$data=file_get_contents("tmp/$id"); |             exit; | ||||||
| 		if(empty($data)) { echo "Invalid Block data"; exit; } |  | ||||||
| 		$data=json_decode($data,true); |  | ||||||
|         } |         } | ||||||
| 	$hostname=base58_decode($peer); |     } 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 |     // send the block as POST to the peer | ||||||
|     echo "Block sent to $hostname:\n"; |     echo "Block sent to $hostname:\n"; | ||||||
| 	$response= peer_post($hostname."/peer.php?q=submitBlock",$data,60, $debug); |     $response = peer_post($hostname."/peer.php?q=submitBlock", $data, 60, $debug); | ||||||
| 	if($response=="block-ok") { echo "Block $i accepted. Exiting.\n"; exit;} |     _log("Propagating block to $hostname - [result: $response] $data[height] - $data[id]",2); | ||||||
| 	elseif($response['request']=="microsync"){ |     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 |         // the peer requested us to send more blocks, as it's behind | ||||||
|         echo "Microsync request\n"; |         echo "Microsync request\n"; | ||||||
| 		$height=intval($response['height']); |         $height = intval($response['height']); | ||||||
| 		$bl=san($response['block']); |         $bl = san($response['block']); | ||||||
| 		$current=$block->current(); |         $current = $block->current(); | ||||||
|         // maximum microsync is 10 blocks, for more, the peer should sync by sanity |         // 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; } |         if ($current['height'] - $height > 10) { | ||||||
| 		$last_block=$block->get($height); |             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 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; } |         if ($last_block['id'] != $bl) { | ||||||
|  |             echo "Last block does not match\n"; | ||||||
|  |             exit; | ||||||
|  |         } | ||||||
|         echo "Sending the requested blocks\n"; |         echo "Sending the requested blocks\n"; | ||||||
|         //start sending the requested block |         //start sending the requested block | ||||||
| 		for($i=$height+1;$i<=$current['height'];$i++){ |         for ($i = $height + 1; $i <= $current['height']; $i++) { | ||||||
| 			$data=$block->export("",$i); |             $data = $block->export("", $i); | ||||||
| 			$response = peer_post($hostname."/peer.php?q=submitBlock",$data,60,$debug); |             $response = peer_post($hostname."/peer.php?q=submitBlock", $data, 60, $debug); | ||||||
| 			if($response!="block-ok") { echo "Block $i not accepted. Exiting.\n"; exit;} |             if ($response != "block-ok") { | ||||||
|  |                 echo "Block $i not accepted. Exiting.\n"; | ||||||
|  |                 exit; | ||||||
|  |             } | ||||||
|             echo "Block\t$i\t accepted\n"; |             echo "Block\t$i\t accepted\n"; | ||||||
|         } |         } | ||||||
|  |     } elseif ($response == "reverse-microsanity") { | ||||||
| 	} elseif($response=="reverse-microsanity"){ |  | ||||||
|         // the peer informe us that we should run a microsanity |         // the peer informe us that we should run a microsanity | ||||||
|         echo "Running microsanity\n"; |         echo "Running microsanity\n"; | ||||||
| 		$ip=trim($argv[4]); |         $ip = trim($argv[4]); | ||||||
| 		$ip=filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); |         $ip = filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); | ||||||
| 		if(empty($ip)) die("Invalid IP"); |         if (empty($ip)) { | ||||||
|  |             die("Invalid IP"); | ||||||
|  |         } | ||||||
|         // fork a microsanity in a new process |         // fork a microsanity in a new process | ||||||
|         system("php sanity.php microsanity '$ip'  > /dev/null 2>&1  &"); |         system("php sanity.php microsanity '$ip'  > /dev/null 2>&1  &"); | ||||||
|  |     } else { | ||||||
|  |         echo "Block not accepted!\n"; | ||||||
|     } |     } | ||||||
| 	else echo "Block not accepted!\n"; |  | ||||||
|  |  | ||||||
| } | } | ||||||
| // broadcast a transaction to some peers | // broadcast a transaction to some peers | ||||||
| if($type=="transaction"){ | if ($type == "transaction") { | ||||||
|  |     $trx = new Transaction(); | ||||||
| 	$trx=new Transaction; |  | ||||||
|     // get the transaction data |     // get the transaction data | ||||||
| 	$data=$trx->export($id); |     $data = $trx->export($id); | ||||||
|  |  | ||||||
| 	if(!$data){ echo "Invalid transaction id\n"; exit; } |     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 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()"); |     if ($data['peer'] == "local") { | ||||||
| 	else $r=$db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0  ORDER by RAND() LIMIT ".intval($_config['transaction_propagation_peers'])); |         $r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP()"); | ||||||
| 	foreach($r as $x){ |     } else { | ||||||
| 		$res= peer_post($x['hostname']."/peer.php?q=submitTransaction",$data); |         $r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0  ORDER by RAND() LIMIT ".intval($_config['transaction_propagation_peers'])); | ||||||
| 		if(!$res) echo "Transaction not accepted\n"; |     } | ||||||
| 		else echo "Transaction accepted\n"; |     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"; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
							
								
								
									
										702
									
								
								sanity.php
									
									
									
									
									
								
							
							
						
						
									
										702
									
								
								sanity.php
									
									
									
									
									
								
							| @@ -27,82 +27,173 @@ set_time_limit(0); | |||||||
| error_reporting(0); | error_reporting(0); | ||||||
|  |  | ||||||
| // make sure it's not accessible in the browser | // make sure it's not accessible in the browser | ||||||
| if(php_sapi_name() !== 'cli') die("This should only be run as cli"); | if (php_sapi_name() !== 'cli') { | ||||||
|  |     die("This should only be run as cli"); | ||||||
|  | } | ||||||
|  |  | ||||||
| // make sure there's only a single sanity process running at the same time | // make sure there's only a single sanity process running at the same time | ||||||
| if(file_exists("tmp/sanity-lock")){ | if (file_exists("tmp/sanity-lock")) { | ||||||
| 	$ignore_lock=false; |     $ignore_lock = false; | ||||||
| 	if($argv[1]=="force"){ |     if ($argv[1] == "force") { | ||||||
| 		$res=intval(shell_exec("ps aux|grep sanity.php|grep -v grep|wc -l")); |         $res = intval(shell_exec("ps aux|grep sanity.php|grep -v grep|wc -l")); | ||||||
| 		if($res==1){ |         if ($res == 1) { | ||||||
| 			$ignore_lock=true; |             $ignore_lock = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 	$pid_time=filemtime("tmp/sanity-lock"); |     $pid_time = filemtime("tmp/sanity-lock"); | ||||||
|     // if the process died, restart after 1day |     // if the process died, restart after 1day | ||||||
| 	if(time()-$pid_time>86400){ |     if (time() - $pid_time > 86400) { | ||||||
|         @unlink("tmp/sanity-lock"); |         @unlink("tmp/sanity-lock"); | ||||||
|     } |     } | ||||||
| 	if(!$ignore_lock) die("Sanity lock in place"); |     if (!$ignore_lock) { | ||||||
|  |         die("Sanity lock in place"); | ||||||
|  |     } | ||||||
| } | } | ||||||
| // set the new sanity lock | // set the new sanity lock | ||||||
| $lock = fopen("tmp/sanity-lock", "w"); | $lock = fopen("tmp/sanity-lock", "w"); | ||||||
| fclose($lock); | fclose($lock); | ||||||
| $arg=trim($argv[1]); | $arg = trim($argv[1]); | ||||||
| $arg2=trim($argv[2]); | $arg2 = trim($argv[2]); | ||||||
| echo "Sleeping for 3 seconds\n"; | echo "Sleeping for 3 seconds\n"; | ||||||
| // sleep for 3 seconds to make sure there's a delay between starting the sanity and other processes | // sleep for 3 seconds to make sure there's a delay between starting the sanity and other processes | ||||||
| if($arg!="microsanity") sleep(3); | if ($arg != "microsanity") { | ||||||
|  |     sleep(3); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
| require_once("include/init.inc.php"); | require_once("include/init.inc.php"); | ||||||
|  |  | ||||||
| // the sanity can't run without the schema being installed | // the sanity can't run without the schema being installed | ||||||
| if($_config['dbversion']<2){ | if ($_config['dbversion'] < 2) { | ||||||
|     die("DB schema not created"); |     die("DB schema not created"); | ||||||
|     @unlink("tmp/sanity-lock"); |     @unlink("tmp/sanity-lock"); | ||||||
|     exit; |     exit; | ||||||
| } | } | ||||||
|  |  | ||||||
| $block=new Block(); | ini_set('memory_limit', '2G'); | ||||||
| $acc=new Account(); |  | ||||||
| $current=$block->current(); |  | ||||||
|  |  | ||||||
|  | $block = new Block(); | ||||||
|  | $acc = new Account(); | ||||||
|  | $current = $block->current(); | ||||||
|  |  | ||||||
|  | // bootstrapping the initial sync | ||||||
|  | if ($current['height']==1) { | ||||||
|  |     echo "Bootstrapping!\n"; | ||||||
|  |     $last=file_get_contents("http://dumps.arionum.com/last"); | ||||||
|  |     $last=intval($last); | ||||||
|  |     $failed_sync=false; | ||||||
|  |     for ($i=1000;$i<=$last;$i=$i+1000) { | ||||||
|  |         echo "Download file $i\n"; | ||||||
|  |         $res=trim(file_get_contents("http://dumps.arionum.com/aro.db.$i")); | ||||||
|  |         if ($res===false) { | ||||||
|  |             echo "Could not download the bootstrap file $i. Syncing the old fashioned way.\n"; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         $data=json_decode($res, true); | ||||||
|  |          | ||||||
|  |         if ($data===false||is_null($data)) { | ||||||
|  |             echo "Could not parse the bootstrap file $i. Syncing the old fashioned way.\n"; | ||||||
|  |             echo json_last_error_msg(); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         foreach ($data as $x) { | ||||||
|  |             if (count($x['data'])>0) { | ||||||
|  |                 $transactions=[]; | ||||||
|  |                  | ||||||
|  |                 foreach ($x['data'] as $d) { | ||||||
|  |                     $trans = [ | ||||||
|  |                             "id"         => $d[0], | ||||||
|  |                             "dst"        => $d[1], | ||||||
|  |                             "val"        => $d[2], | ||||||
|  |                             "fee"        => $d[3], | ||||||
|  |                             "signature"  => $d[4], | ||||||
|  |                             "message"    => $d[5], | ||||||
|  |                             "version"    => $d[6], | ||||||
|  |                             "date"       => $d[7], | ||||||
|  |                             "public_key" => $d[8], | ||||||
|  |                         ]; | ||||||
|  |                     ksort($trans); | ||||||
|  |                     $transactions[$d[0]] = $trans; | ||||||
|  |                 } | ||||||
|  |                 ksort($transactions); | ||||||
|  |                 $x['data']=$transactions; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |          | ||||||
|  |             echo "-> Adding block $x[height]\n"; | ||||||
|  |  | ||||||
|  |             $res=$block->add($x['height'], $x['public_key'], $x['nonce'], $x['data'], $x['date'], $x['signature'], $x['difficulty'], $x['reward_signature'], $x['argon'], true); | ||||||
|  |             if (!$res) { | ||||||
|  |                 echo "Error: Adding the block failed. Syncing the old way.\n"; | ||||||
|  |                 $failed_sync=true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         if ($failed_sync) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     $current = $block->current(); | ||||||
|  | } | ||||||
| // the microsanity process is an anti-fork measure that will determine the best blockchain to choose for the last block | // the microsanity process is an anti-fork measure that will determine the best blockchain to choose for the last block | ||||||
| $microsanity=false; | $microsanity = false; | ||||||
| if($arg=="microsanity"&&!empty($arg2)){ | if ($arg == "microsanity" && !empty($arg2)) { | ||||||
|  |     do { | ||||||
| do { |  | ||||||
|         // the microsanity runs only against 1 specific peer |         // the microsanity runs only against 1 specific peer | ||||||
| 	$x=$db->row("SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP() AND ip=:ip",array(":ip"=>$arg2)); |         $x = $db->row( | ||||||
|  |             "SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP() AND ip=:ip", | ||||||
|  |             [":ip" => $arg2] | ||||||
|  |         ); | ||||||
|  |  | ||||||
| 	if(!$x){ echo "Invalid node - $arg2\n"; break; } |         if (!$x) { | ||||||
| 	$url=$x['hostname']."/peer.php?q="; |             echo "Invalid node - $arg2\n"; | ||||||
| 	$data=peer_post($url."getBlock",array("height"=>$current['height'])); |             break; | ||||||
|  |         } | ||||||
|  |         $url = $x['hostname']."/peer.php?q="; | ||||||
|  |         $data = peer_post($url."getBlock", ["height" => $current['height']]); | ||||||
|  |  | ||||||
| 	if(!$data) {echo "Invalid getBlock result\n"; break; } |         if (!$data) { | ||||||
|  |             echo "Invalid getBlock result\n"; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         $data['id'] = san($data['id']); | ||||||
|  |         $data['height'] = san($data['height']); | ||||||
|         // nothing to be done, same blockchain |         // nothing to be done, same blockchain | ||||||
| 	if($data['id']==$current['id']) {echo "Same block\n"; break;} |         if ($data['id'] == $current['id']) { | ||||||
|  |             echo "Same block\n"; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // the blockchain with the most transactions wins the fork (to encourage the miners to include as many transactions as possible) / might backfire on garbage |         // the blockchain with the most transactions wins the fork (to encourage the miners to include as many transactions as possible) / might backfire on garbage | ||||||
| 	if($current['transactions']>$data['transactions']){ |  | ||||||
| 		echo "Block has less transactions\n"; |  | ||||||
| 		break; |  | ||||||
| 	} elseif($current['transactions']==$data['transactions']) { |  | ||||||
| 		// transform the first 12 chars into an integer and choose the blockchain with the biggest value |  | ||||||
| 		$no1=hexdec(substr(coin2hex($current['id']),0,12)); |  | ||||||
| 		$no2=hexdec(substr(coin2hex($data['id']),0,12)); |  | ||||||
|  |  | ||||||
| 		if(gmp_cmp($no1,$no2)!=-1){ |         // transform the first 12 chars into an integer and choose the blockchain with the biggest value | ||||||
|  |         $no1 = hexdec(substr(coin2hex($current['id']), 0, 12)); | ||||||
|  |         $no2 = hexdec(substr(coin2hex($data['id']), 0, 12)); | ||||||
|  |  | ||||||
|  |         if (gmp_cmp($no1, $no2) != -1) { | ||||||
|             echo "Block hex larger than current\n"; |             echo "Block hex larger than current\n"; | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 	} |          | ||||||
|         // make sure the block is valid |         // make sure the block is valid | ||||||
| 	$prev = $block->get($current['height']-1); |         $prev = $block->get($current['height'] - 1); | ||||||
| 	$public=$acc->public_key($data['generator']); |         $public = $acc->public_key($data['generator']); | ||||||
| 	if(!$block->mine($public, $data['nonce'],$data['argon'],$block->difficulty($current['height']-1),$prev['id'], $prev['height'])) { echo "Invalid prev-block\n"; break;} |         if (!$block->mine( | ||||||
| 	if(!$block->check($data)) break; |             $public, | ||||||
|  |             $data['nonce'], | ||||||
|  |             $data['argon'], | ||||||
|  |             $block->difficulty($current['height'] - 1), | ||||||
|  |             $prev['id'], | ||||||
|  |             $prev['height'], | ||||||
|  |             $data['date'] | ||||||
|  |         )) { | ||||||
|  |             echo "Invalid prev-block\n"; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         if (!$block->check($data)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         // delete the last block |         // delete the last block | ||||||
|         $block->pop(1); |         $block->pop(1); | ||||||
| @@ -110,192 +201,241 @@ do { | |||||||
|  |  | ||||||
|         // add the new block |         // add the new block | ||||||
|         echo "Starting to sync last block from $x[hostname]\n"; |         echo "Starting to sync last block from $x[hostname]\n"; | ||||||
| 	$b=$data; |         $b = $data; | ||||||
| 	$res=$block->add($b['height'], $b['public_key'], $b['nonce'], $b['data'], $b['date'], $b['signature'], $b['difficulty'], $b['reward_signature'], $b['argon']);	 |  | ||||||
| 	if(!$res) { |  | ||||||
|  |  | ||||||
|  |          | ||||||
|  |         $res = $block->add( | ||||||
|  |             $b['height'], | ||||||
|  |             $b['public_key'], | ||||||
|  |             $b['nonce'], | ||||||
|  |             $b['data'], | ||||||
|  |             $b['date'], | ||||||
|  |             $b['signature'], | ||||||
|  |             $b['difficulty'], | ||||||
|  |             $b['reward_signature'], | ||||||
|  |             $b['argon'] | ||||||
|  |         ); | ||||||
|  |         if (!$res) { | ||||||
|             _log("Block add: could not add block - $b[id] - $b[height]"); |             _log("Block add: could not add block - $b[id] - $b[height]"); | ||||||
|  |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         _log("Synced block from $host - $b[height] $b[difficulty]"); |         _log("Synced block from $host - $b[height] $b[difficulty]"); | ||||||
| 	 |     } while (0); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } while(0); |  | ||||||
|  |  | ||||||
|     @unlink("tmp/sanity-lock"); |     @unlink("tmp/sanity-lock"); | ||||||
| exit; |     exit; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| $t=time(); | $t = time(); | ||||||
| //if($t-$_config['sanity_last']<300) {@unlink("tmp/sanity-lock");  die("The sanity cron was already run recently"); } | //if($t-$_config['sanity_last']<300) {@unlink("tmp/sanity-lock");  die("The sanity cron was already run recently"); } | ||||||
|  |  | ||||||
| _log("Starting sanity"); | _log("Starting sanity"); | ||||||
|  |  | ||||||
| // update the last time sanity ran, to set the execution of the next run | // update the last time sanity ran, to set the execution of the next run | ||||||
| $db->run("UPDATE config SET val=:time WHERE cfg='sanity_last'",array(":time"=>$t)); | $db->run("UPDATE config SET val=:time WHERE cfg='sanity_last'", [":time" => $t]); | ||||||
| $block_peers=array(); | $block_peers = []; | ||||||
| $longest_size=0; | $longest_size = 0; | ||||||
| $longest=0; | $longest = 0; | ||||||
| $blocks=array(); | $blocks = []; | ||||||
| $blocks_count=array(); | $blocks_count = []; | ||||||
| $most_common=""; | $most_common = ""; | ||||||
| $most_common_size=0; | $most_common_size = 0; | ||||||
| $total_active_peers=0; | $total_active_peers = 0; | ||||||
|  |  | ||||||
| // checking peers | // checking peers | ||||||
|  |  | ||||||
| // delete the dead peers | // delete the dead peers | ||||||
| $db->run("DELETE from peers WHERE fails>100 OR stuckfail>200"); | $db->run("DELETE from peers WHERE fails>100 OR stuckfail>200"); | ||||||
| $r=$db->run("SELECT id,hostname,stuckfail,fails FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()"); | $r = $db->run("SELECT id,hostname,stuckfail,fails FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()"); | ||||||
|  |  | ||||||
| $total_peers=count($r); | $total_peers = count($r); | ||||||
|  |  | ||||||
| $peered=array(); | $peered = []; | ||||||
| // if we have no peers, get the seed list from the official site | // if we have no peers, get the seed list from the official site | ||||||
| if($total_peers==0&&$_config['testnet']==false){ | if ($total_peers == 0 && $_config['testnet'] == false) { | ||||||
| 	$i=0; |     $i = 0; | ||||||
|     echo "No peers found. Attempting to get peers from arionum.com\n"; |     echo "No peers found. Attempting to get peers from arionum.com\n"; | ||||||
| 	$f=file("https://www.arionum.com/peers.txt"); |     $f = file("https://www.arionum.com/peers.txt"); | ||||||
|     shuffle($f); |     shuffle($f); | ||||||
|     // we can't connect to arionum.com |     // we can't connect to arionum.com | ||||||
| 	if(count($f)<2){ @unlink("tmp/sanity-lock"); die("Could nto connect to arionum.com! Will try later!\n"); } |     if (count($f) < 2) { | ||||||
| 	foreach($f as $peer){ |         @unlink("tmp/sanity-lock"); | ||||||
|  |         die("Could not connect to arionum.com! Will try later!\n"); | ||||||
|  |     } | ||||||
|  |     foreach ($f as $peer) { | ||||||
|         //peer with all until max_peers, this will ask them to send a peering request to our peer.php where we add their peer to the db. |         //peer with all until max_peers, this will ask them to send a peering request to our peer.php where we add their peer to the db. | ||||||
| 		$peer=trim($peer); |         $peer = trim(san_host($peer)); | ||||||
| 		$bad_peers=array("127.0.0.1","localhost"); |         $bad_peers = ["127.", "localhost", "10.", "192.168.","172.16.","172.17.","172.18.","172.19.","172.20.","172.21.","172.22.","172.23.","172.24.","172.25.","172.26.","172.27.","172.28.","172.29.","172.30.","172.31."]; | ||||||
| 		if(str_replace($bad_peers,"",$peer)!=$peer) continue; |  | ||||||
|  |         $tpeer=str_replace(["https://","http://","//"], "", $peer); | ||||||
|  |         foreach ($bad_peers as $bp) { | ||||||
|  |             if (strpos($tpeer, $bp)===0) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         $peer = filter_var($peer, FILTER_SANITIZE_URL); |         $peer = filter_var($peer, FILTER_SANITIZE_URL); | ||||||
|         	if (!filter_var($peer, FILTER_VALIDATE_URL)) continue; |         if (!filter_var($peer, FILTER_VALIDATE_URL)) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|         // store the hostname as md5 hash, for easier checking |         // store the hostname as md5 hash, for easier checking | ||||||
| 		$pid=md5($peer); |         $pid = md5($peer); | ||||||
|         // do not peer if we are already peered |         // do not peer if we are already peered | ||||||
| 		if($peered[$pid]==1) continue; |         if ($peered[$pid] == 1) { | ||||||
| 		$peered[$pid]=1; |             continue; | ||||||
| 		$res=peer_post($peer."/peer.php?q=peer",array("hostname"=>$_config['hostname'], "repeer"=>1)); |         } | ||||||
| 		if($res!==false) {$i++; echo "Peering OK - $peer\n"; } |         $peered[$pid] = 1; | ||||||
| 		else echo "Peering FAIL - $peer\n"; |         $res = peer_post($peer."/peer.php?q=peer", ["hostname" => $_config['hostname'], "repeer" => 1]); | ||||||
| 		if($i>$_config['max_peers']) break; |         if ($res !== false) { | ||||||
|  |             $i++; | ||||||
|  |             echo "Peering OK - $peer\n"; | ||||||
|  |         } else { | ||||||
|  |             echo "Peering FAIL - $peer\n"; | ||||||
|  |         } | ||||||
|  |         if ($i > $_config['max_peers']) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     // count the total peers we have |     // count the total peers we have | ||||||
| 	$r=$db->run("SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()"); |     $r = $db->run("SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()"); | ||||||
| 	$total_peers=count($r); |     $total_peers = count($r); | ||||||
| 	if($total_peers==0){ |     if ($total_peers == 0) { | ||||||
| 		// something went wrong, could nto add any peers -> exit |         // something went wrong, could not add any peers -> exit | ||||||
|         @unlink("tmp/sanity-lock"); |         @unlink("tmp/sanity-lock"); | ||||||
|         die("Could not peer to any peers! Please check internet connectivity!\n"); |         die("Could not peer to any peers! Please check internet connectivity!\n"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| // contact all the active peers | // contact all the active peers | ||||||
| foreach($r as $x){ | foreach ($r as $x) { | ||||||
|     _log("Contacting peer $x[hostname]"); |     _log("Contacting peer $x[hostname]"); | ||||||
| 	$url=$x['hostname']."/peer.php?q="; |     $url = $x['hostname']."/peer.php?q="; | ||||||
|     // get their peers list |     // get their peers list | ||||||
| 	$data=peer_post($url."getPeers",array(),5); | if($_config['get_more_peers']==true){  | ||||||
| 	if($data===false) {  |    $data = peer_post($url."getPeers", [], 5); | ||||||
|  |     if ($data === false) { | ||||||
|         _log("Peer $x[hostname] unresponsive"); |         _log("Peer $x[hostname] unresponsive"); | ||||||
|         // if the peer is unresponsive, mark it as failed and blacklist it for a while |         // if the peer is unresponsive, mark it as failed and blacklist it for a while | ||||||
| 		$db->run("UPDATE peers SET fails=fails+1, blacklisted=UNIX_TIMESTAMP()+((fails+1)*3600) WHERE id=:id",array(":id"=>$x['id']));		 |         $db->run( | ||||||
|  |             "UPDATE peers SET fails=fails+1, blacklisted=UNIX_TIMESTAMP()+((fails+1)*3600) WHERE id=:id", | ||||||
|  |             [":id" => $x['id']] | ||||||
|  |         ); | ||||||
|         continue; |         continue; | ||||||
|     } |     } | ||||||
| 	 |     $i = 0; | ||||||
| 		$i=0; |     foreach ($data as $peer) { | ||||||
| 		foreach($data as $peer){ |  | ||||||
|         // store the hostname as md5 hash, for easier checking |         // store the hostname as md5 hash, for easier checking | ||||||
| 			$pid=md5($peer['hostname']); |         $peer['hostname'] = san_host($peer['hostname']); | ||||||
|  |         $peer['ip'] = san_ip($peer['ip']); | ||||||
|  |         $pid = md5($peer['hostname']); | ||||||
|         // do not peer if we are already peered |         // do not peer if we are already peered | ||||||
|         	        if($peered[$pid]==1) continue; |         if ($peered[$pid] == 1) { | ||||||
| 	                $peered[$pid]=1; |             continue; | ||||||
| 			$bad_peers=array("127.0.0.1","localhost"); |         } | ||||||
|                 	if(str_replace($bad_peers,"",$peer['hostname'])!=$peer['hostname']) continue; |         $peered[$pid] = 1; | ||||||
|  |         $bad_peers = ["127.", "localhost", "10.", "192.168.","172.16.","172.17.","172.18.","172.19.","172.20.","172.21.","172.22.","172.23.","172.24.","172.25.","172.26.","172.27.","172.28.","172.29.","172.30.","172.31."]; | ||||||
|  |         $tpeer=str_replace(["https://","http://","//"], "", $peer['hostname']); | ||||||
|  |         foreach ($bad_peers as $bp) { | ||||||
|  |             if (strpos($tpeer, $bp)===0) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|         // if it's our hostname, ignore |         // if it's our hostname, ignore | ||||||
| 			if($peer['hostname']==$_config['hostname']) continue; |         if ($peer['hostname'] == $_config['hostname']) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|         // if invalid hostname, ignore |         // if invalid hostname, ignore | ||||||
| 			if (!filter_var($peer['hostname'], FILTER_VALIDATE_URL)) continue; |         if (!filter_var($peer['hostname'], FILTER_VALIDATE_URL)) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|         // make sure there's no peer in db with this ip or hostname |         // make sure there's no peer in db with this ip or hostname | ||||||
| 				if(!$db->single("SELECT COUNT(1) FROM peers WHERE ip=:ip or hostname=:hostname",array(":ip"=>$peer['ip'],":hostname"=>$peer['hostname']))){ |         if (!$db->single( | ||||||
|  |             "SELECT COUNT(1) FROM peers WHERE ip=:ip or hostname=:hostname", | ||||||
|  |             [":ip" => $peer['ip'], ":hostname" => $peer['hostname']] | ||||||
|  |         )) { | ||||||
|             $i++; |             $i++; | ||||||
|             // check a max_test_peers number of peers from each peer |             // check a max_test_peers number of peers from each peer | ||||||
| 					if($i>$_config['max_test_peers']) break; |             if ($i > $_config['max_test_peers']) { | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|             $peer['hostname'] = filter_var($peer['hostname'], FILTER_SANITIZE_URL); |             $peer['hostname'] = filter_var($peer['hostname'], FILTER_SANITIZE_URL); | ||||||
|             // peer with each one |             // peer with each one | ||||||
|             _log("Trying to peer with recommended peer: $peer[hostname]"); |             _log("Trying to peer with recommended peer: $peer[hostname]"); | ||||||
| 					$test=peer_post($peer['hostname']."/peer.php?q=peer",array("hostname"=>$_config['hostname']),5); |             $test = peer_post($peer['hostname']."/peer.php?q=peer", ["hostname" => $_config['hostname']], 5); | ||||||
| 					if($test!==false){ |             if ($test !== false) { | ||||||
|                 $total_peers++; |                 $total_peers++; | ||||||
|                 echo "Peered with: $peer[hostname]\n"; |                 echo "Peered with: $peer[hostname]\n"; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 	 | } | ||||||
|  |  | ||||||
|  |  | ||||||
| 	 |  | ||||||
|  |  | ||||||
|     // get the current block and check it's blockchain |     // get the current block and check it's blockchain | ||||||
| 	$data=peer_post($url."currentBlock",array(),5); |     $data = peer_post($url."currentBlock", [], 5); | ||||||
| 	if($data===false) continue; |     if ($data === false) { | ||||||
|  |         continue; | ||||||
|  |     } | ||||||
|     // peer was responsive, mark it as good |     // peer was responsive, mark it as good | ||||||
| 	if($x['fails']>0) $db->run("UPDATE peers SET fails=0 WHERE id=:id",array(":id"=>$x['id']));		 |     if ($x['fails'] > 0) { | ||||||
| 		if($data['height']<$current['height']-500) { |         $db->run("UPDATE peers SET fails=0 WHERE id=:id", [":id" => $x['id']]); | ||||||
| 			$db->run("UPDATE peers SET stuckfail=stuckfail+1, blacklisted=UNIX_TIMESTAMP()+7200 WHERE id=:id",array(":id"=>$x['id'])); |     } | ||||||
|  |     $data['id'] = san($data['id']); | ||||||
|  |     $data['height'] = san($data['height']); | ||||||
|  |  | ||||||
|  |     if ($data['height'] < $current['height'] - 500) { | ||||||
|  |         $db->run( | ||||||
|  |             "UPDATE peers SET stuckfail=stuckfail+1, blacklisted=UNIX_TIMESTAMP()+7200 WHERE id=:id", | ||||||
|  |             [":id" => $x['id']] | ||||||
|  |         ); | ||||||
|         continue; |         continue; | ||||||
|     } else { |     } else { | ||||||
| 			if($x['stuckfail']>0) $db->run("UPDATE peers SET stuckfail=0 WHERE id=:id",array(":id"=>$x['id'])); |         if ($x['stuckfail'] > 0) { | ||||||
|  |             $db->run("UPDATE peers SET stuckfail=0 WHERE id=:id", [":id" => $x['id']]); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     $total_active_peers++; |     $total_active_peers++; | ||||||
|     // add the hostname and block relationship to an array |     // add the hostname and block relationship to an array | ||||||
| 		$block_peers[$data['id']][]=$x['hostname']; |     $block_peers[$data['id']][] = $x['hostname']; | ||||||
|     // count the number of peers with this block id |     // count the number of peers with this block id | ||||||
|     $blocks_count[$data['id']]++; |     $blocks_count[$data['id']]++; | ||||||
|     // keep block data for this block id |     // keep block data for this block id | ||||||
| 		$blocks[$data['id']]=$data; |     $blocks[$data['id']] = $data; | ||||||
|     // set the most common block on all peers |     // set the most common block on all peers | ||||||
| 		if($blocks_count[$data['id']]>$most_common_size){ |     if ($blocks_count[$data['id']] > $most_common_size) { | ||||||
| 			$most_common=$data['id']; |         $most_common = $data['id']; | ||||||
| 			$most_common_size=$blocks_count[$data['id']]; |         $most_common_size = $blocks_count[$data['id']]; | ||||||
|     } |     } | ||||||
|     // set the largest height block |     // set the largest height block | ||||||
| 		if($data['height']>$largest_height){ |     if ($data['height'] > $largest_height) { | ||||||
| 			 $largest_height=$data['height']; |         $largest_height = $data['height']; | ||||||
| 			 $largest_height_block=$data['id']; |         $largest_height_block = $data['id']; | ||||||
| 		} elseif($data['height']==$largest_height&&$data['id']!=$largest_height_block){ |     } elseif ($data['height'] == $largest_height && $data['id'] != $largest_height_block) { | ||||||
|         // if there are multiple blocks on the largest height, choose one with the smallest (hardest) difficulty |         // if there are multiple blocks on the largest height, choose one with the smallest (hardest) difficulty | ||||||
| 			if($data['difficulty']==$blocks[$largest_height_block]['difficulty']){ |         if ($data['difficulty'] == $blocks[$largest_height_block]['difficulty']) { | ||||||
|             // if they have the same difficulty, choose if it's most common |             // if they have the same difficulty, choose if it's most common | ||||||
| 					if($most_common==$data['id']){ |             if ($most_common == $data['id']) { | ||||||
| 						$largest_height=$data['height']; |                 $largest_height = $data['height']; | ||||||
| 						$largest_height_block=$data['id']; |                 $largest_height_block = $data['id']; | ||||||
|             } else { |             } else { | ||||||
| 						// if this block has more transactions, declare it as winner |                 | ||||||
| 						if($blocks[$largest_height_block]['transactions']<$data['transactions']){ |  | ||||||
| 							$largest_height=$data['height']; |  | ||||||
| 							$largest_height_block=$data['id']; |  | ||||||
| 						} elseif($blocks[$largest_height_block]['transactions']==$data['transactions']) { |  | ||||||
|                     // if the blocks have the same number of transactions, choose the one with the highest derived integer from the first 12 hex characters |                     // if the blocks have the same number of transactions, choose the one with the highest derived integer from the first 12 hex characters | ||||||
| 							$no1=hexdec(substr(coin2hex($largest_height_block),0,12)); |                 $no1 = hexdec(substr(coin2hex($largest_height_block), 0, 12)); | ||||||
| 							$no2=hexdec(substr(coin2hex($data['id']),0,12)); |                 $no2 = hexdec(substr(coin2hex($data['id']), 0, 12)); | ||||||
| 							if(gmp_cmp($no1,$no2)==1){ |                 if (gmp_cmp($no1, $no2) == 1) { | ||||||
| 								$largest_height=$data['height']; |                     $largest_height = $data['height']; | ||||||
| 								$largest_height_block=$data['id']; |                     $largest_height_block = $data['id']; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| 					} |         } elseif ($data['difficulty'] < $blocks[$largest_height_block]['difficulty']) { | ||||||
| 			} elseif($data['difficulty']<$blocks[$largest_height_block]['difficulty']){ |  | ||||||
|             // choose smallest (hardest) difficulty |             // choose smallest (hardest) difficulty | ||||||
| 				$largest_height=$data['height']; |             $largest_height = $data['height']; | ||||||
| 				$largest_height_block=$data['id']; |             $largest_height_block = $data['id']; | ||||||
|         } |         } | ||||||
| 			 |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
| echo "Most common: $most_common\n"; | echo "Most common: $most_common\n"; | ||||||
| echo "Most common block: $most_common_size\n"; | echo "Most common block: $most_common_size\n"; | ||||||
| @@ -303,96 +443,149 @@ echo "Max height: $largest_height\n"; | |||||||
| echo "Current block: $current[height]\n"; | echo "Current block: $current[height]\n"; | ||||||
|  |  | ||||||
| // if we're not on the largest height | // if we're not on the largest height | ||||||
| if($current['height']<$largest_height&&$largest_height>1){ | if ($current['height'] < $largest_height && $largest_height > 1) { | ||||||
|     // start  sanity sync / block all other transactions/blocks |     // start  sanity sync / block all other transactions/blocks | ||||||
|     $db->run("UPDATE config SET val=1 WHERE cfg='sanity_sync'"); |     $db->run("UPDATE config SET val=1 WHERE cfg='sanity_sync'"); | ||||||
|     sleep(10); |     sleep(10); | ||||||
|     _log("Longest chain rule triggered - $largest_height - $largest_height_block"); |     _log("Longest chain rule triggered - $largest_height - $largest_height_block"); | ||||||
|     // choose the peers which have the larget height block |     // choose the peers which have the larget height block | ||||||
| 	$peers=$block_peers[$largest_height_block]; |     $peers = $block_peers[$largest_height_block]; | ||||||
|     shuffle($peers); |     shuffle($peers); | ||||||
|     // sync from them |     // sync from them | ||||||
| 	foreach($peers as $host){ |     foreach ($peers as $host) { | ||||||
|         _log("Starting to sync from $host"); |         _log("Starting to sync from $host"); | ||||||
| 		$url=$host."/peer.php?q="; |         $url = $host."/peer.php?q="; | ||||||
| 		$data=peer_post($url."getBlock",array("height"=>$current['height']),60); |         $data = peer_post($url."getBlock", ["height" => $current['height']], 60); | ||||||
|         // invalid data |         // invalid data | ||||||
| 		if($data===false){ _log("Could not get block from $host - $current[height]");  continue; } |         if ($data === false) { | ||||||
|  |             _log("Could not get block from $host - $current[height]"); | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         $data['id'] = san($data['id']); | ||||||
|  |         $data['height'] = san($data['height']); | ||||||
|  |  | ||||||
|         // if we're not on the same blockchain but the blockchain is most common with over 90% of the peers, delete the last 3 blocks and retry |         // if we're not on the same blockchain but the blockchain is most common with over 90% of the peers, delete the last 3 blocks and retry | ||||||
| 		if($data['id']!=$current['id']&&$data['id']==$most_common&&($most_common_size/$total_active_peers)>0.90){ |         if ($data['id'] != $current['id'] && $data['id'] == $most_common && ($most_common_size / $total_active_peers) > 0.90) { | ||||||
| 			$block->delete($current['height']-3); |             $block->delete($current['height'] - 3); | ||||||
| 			$current=$block->current(); |             $current = $block->current(); | ||||||
| 			$data=peer_post($url."getBlock",array("height"=>$current['height'])); |             $data = peer_post($url."getBlock", ["height" => $current['height']]); | ||||||
|  |  | ||||||
| 			if($data===false){_log("Could not get block from $host - $current[height]"); 	 break; } |             if ($data === false) { | ||||||
| 		 |                 _log("Could not get block from $host - $current[height]"); | ||||||
| 		}elseif($data['id']!=$current['id']&&$data['id']!=$most_common){ |                 break; | ||||||
|  |             } | ||||||
|  |         } elseif ($data['id'] != $current['id'] && $data['id'] != $most_common) { | ||||||
|             //if we're not on the same blockchain and also it's not the most common, verify all the blocks on on this blockchain starting at current-10 until current |             //if we're not on the same blockchain and also it's not the most common, verify all the blocks on on this blockchain starting at current-10 until current | ||||||
| 				$invalid=false; |             $invalid = false; | ||||||
| 				$last_good=$current['height']; |             $last_good = $current['height']; | ||||||
| 				for($i=$current['height']-10;$i<$current['height'];$i++){ |             for ($i = $current['height'] - 10; $i < $current['height']; $i++) { | ||||||
| 				 	$data=peer_post($url."getBlock",array("height"=>$i)); |                 $data = peer_post($url."getBlock", ["height" => $i]); | ||||||
| 					if($data===false){ $invalid=true; break; } |                 if ($data === false) { | ||||||
| 					$ext=$block->get($i); |                     $invalid = true; | ||||||
| 					if($i==$current['height']-10&&$ext['id']!=$data['id']){ $invalid=true; break; } |                     break; | ||||||
| 					 |                 } | ||||||
| 					if($ext['id']==$data['id']) $last_good=$i; |                 $ext = $block->get($i); | ||||||
|  |                 if ($i == $current['height'] - 10 && $ext['id'] != $data['id']) { | ||||||
|  |                     $invalid = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 if ($ext['id'] == $data['id']) { | ||||||
|  |                     $last_good = $i; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if ($last_good==$current['height']-1&&$last_good%3==2) { | ||||||
|  |                 $block->pop(1); | ||||||
|             } |             } | ||||||
|             // if last 10 blocks are good, verify all the blocks |             // if last 10 blocks are good, verify all the blocks | ||||||
| 				if($invalid==false) { |             if ($invalid == false) { | ||||||
| 					$cblock=array(); |                 $cblock = []; | ||||||
| 					for($i=$last_good;$i<=$largest_height;$i++){ |                 for ($i = $last_good; $i <= $largest_height; $i++) { | ||||||
| 						$data=peer_post($url."getBlock",array("height"=>$i)); |                     $data = peer_post($url."getBlock", ["height" => $i]); | ||||||
| 						if($data===false){ $invalid=true; break; } |                     if ($data === false) { | ||||||
| 						$cblock[$i]=$data; |                         $invalid = true; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|  |                     $cblock[$i] = $data; | ||||||
|                 } |                 } | ||||||
|                 // check if the block mining data is correct |                 // check if the block mining data is correct | ||||||
| 					for($i=$last_good+1;$i<=$largest_height;$i++){ |                 for ($i = $last_good + 1; $i <= $largest_height; $i++) { | ||||||
| 						if(!$block->mine($cblock[$i]['public_key'], $cblock[$i]['nonce'], $cblock[$i]['argon'], $cblock[$i]['difficulty'], $cblock[$i-1]['id'],$cblock[$i-1]['height'])) {$invalid=true; break; } |                     if (($i-1)%3==2) { | ||||||
|  |                         continue; | ||||||
|  |                     } | ||||||
|  |                     if (!$block->mine( | ||||||
|  |                         $cblock[$i]['public_key'], | ||||||
|  |                         $cblock[$i]['nonce'], | ||||||
|  |                         $cblock[$i]['argon'], | ||||||
|  |                         $cblock[$i]['difficulty'], | ||||||
|  |                         $cblock[$i - 1]['id'], | ||||||
|  |                         $cblock[$i - 1]['height'], | ||||||
|  |                         $cblock[$i]['date'] | ||||||
|  |                     )) { | ||||||
|  |                         $invalid = true; | ||||||
|  |                         break; | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             // if the blockchain proves ok, delete until the last block |             // if the blockchain proves ok, delete until the last block | ||||||
| 				if($invalid==false){ |             if ($invalid == false) { | ||||||
|  |                 _log("Changing fork, deleting $last_good", 1); | ||||||
|                 $block->delete($last_good); |                 $block->delete($last_good); | ||||||
| 					$current=$block->current(); |                 $current = $block->current(); | ||||||
| 					$data=$current; |                 $data = $current; | ||||||
|             } |             } | ||||||
| 			 |  | ||||||
|         } |         } | ||||||
|         // if current still doesn't match the data, something went wrong |         // if current still doesn't match the data, something went wrong | ||||||
| 		if($data['id']!=$current['id']) continue; |         if ($data['id'] != $current['id']) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|         // start syncing all blocks |         // start syncing all blocks | ||||||
| 		while($current['height']<$largest_height){ |         while ($current['height'] < $largest_height) { | ||||||
| 			$data=peer_post($url."getBlocks",array("height"=>$current['height']+1)); |             $data = peer_post($url."getBlocks", ["height" => $current['height'] + 1]); | ||||||
|  |  | ||||||
| 			if($data===false){_log("Could not get blocks from $host - height: $current[height]");  break; } |             if ($data === false) { | ||||||
| 			$good_peer=true; |                 _log("Could not get blocks from $host - height: $current[height]"); | ||||||
| 			foreach($data as $b){ |  | ||||||
| 				if(!$block->check($b)){ |  | ||||||
| 					_log("Block check: could not add block - $b[id] - $b[height]"); |  | ||||||
| 					$good_peer=false;  |  | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
| 				$res=$block->add($b['height'], $b['public_key'], $b['nonce'], $b['data'], $b['date'], $b['signature'], $b['difficulty'], $b['reward_signature'], $b['argon']);	 |             $good_peer = true; | ||||||
| 				if(!$res) { |             foreach ($data as $b) { | ||||||
|  |                 $b['id'] = san($b['id']); | ||||||
|  |                 $b['height'] = san($b['height']); | ||||||
|                  |                  | ||||||
|  |                 if (!$block->check($b)) { | ||||||
|  |                     _log("Block check: could not add block - $b[id] - $b[height]"); | ||||||
|  |                     $good_peer = false; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |                 $res = $block->add( | ||||||
|  |                     $b['height'], | ||||||
|  |                     $b['public_key'], | ||||||
|  |                     $b['nonce'], | ||||||
|  |                     $b['data'], | ||||||
|  |                     $b['date'], | ||||||
|  |                     $b['signature'], | ||||||
|  |                     $b['difficulty'], | ||||||
|  |                     $b['reward_signature'], | ||||||
|  |                     $b['argon'] | ||||||
|  |                 ); | ||||||
|  |                 if (!$res) { | ||||||
|                     _log("Block add: could not add block - $b[id] - $b[height]"); |                     _log("Block add: could not add block - $b[id] - $b[height]"); | ||||||
| 					$good_peer=false; |                     $good_peer = false; | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 _log("Synced block from $host - $b[height] $b[difficulty]"); |                 _log("Synced block from $host - $b[height] $b[difficulty]"); | ||||||
| 				 |  | ||||||
|             } |             } | ||||||
| 			if(!$good_peer) break; |             if (!$good_peer) { | ||||||
| 			$current=$block->current();		 |                 break; | ||||||
|  |  | ||||||
|             } |             } | ||||||
| 		if($good_peer) break; |             $current = $block->current(); | ||||||
| 		 |  | ||||||
|         } |         } | ||||||
| 	$db->run("UPDATE config SET val=0 WHERE cfg='sanity_sync'",array(":time"=>$t)); |         if ($good_peer) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     $db->run("UPDATE config SET val=0 WHERE cfg='sanity_sync'", [":time" => $t]); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -400,96 +593,121 @@ if($current['height']<$largest_height&&$largest_height>1){ | |||||||
| $db->run("DELETE FROM `mempool` WHERE `date` < UNIX_TIMESTAMP()-(3600*24*14)"); | $db->run("DELETE FROM `mempool` WHERE `date` < UNIX_TIMESTAMP()-(3600*24*14)"); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| //rebroadcasting local transactions | //rebroadcasting local transactions | ||||||
| if($_config['sanity_rebroadcast_locals']==true){ | if ($_config['sanity_rebroadcast_locals'] == true) { | ||||||
| $r=$db->run("SELECT id FROM mempool WHERE height>=:current and peer='local' order by `height` asc LIMIT 20",array(":current"=>$current['height'])); |     $r = $db->run( | ||||||
| _log("Rebroadcasting local transactions - ".count($r)); |         "SELECT id FROM mempool WHERE height>=:current and peer='local' order by `height` asc LIMIT 20", | ||||||
| foreach($r as $x){ |         [":current" => $current['height']] | ||||||
|         $x['id']=san($x['id']); |     ); | ||||||
|  |     _log("Rebroadcasting local transactions - ".count($r)); | ||||||
|  |     foreach ($r as $x) { | ||||||
|  |         $x['id'] = san($x['id']); | ||||||
|         system("php propagate.php transaction $x[id]  > /dev/null 2>&1  &"); |         system("php propagate.php transaction $x[id]  > /dev/null 2>&1  &"); | ||||||
|         $db->run("UPDATE mempool SET height=:current WHERE id=:id",array(":id"=>$x['id'], ":current"=>$current['height'])); |         $db->run( | ||||||
| } |             "UPDATE mempool SET height=:current WHERE id=:id", | ||||||
|  |             [":id" => $x['id'], ":current" => $current['height']] | ||||||
|  |         ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| //rebroadcasting transactions | //rebroadcasting transactions | ||||||
| $forgotten=$current['height']-$_config['sanity_rebroadcast_height']; | $forgotten = $current['height'] - $_config['sanity_rebroadcast_height']; | ||||||
| $r=$db->run("SELECT id FROM mempool WHERE height<:forgotten ORDER by val DESC LIMIT 10",array(":forgotten"=>$forgotten)); | $r = $db->run( | ||||||
|  |     "SELECT id FROM mempool WHERE height<:forgotten ORDER by val DESC LIMIT 10", | ||||||
|  |     [":forgotten" => $forgotten] | ||||||
|  | ); | ||||||
|  |  | ||||||
| _log("Rebroadcasting external transactions - ".count($r)); | _log("Rebroadcasting external transactions - ".count($r)); | ||||||
|  |  | ||||||
| foreach($r as $x){ | foreach ($r as $x) { | ||||||
| 	$x['id']=san($x['id']); |     $x['id'] = san($x['id']); | ||||||
|     system("php propagate.php transaction $x[id]  > /dev/null 2>&1  &"); |     system("php propagate.php transaction $x[id]  > /dev/null 2>&1  &"); | ||||||
| 	$db->run("UPDATE mempool SET height=:current WHERE id=:id",array(":id"=>$x['id'], ":current"=>$current['height'])); |     $db->run("UPDATE mempool SET height=:current WHERE id=:id", [":id" => $x['id'], ":current" => $current['height']]); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| //add new peers if there aren't enough active | //add new peers if there aren't enough active | ||||||
| if($total_peers<$_config['max_peers']*0.7){ | if ($total_peers < $_config['max_peers'] * 0.7) { | ||||||
| 	$res=$_config['max_peers']-$total_peers; |     $res = $_config['max_peers'] - $total_peers; | ||||||
|     $db->run("UPDATE peers SET reserve=0 WHERE reserve=1 AND blacklisted<UNIX_TIMESTAMP() LIMIT $res"); |     $db->run("UPDATE peers SET reserve=0 WHERE reserve=1 AND blacklisted<UNIX_TIMESTAMP() LIMIT $res"); | ||||||
| } | } | ||||||
|  |  | ||||||
| //random peer check | //random peer check | ||||||
| $r=$db->run("SELECT * FROM peers WHERE blacklisted<UNIX_TIMESTAMP() and reserve=1 LIMIT ".$_config['max_test_peers']); | $r = $db->run("SELECT * FROM peers WHERE blacklisted<UNIX_TIMESTAMP() and reserve=1 LIMIT ".$_config['max_test_peers']); | ||||||
| foreach($r as $x){ | foreach ($r as $x) { | ||||||
| 	 |     $url = $x['hostname']."/peer.php?q="; | ||||||
| 	$url=$x['hostname']."/peer.php?q="; |     $data = peer_post($url."ping", [], 5); | ||||||
| 	$data=peer_post($url."ping",array(),5); |     if ($data === false) { | ||||||
| 	if($data===false){ |         $db->run( | ||||||
| 		 $db->run("UPDATE peers SET fails=fails+1, blacklisted=UNIX_TIMESTAMP()+((fails+1)*60) WHERE id=:id",array(":id"=>$x['id']));  |             "UPDATE peers SET fails=fails+1, blacklisted=UNIX_TIMESTAMP()+((fails+1)*60) WHERE id=:id", | ||||||
|  |             [":id" => $x['id']] | ||||||
|  |         ); | ||||||
|         _log("Random reserve peer test $x[hostname] -> FAILED"); |         _log("Random reserve peer test $x[hostname] -> FAILED"); | ||||||
| 	}else{ |     } else { | ||||||
|         _log("Random reserve peer test $x[hostname] -> OK"); |         _log("Random reserve peer test $x[hostname] -> OK"); | ||||||
| 		 $db->run("UPDATE peers SET fails=0 WHERE id=:id",array(":id"=>$x['id'])); |         $db->run("UPDATE peers SET fails=0 WHERE id=:id", [":id" => $x['id']]); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| //clean tmp files | //clean tmp files | ||||||
| _log("Cleaning tmp files"); | _log("Cleaning tmp files"); | ||||||
| $f=scandir("tmp/"); | $f = scandir("tmp/"); | ||||||
| $time=time(); | $time = time(); | ||||||
| foreach($f as $x){ | foreach ($f as $x) { | ||||||
| 	if(strlen($x)<5&&substr($x,0,1)==".") continue; |     if (strlen($x) < 5 && substr($x, 0, 1) == ".") { | ||||||
| 	$pid_time=filemtime("tmp/$x"); |         continue; | ||||||
| 	if($time-$pid_time>7200) @unlink("tmp/$x"); |     } | ||||||
|  |     $pid_time = filemtime("tmp/$x"); | ||||||
|  |     if ($time - $pid_time > 7200) { | ||||||
|  |         @unlink("tmp/$x"); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| //recheck the last blocks | //recheck the last blocks | ||||||
| if($_config['sanity_recheck_blocks']>0){ | if ($_config['sanity_recheck_blocks'] > 0 && $_config['testnet'] == false&&1==2) { | ||||||
| _log("Rechecking blocks"); |     _log("Rechecking blocks"); | ||||||
| 	$blocks=array(); |     $blocks = []; | ||||||
| 	$all_blocks_ok=true; |     $all_blocks_ok = true; | ||||||
| 	$start=$current['height']-$_config['sanity_recheck_blocks']; |     $start = $current['height'] - $_config['sanity_recheck_blocks']; | ||||||
| 	if($start<2) $start=2; |     if ($start < 2) { | ||||||
| 	$r=$db->run("SELECT * FROM blocks WHERE height>=:height ORDER by height ASC",array(":height"=>$start)); |         $start = 2; | ||||||
| 	foreach($r as $x){ |     } | ||||||
| 			$blocks[$x['height']]=$x; |     $r = $db->run("SELECT * FROM blocks WHERE height>=:height ORDER by height ASC", [":height" => $start]); | ||||||
| 			$max_height=$x['height']; |     foreach ($r as $x) { | ||||||
|  |         $blocks[$x['height']] = $x; | ||||||
|  |         $max_height = $x['height']; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 	for($i=$start+1;$i<=$max_height;$i++){ |     for ($i = $start + 1; $i <= $max_height; $i++) { | ||||||
| 			$data=$blocks[$i]; |         $data = $blocks[$i]; | ||||||
|  |  | ||||||
| 			$key=$db->single("SELECT public_key FROM accounts WHERE id=:id",array(":id"=>$data['generator'])); |         $key = $db->single("SELECT public_key FROM accounts WHERE id=:id", [":id" => $data['generator']]); | ||||||
|  |  | ||||||
| 			if(!$block->mine($key,$data['nonce'], $data['argon'], $data['difficulty'], $blocks[$i-1]['id'], $blocks[$i-1]['height'])) { |         if (!$block->mine( | ||||||
|  |             $key, | ||||||
|  |             $data['nonce'], | ||||||
|  |             $data['argon'], | ||||||
|  |             $data['difficulty'], | ||||||
|  |             $blocks[$i - 1]['id'], | ||||||
|  |             $blocks[$i - 1]['height'], | ||||||
|  |             $data['date'] | ||||||
|  |         )) { | ||||||
|             $db->run("UPDATE config SET val=1 WHERE cfg='sanity_sync'"); |             $db->run("UPDATE config SET val=1 WHERE cfg='sanity_sync'"); | ||||||
|             _log("Invalid block detected. Deleting everything after $data[height] - $data[id]"); |             _log("Invalid block detected. Deleting everything after $data[height] - $data[id]"); | ||||||
|             sleep(10); |             sleep(10); | ||||||
| 					$all_blocks_ok=false; |             $all_blocks_ok = false; | ||||||
|             $block->delete($i); |             $block->delete($i); | ||||||
|  |  | ||||||
|             $db->run("UPDATE config SET val=0 WHERE cfg='sanity_sync'"); |             $db->run("UPDATE config SET val=0 WHERE cfg='sanity_sync'"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 	if($all_blocks_ok) echo "All checked blocks are ok\n"; |     if ($all_blocks_ok) { | ||||||
|  |         echo "All checked blocks are ok\n"; | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| _log("Finishing sanity"); | _log("Finishing sanity"); | ||||||
|  |  | ||||||
| @unlink("tmp/sanity-lock"); | @unlink("tmp/sanity-lock"); | ||||||
| ?> |  | ||||||
|   | |||||||
| @@ -0,0 +1 @@ | |||||||
|  | 4.0.1 | ||||||
|   | |||||||
							
								
								
									
										315
									
								
								util.php
									
									
									
									
									
								
							
							
						
						
									
										315
									
								
								util.php
									
									
									
									
									
								
							| @@ -24,14 +24,13 @@ 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. | ||||||
| */ | */ | ||||||
|  |  | ||||||
|  |  | ||||||
| // make sure it's not accessible in the browser | // make sure it's not accessible in the browser | ||||||
| if(php_sapi_name() !== 'cli') die("This should only be run as cli"); | if (php_sapi_name() !== 'cli') { | ||||||
|  |     die("This should only be run as cli"); | ||||||
|  | } | ||||||
|  |  | ||||||
| require_once("include/init.inc.php"); | require_once("include/init.inc.php"); | ||||||
| $cmd=trim($argv[1]); | $cmd = trim($argv[1]); | ||||||
|  |  | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * @api {php util.php} clean Clean |  * @api {php util.php} clean Clean | ||||||
| @@ -43,16 +42,16 @@ $cmd=trim($argv[1]); | |||||||
|  * php util.php clean |  * php util.php clean | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| if($cmd=='clean'){ | if ($cmd == 'clean') { | ||||||
| $tables=array("blocks","accounts","transactions","mempool"); |     $db->run("SET foreign_key_checks=0;"); | ||||||
| foreach($tables as $table) $db->run("DELETE FROM {$table}"); |     $tables = ["accounts", "transactions", "mempool", "masternode","blocks"]; | ||||||
|  |     foreach ($tables as $table) { | ||||||
|  |         $db->run("TRUNCATE TABLE {$table}"); | ||||||
|  |     } | ||||||
|  |     $db->run("SET foreign_key_checks=1;"); | ||||||
|  |  | ||||||
| echo "\n The database has been cleared\n"; |     echo "\n The database has been cleared\n"; | ||||||
|  | } /** | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @api {php util.php} pop Pop |  * @api {php util.php} pop Pop | ||||||
|  * @apiName pop |  * @apiName pop | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -64,13 +63,11 @@ echo "\n The database has been cleared\n"; | |||||||
|  * php util.php pop 1 |  * php util.php pop 1 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| elseif($cmd=='pop'){ | elseif ($cmd == 'pop') { | ||||||
| 	$no=intval($argv[2]); |     $no = intval($argv[2]); | ||||||
| 	$block=new Block; |     $block = new Block(); | ||||||
|     $block->pop($no); |     $block->pop($no); | ||||||
| } | } /** | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * @api {php util.php} block-time Block-time |  * @api {php util.php} block-time Block-time | ||||||
|  * @apiName block-time |  * @apiName block-time | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -86,22 +83,21 @@ elseif($cmd=='pop'){ | |||||||
|  * Average block time: 217 seconds |  * Average block time: 217 seconds | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| elseif($cmd=='block-time'){ | elseif ($cmd == 'block-time') { | ||||||
| 	$t=time(); |     $t = time(); | ||||||
| 	$r=$db->run("SELECT * FROM blocks ORDER by height DESC LIMIT 100"); |     $r = $db->run("SELECT * FROM blocks ORDER by height DESC LIMIT 100"); | ||||||
| 	$start=0; |     $start = 0; | ||||||
| 	foreach($r as $x){ |     foreach ($r as $x) { | ||||||
| 		if($start==0) $start=$x['date']; |         if ($start == 0) { | ||||||
| 		$time=$t-$x['date']; |             $start = $x['date']; | ||||||
| 		$t=$x['date']; |  | ||||||
| 		echo "$x[height] -> $time\n"; |  | ||||||
| 		$end=$x['date']; |  | ||||||
|         } |         } | ||||||
| echo "Average block time: ".ceil(($start-$end)/100)." seconds\n"; |         $time = $t - $x['date']; | ||||||
|  |         $t = $x['date']; | ||||||
|  |         echo "$x[height] -> $time\n"; | ||||||
| } |         $end = $x['date']; | ||||||
| /** |     } | ||||||
|  |     echo "Average block time: ".ceil(($start - $end) / 100)." seconds\n"; | ||||||
|  | } /** | ||||||
|  * @api {php util.php} peer Peer |  * @api {php util.php} peer Peer | ||||||
|  * @apiName peer |  * @apiName peer | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -117,12 +113,14 @@ echo "Average block time: ".ceil(($start-$end)/100)." seconds\n"; | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
| elseif($cmd=="peer"){ | elseif ($cmd == "peer") { | ||||||
| 	$res=peer_post($argv[2]."/peer.php?q=peer",array("hostname"=>$_config['hostname'])); |     $res = peer_post($argv[2]."/peer.php?q=peer", ["hostname" => $_config['hostname']]); | ||||||
| 	if($res!==false) echo "Peering OK\n"; |     if ($res !== false) { | ||||||
| 	else echo "Peering FAIL\n"; |         echo "Peering OK\n"; | ||||||
| }  |     } else { | ||||||
| /** |         echo "Peering FAIL\n"; | ||||||
|  |     } | ||||||
|  | } /** | ||||||
|  * @api {php util.php} current Current |  * @api {php util.php} current Current | ||||||
|  * @apiName current |  * @apiName current | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -155,11 +153,10 @@ elseif($cmd=="peer"){ | |||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| elseif ($cmd=="current") { | elseif ($cmd == "current") { | ||||||
| 	$block=new Block; |     $block = new Block(); | ||||||
|     var_dump($block->current()); |     var_dump($block->current()); | ||||||
| } | } /** | ||||||
| /** |  | ||||||
|  * @api {php util.php} blocks Blocks |  * @api {php util.php} blocks Blocks | ||||||
|  * @apiName blocks |  * @apiName blocks | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -180,16 +177,17 @@ elseif ($cmd=="current") { | |||||||
|  * 10805   5RBeWXo2c9NZ7UF2ubztk53PZpiA4tsk3bhXNXbcBk89cNqorNj771Qu4kthQN5hXLtu1hzUnv7nkH33hDxBM34m |  * 10805   5RBeWXo2c9NZ7UF2ubztk53PZpiA4tsk3bhXNXbcBk89cNqorNj771Qu4kthQN5hXLtu1hzUnv7nkH33hDxBM34m | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
|  elseif($cmd=="blocks"){ | elseif ($cmd == "blocks") { | ||||||
| 	$height=intval($argv[2]); |     $height = intval($argv[2]); | ||||||
| 	$limit=intval($argv[3]); |     $limit = intval($argv[3]); | ||||||
| 	if($limit<1) $limit=100; |     if ($limit < 1) { | ||||||
| 	$r=$db->run("SELECT * FROM blocks WHERE height>:height ORDER by height ASC LIMIT $limit",array(":height"=>$height)); |         $limit = 100; | ||||||
| 	foreach($r as $x){ |     } | ||||||
|  |     $r = $db->run("SELECT * FROM blocks WHERE height>:height ORDER by height ASC LIMIT $limit", [":height" => $height]); | ||||||
|  |     foreach ($r as $x) { | ||||||
|         echo "$x[height]\t$x[id]\n"; |         echo "$x[height]\t$x[id]\n"; | ||||||
|     } |     } | ||||||
| } | } /** | ||||||
| /** |  | ||||||
|  * @api {php util.php} recheck-blocks Recheck-Blocks |  * @api {php util.php} recheck-blocks Recheck-Blocks | ||||||
|  * @apiName recheck-blocks |  * @apiName recheck-blocks | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -199,26 +197,33 @@ elseif ($cmd=="current") { | |||||||
|  * php util.php recheck-blocks |  * php util.php recheck-blocks | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| elseif($cmd=="recheck-blocks"){ | elseif ($cmd == "recheck-blocks") { | ||||||
| 	$blocks=array(); |     $blocks = []; | ||||||
| 	$block=new Block(); |     $block = new Block(); | ||||||
| 	$r=$db->run("SELECT * FROM blocks ORDER by height ASC"); |     $r = $db->run("SELECT * FROM blocks ORDER by height ASC"); | ||||||
| 	foreach($r as $x){ |     foreach ($r as $x) { | ||||||
| 		$blocks[$x['height']]=$x; |         $blocks[$x['height']] = $x; | ||||||
| 		$max_height=$x['height']; |         $max_height = $x['height']; | ||||||
|     } |     } | ||||||
| 	for($i=2;$i<=$max_height;$i++){ |     for ($i = 2; $i <= $max_height; $i++) { | ||||||
| 		$data=$blocks[$i]; |         $data = $blocks[$i]; | ||||||
|  |  | ||||||
| 		$key=$db->single("SELECT public_key FROM accounts WHERE id=:id",array(":id"=>$data['generator'])); |         $key = $db->single("SELECT public_key FROM accounts WHERE id=:id", [":id" => $data['generator']]); | ||||||
|  |  | ||||||
| 		if(!$block->mine($key,$data['nonce'], $data['argon'], $data['difficulty'], $blocks[$i-1]['id'],$blocks[$i-1]['height'])) { |         if (!$block->mine( | ||||||
|  |             $key, | ||||||
|  |             $data['nonce'], | ||||||
|  |             $data['argon'], | ||||||
|  |             $data['difficulty'], | ||||||
|  |             $blocks[$i - 1]['id'], | ||||||
|  |             $blocks[$i - 1]['height'], | ||||||
|  |             $data['date'] | ||||||
|  |         )) { | ||||||
|             _log("Invalid block detected. We should delete everything after $data[height] - $data[id]"); |             _log("Invalid block detected. We should delete everything after $data[height] - $data[id]"); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } /** | ||||||
| /** |  | ||||||
|  * @api {php util.php} peers Peers |  * @api {php util.php} peers Peers | ||||||
|  * @apiName peers |  * @apiName peers | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -232,15 +237,16 @@ elseif($cmd=="recheck-blocks"){ | |||||||
|  * ... |  * ... | ||||||
|  * http://aro.master.hashpi.com    active |  * http://aro.master.hashpi.com    active | ||||||
|  */ |  */ | ||||||
|  elseif($cmd=="peers"){ | elseif ($cmd == "peers") { | ||||||
| 	$r=$db->run("SELECT * FROM peers ORDER by reserve ASC"); |     $r = $db->run("SELECT * FROM peers ORDER by reserve ASC"); | ||||||
| 	$status="active"; |     $status = "active"; | ||||||
| 	if($x['reserve']==1) $status="reserve"; |     if ($x['reserve'] == 1) { | ||||||
| 	foreach($r as $x){ |         $status = "reserve"; | ||||||
|  |     } | ||||||
|  |     foreach ($r as $x) { | ||||||
|         echo "$x[hostname]\t$status\n"; |         echo "$x[hostname]\t$status\n"; | ||||||
|     } |     } | ||||||
| } | } /** | ||||||
| /** |  | ||||||
|  * @api {php util.php} mempool Mempool |  * @api {php util.php} mempool Mempool | ||||||
|  * @apiName mempool |  * @apiName mempool | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -252,12 +258,10 @@ elseif($cmd=="recheck-blocks"){ | |||||||
|  * @apiSuccessExample {text} Success-Response: |  * @apiSuccessExample {text} Success-Response: | ||||||
|  * Mempool size: 12 |  * Mempool size: 12 | ||||||
|  */ |  */ | ||||||
|  elseif($cmd=="mempool"){ | elseif ($cmd == "mempool") { | ||||||
| $res=$db->single("SELECT COUNT(1) from mempool"); |     $res = $db->single("SELECT COUNT(1) from mempool"); | ||||||
| echo "Mempool size: $res\n"; |     echo "Mempool size: $res\n"; | ||||||
|  | } /** | ||||||
| }  |  | ||||||
| /** |  | ||||||
|  * @api {php util.php} delete-peer Delete-peer |  * @api {php util.php} delete-peer Delete-peer | ||||||
|  * @apiName delete-peer |  * @apiName delete-peer | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -271,24 +275,25 @@ echo "Mempool size: $res\n"; | |||||||
|  * @apiSuccessExample {text} Success-Response: |  * @apiSuccessExample {text} Success-Response: | ||||||
|  * Peer removed |  * Peer removed | ||||||
|  */ |  */ | ||||||
| elseif($cmd=="delete-peer"){ | elseif ($cmd == "delete-peer") { | ||||||
|         $peer=trim($argv[2]); |     $peer = trim($argv[2]); | ||||||
|         if(empty($peer)) die("Invalid peer"); |     if (empty($peer)) { | ||||||
|         $db->run("DELETE FROM peers WHERE ip=:ip",array(":ip"=>$peer)); |         die("Invalid peer"); | ||||||
|         echo "Peer removed\n"; |  | ||||||
| }elseif($cmd=="recheck-peers"){ |  | ||||||
| 	$r=$db->run("SELECT * FROM peers"); |  | ||||||
| 	foreach($r as $x){ |  | ||||||
| 		$a=peer_post($x['hostname']."/peer.php?q=ping"); |  | ||||||
| 		if($a!="pong"){ |  | ||||||
| 			echo "$x[hostname] -> failed\n"; |  | ||||||
| 			$db->run("DELETE FROM peers WHERE id=:id",array(":id"=>$x['id'])); |  | ||||||
| 		} else echo "$x[hostname] ->ok \n"; |  | ||||||
|     } |     } | ||||||
|  |     $db->run("DELETE FROM peers WHERE ip=:ip", [":ip" => $peer]); | ||||||
| } |     echo "Peer removed\n"; | ||||||
|  | } elseif ($cmd == "recheck-peers") { | ||||||
| /** |     $r = $db->run("SELECT * FROM peers"); | ||||||
|  |     foreach ($r as $x) { | ||||||
|  |         $a = peer_post($x['hostname']."/peer.php?q=ping"); | ||||||
|  |         if ($a != "pong") { | ||||||
|  |             echo "$x[hostname] -> failed\n"; | ||||||
|  |             $db->run("DELETE FROM peers WHERE id=:id", [":id" => $x['id']]); | ||||||
|  |         } else { | ||||||
|  |             echo "$x[hostname] ->ok \n"; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } /** | ||||||
|  * @api {php util.php} peers-block Peers-Block |  * @api {php util.php} peers-block Peers-Block | ||||||
|  * @apiName peers-block |  * @apiName peers-block | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -302,23 +307,24 @@ elseif($cmd=="delete-peer"){ | |||||||
|  * ... |  * ... | ||||||
|  * http://peer10.arionum.com        16849 |  * http://peer10.arionum.com        16849 | ||||||
|  */ |  */ | ||||||
| elseif($cmd=="peers-block"){ | elseif ($cmd == "peers-block") { | ||||||
| 	$only_diff=false; |     $only_diff = false; | ||||||
| 	if($argv[2]=="diff"){ |     if ($argv[2] == "diff") { | ||||||
| 		$current=$db->single("SELECT height FROM blocks ORDER by height DESC LIMIT 1"); |         $current = $db->single("SELECT height FROM blocks ORDER by height DESC LIMIT 1"); | ||||||
| 		$only_diff=true; |         $only_diff = true; | ||||||
|     } |     } | ||||||
| 	$r=$db->run("SELECT * FROM peers WHERE blacklisted<UNIX_TIMESTAMP()"); |     $r = $db->run("SELECT * FROM peers WHERE blacklisted<UNIX_TIMESTAMP()"); | ||||||
|         foreach($r as $x){ |     foreach ($r as $x) { | ||||||
|                 $a=peer_post($x['hostname']."/peer.php?q=currentBlock",array(),5); |         $a = peer_post($x['hostname']."/peer.php?q=currentBlock", [], 5); | ||||||
| 		$enc=base58_encode($x['hostname']); |         $enc = base58_encode($x['hostname']); | ||||||
| 		if($argv[2]=="debug") echo "$enc\t"; |         if ($argv[2] == "debug") { | ||||||
| 		if($only_diff==false||$current!=$a['height']) echo "$x[hostname]\t$a[height]\n"; |             echo "$enc\t"; | ||||||
|  |  | ||||||
|         } |         } | ||||||
| } |         if ($only_diff == false || $current != $a['height']) { | ||||||
|  |             echo "$x[hostname]\t$a[height]\n"; | ||||||
| /** |         } | ||||||
|  |     } | ||||||
|  | } /** | ||||||
|  * @api {php util.php} balance Balance |  * @api {php util.php} balance Balance | ||||||
|  * @apiName balance |  * @apiName balance | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -333,14 +339,15 @@ elseif($cmd=="peers-block"){ | |||||||
|  * Balance: 2,487 |  * Balance: 2,487 | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| elseif($cmd=="balance"){ | elseif ($cmd == "balance") { | ||||||
|  |     $id = san($argv[2]); | ||||||
| 	$id=san($argv[2]); |     $res = $db->single( | ||||||
| 	$res=$db->single("SELECT balance FROM accounts WHERE id=:id OR public_key=:id2 LIMIT 1",array(":id"=>$id, ":id2"=>$id)); |         "SELECT balance FROM accounts WHERE id=:id OR public_key=:id2 LIMIT 1", | ||||||
|  |         [":id" => $id, ":id2" => $id] | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     echo "Balance: ".number_format($res)."\n"; |     echo "Balance: ".number_format($res)."\n"; | ||||||
| } | } /** | ||||||
| /** |  | ||||||
|  * @api {php util.php} block Block |  * @api {php util.php} block Block | ||||||
|  * @apiName block |  * @apiName block | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -373,14 +380,12 @@ elseif($cmd=="balance"){ | |||||||
|  *  int(0) |  *  int(0) | ||||||
|  * } |  * } | ||||||
|  */ |  */ | ||||||
| elseif($cmd=="block"){ | elseif ($cmd == "block") { | ||||||
|         $id=san($argv[2]); |     $id = san($argv[2]); | ||||||
|         $res=$db->row("SELECT * FROM blocks WHERE id=:id OR height=:id2 LIMIT 1",array(":id"=>$id, ":id2"=>$id)); |     $res = $db->row("SELECT * FROM blocks WHERE id=:id OR height=:id2 LIMIT 1", [":id" => $id, ":id2" => $id]); | ||||||
|  |  | ||||||
|     var_dump($res); |     var_dump($res); | ||||||
|  | } /** | ||||||
| } |  | ||||||
| /** |  | ||||||
|  * @api {php util.php} check-address Check-Address |  * @api {php util.php} check-address Check-Address | ||||||
|  * @apiName check-address |  * @apiName check-address | ||||||
|  * @apiGroup UTIL |  * @apiGroup UTIL | ||||||
| @@ -394,12 +399,16 @@ elseif($cmd=="block"){ | |||||||
|  * @apiSuccessExample {text} Success-Response: |  * @apiSuccessExample {text} Success-Response: | ||||||
|  * The address is valid |  * The address is valid | ||||||
|  */ |  */ | ||||||
| elseif($cmd=="check-address"){ | elseif ($cmd == "check-address") { | ||||||
| 	$dst=trim($argv[2]); |     $dst = trim($argv[2]); | ||||||
| 	$acc=new Account; |     $acc = new Account(); | ||||||
| 	if(!$acc->valid($dst)) die("Invalid address"); |     if (!$acc->valid($dst)) { | ||||||
| 	$dst_b=base58_decode($dst); |         die("Invalid address"); | ||||||
| 	if(strlen($dst_b)!=64)  die("Invalid address - ".strlen($dst_b)." bytes"); |     } | ||||||
|  |     $dst_b = base58_decode($dst); | ||||||
|  |     if (strlen($dst_b) != 64) { | ||||||
|  |         die("Invalid address - ".strlen($dst_b)." bytes"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     echo "The address is valid\n"; |     echo "The address is valid\n"; | ||||||
| }  | }  | ||||||
| @@ -418,15 +427,49 @@ elseif($cmd=="check-address"){ | |||||||
|  * 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr |  * 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| elseif($cmd=='get-address'){ | elseif ($cmd == 'get-address') { | ||||||
|  |     $public_key = trim($argv2); | ||||||
|    $public_key=trim($argv2); |     if (strlen($public_key) < 32) { | ||||||
|     if(strlen($public_key)<32) die("Invalid public key"); |         die("Invalid public key"); | ||||||
|  |     } | ||||||
|     print($acc->get_address($public_key)); |     print($acc->get_address($public_key)); | ||||||
|  | /** | ||||||
|  |  * @api {php util.php} clean-blacklist Clean-Blacklist | ||||||
|  |  * @apiName clean-blacklist | ||||||
|  |  * @apiGroup UTIL | ||||||
|  |  * @apiDescription Removes all the peers from blacklist | ||||||
|  |  * | ||||||
|  |  * @apiExample {cli} Example usage: | ||||||
|  |  * php util.php clean-blacklist | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | } elseif ($cmd == 'clean-blacklist') { | ||||||
|  |    $db->run("UPDATE peers SET blacklisted=0, fails=0, stuckfail=0"); | ||||||
|  |    echo "All the peers have been removed from the blacklist\n"; | ||||||
|  | }elseif($cmd == 'resync-accounts'){ | ||||||
|  | // resyncs the balance on all accounts | ||||||
|  |  | ||||||
|  |  // lock table to avoid race conditions on blocks | ||||||
|  |         $db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE"); | ||||||
|  |  | ||||||
|  | $r=$db->run("SELECT * FROM accounts"); | ||||||
|  | foreach($r as $x){ | ||||||
|  |         $alias=$x['alias']; | ||||||
|  |         if(empty($alias)) $alias="A"; | ||||||
|  |         $rec=$db->single("SELECT SUM(val) FROM transactions WHERE (dst=:id or dst=:alias) AND (height<80000 OR (version!=100 AND version!=103)) and version<111",[":id"=>$x['id'], ":alias"=>$alias]); | ||||||
|  |         $spent=$db->single("SELECT SUM(val+fee) FROM transactions WHERE public_key=:pub AND version>0",[":pub"=>$x['public_key']]); | ||||||
|  |         if($spent==false) $spent=0; | ||||||
|  |         $balance=round(($rec-$spent),8); | ||||||
|  |         if($x['balance']!=$balance){ | ||||||
|  |                 echo "rec: $rec, spent: $spent, bal: $x[balance], should be: $balance - $x[id] $x[public_key]\n"; | ||||||
|  |                 $db->run("UPDATE accounts SET balance=:bal WHERE id=:id",[":id"=>$x['id'], ":bal"=>$balance]); | ||||||
|  |         } | ||||||
|  | } | ||||||
|  | $db->exec("UNLOCK TABLES"); | ||||||
|  | echo "All done"; | ||||||
|  |  | ||||||
|  |  | ||||||
| } else { | } else { | ||||||
|     echo "Invalid command\n"; |     echo "Invalid command\n"; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| ?> |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user