documentation + base58 fix
This commit is contained in:
2
api.php
2
api.php
@@ -40,6 +40,8 @@ OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @apiSuccess {String} status "ok"
|
||||
* @apiSuccess {String} data The data provided by the api will be under this object.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @apiSuccessExample {json} Success-Response:
|
||||
*{
|
||||
|
||||
489
doc/api_data.js
489
doc/api_data.js
@@ -999,6 +999,495 @@ define({ "api": [
|
||||
"filename": "./api.php",
|
||||
"groupTitle": "API"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "balance",
|
||||
"title": "Balance",
|
||||
"name": "balance",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the balance of an address or a public key</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>address or public_key</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php balance 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Balance: 2,487",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "block",
|
||||
"title": "Block",
|
||||
"name": "block",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Returns a specific block</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>block id</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php block 4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "array(9) {\n [\"id\"]=>\n string(88) \"4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR\"\n [\"generator\"]=>\n string(88) \"5ADfrJUnLefPsaYjMTR4KmvQ79eHo2rYWnKBRCXConYKYJVAw2adtzb38oUG5EnsXEbTct3p7GagT2VVZ9hfVTVn\"\n [\"height\"]=>\n int(16833)\n [\"date\"]=>\n int(1519312385)\n [\"nonce\"]=>\n string(41) \"EwtJ1EigKrLurlXROuuiozrR6ICervJDF2KFl4qEY\"\n [\"signature\"]=>\n string(97) \"AN1rKpqit8UYv6uvf79GnbjyihCPE1UZu4CGRx7saZ68g396yjHFmzkzuBV69Hcr7TF2egTsEwVsRA3CETiqXVqet58MCM6tu\"\n [\"difficulty\"]=>\n string(8) \"61982809\"\n [\"argon\"]=>\n string(68) \"$SfghIBNSHoOJDlMthVcUtg$WTJMrQWHHqDA6FowzaZJ+O9JC8DPZTjTxNE4Pj/ggwg\"\n [\"transactions\"]=>\n int(0)\n}",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "block-time",
|
||||
"title": "Block-time",
|
||||
"name": "block_time",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Shows the block time of the last 100 blocks</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php block-time",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "16830 -> 323\n...\n16731 -> 302\nAverage block time: 217 seconds",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "blocks",
|
||||
"title": "Blocks",
|
||||
"name": "blocks",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the id and the height of the blocks >=arg2, max 100 or arg3</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "number",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>Starting height</p>"
|
||||
},
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "number",
|
||||
"optional": true,
|
||||
"field": "arg3",
|
||||
"description": "<p>Block Limit</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php blocks 10800 5",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "10801 2yAHaZ3ghNnThaNK6BJcup2zq7EXuFsruMb5qqXaHP9M6JfBfstAag1n1PX7SMKGcuYGZddMzU7hW87S5ZSayeKX\n10802 wNa4mRvRPCMHzsgLdseMdJCvmeBaCNibRJCDhsuTeznJh8C1aSpGuXRDPYMbqKiVtmGAaYYb9Ze2NJdmK1HY9zM\n10803 3eW3B8jCFBauw8EoKN4SXgrn33UBPw7n8kvDDpyQBw1uQcmJQEzecAvwBk5sVfQxUqgzv31JdNHK45JxUFcupVot\n10804 4mWK1f8ch2Ji3D6aw1BsCJavLNBhQgpUHBCHihnrLDuh8Bjwsou5bQDj7D7nV4RsEPmP2ZbjUUMZwqywpRc8r6dR\n10805 5RBeWXo2c9NZ7UF2ubztk53PZpiA4tsk3bhXNXbcBk89cNqorNj771Qu4kthQN5hXLtu1hzUnv7nkH33hDxBM34m",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "check-address",
|
||||
"title": "Check-Address",
|
||||
"name": "check_address",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Checks a specific address for validity</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>block id</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php check-address 4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "The address is valid",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "clean",
|
||||
"title": "Clean",
|
||||
"name": "clean",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Cleans the entire database</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php clean",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "current",
|
||||
"title": "Current",
|
||||
"name": "current",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the current block in var_dump</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php current",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "array(9) {\n [\"id\"]=>\n string(88) \"4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR\"\n [\"generator\"]=>\n string(88) \"5ADfrJUnLefPsaYjMTR4KmvQ79eHo2rYWnKBRCXConYKYJVAw2adtzb38oUG5EnsXEbTct3p7GagT2VVZ9hfVTVn\"\n [\"height\"]=>\n int(16833)\n [\"date\"]=>\n int(1519312385)\n [\"nonce\"]=>\n string(41) \"EwtJ1EigKrLurlXROuuiozrR6ICervJDF2KFl4qEY\"\n [\"signature\"]=>\n string(97) \"AN1rKpqit8UYv6uvf79GnbjyihCPE1UZu4CGRx7saZ68g396yjHFmzkzuBV69Hcr7TF2egTsEwVsRA3CETiqXVqet58MCM6tu\"\n [\"difficulty\"]=>\n string(8) \"61982809\"\n [\"argon\"]=>\n string(68) \"$SfghIBNSHoOJDlMthVcUtg$WTJMrQWHHqDA6FowzaZJ+O9JC8DPZTjTxNE4Pj/ggwg\"\n [\"transactions\"]=>\n int(0)\n}",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "delete-peer",
|
||||
"title": "Delete-peer",
|
||||
"name": "delete_peer",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Removes a peer from the peerlist</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>Peer's hostname</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php delete-peer http://peer1.arionum.com",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Peer removed",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "get-address",
|
||||
"title": "Get-Address",
|
||||
"name": "get_address",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Converts a public key into an address</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>public key</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php get-address PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwQr8cE5s6APWAE1SWAmH6NM1nJTryBURULEsifA2hLVuW5GXFD1XU6s6REG1iPK7qGaRDkGpQwJjDhQKVoSVkSNp",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "mempool",
|
||||
"title": "Mempool",
|
||||
"name": "mempool",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the number of transactions in mempool</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php mempool",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Mempool size: 12",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "peer",
|
||||
"title": "Peer",
|
||||
"name": "peer",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Creates a peering session with another node</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>The Hostname of the other node</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php peer http://peer1.arionum.com",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Peering OK",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "peers",
|
||||
"title": "Peers",
|
||||
"name": "peers",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints all the peers and their status</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php peers",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "http://35.190.160.142 active\n...\nhttp://aro.master.hashpi.com active",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "peers-block",
|
||||
"title": "Peers-Block",
|
||||
"name": "peers_block",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the current height of all the peers</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php peers-block",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "http://peer5.arionum.com 16849\n...\nhttp://peer10.arionum.com 16849",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "pop",
|
||||
"title": "Pop",
|
||||
"name": "pop",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Cleans the entire database</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "Number",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>Number of blocks to delete</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php pop 1",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "recheck-blocks",
|
||||
"title": "Recheck-Blocks",
|
||||
"name": "recheck_blocks",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Recheck all the blocks to make sure the blockchain is correct</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php recheck-blocks",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"success": {
|
||||
"fields": {
|
||||
|
||||
@@ -999,6 +999,495 @@
|
||||
"filename": "./api.php",
|
||||
"groupTitle": "API"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "balance",
|
||||
"title": "Balance",
|
||||
"name": "balance",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the balance of an address or a public key</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>address or public_key</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php balance 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Balance: 2,487",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "block",
|
||||
"title": "Block",
|
||||
"name": "block",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Returns a specific block</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>block id</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php block 4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "array(9) {\n [\"id\"]=>\n string(88) \"4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR\"\n [\"generator\"]=>\n string(88) \"5ADfrJUnLefPsaYjMTR4KmvQ79eHo2rYWnKBRCXConYKYJVAw2adtzb38oUG5EnsXEbTct3p7GagT2VVZ9hfVTVn\"\n [\"height\"]=>\n int(16833)\n [\"date\"]=>\n int(1519312385)\n [\"nonce\"]=>\n string(41) \"EwtJ1EigKrLurlXROuuiozrR6ICervJDF2KFl4qEY\"\n [\"signature\"]=>\n string(97) \"AN1rKpqit8UYv6uvf79GnbjyihCPE1UZu4CGRx7saZ68g396yjHFmzkzuBV69Hcr7TF2egTsEwVsRA3CETiqXVqet58MCM6tu\"\n [\"difficulty\"]=>\n string(8) \"61982809\"\n [\"argon\"]=>\n string(68) \"$SfghIBNSHoOJDlMthVcUtg$WTJMrQWHHqDA6FowzaZJ+O9JC8DPZTjTxNE4Pj/ggwg\"\n [\"transactions\"]=>\n int(0)\n}",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "block-time",
|
||||
"title": "Block-time",
|
||||
"name": "block_time",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Shows the block time of the last 100 blocks</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php block-time",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "16830 -> 323\n...\n16731 -> 302\nAverage block time: 217 seconds",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "blocks",
|
||||
"title": "Blocks",
|
||||
"name": "blocks",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the id and the height of the blocks >=arg2, max 100 or arg3</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "number",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>Starting height</p>"
|
||||
},
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "number",
|
||||
"optional": true,
|
||||
"field": "arg3",
|
||||
"description": "<p>Block Limit</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php blocks 10800 5",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "10801 2yAHaZ3ghNnThaNK6BJcup2zq7EXuFsruMb5qqXaHP9M6JfBfstAag1n1PX7SMKGcuYGZddMzU7hW87S5ZSayeKX\n10802 wNa4mRvRPCMHzsgLdseMdJCvmeBaCNibRJCDhsuTeznJh8C1aSpGuXRDPYMbqKiVtmGAaYYb9Ze2NJdmK1HY9zM\n10803 3eW3B8jCFBauw8EoKN4SXgrn33UBPw7n8kvDDpyQBw1uQcmJQEzecAvwBk5sVfQxUqgzv31JdNHK45JxUFcupVot\n10804 4mWK1f8ch2Ji3D6aw1BsCJavLNBhQgpUHBCHihnrLDuh8Bjwsou5bQDj7D7nV4RsEPmP2ZbjUUMZwqywpRc8r6dR\n10805 5RBeWXo2c9NZ7UF2ubztk53PZpiA4tsk3bhXNXbcBk89cNqorNj771Qu4kthQN5hXLtu1hzUnv7nkH33hDxBM34m",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "check-address",
|
||||
"title": "Check-Address",
|
||||
"name": "check_address",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Checks a specific address for validity</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>block id</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php check-address 4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "The address is valid",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "clean",
|
||||
"title": "Clean",
|
||||
"name": "clean",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Cleans the entire database</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php clean",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "current",
|
||||
"title": "Current",
|
||||
"name": "current",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the current block in var_dump</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php current",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "array(9) {\n [\"id\"]=>\n string(88) \"4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR\"\n [\"generator\"]=>\n string(88) \"5ADfrJUnLefPsaYjMTR4KmvQ79eHo2rYWnKBRCXConYKYJVAw2adtzb38oUG5EnsXEbTct3p7GagT2VVZ9hfVTVn\"\n [\"height\"]=>\n int(16833)\n [\"date\"]=>\n int(1519312385)\n [\"nonce\"]=>\n string(41) \"EwtJ1EigKrLurlXROuuiozrR6ICervJDF2KFl4qEY\"\n [\"signature\"]=>\n string(97) \"AN1rKpqit8UYv6uvf79GnbjyihCPE1UZu4CGRx7saZ68g396yjHFmzkzuBV69Hcr7TF2egTsEwVsRA3CETiqXVqet58MCM6tu\"\n [\"difficulty\"]=>\n string(8) \"61982809\"\n [\"argon\"]=>\n string(68) \"$SfghIBNSHoOJDlMthVcUtg$WTJMrQWHHqDA6FowzaZJ+O9JC8DPZTjTxNE4Pj/ggwg\"\n [\"transactions\"]=>\n int(0)\n}",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "delete-peer",
|
||||
"title": "Delete-peer",
|
||||
"name": "delete_peer",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Removes a peer from the peerlist</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>Peer's hostname</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php delete-peer http://peer1.arionum.com",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Peer removed",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "get-address",
|
||||
"title": "Get-Address",
|
||||
"name": "get_address",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Converts a public key into an address</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>public key</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php get-address PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwQr8cE5s6APWAE1SWAmH6NM1nJTryBURULEsifA2hLVuW5GXFD1XU6s6REG1iPK7qGaRDkGpQwJjDhQKVoSVkSNp",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "mempool",
|
||||
"title": "Mempool",
|
||||
"name": "mempool",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the number of transactions in mempool</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php mempool",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Mempool size: 12",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "peer",
|
||||
"title": "Peer",
|
||||
"name": "peer",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Creates a peering session with another node</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "text",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>The Hostname of the other node</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php peer http://peer1.arionum.com",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "Peering OK",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "peers",
|
||||
"title": "Peers",
|
||||
"name": "peers",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints all the peers and their status</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php peers",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "http://35.190.160.142 active\n...\nhttp://aro.master.hashpi.com active",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "peers-block",
|
||||
"title": "Peers-Block",
|
||||
"name": "peers_block",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Prints the current height of all the peers</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php peers-block",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"success": {
|
||||
"examples": [
|
||||
{
|
||||
"title": "Success-Response:",
|
||||
"content": "http://peer5.arionum.com 16849\n...\nhttp://peer10.arionum.com 16849",
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "pop",
|
||||
"title": "Pop",
|
||||
"name": "pop",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Cleans the entire database</p>",
|
||||
"parameter": {
|
||||
"fields": {
|
||||
"Parameter": [
|
||||
{
|
||||
"group": "Parameter",
|
||||
"type": "Number",
|
||||
"optional": false,
|
||||
"field": "arg2",
|
||||
"description": "<p>Number of blocks to delete</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php pop 1",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"type": "php util.php",
|
||||
"url": "recheck-blocks",
|
||||
"title": "Recheck-Blocks",
|
||||
"name": "recheck_blocks",
|
||||
"group": "UTIL",
|
||||
"description": "<p>Recheck all the blocks to make sure the blockchain is correct</p>",
|
||||
"examples": [
|
||||
{
|
||||
"title": "Example usage:",
|
||||
"content": "php util.php recheck-blocks",
|
||||
"type": "cli"
|
||||
}
|
||||
],
|
||||
"version": "0.0.0",
|
||||
"filename": "./util.php",
|
||||
"groupTitle": "UTIL"
|
||||
},
|
||||
{
|
||||
"success": {
|
||||
"fields": {
|
||||
|
||||
@@ -7,7 +7,7 @@ define({
|
||||
"apidoc": "0.3.0",
|
||||
"generator": {
|
||||
"name": "apidoc",
|
||||
"time": "2018-02-15T01:57:51.098Z",
|
||||
"time": "2018-02-22T16:13:41.713Z",
|
||||
"url": "http://apidocjs.com",
|
||||
"version": "0.17.6"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"apidoc": "0.3.0",
|
||||
"generator": {
|
||||
"name": "apidoc",
|
||||
"time": "2018-02-15T01:57:51.098Z",
|
||||
"time": "2018-02-22T16:13:41.713Z",
|
||||
"url": "http://apidocjs.com",
|
||||
"version": "0.17.6"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
class Account {
|
||||
|
||||
|
||||
|
||||
// inserts the account in the DB and updates the public key if empty
|
||||
public function add($public_key, $block){
|
||||
global $db;
|
||||
$id=$this->get_address($public_key);
|
||||
@@ -11,52 +11,64 @@ class Account {
|
||||
|
||||
$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
|
||||
public function add_id($id, $block){
|
||||
global $db;
|
||||
$bind=array(":id"=>$id, ":block"=>$block);
|
||||
$db->run("INSERT ignore INTO accounts SET id=:id, public_key='', block=:block, balance=0",$bind);
|
||||
}
|
||||
|
||||
// generates Account's address from the public key
|
||||
public function get_address($hash){
|
||||
for($i=0;$i<9;$i++) $hash=hash('sha512',$hash, true);
|
||||
|
||||
|
||||
|
||||
|
||||
return base58_encode($hash);
|
||||
|
||||
//broken base58 addresses, which are block winners, missing the first 0 bytes from the address.
|
||||
if($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwCpspGFGQSaF9yVGLamBgymdf8M7FafghmP3oPzQb3W4PZsZApVa41uQrrHRVBH5p9bdoz7c6XeRQHK2TkzWR45e') return '22SoB29oyq2JhMxtBbesL7JioEYytyC6VeFmzvBH6fRQrueSvyZfEXR5oR7ajSQ9mLERn6JKU85EAbVDNChke32';
|
||||
elseif($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCzbRyyz5oDNDKhk5jyjg4caRjkbqegMZMrUkuBjVMuYcVfPyc3aKuLmPHS4QEDjCrNGks7Z5oPxwv4yXSv7WJnkbL') return 'AoFnv3SLujrJSa2J7FDTADGD7Eb9kv3KtNAp7YVYQEUPcLE6cC6nLvvhVqcVnRLYF5BFF38C1DyunUtmfJBhyU';
|
||||
elseif($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyradtFFJoaYB4QdcXyBGSXjiASMMnofsT4f5ZNaxTnNDJt91ubemn3LzgKrfQh8CBpqaphkVNoRLub2ctdMnrzG1') return 'RncXQuc7S7aWkvTUJSHEFvYoV3ntAf7bfxEHjSiZNBvQV37MzZtg44L7GAV7szZ3uV8qWqikBewa3piZMqzBqm';
|
||||
elseif($hash=='PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyjKMBY4ihhJ2G25EVezg7KnoCBVbhdvWfqzNA4LC5R7wgu3VNfJgvqkCq9sKKZcCoCpX6Qr9cN882MoXsfGTvZoj') return 'Rq53oLzpCrb4BdJZ1jqQ2zsixV2ukxVdM4H9uvUhCGJCz1q2wagvuXV4hC6UVwK7HqAt1FenukzhVXgzyG1y32';
|
||||
|
||||
|
||||
// hashes 9 times in sha512 (binary) and encodes in base58
|
||||
for($i=0;$i<9;$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);
|
||||
}
|
||||
|
||||
|
||||
// generates a new account and a public/private key pair
|
||||
public function generate_account(){
|
||||
|
||||
// using secp256k1 curve for ECDSA
|
||||
$args = array(
|
||||
"curve_name" => "secp256k1",
|
||||
"private_key_type" => OPENSSL_KEYTYPE_EC,
|
||||
);
|
||||
|
||||
|
||||
// generates a new key pair
|
||||
$key1 = openssl_pkey_new($args);
|
||||
|
||||
|
||||
// exports the private key encoded as PEM
|
||||
openssl_pkey_export($key1, $pvkey);
|
||||
|
||||
|
||||
// converts the PEM to a base58 format
|
||||
$private_key= pem2coin($pvkey);
|
||||
|
||||
|
||||
// exports the private key encoded as PEM
|
||||
$pub = openssl_pkey_get_details($key1);
|
||||
|
||||
// converts the PEM to a base58 format
|
||||
$public_key= pem2coin($pub['key']);
|
||||
|
||||
// generates the account's address based on the public key
|
||||
$address=$this->get_address($public_key);
|
||||
return array("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.
|
||||
public function valid_key($id){
|
||||
$chars = str_split("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
||||
for($i=0;$i<strlen($id);$i++) if(!in_array($id[$i],$chars)) return false;
|
||||
@@ -64,6 +76,7 @@ class Account {
|
||||
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.
|
||||
public function valid($id){
|
||||
if(strlen($id)<70||strlen($id)>128) return false;
|
||||
$chars = str_split("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
||||
@@ -72,26 +85,31 @@ class Account {
|
||||
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();
|
||||
$current=$block->current();
|
||||
$public_key=$this->public_key($id);
|
||||
$limit=intval($limit);
|
||||
if($limit>100||$limit<1) $limit=100;
|
||||
@@ -102,7 +120,8 @@ class Account {
|
||||
$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";
|
||||
@@ -115,6 +134,7 @@ class Account {
|
||||
}
|
||||
return $transactions;
|
||||
}
|
||||
// returns the transactions from the mempool
|
||||
public function get_mempool_transactions($id){
|
||||
global $db;
|
||||
$transactions=array();
|
||||
@@ -122,12 +142,14 @@ class Account {
|
||||
foreach($res as $x){
|
||||
$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']);
|
||||
$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",array(":id"=>$id));
|
||||
|
||||
@@ -8,28 +8,27 @@ public function add($height, $public_key, $nonce, $data, $date, $signature, $dif
|
||||
global $db;
|
||||
$acc=new Account;
|
||||
$trx=new Transaction;
|
||||
//try {
|
||||
|
||||
// } catch (Exception $e){
|
||||
|
||||
// }
|
||||
|
||||
$generator=$acc->get_address($public_key);
|
||||
|
||||
// the transactions are always sorted in the same way, on all nodes, as they are hashed as json
|
||||
ksort($data);
|
||||
|
||||
// create the hash / block id
|
||||
$hash=$this->hash($generator, $height, $date, $nonce, $data, $signature, $difficulty, $argon);
|
||||
|
||||
//fix for the broken base58 library used until block 17000, trimming the first 0 bytes.
|
||||
if($height<=17000) $hash=ltrim($hash,'1');
|
||||
|
||||
$json=json_encode($data);
|
||||
|
||||
// create the block data and check it against the signature
|
||||
$info="{$generator}-{$height}-{$date}-{$nonce}-{$json}-{$difficulty}-{$argon}";
|
||||
|
||||
if(!$acc->check_signature($info,$signature,$public_key)) return false;
|
||||
if(!$acc->check_signature($info,$signature,$public_key)) { _log("Block signature check failed"); return false; }
|
||||
|
||||
|
||||
if(!$this->parse_block($hash,$height,$data, true)) return false;
|
||||
if(!$this->parse_block($hash,$height,$data, true)) { _log("Parse block failed"); return false; }
|
||||
|
||||
// lock table to avoid race conditions on blocks
|
||||
$db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE");
|
||||
|
||||
$reward=$this->reward($height,$data);
|
||||
@@ -37,34 +36,42 @@ public function add($height, $public_key, $nonce, $data, $date, $signature, $dif
|
||||
$msg='';
|
||||
|
||||
|
||||
// the reward transaction
|
||||
$transaction=array("src"=>$generator, "dst"=>$generator, "val"=>$reward, "version"=>0, "date"=>$date, "message"=>$msg, "fee"=>"0.00000000","public_key"=>$public_key);
|
||||
$transaction['signature']=$reward_signature;
|
||||
// hash the transaction
|
||||
$transaction['id']=$trx->hash($transaction);
|
||||
$info=$transaction['val']."-".$transaction['fee']."-".$transaction['dst']."-".$transaction['message']."-".$transaction['version']."-".$transaction['public_key']."-".$transaction['date'];
|
||||
|
||||
if(!$acc->check_signature($info,$reward_signature,$public_key)) return false;
|
||||
// check the signature
|
||||
$info=$transaction['val']."-".$transaction['fee']."-".$transaction['dst']."-".$transaction['message']."-".$transaction['version']."-".$transaction['public_key']."-".$transaction['date'];
|
||||
if(!$acc->check_signature($info,$reward_signature,$public_key)) {_log("Reward signature failed"); return false; }
|
||||
|
||||
// insert the block into the db
|
||||
$db->beginTransaction();
|
||||
$total=count($data);
|
||||
$bind=array(":id"=>$hash,":generator"=>$generator, ":signature"=>$signature, ":height"=>$height, ":date"=>$date, ":nonce"=>$nonce, ":difficulty"=>$difficulty,":argon"=>$argon, ":transactions"=>$total);
|
||||
$res=$db->run("INSERT into blocks SET id=:id, generator=:generator, height=:height,`date`=:date,nonce=:nonce, signature=:signature, difficulty=:difficulty, argon=:argon, transactions=:transactions",$bind);
|
||||
if($res!=1) {
|
||||
// rollback and exit if it fails
|
||||
_log("Block DB insert failed");
|
||||
$db->rollback();
|
||||
$db->exec("UNLOCK TABLES");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// insert the reward transaction in the db
|
||||
$trx->add($hash, $height,$transaction);
|
||||
|
||||
|
||||
// parse the block's transactions and insert them to db
|
||||
$res=$this->parse_block($hash,$height,$data, false);
|
||||
// if any fails, rollback
|
||||
if($res==false) $db->rollback();
|
||||
else $db->commit();
|
||||
// relese the locking as everything is finished
|
||||
$db->exec("UNLOCK TABLES");
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns the current block, without the transactions
|
||||
public function current(){
|
||||
global $db;
|
||||
$current=$db->row("SELECT * FROM blocks ORDER by height DESC LIMIT 1");
|
||||
@@ -75,7 +82,7 @@ public function current(){
|
||||
return $current;
|
||||
|
||||
}
|
||||
|
||||
// returns the previous block
|
||||
public function prev(){
|
||||
global $db;
|
||||
$current=$db->row("SELECT * FROM blocks ORDER by height DESC LIMIT 1,1");
|
||||
@@ -83,9 +90,11 @@ public function prev(){
|
||||
return $current;
|
||||
|
||||
}
|
||||
|
||||
// calculates the difficulty / base target for a specific block. The higher the difficulty number, the easier it is to win a block.
|
||||
public function difficulty($height=0){
|
||||
global $db;
|
||||
|
||||
// if no block height is specified, use the current block.
|
||||
if($height==0){
|
||||
$current=$this->current();
|
||||
} else{
|
||||
@@ -94,35 +103,46 @@ public function difficulty($height=0){
|
||||
|
||||
|
||||
$height=$current['height'];
|
||||
|
||||
if($height==10801) return 5555555555; //hard fork 10900 resistance, force new difficulty
|
||||
|
||||
if($height==10801) return 5555555555; //hard fork 10900 resistance
|
||||
|
||||
// last 20 blocks used to check the block times
|
||||
$limit=20;
|
||||
if($height<20)
|
||||
$limit=$height-1;
|
||||
|
||||
// for the first 10 blocks, use the genesis difficulty
|
||||
if($height<10) return $current['difficulty'];
|
||||
|
||||
|
||||
// elapsed time between the last 20 blocks
|
||||
$first=$db->row("SELECT `date` FROM blocks ORDER by height DESC LIMIT $limit,1");
|
||||
$time=$current['date']-$first['date'];
|
||||
|
||||
// avg block time
|
||||
$result=ceil($time/$limit);
|
||||
|
||||
// if larger than 200 sec, increase by 5%
|
||||
if($result>220){
|
||||
$dif= bcmul($current['difficulty'], 1.05);
|
||||
} elseif($result<260){
|
||||
// if lower, decrease by 5%
|
||||
$dif= bcmul($current['difficulty'], 0.95);
|
||||
} else {
|
||||
// keep current difficulty
|
||||
$dif=$current['difficulty'];
|
||||
}
|
||||
if(strpos($dif,'.')!==false){
|
||||
$dif=substr($dif,0,strpos($dif,'.'));
|
||||
}
|
||||
|
||||
//minimum and maximum diff
|
||||
if($dif<1000) $dif=1000;
|
||||
if($dif>9223372036854775800) $dif=9223372036854775800;
|
||||
|
||||
return $dif;
|
||||
}
|
||||
|
||||
// calculates the maximum block size and increase by 10% the number of transactions if > 100 on the last 100 blocks
|
||||
public function max_transactions(){
|
||||
global $db;
|
||||
$current=$this->current();
|
||||
@@ -132,15 +152,19 @@ public function max_transactions(){
|
||||
return ceil($avg*1.1);
|
||||
}
|
||||
|
||||
// calculate the reward for each block
|
||||
public function reward($id,$data=array()){
|
||||
|
||||
|
||||
// starting reward
|
||||
$reward=1000;
|
||||
|
||||
// decrease by 1% each 10800 blocks (approx 1 month)
|
||||
|
||||
$factor=floor($id/10800)/100;
|
||||
$reward-=$reward*$factor;
|
||||
if($reward<0) $reward=0;
|
||||
|
||||
// calculate the transaction fees
|
||||
$fees=0;
|
||||
if(count($data)>0){
|
||||
|
||||
@@ -151,28 +175,39 @@ public function reward($id,$data=array()){
|
||||
return number_format($reward+$fees,8,'.','');
|
||||
}
|
||||
|
||||
|
||||
// checks the validity of a block
|
||||
public function check($data){
|
||||
if(strlen($data['argon'])<20) return false;
|
||||
// argon must have at least 20 chars
|
||||
if(strlen($data['argon'])<20) { _log("Invalid block argon - $data[argon]"); return false; }
|
||||
$acc=new Account;
|
||||
if(!$acc->valid_key($data['public_key'])) return false;
|
||||
if($data['difficulty']!=$this->difficulty()) return false;
|
||||
if(!$this->mine($data['public_key'],$data['nonce'], $data['argon'])) return false;
|
||||
// generator's public key must be valid
|
||||
|
||||
if(!$acc->valid_key($data['public_key'])) { _log("Invalid public key - $data[public_key]"); return false; }
|
||||
|
||||
//difficulty should be the same as our calculation
|
||||
if($data['difficulty']!=$this->difficulty()) { _log("Invalid difficulty - $data[difficulty] - ".$this->difficulty()); return false; }
|
||||
|
||||
//check the argon hash and the nonce to produce a valid block
|
||||
if(!$this->mine($data['public_key'],$data['nonce'], $data['argon'])) { _log("Mine check failed"); return false; }
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// creates a new block on this node
|
||||
public function forge($nonce, $argon, $public_key, $private_key){
|
||||
|
||||
//check the argon hash and the nonce to produce a valid block
|
||||
|
||||
if(!$this->mine($public_key,$nonce, $argon)) return false;
|
||||
|
||||
// the block's date timestamp must be bigger than the last block
|
||||
$current=$this->current();
|
||||
$height=$current['height']+=1;
|
||||
$date=time();
|
||||
if($date<=$current['date']) return 0;
|
||||
|
||||
// get the mempool transactions
|
||||
$txn=new Transaction;
|
||||
$data=$txn->mempool($this->max_transactions());
|
||||
|
||||
@@ -180,55 +215,72 @@ public function forge($nonce, $argon, $public_key, $private_key){
|
||||
$difficulty=$this->difficulty();
|
||||
$acc=new Account;
|
||||
$generator=$acc->get_address($public_key);
|
||||
|
||||
// always sort the transactions in the same way
|
||||
ksort($data);
|
||||
|
||||
// sign the block
|
||||
$signature=$this->sign($generator, $height, $date, $nonce, $data, $private_key, $difficulty, $argon);
|
||||
|
||||
// reward signature
|
||||
// reward transaction and signature
|
||||
$reward=$this->reward($height,$data);
|
||||
$msg='';
|
||||
$transaction=array("src"=>$generator, "dst"=>$generator, "val"=>$reward, "version"=>0, "date"=>$date, "message"=>$msg, "fee"=>"0.00000000","public_key"=>$public_key);
|
||||
ksort($transaction);
|
||||
$reward_signature=$txn->sign($transaction, $private_key);
|
||||
|
||||
|
||||
// add the block to the blockchain
|
||||
$res=$this->add($height, $public_key, $nonce, $data, $date, $signature, $difficulty, $reward_signature, $argon);
|
||||
if(!$res) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// check if the arguments are good for mining a specific block
|
||||
public function mine($public_key, $nonce, $argon, $difficulty=0, $current_id=0, $current_height=0){
|
||||
global $_config;
|
||||
// if no id is specified, we use the current
|
||||
if($current_id===0){
|
||||
$current=$this->current();
|
||||
$current_id=$current['id'];
|
||||
$current_height=$current['height'];
|
||||
}
|
||||
// get the current difficulty if empty
|
||||
if($difficulty===0) $difficulty=$this->difficulty();
|
||||
|
||||
|
||||
if($current_height>10800) $argon='$argon2i$v=19$m=524288,t=1,p=1'.$argon; //10800
|
||||
// the argon parameters are hardcoded to avoid any exploits
|
||||
if($current_height>10800) $argon='$argon2i$v=19$m=524288,t=1,p=1'.$argon; //10800 block hard fork - resistance against gpu
|
||||
else $argon='$argon2i$v=19$m=16384,t=4,p=4'.$argon;
|
||||
|
||||
// the hash base for agon
|
||||
$base="$public_key-$nonce-".$current_id."-$difficulty";
|
||||
|
||||
|
||||
|
||||
|
||||
// check argon's hash validity
|
||||
if(!password_verify($base,$argon)) { return false; }
|
||||
|
||||
|
||||
// all nonces are valid in testnet
|
||||
if($_config['testnet']==true) return true;
|
||||
|
||||
|
||||
// prepare the base for the hashing
|
||||
$hash=$base.$argon;
|
||||
|
||||
// hash the base 6 times
|
||||
for($i=0;$i<5;$i++) $hash=hash("sha512",$hash,true);
|
||||
$hash=hash("sha512",$hash);
|
||||
|
||||
// split it in 2 char substrings, to be used as hex
|
||||
$m=str_split($hash,2);
|
||||
|
||||
// calculate a number based on 8 hex numbers - no specific reason, we just needed an algoritm to generate the number from the hash
|
||||
$duration=hexdec($m[10]).hexdec($m[15]).hexdec($m[20]).hexdec($m[23]).hexdec($m[31]).hexdec($m[40]).hexdec($m[45]).hexdec($m[55]);
|
||||
$duration=ltrim($duration, '0');
|
||||
$result=gmp_div($duration, $difficulty);
|
||||
|
||||
// the number must not start with 0
|
||||
$duration=ltrim($duration, '0');
|
||||
|
||||
// divide the number by the difficulty and create the deadline
|
||||
$result=gmp_div($duration, $difficulty);
|
||||
|
||||
// if the deadline >0 and <=240, the arguments are valid fora block win
|
||||
if($result>0&&$result<=240) return true;
|
||||
return false;
|
||||
|
||||
@@ -236,35 +288,43 @@ public function mine($public_key, $nonce, $argon, $difficulty=0, $current_id=0,
|
||||
|
||||
|
||||
|
||||
|
||||
// parse the block transactions
|
||||
public function parse_block($block, $height, $data, $test=true){
|
||||
global $db;
|
||||
|
||||
// data must be array
|
||||
if($data===false) return false;
|
||||
$acc=new Account;
|
||||
$trx=new Transaction;
|
||||
// no transactions means all are valid
|
||||
if(count($data)==0) return true;
|
||||
|
||||
// check if the number of transactions is not bigger than current block size
|
||||
$max=$this->max_transactions();
|
||||
|
||||
if(count($data)>$max) return false;
|
||||
|
||||
$balance=array();
|
||||
foreach($data as &$x){
|
||||
// get the sender's account if empty
|
||||
if(empty($x['src'])) $x['src']=$acc->get_address($x['public_key']);
|
||||
|
||||
|
||||
//validate the transaction
|
||||
if(!$trx->check($x,$height)) return false;
|
||||
|
||||
$balance[$x['src']]+=$x['val']+$x['fee'];
|
||||
|
||||
if($db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$x['id']))>0) return false; //duplicate transaction
|
||||
// prepare total balance
|
||||
$balance[$x['src']]+=$x['val']+$x['fee'];
|
||||
|
||||
// check if the transaction is already on the blockchain
|
||||
if($db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$x['id']))>0) return false;
|
||||
|
||||
}
|
||||
|
||||
// check if the account has enough balance to perform the transaction
|
||||
foreach($balance as $id=>$bal){
|
||||
$res=$db->single("SELECT COUNT(1) FROM accounts WHERE id=:id AND balance>=:balance",array(":id"=>$id, ":balance"=>$bal));
|
||||
if($res==0) return false; // not enough balance for the transactions
|
||||
}
|
||||
|
||||
// if the test argument is false, add the transactions to the blockchain
|
||||
if($test==false){
|
||||
|
||||
foreach($data as $d){
|
||||
@@ -277,6 +337,7 @@ public function parse_block($block, $height, $data, $test=true){
|
||||
}
|
||||
|
||||
|
||||
// initialize the blockchain, add the genesis block
|
||||
private function genesis(){
|
||||
global $db;
|
||||
$signature='AN1rKvtLTWvZorbiiNk5TBYXLgxiLakra2byFef9qoz1bmRzhQheRtiWivfGSwP6r8qHJGrf8uBeKjNZP1GZvsdKUVVN2XQoL';
|
||||
@@ -301,6 +362,7 @@ public function pop($no=1){
|
||||
$this->delete($current['height']-$no+1);
|
||||
}
|
||||
|
||||
// delete all blocks >= height
|
||||
public function delete($height){
|
||||
if($height<2) $height=2;
|
||||
global $db;
|
||||
@@ -331,6 +393,8 @@ public function delete($height){
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// delete specific block
|
||||
public function delete_id($id){
|
||||
|
||||
global $db;
|
||||
@@ -339,27 +403,33 @@ public function delete_id($id){
|
||||
$x=$db->row("SELECT * FROM blocks WHERE id=:id",array(":id"=>$id));
|
||||
|
||||
if($x===false) return false;
|
||||
// avoid race conditions on blockchain manipulations
|
||||
$db->beginTransaction();
|
||||
$db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE");
|
||||
|
||||
// reverse all transactions of the block
|
||||
$res=$trx->reverse($x['id']);
|
||||
if($res===false) {
|
||||
// rollback if you can't reverse the transactions
|
||||
$db->rollback();
|
||||
$db->exec("UNLOCK TABLES");
|
||||
return false;
|
||||
}
|
||||
// remove the actual block
|
||||
$res=$db->run("DELETE FROM blocks WHERE id=:id",array(":id"=>$x['id']));
|
||||
if($res!=1){
|
||||
//rollback if you can't delete the block
|
||||
$db->rollback();
|
||||
$db->exec("UNLOCK TABLES");
|
||||
return false;
|
||||
}
|
||||
|
||||
// commit and release if all good
|
||||
$db->commit();
|
||||
$db->exec("UNLOCK TABLES");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// sign a new block, used when mining
|
||||
public function sign($generator, $height, $date, $nonce, $data, $key, $difficulty, $argon){
|
||||
|
||||
$json=json_encode($data);
|
||||
@@ -370,6 +440,7 @@ public function sign($generator, $height, $date, $nonce, $data, $key, $difficult
|
||||
|
||||
}
|
||||
|
||||
// generate the sha512 hash of the block data and converts it to base58
|
||||
public function hash($public_key, $height, $date, $nonce, $data, $signature, $difficulty, $argon){
|
||||
$json=json_encode($data);
|
||||
$hash= hash("sha512", "{$public_key}-{$height}-{$date}-{$nonce}-{$json}-{$signature}-{$difficulty}-{$argon}");
|
||||
@@ -377,6 +448,7 @@ public function hash($public_key, $height, $date, $nonce, $data, $signature, $di
|
||||
}
|
||||
|
||||
|
||||
// exports the block data, to be used when submitting to other peers
|
||||
public function export($id="",$height=""){
|
||||
if(empty($id)&&empty($height)) return false;
|
||||
|
||||
@@ -396,13 +468,14 @@ public function export($id="",$height=""){
|
||||
ksort($transactions);
|
||||
$block['data']=$transactions;
|
||||
|
||||
// the reward transaction always has version 0
|
||||
$gen=$db->row("SELECT public_key, signature FROM transactions WHERE version=0 AND block=:block",array(":block"=>$block['id']));
|
||||
$block['public_key']=$gen['public_key'];
|
||||
$block['reward_signature']=$gen['signature'];
|
||||
return $block;
|
||||
|
||||
}
|
||||
|
||||
//return a specific block as array
|
||||
public function get($height){
|
||||
global $db;
|
||||
if(empty($height)) return false;
|
||||
|
||||
@@ -1,17 +1,34 @@
|
||||
<?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;
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
// a simple wrapper for pdo
|
||||
class db extends PDO {
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
// simple santization function to accept only alphanumeric characters
|
||||
function san($a,$b=""){
|
||||
$a = preg_replace("/[^a-zA-Z0-9".$b."]/", "", $a);
|
||||
|
||||
return $a;
|
||||
}
|
||||
|
||||
// api error and exit
|
||||
function api_err($data){
|
||||
global $_config;
|
||||
echo json_encode(array("status"=>"error","data"=>$data, "coin"=>$_config['coin']));
|
||||
exit;
|
||||
}
|
||||
// api print ok and exit
|
||||
function api_echo($data){
|
||||
global $_config;
|
||||
echo json_encode(array("status"=>"ok","data"=>$data, "coin"=>$_config['coin']));
|
||||
exit;
|
||||
}
|
||||
|
||||
// log function, shows only in cli atm
|
||||
function _log($data){
|
||||
$date=date("[Y-m-d H:s:]");
|
||||
$trace=debug_backtrace();
|
||||
@@ -26,6 +27,7 @@ function _log($data){
|
||||
if(php_sapi_name() === 'cli') echo "$date [$location] $data\n";
|
||||
}
|
||||
|
||||
// converts PEM key to hex
|
||||
function pem2hex ($data) {
|
||||
$data=str_replace("-----BEGIN PUBLIC KEY-----","",$data);
|
||||
$data=str_replace("-----END PUBLIC KEY-----","",$data);
|
||||
@@ -37,6 +39,7 @@ function pem2hex ($data) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
// converts hex key to PEM
|
||||
function hex2pem ($data, $is_private_key=false) {
|
||||
$data=hex2bin($data);
|
||||
$data=base64_encode($data);
|
||||
@@ -46,66 +49,94 @@ function hex2pem ($data, $is_private_key=false) {
|
||||
|
||||
|
||||
|
||||
//all credits for this base58 functions should go to tuupola / https://github.com/tuupola/base58/
|
||||
function baseConvert(array $source, $source_base, $target_base)
|
||||
|
||||
// Base58 encoding/decoding functions - all credits go to https://github.com/stephen-hill/base58php
|
||||
function base58_encode($string)
|
||||
{
|
||||
$result = [];
|
||||
while ($count = count($source)) {
|
||||
$quotient = [];
|
||||
$remainder = 0;
|
||||
for ($i = 0; $i !== $count; $i++) {
|
||||
$accumulator = $source[$i] + $remainder * $source_base;
|
||||
$digit = (integer) ($accumulator / $target_base);
|
||||
$remainder = $accumulator % $target_base;
|
||||
if (count($quotient) || $digit) {
|
||||
array_push($quotient, $digit);
|
||||
};
|
||||
$alphabet='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||
$base=strlen($alphabet);
|
||||
// Type validation
|
||||
if (is_string($string) === false) {
|
||||
return false;
|
||||
}
|
||||
// If the string is empty, then the encoded string is obviously empty
|
||||
if (strlen($string) === 0) {
|
||||
return '';
|
||||
}
|
||||
// Now we need to convert the byte array into an arbitrary-precision decimal
|
||||
// We basically do this by performing a base256 to base10 conversion
|
||||
$hex = unpack('H*', $string);
|
||||
$hex = reset($hex);
|
||||
$decimal = gmp_init($hex, 16);
|
||||
// This loop now performs base 10 to base 58 conversion
|
||||
// The remainder or modulo on each loop becomes a base 58 character
|
||||
$output = '';
|
||||
while (gmp_cmp($decimal, $base) >= 0) {
|
||||
list($decimal, $mod) = gmp_div_qr($decimal, $base);
|
||||
$output .= $alphabet[gmp_intval($mod)];
|
||||
}
|
||||
// If there's still a remainder, append it
|
||||
if (gmp_cmp($decimal, 0) > 0) {
|
||||
$output .= $alphabet[gmp_intval($decimal)];
|
||||
}
|
||||
// Now we need to reverse the encoded data
|
||||
$output = strrev($output);
|
||||
// Now we need to add leading zeros
|
||||
$bytes = str_split($string);
|
||||
foreach ($bytes as $byte) {
|
||||
if ($byte === "\x00") {
|
||||
$output = $alphabet[0] . $output;
|
||||
continue;
|
||||
}
|
||||
array_unshift($result, $remainder);
|
||||
$source = $quotient;
|
||||
break;
|
||||
}
|
||||
return $result;
|
||||
return (string) $output;
|
||||
}
|
||||
function base58_encode($data)
|
||||
function base58_decode($base58)
|
||||
{
|
||||
if (is_integer($data)) {
|
||||
$data = [$data];
|
||||
} else {
|
||||
$data = str_split($data);
|
||||
$data = array_map(function ($character) {
|
||||
return ord($character);
|
||||
}, $data);
|
||||
$alphabet='123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||
$base=strlen($alphabet);
|
||||
|
||||
// Type Validation
|
||||
if (is_string($base58) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$converted = baseConvert($data, 256, 58);
|
||||
|
||||
return implode("", array_map(function ($index) {
|
||||
$chars="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
return $chars[$index];
|
||||
}, $converted));
|
||||
}
|
||||
function base58_decode($data, $integer = false)
|
||||
{
|
||||
$data = str_split($data);
|
||||
$data = array_map(function ($character) {
|
||||
$chars="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
||||
return strpos($chars, $character);
|
||||
}, $data);
|
||||
/* Return as integer when requested. */
|
||||
if ($integer) {
|
||||
$converted = baseConvert($data, 58, 10);
|
||||
return (integer) implode("", $converted);
|
||||
// If the string is empty, then the decoded string is obviously empty
|
||||
if (strlen($base58) === 0) {
|
||||
return '';
|
||||
}
|
||||
$converted = baseConvert($data, 58, 256);
|
||||
return implode("", array_map(function ($ascii) {
|
||||
return chr($ascii);
|
||||
}, $converted));
|
||||
$indexes = array_flip(str_split($alphabet));
|
||||
$chars = str_split($base58);
|
||||
// Check for invalid characters in the supplied base58 string
|
||||
foreach ($chars as $char) {
|
||||
if (isset($indexes[$char]) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Convert from base58 to base10
|
||||
$decimal = gmp_init($indexes[$chars[0]], 10);
|
||||
for ($i = 1, $l = count($chars); $i < $l; $i++) {
|
||||
$decimal = gmp_mul($decimal, $base);
|
||||
$decimal = gmp_add($decimal, $indexes[$chars[$i]]);
|
||||
}
|
||||
// Convert from base10 to base256 (8-bit byte array)
|
||||
$output = '';
|
||||
while (gmp_cmp($decimal, 0) > 0) {
|
||||
list($decimal, $byte) = gmp_div_qr($decimal, 256);
|
||||
$output = pack('C', gmp_intval($byte)) . $output;
|
||||
}
|
||||
// Now we need to add leading zeros
|
||||
foreach ($chars as $char) {
|
||||
if ($indexes[$char] === 0) {
|
||||
$output = "\x00" . $output;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// converts PEM key to the base58 version used by ARO
|
||||
function pem2coin ($data) {
|
||||
$data=str_replace("-----BEGIN PUBLIC KEY-----","",$data);
|
||||
$data=str_replace("-----END PUBLIC KEY-----","",$data);
|
||||
@@ -118,7 +149,7 @@ function pem2coin ($data) {
|
||||
return base58_encode($data);
|
||||
|
||||
}
|
||||
|
||||
// converts the key in base58 to PEM
|
||||
function coin2pem ($data, $is_private_key=false) {
|
||||
|
||||
|
||||
@@ -133,9 +164,9 @@ function coin2pem ($data, $is_private_key=false) {
|
||||
return "-----BEGIN PUBLIC KEY-----\n".$data."\n-----END PUBLIC KEY-----\n";
|
||||
}
|
||||
|
||||
|
||||
// sign data with private key
|
||||
function ec_sign($data, $key){
|
||||
|
||||
// transform the base58 key format to PEM
|
||||
$private_key=coin2pem($key,true);
|
||||
|
||||
|
||||
@@ -145,9 +176,8 @@ function ec_sign($data, $key){
|
||||
|
||||
|
||||
openssl_sign($data,$signature,$pkey,OPENSSL_ALGO_SHA256);
|
||||
|
||||
|
||||
|
||||
|
||||
// the signature will be base58 encoded
|
||||
return base58_encode($signature);
|
||||
|
||||
}
|
||||
@@ -156,7 +186,7 @@ function ec_sign($data, $key){
|
||||
function ec_verify($data, $signature, $key){
|
||||
|
||||
|
||||
|
||||
// transform the base58 key to PEM
|
||||
$public_key=coin2pem($key);
|
||||
|
||||
$signature=base58_decode($signature);
|
||||
@@ -170,7 +200,7 @@ function ec_verify($data, $signature, $key){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 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){
|
||||
global $_config;
|
||||
if($debug) echo "\nPeer post: $url\n";
|
||||
@@ -195,16 +225,19 @@ function peer_post($url, $data=array(),$timeout=60,$debug=false){
|
||||
$result = file_get_contents($url, false, $context);
|
||||
if($debug) echo "\nPeer response: $result\n";
|
||||
$res=json_decode($result,true);
|
||||
|
||||
// the function will return false if something goes wrong
|
||||
if($res['status']!="ok"||$res['coin']!=$_config['coin']) return false;
|
||||
return $res['data'];
|
||||
}
|
||||
|
||||
|
||||
// convers hex to base58
|
||||
function hex2coin($hex){
|
||||
|
||||
$data=hex2bin($hex);
|
||||
return base58_encode($data);
|
||||
}
|
||||
// converts base58 to hex
|
||||
function coin2hex($data){
|
||||
|
||||
$bin= base58_decode($data);
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<?php
|
||||
|
||||
// ARO version
|
||||
define("VERSION", "0.2b");
|
||||
|
||||
// Amsterdam timezone by default, should probably be moved to config
|
||||
date_default_timezone_set("Europe/Amsterdam");
|
||||
|
||||
|
||||
|
||||
//error_reporting(E_ALL & ~E_NOTICE);
|
||||
error_reporting(0);
|
||||
ini_set('display_errors',"off");
|
||||
|
||||
|
||||
// not accessible directly
|
||||
if(php_sapi_name() !== 'cli'&&substr_count($_SERVER['PHP_SELF'],"/")>1){
|
||||
die("This application should only be run in the main directory /");
|
||||
}
|
||||
@@ -26,6 +27,8 @@ if($_config['db_pass']=="ENTER-DB-PASS") die("Please update your config file and
|
||||
// initial DB connection
|
||||
$db=new DB($_config['db_connect'],$_config['db_user'],$_config['db_pass'],0);
|
||||
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");
|
||||
@@ -47,10 +50,11 @@ foreach($query as $res){
|
||||
|
||||
|
||||
|
||||
|
||||
// nothing is allowed while in maintenance
|
||||
if($_config['maintenance']==1) api_err("under-maintenance");
|
||||
|
||||
|
||||
// update the db schema, on every git pull or initial install
|
||||
if(file_exists("tmp/db-update")){
|
||||
|
||||
$res=unlink("tmp/db-update");
|
||||
@@ -62,19 +66,22 @@ if(file_exists("tmp/db-update")){
|
||||
echo "Could not access the tmp/db-update file. Please give full permissions to this file\n";
|
||||
}
|
||||
|
||||
// something went wront with the db schema
|
||||
if($_config['dbversion']<2) exit;
|
||||
|
||||
// separate blockchain for testnet
|
||||
if($_config['testnet']==true) $_config['coin'].="-testnet";
|
||||
|
||||
// current hostname
|
||||
$hostname=(!empty($_SERVER['HTTPS'])?'https':'http')."://".$_SERVER['HTTP_HOST'];
|
||||
|
||||
if($hostname!=$_config['hostname']&&$_SERVER['HTTP_HOST']!="localhost"&&$_SERVER['HTTP_HOST']!="127.0.0.1"&&$_SERVER['hostname']!='::1'&&php_sapi_name() !== 'cli'){
|
||||
// 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']))){
|
||||
$db->run("UPDATE config SET val=:hostname WHERE cfg='hostname' LIMIT 1",array(":hostname"=>$hostname));
|
||||
$_config['hostname']=$hostname;
|
||||
}
|
||||
if(empty($_config['hostname'])||$_config['hostname']=="http://"||$_config['hostname']=="https://") api_err("Invalid hostname");
|
||||
|
||||
|
||||
// run sanity
|
||||
$t=time();
|
||||
if($t-$_config['sanity_last']>$_config['sanity_interval']&& php_sapi_name() !== 'cli') system("php sanity.php > /dev/null 2>&1 &");
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
// when db schema modifications are done, this function is run.
|
||||
|
||||
$dbversion=intval($_config['dbversion']);
|
||||
$db->beginTransaction();
|
||||
@@ -135,8 +136,9 @@ if($dbversion==5){
|
||||
$db->run("ALTER TABLE `peers` ADD `fails` TINYINT NOT NULL DEFAULT '0' AFTER `ip`; ");
|
||||
$dbversion++;
|
||||
}
|
||||
// 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));
|
||||
$db->commit();
|
||||
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
class Transaction {
|
||||
|
||||
|
||||
// reverse and remove all transactions from a block
|
||||
public function reverse($block){
|
||||
global $db;
|
||||
$acc=new Account;
|
||||
@@ -10,14 +9,17 @@ class Transaction {
|
||||
foreach($r as $x){
|
||||
if(empty($x['src'])) $x['src']=$acc->get_address($x['public_key']);
|
||||
$db->run("UPDATE accounts SET balance=balance-:val WHERE id=:id",array(":id"=>$x['dst'], ":val"=>$x['val']));
|
||||
|
||||
// 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) $this->add_mempool($x);
|
||||
|
||||
// add the transactions to mempool
|
||||
if($x['version']>0) $this->add_mempool($x);
|
||||
$res= $db->run("DELETE FROM transactions WHERE id=:id",array(":id"=>$x['id']));
|
||||
if($res!=1) return false;
|
||||
}
|
||||
}
|
||||
|
||||
// clears the mempool
|
||||
public function clean_mempool(){
|
||||
global $db;
|
||||
$block= new Block;
|
||||
@@ -26,12 +28,14 @@ class Transaction {
|
||||
$limit=$height-1000;
|
||||
$db->run("DELETE FROM mempool WHERE height<:limit",array(":limit"=>$limit));
|
||||
}
|
||||
|
||||
|
||||
// returns X transactions from mempool
|
||||
public function mempool($max){
|
||||
global $db;
|
||||
$block=new Block;
|
||||
$current=$block->current();
|
||||
$height=$current['height']+1;
|
||||
// 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));
|
||||
$transactions=array();
|
||||
if(count($r)>0){
|
||||
@@ -72,11 +76,13 @@ class Transaction {
|
||||
$transactions[$x['id']]=$trans;
|
||||
}
|
||||
}
|
||||
// always sort the array
|
||||
ksort($transactions);
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
// add a new transaction to mempool and lock it with the current height
|
||||
public function add_mempool($x, $peer=""){
|
||||
global $db;
|
||||
$block= new Block;
|
||||
@@ -90,6 +96,7 @@ class Transaction {
|
||||
|
||||
}
|
||||
|
||||
// add a new transaction to the blockchain
|
||||
public function add($block,$height, $x){
|
||||
global $db;
|
||||
$acc= new Account;
|
||||
@@ -100,22 +107,24 @@ class Transaction {
|
||||
$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;
|
||||
$db->run("UPDATE accounts SET balance=balance+:val WHERE id=:id",array(":id"=>$x['dst'], ":val"=>$x['val']));
|
||||
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']));
|
||||
// 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']));
|
||||
$db->run("DELETE FROM mempool WHERE id=:id",array(":id"=>$x['id']));
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// hash the transaction's most important fields and create the transaction ID
|
||||
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);
|
||||
return hex2coin($hash);
|
||||
}
|
||||
|
||||
|
||||
// check the transaction for validity
|
||||
public function check($x, $height=0){
|
||||
|
||||
// if no specific block, use current
|
||||
if($height===0){
|
||||
$block=new Block;
|
||||
$current=$block->current();
|
||||
@@ -124,32 +133,54 @@ class Transaction {
|
||||
$acc= new Account;
|
||||
$info=$x['val']."-".$x['fee']."-".$x['dst']."-".$x['message']."-".$x['version']."-".$x['public_key']."-".$x['date'];
|
||||
|
||||
// the value must be >=0
|
||||
if($x['val']<0){ _log("$x[id] - Value below 0"); return false; }
|
||||
if($x['fee']<0) { _log("$x[id] - Fee below 0"); return false; }
|
||||
|
||||
// the fee must be >=0
|
||||
if($x['fee']<0) { _log("$x[id] - Fee below 0"); 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;
|
||||
// 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; }
|
||||
|
||||
if(strlen($x['public_key'])<15) { _log("$x[id] - Invalid public key size"); 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>17000&&$x['date']<1519319340) return false;
|
||||
$id=$this->hash($x);
|
||||
if($x['id']!=$id) { _log("$x[id] - Invalid hash"); return false; }
|
||||
// the hash does not match our regenerated hash
|
||||
if($x['id']!=$id) {
|
||||
// fix for broken base58 library which was used until block 17000, 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>17000){
|
||||
_log("$x[id] - $id - Invalid hash");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if(!$acc->check_signature($info, $x['signature'], $x['public_key'])) { _log("$x[id] - Invalid signature"); return false; }
|
||||
//verify the ecdsa signature
|
||||
if(!$acc->check_signature($info, $x['signature'], $x['public_key'])) { _log("$x[id] - Invalid signature"); return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
// sign a transaction
|
||||
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);
|
||||
@@ -158,14 +189,14 @@ class Transaction {
|
||||
|
||||
}
|
||||
|
||||
|
||||
//export a mempool transaction
|
||||
public function export($id){
|
||||
global $db;
|
||||
$r=$db->row("SELECT * FROM mempool WHERE id=:id",array(":id"=>$id));
|
||||
//unset($r['peer']);
|
||||
return $r;
|
||||
|
||||
}
|
||||
// get the transaction data as array
|
||||
public function get_transaction($id){
|
||||
global $db;
|
||||
$acc=new Account;
|
||||
@@ -188,6 +219,7 @@ class Transaction {
|
||||
|
||||
}
|
||||
|
||||
// return the transactions for a specific block id or height
|
||||
public function get_transactions($height="", $id=""){
|
||||
global $db;
|
||||
$acc=new Account;
|
||||
@@ -216,7 +248,7 @@ class Transaction {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// get a specific mempool transaction as array
|
||||
public function get_mempool_transaction($id){
|
||||
global $db;
|
||||
$x=$db->row("SELECT * FROM mempool WHERE id=:id",array(":id"=>$id));
|
||||
|
||||
8
mine.php
8
mine.php
@@ -30,24 +30,27 @@ set_time_limit(360);
|
||||
$q=$_GET['q'];
|
||||
|
||||
$ip=$_SERVER['REMOTE_ADDR'];
|
||||
// in case of testnet, all IPs are accepted for mining
|
||||
if($_config['testnet']==false&&!in_array($ip,$_config['allowed_hosts'])) api_err("unauthorized");
|
||||
|
||||
if($q=="info"){
|
||||
// provides the mining info to the miner
|
||||
$diff=$block->difficulty();
|
||||
$current=$block->current();
|
||||
api_echo(array("difficulty"=>$diff, "block"=>$current['id'], "height"=>$current['height']));
|
||||
exit;
|
||||
} elseif($q=="submitNonce"){
|
||||
// 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']);
|
||||
$private_key=san($_POST['private_key']);
|
||||
|
||||
// check if the miner won the block
|
||||
$result=$block->mine($public_key, $nonce, $argon);
|
||||
|
||||
if($result) {
|
||||
|
||||
// generate the new block
|
||||
$res=$block->forge($nonce,$argon, $public_key, $private_key);
|
||||
|
||||
|
||||
@@ -55,6 +58,7 @@ if($q=="info"){
|
||||
|
||||
|
||||
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");
|
||||
|
||||
71
peer.php
71
peer.php
@@ -27,24 +27,26 @@ require_once("include/init.inc.php");
|
||||
$trx = new Transaction;
|
||||
$block=new Block;
|
||||
$q=$_GET['q'];
|
||||
|
||||
// the data is sent as json, in $_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
|
||||
if($_POST['coin']!=$_config['coin']) api_err("Invalid coin");
|
||||
$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
|
||||
if($q=="peer"){
|
||||
|
||||
// sanitize the hostname
|
||||
$hostname = filter_var($data['hostname'], FILTER_SANITIZE_URL);
|
||||
|
||||
if (!filter_var($hostname, FILTER_VALIDATE_URL)) api_err("invalid-hostname");
|
||||
|
||||
|
||||
// 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));
|
||||
|
||||
if($res==1){
|
||||
if($data['repeer']==1){
|
||||
$res=peer_post($hostname."/peer.php?q=peer",array("hostname"=>$_config['hostname']));
|
||||
@@ -53,11 +55,12 @@ if($q=="peer"){
|
||||
}
|
||||
api_echo("peer-ok-already");
|
||||
}
|
||||
// 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");
|
||||
$reserve=1;
|
||||
if($res<$_config['max_peers']) $reserve=0;
|
||||
$db->run("INSERT ignore INTO peers SET hostname=:hostname, reserve=:reserve, ping=UNIX_TIMESTAMP(), ip=:ip ON DUPLICATE KEY UPDATE hostname=:hostname2",array(":ip"=>$ip, ":hostname2"=>$hostname,":hostname"=>$hostname, ":reserve"=>$reserve));
|
||||
|
||||
// re-peer to make sure the peer is valid
|
||||
$res=peer_post($hostname."/peer.php?q=peer",array("hostname"=>$_config['hostname']));
|
||||
if($res!==false) api_echo("re-peer-ok");
|
||||
else{
|
||||
@@ -66,60 +69,68 @@ if($q=="peer"){
|
||||
}
|
||||
}
|
||||
elseif($q=="ping"){
|
||||
// confirm peer is active
|
||||
api_echo("pong");
|
||||
}
|
||||
|
||||
|
||||
elseif($q=="submitTransaction"){
|
||||
|
||||
} elseif($q=="submitTransaction"){
|
||||
// receive a new transaction from a peer
|
||||
$current=$block->current();
|
||||
|
||||
if($current['height']>10790&&$current['height']<10810) api_err("Hard fork in progress. Please retry the transaction later!");
|
||||
|
||||
|
||||
// no transactions accepted if the sanity is syncing
|
||||
if($_config['sanity_sync']==1) api_err("sanity-sync");
|
||||
|
||||
$data['id']=san($data['id']);
|
||||
|
||||
// validate transaction data
|
||||
if(!$trx->check($data)) api_err("Invalid transaction");
|
||||
$hash=$data['id'];
|
||||
$hash=$data['id'];
|
||||
// make sure it's not already in mempool
|
||||
$res=$db->single("SELECT COUNT(1) FROM mempool WHERE id=:id",array(":id"=>$hash));
|
||||
if($res!=0) api_err("The transaction is already in mempool");
|
||||
|
||||
// make sure the peer is not flooding us with transactions
|
||||
$res=$db->single("SELECT COUNT(1) FROM mempool WHERE src=:src",array(":src"=>$data['src']));
|
||||
if($res>25) api_err("Too many transactions from this address in mempool. Please rebroadcast later.");
|
||||
$res=$db->single("SELECT COUNT(1) FROM mempool WHERE peer=:peer",array(":peer"=>$_SERVER['REMOTE_ADDR']));
|
||||
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
|
||||
$res=$db->single("SELECT COUNT(1) FROM transactions WHERE id=:id",array(":id"=>$hash));
|
||||
if($res!=0) api_err("The transaction is already in a block");
|
||||
$acc=new Account;
|
||||
$src=$acc->get_address($data['public_key']);
|
||||
|
||||
// make sure the sender has enough balance
|
||||
$balance=$db->single("SELECT balance FROM accounts WHERE id=:id",array(":id"=>$src));
|
||||
if($balance<$val+$fee) api_err("Not enough funds");
|
||||
|
||||
|
||||
// make sure the sender has enough pending balance
|
||||
$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)");
|
||||
|
||||
// add to mempool
|
||||
$trx->add_mempool($data, $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
// 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']));
|
||||
if($res['c']<$_config['max_mempool_rebroadcast']&&$res['v']/$res['c']<$data['val']) system("php propagate.php transaction '$data[id]' > /dev/null 2>&1 &");
|
||||
api_echo("transaction-ok");
|
||||
}
|
||||
elseif($q=="submitBlock"){
|
||||
// receive a new block from a peer
|
||||
|
||||
// if sanity sync, refuse all
|
||||
if($_config['sanity_sync']==1) api_err("sanity-sync");
|
||||
$data['id']=san($data['id']);
|
||||
$current=$block->current();
|
||||
// block already in the blockchain
|
||||
if($current['id']==$data['id']) api_echo("block-ok");
|
||||
if($current['height']==$data['height']&&$current['id']!=$data['id']){
|
||||
// different forks, same height
|
||||
$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
|
||||
$no1=hexdec(substr(coin2hex($current['id']),0,12));
|
||||
$no2=hexdec(substr(coin2hex($data['id']),0,12));
|
||||
if(gmp_cmp($no1,$no2)==1){
|
||||
@@ -127,12 +138,15 @@ elseif($q=="submitBlock"){
|
||||
}
|
||||
}
|
||||
if($accept_new){
|
||||
// if the new block is accepted, run a microsanity to sync it
|
||||
system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &");
|
||||
api_echo("microsanity");
|
||||
} else api_echo("reverse-microsanity");
|
||||
|
||||
} else 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($current['height']!=$data['height']-1) {
|
||||
// if the height of the block submitted is lower than our current height, send them our current block
|
||||
if($data['height']<$current['height']){
|
||||
$pr=$db->row("SELECT * FROM peers WHERE ip=:ip",array(":ip"=>$ip));
|
||||
if(!$pr) api_err("block-too-old");
|
||||
@@ -140,25 +154,30 @@ elseif($q=="submitBlock"){
|
||||
system("php propagate.php block current '$peer_host' '$pr[ip]' > /dev/null 2>&1 &");
|
||||
api_err("block-too-old");
|
||||
}
|
||||
// if the block difference is bigger than 150, nothing should be done. They should sync via sanity
|
||||
if($data['height']-$current['height']>150) api_err("block-out-of-sync");
|
||||
// request them to send us a microsync with the latest blocks
|
||||
api_echo(array("request"=>"microsync","height"=>$current['height'], "block"=>$current['id']));
|
||||
|
||||
}
|
||||
// check block data
|
||||
if(!$block->check($data)) api_err("invalid-block");
|
||||
$b=$data;
|
||||
// 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']);
|
||||
|
||||
if(!$res) api_err("invalid-block-data");
|
||||
api_echo("block-ok");
|
||||
|
||||
// send it to all our peers
|
||||
system("php propagate.php block '$data[id]' > /dev/null 2>&1 &");
|
||||
|
||||
}
|
||||
|
||||
// return the current block, used in syncing
|
||||
elseif($q=="currentBlock"){
|
||||
$current=$block->current();
|
||||
api_echo($current);
|
||||
}
|
||||
// return a specific block, used in syncing
|
||||
elseif($q=="getBlock"){
|
||||
$height=intval($data['height']);
|
||||
|
||||
@@ -167,6 +186,8 @@ elseif($q=="getBlock"){
|
||||
api_echo($export);
|
||||
}
|
||||
elseif($q=="getBlocks"){
|
||||
// returns X block starting at height, used in syncing
|
||||
|
||||
$height=intval($data['height']);
|
||||
|
||||
$r=$db->run("SELECT id,height FROM blocks WHERE height>=:height ORDER by height ASC LIMIT 100",array(":height"=>$height));
|
||||
@@ -176,7 +197,7 @@ elseif($q=="getBlock"){
|
||||
api_echo($blocks);
|
||||
|
||||
}
|
||||
|
||||
// returns a full list of unblacklisted peers in a random order
|
||||
elseif($q=="getPeers"){
|
||||
$peers=$db->run("SELECT ip,hostname FROM peers WHERE blacklisted<UNIX_TIMESTAMP() ORDER by RAND()");
|
||||
api_echo($peers);
|
||||
|
||||
@@ -26,13 +26,17 @@ OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
set_time_limit(360);
|
||||
require_once("include/init.inc.php");
|
||||
$block= new Block();
|
||||
$type=san($argv[1]);
|
||||
|
||||
$type=san($argv[1]);
|
||||
$id=san($argv[2]);
|
||||
$debug=false;
|
||||
// if debug mode, all data is printed to console, no background processes
|
||||
if(trim($argv[5])=='debug') $debug=true;
|
||||
|
||||
$peer=san(trim($argv[3]));
|
||||
|
||||
|
||||
// broadcasting a block to all peers
|
||||
if((empty($peer)||$peer=='all')&&$type=="block"){
|
||||
$whr="";
|
||||
if($id=="current") {
|
||||
@@ -40,16 +44,19 @@ if((empty($peer)||$peer=='all')&&$type=="block"){
|
||||
$id=$current['id'];
|
||||
}
|
||||
$data=$block->export($id);
|
||||
|
||||
$id=san($id);
|
||||
if($data===false||empty($data)) die("Could not export block");
|
||||
$data=json_encode($data);
|
||||
// cache it to reduce the load
|
||||
$res=file_put_contents("tmp/$id",$data);
|
||||
if($res===false) die("Could not write the cache file");
|
||||
// broadcasting to all peers
|
||||
$r=$db->run("SELECT * FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0");
|
||||
foreach($r as $x) {
|
||||
// encode the hostname in base58 and sanitize the IP to avoid any second order shell injections
|
||||
$host=base58_encode($x['hostname']);
|
||||
$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
|
||||
if($debug) system("php propagate.php '$type' '$id' '$host' '$ip' debug");
|
||||
else system("php propagate.php '$type' '$id' '$host' 'ip' > /dev/null 2>&1 &");
|
||||
}
|
||||
@@ -58,9 +65,9 @@ if((empty($peer)||$peer=='all')&&$type=="block"){
|
||||
|
||||
|
||||
|
||||
|
||||
// broadcast a block to a single peer (usually a forked process from above)
|
||||
if($type=="block"){
|
||||
|
||||
// current block or read cache
|
||||
if($id=="current"){
|
||||
$current=$block->current();
|
||||
$data=$block->export($current['id']);
|
||||
@@ -71,21 +78,23 @@ if($type=="block"){
|
||||
$data=json_decode($data,true);
|
||||
}
|
||||
$hostname=base58_decode($peer);
|
||||
|
||||
// send the block as POST to the peer
|
||||
echo "Block sent to $hostname:\n";
|
||||
$response= peer_post($hostname."/peer.php?q=submitBlock",$data,60,$debug);
|
||||
if($response=="block-ok") { echo "Block $i accepted. Exiting.\n"; exit;}
|
||||
elseif($response['request']=="microsync"){
|
||||
// the peer requested us to send more blocks, as it's behind
|
||||
echo "Microsync request\n";
|
||||
$height=intval($response['height']);
|
||||
$bl=san($response['block']);
|
||||
$current=$block->current();
|
||||
// maximum microsync is 10 blocks, for more, the peer should sync by sanity
|
||||
if($current['height']-$height>10) { echo "Height Differece too high\n"; exit; }
|
||||
$last_block=$block->get($height);
|
||||
|
||||
// if their last block does not match our blockchain/fork, ignore the request
|
||||
if ($last_block['id'] != $bl ) { echo "Last block does not match\n"; exit; }
|
||||
echo "Sending the requested blocks\n";
|
||||
|
||||
//start sending the requested block
|
||||
for($i=$height+1;$i<=$current['height'];$i++){
|
||||
$data=$block->export("",$i);
|
||||
$response = peer_post($hostname."/peer.php?q=submitBlock",$data,60,$debug);
|
||||
@@ -94,25 +103,28 @@ if($type=="block"){
|
||||
}
|
||||
|
||||
} elseif($response=="reverse-microsanity"){
|
||||
// the peer informe us that we should run a microsanity
|
||||
echo "Running microsanity\n";
|
||||
$ip=trim($argv[4]);
|
||||
$ip=filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
|
||||
if(empty($ip)) die("Invalid IP");
|
||||
// fork a microsanity in a new process
|
||||
system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &");
|
||||
}
|
||||
else echo "Block not accepted!\n";
|
||||
|
||||
}
|
||||
// broadcast a transaction to some peers
|
||||
if($type=="transaction"){
|
||||
|
||||
$trx=new Transaction;
|
||||
|
||||
// get the transaction data
|
||||
$data=$trx->export($id);
|
||||
|
||||
if(!$data){ echo "Invalid transaction id\n"; exit; }
|
||||
|
||||
// if the transaction was first sent locally, we will send it to all our peers, otherwise to just a few
|
||||
if($data['peer']=="local") $r=$db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP()");
|
||||
else $r=$db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 ORDER by RAND() LIMIT ".$_config['transaction_propagation_peers']);
|
||||
else $r=$db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 ORDER by RAND() LIMIT ".intval($_config['transaction_propagation_peers']));
|
||||
foreach($r as $x){
|
||||
$res= peer_post($x['hostname']."/peer.php?q=submitTransaction",$data);
|
||||
if(!$res) echo "Transaction not accepted\n";
|
||||
|
||||
87
sanity.php
87
sanity.php
@@ -25,26 +25,33 @@ OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
set_time_limit(0);
|
||||
error_reporting(0);
|
||||
|
||||
// make sure it's not accessible in the browser
|
||||
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
|
||||
if(file_exists("tmp/sanity-lock")){
|
||||
|
||||
$pid_time=filemtime("tmp/sanity-lock");
|
||||
// if the process died, restart after 1day
|
||||
if(time()-$pid_time>86400){
|
||||
@unlink("tmp/sanity-lock");
|
||||
}
|
||||
die("Sanity lock in place");
|
||||
}
|
||||
// set the new sanity lock
|
||||
$lock = fopen("tmp/sanity-lock", "w");
|
||||
fclose($lock);
|
||||
$arg=trim($argv[1]);
|
||||
$arg2=trim($argv[2]);
|
||||
|
||||
// sleep for 10 seconds to make sure there's a delay between starting the sanity and other processes
|
||||
if($arg!="microsanity") sleep(10);
|
||||
|
||||
|
||||
require_once("include/init.inc.php");
|
||||
|
||||
// the sanity can't run without the schema being installed
|
||||
if($_config['dbversion']<2){
|
||||
die("DB schema not created");
|
||||
@unlink("tmp/sanity-lock");
|
||||
@@ -55,11 +62,12 @@ $block=new Block();
|
||||
$acc=new Account();
|
||||
$current=$block->current();
|
||||
|
||||
|
||||
// the microsanity process is an anti-fork measure that will determine the best blockchain to choose for the last block
|
||||
$microsanity=false;
|
||||
if($arg=="microsanity"&&!empty($arg2)){
|
||||
|
||||
do {
|
||||
// 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));
|
||||
|
||||
if(!$x){ echo "Invalid node - $arg2\n"; break; }
|
||||
@@ -67,12 +75,15 @@ do {
|
||||
$data=peer_post($url."getBlock",array("height"=>$current['height']));
|
||||
|
||||
if(!$data) {echo "Invalid getBlock result\n"; break; }
|
||||
// nothing to be done, same blockchain
|
||||
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
|
||||
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));
|
||||
|
||||
@@ -81,15 +92,17 @@ do {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the block is valid
|
||||
$prev = $block->get($current['height']-1);
|
||||
|
||||
$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;}
|
||||
$block->pop(1);
|
||||
if(!$block->check($data)) break;
|
||||
|
||||
|
||||
// delete the last block
|
||||
$block->pop(1);
|
||||
|
||||
|
||||
// add the new block
|
||||
echo "Starting to sync last block from $x[hostname]\n";
|
||||
$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']);
|
||||
@@ -114,6 +127,8 @@ exit;
|
||||
|
||||
$t=time();
|
||||
//if($t-$_config['sanity_last']<300) {@unlink("tmp/sanity-lock"); die("The sanity cron was already run recently"); }
|
||||
|
||||
// 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));
|
||||
$block_peers=array();
|
||||
$longest_size=0;
|
||||
@@ -126,6 +141,7 @@ $total_active_peers=0;
|
||||
|
||||
// checking peers
|
||||
|
||||
// delete the dead peers
|
||||
$db->run("DELETE from peers WHERE fails>100");
|
||||
|
||||
$r=$db->run("SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()");
|
||||
@@ -133,18 +149,22 @@ $r=$db->run("SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_
|
||||
$total_peers=count($r);
|
||||
|
||||
$peered=array();
|
||||
|
||||
// if we have no peers, get the seed list from the official site
|
||||
if($total_peers==0&&$_config['testnet']==false){
|
||||
$i=0;
|
||||
echo "No peers found. Attempting to get peers from arionum.com\n";
|
||||
$f=file("https://www.arionum.com/peers.txt");
|
||||
shuffle($f);
|
||||
// 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"); }
|
||||
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=trim($peer);
|
||||
$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
|
||||
$pid=md5($peer);
|
||||
// do not peer if we are already peered
|
||||
if($peered[$pid]==1) continue;
|
||||
$peered[$pid]=1;
|
||||
$res=peer_post($peer."/peer.php?q=peer",array("hostname"=>$_config['hostname'], "repeer"=>1));
|
||||
@@ -152,38 +172,45 @@ if($total_peers==0&&$_config['testnet']==false){
|
||||
else echo "Peering FAIL - $peer\n";
|
||||
if($i>$_config['max_peers']) break;
|
||||
}
|
||||
// count the total peers we have
|
||||
$r=$db->run("SELECT id,hostname FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()");
|
||||
$total_peers=count($r);
|
||||
if($total_peers==0){
|
||||
// something went wrong, could nto add any peers -> exit
|
||||
@unlink("tmp/sanity-lock");
|
||||
die("Could not peer to any peers! Please check internet connectivity!\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// contact all the active peers
|
||||
foreach($r as $x){
|
||||
$url=$x['hostname']."/peer.php?q=";
|
||||
// get their peers list
|
||||
$data=peer_post($url."getPeers");
|
||||
if($data===false) {
|
||||
|
||||
// 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)*60) WHERE id=:id",array(":id"=>$x['id']));
|
||||
continue;
|
||||
}
|
||||
|
||||
$i=0;
|
||||
foreach($data as $peer){
|
||||
$pid=md5($peer);
|
||||
// store the hostname as md5 hash, for easier checking
|
||||
$pid=md5($peer['hostname']);
|
||||
// do not peer if we are already peered
|
||||
if($peered[$pid]==1) continue;
|
||||
$peered[$pid]=1;
|
||||
|
||||
// if it's our hostname, ignore
|
||||
if($peer['hostname']==$_config['hostname']) continue;
|
||||
// if invalid hostname, ignore
|
||||
if (!filter_var($peer['hostname'], FILTER_VALIDATE_URL)) continue;
|
||||
|
||||
// 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']))){
|
||||
$i++;
|
||||
// check a max_test_peers number of peers from each peer
|
||||
if($i>$_config['max_test_peers']) break;
|
||||
$peer['hostname'] = filter_var($peer['hostname'], FILTER_SANITIZE_URL);
|
||||
|
||||
// peer with each one
|
||||
$test=peer_post($peer['hostname']."/peer.php?q=peer",array("hostname"=>$_config['hostname']),20);
|
||||
if($test!==false){
|
||||
$total_peers++;
|
||||
@@ -196,32 +223,42 @@ foreach($r as $x){
|
||||
|
||||
|
||||
|
||||
|
||||
// get the current block and check it's blockchain
|
||||
$data=peer_post($url."currentBlock");
|
||||
if($data===false) continue;
|
||||
// peer was responsive, mark it as good
|
||||
$db->run("UPDATE peers SET fails=0 WHERE id=:id",array(":id"=>$x['id']));
|
||||
|
||||
$total_active_peers++;
|
||||
// add the hostname and block relationship to an array
|
||||
$block_peers[$data['id']][]=$x['hostname'];
|
||||
// count the number of peers with this block id
|
||||
$blocks_count[$data['id']]++;
|
||||
// keep block data for this block id
|
||||
$blocks[$data['id']]=$data;
|
||||
// set the most common block on all peers
|
||||
if($blocks_count[$data['id']]>$most_common_size){
|
||||
$most_common=$data['id'];
|
||||
$most_common_size=$blocks_count[$data['id']];
|
||||
}
|
||||
// set the largest height block
|
||||
if($data['height']>$largest_height){
|
||||
$largest_height=$data['height'];
|
||||
$largest_height_block=$data['id'];
|
||||
} elseif($data['height']==$largestblock&&$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($data['difficulty']==$blocks[$largest_height_block]['difficulty']){
|
||||
// if they have the same difficulty, choose if it's most common
|
||||
if($most_common==$data['id']){
|
||||
$largest_height=$data['height'];
|
||||
$largest_height_block=$data['id'];
|
||||
} 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
|
||||
$no1=hexdec(substr(coin2hex($largest_height_block),0,12));
|
||||
$no2=hexdec(substr(coin2hex($data['id']),0,12));
|
||||
if(gmp_cmp($no1,$no2)==1){
|
||||
@@ -231,6 +268,7 @@ foreach($r as $x){
|
||||
}
|
||||
}
|
||||
} elseif($data['difficulty']<$blocks[$largest_height_block]['difficulty']){
|
||||
// choose smallest (hardest) difficulty
|
||||
$largest_height=$data['height'];
|
||||
$largest_height_block=$data['id'];
|
||||
}
|
||||
@@ -244,18 +282,24 @@ echo "Most common: $most_common\n";
|
||||
echo "Most common block: $most_common_size\n";
|
||||
echo "Max height: $largest_height\n";
|
||||
echo "Current block: $current[height]\n";
|
||||
|
||||
// if we're not on the largest height
|
||||
if($current['height']<$largest_height&&$largest_height>1){
|
||||
// start sanity sync / block all other transactions/blocks
|
||||
$db->run("UPDATE config SET val=1 WHERE cfg='sanity_sync'");
|
||||
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
|
||||
$peers=$block_peers[$largest_height_block];
|
||||
shuffle($peers);
|
||||
// sync from them
|
||||
foreach($peers as $host){
|
||||
_log("Starting to sync from $host");
|
||||
$url=$host."/peer.php?q=";
|
||||
$data=peer_post($url."getBlock",array("height"=>$current['height']));
|
||||
|
||||
// invalid data
|
||||
if($data===false){ _log("Could not get block from $host - $current[height]"); continue; }
|
||||
// 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){
|
||||
$block->delete($current['height']-3);
|
||||
$current=$block->current();
|
||||
@@ -264,6 +308,7 @@ if($current['height']<$largest_height&&$largest_height>1){
|
||||
if($data===false){_log("Could not get block from $host - $current[height]"); 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
|
||||
$invalid=false;
|
||||
$last_good=$current['height'];
|
||||
for($i=$current['height']-10;$i<$current['height'];$i++){
|
||||
@@ -275,6 +320,7 @@ if($current['height']<$largest_height&&$largest_height>1){
|
||||
if($ext['id']==$data['id']) $last_good=$i;
|
||||
|
||||
}
|
||||
// if last 10 blocks are good, verify all the blocks
|
||||
if($invalid==false) {
|
||||
$cblock=array();
|
||||
for($i=$last_good;$i<=$largest_height;$i++){
|
||||
@@ -282,11 +328,12 @@ if($current['height']<$largest_height&&$largest_height>1){
|
||||
if($data===false){ $invalid=true; break; }
|
||||
$cblock[$i]=$data;
|
||||
}
|
||||
|
||||
// check if the block mining data is correct
|
||||
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 the blockchain proves ok, delete until the last block
|
||||
if($invalid==false){
|
||||
$block->delete($last_good);
|
||||
$current=$block->current();
|
||||
@@ -294,7 +341,9 @@ if($current['height']<$largest_height&&$largest_height>1){
|
||||
}
|
||||
|
||||
}
|
||||
// if current still doesn't match the data, something went wrong
|
||||
if($data['id']!=$current['id']) continue;
|
||||
// start syncing all blocks
|
||||
while($current['height']<$largest_height){
|
||||
$data=peer_post($url."getBlocks",array("height"=>$current['height']+1));
|
||||
|
||||
@@ -364,7 +413,7 @@ foreach($f as $x){
|
||||
}
|
||||
|
||||
|
||||
//recheck blocks
|
||||
//recheck the last blocks
|
||||
if($_config['sanity_recheck_blocks']>0){
|
||||
$blocks=array();
|
||||
$all_blocks_ok=true;
|
||||
|
||||
294
util.php
294
util.php
@@ -23,10 +23,25 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
// make sure it's not accessible in the browser
|
||||
if(php_sapi_name() !== 'cli') die("This should only be run as cli");
|
||||
|
||||
|
||||
require_once("include/init.inc.php");
|
||||
$cmd=trim($argv[1]);
|
||||
|
||||
|
||||
/**
|
||||
* @api {php util.php} clean Clean
|
||||
* @apiName clean
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Cleans the entire database
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php clean
|
||||
*/
|
||||
|
||||
if($cmd=='clean'){
|
||||
$tables=array("blocks","accounts","transactions","mempool");
|
||||
@@ -37,12 +52,39 @@ echo "\n The database has been cleared\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @api {php util.php} pop Pop
|
||||
* @apiName pop
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Cleans the entire database
|
||||
*
|
||||
* @apiParam {Number} arg2 Number of blocks to delete
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php pop 1
|
||||
*/
|
||||
|
||||
elseif($cmd=='pop'){
|
||||
$no=intval($argv[2]);
|
||||
$block=new Block;
|
||||
$block->pop($no);
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {php util.php} block-time Block-time
|
||||
* @apiName block-time
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Shows the block time of the last 100 blocks
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php block-time
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* 16830 -> 323
|
||||
* ...
|
||||
* 16731 -> 302
|
||||
* Average block time: 217 seconds
|
||||
*/
|
||||
|
||||
elseif($cmd=='block-time'){
|
||||
$t=time();
|
||||
@@ -59,16 +101,86 @@ echo "Average block time: ".ceil(($start-$end)/100)." seconds\n";
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} peer Peer
|
||||
* @apiName peer
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Creates a peering session with another node
|
||||
*
|
||||
* @apiParam {text} arg2 The Hostname of the other node
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php peer http://peer1.arionum.com
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* Peering OK
|
||||
*/
|
||||
|
||||
|
||||
elseif($cmd=="peer"){
|
||||
$res=peer_post($argv[2]."/peer.php?q=peer",array("hostname"=>$_config['hostname']));
|
||||
if($res!==false) echo "Peering OK\n";
|
||||
else echo "Peering FAIL\n";
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} current Current
|
||||
* @apiName current
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Prints the current block in var_dump
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php current
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* array(9) {
|
||||
* ["id"]=>
|
||||
* string(88) "4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR"
|
||||
* ["generator"]=>
|
||||
* string(88) "5ADfrJUnLefPsaYjMTR4KmvQ79eHo2rYWnKBRCXConYKYJVAw2adtzb38oUG5EnsXEbTct3p7GagT2VVZ9hfVTVn"
|
||||
* ["height"]=>
|
||||
* int(16833)
|
||||
* ["date"]=>
|
||||
* int(1519312385)
|
||||
* ["nonce"]=>
|
||||
* string(41) "EwtJ1EigKrLurlXROuuiozrR6ICervJDF2KFl4qEY"
|
||||
* ["signature"]=>
|
||||
* string(97) "AN1rKpqit8UYv6uvf79GnbjyihCPE1UZu4CGRx7saZ68g396yjHFmzkzuBV69Hcr7TF2egTsEwVsRA3CETiqXVqet58MCM6tu"
|
||||
* ["difficulty"]=>
|
||||
* string(8) "61982809"
|
||||
* ["argon"]=>
|
||||
* string(68) "$SfghIBNSHoOJDlMthVcUtg$WTJMrQWHHqDA6FowzaZJ+O9JC8DPZTjTxNE4Pj/ggwg"
|
||||
* ["transactions"]=>
|
||||
* int(0)
|
||||
* }
|
||||
*
|
||||
*/
|
||||
|
||||
elseif ($cmd=="current") {
|
||||
$block=new Block;
|
||||
var_dump($block->current());
|
||||
} elseif($cmd=="blocks"){
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} blocks Blocks
|
||||
* @apiName blocks
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Prints the id and the height of the blocks >=arg2, max 100 or arg3
|
||||
*
|
||||
* @apiParam {number} arg2 Starting height
|
||||
*
|
||||
* @apiParam {number} [arg3] Block Limit
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php blocks 10800 5
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* 10801 2yAHaZ3ghNnThaNK6BJcup2zq7EXuFsruMb5qqXaHP9M6JfBfstAag1n1PX7SMKGcuYGZddMzU7hW87S5ZSayeKX
|
||||
* 10802 wNa4mRvRPCMHzsgLdseMdJCvmeBaCNibRJCDhsuTeznJh8C1aSpGuXRDPYMbqKiVtmGAaYYb9Ze2NJdmK1HY9zM
|
||||
* 10803 3eW3B8jCFBauw8EoKN4SXgrn33UBPw7n8kvDDpyQBw1uQcmJQEzecAvwBk5sVfQxUqgzv31JdNHK45JxUFcupVot
|
||||
* 10804 4mWK1f8ch2Ji3D6aw1BsCJavLNBhQgpUHBCHihnrLDuh8Bjwsou5bQDj7D7nV4RsEPmP2ZbjUUMZwqywpRc8r6dR
|
||||
* 10805 5RBeWXo2c9NZ7UF2ubztk53PZpiA4tsk3bhXNXbcBk89cNqorNj771Qu4kthQN5hXLtu1hzUnv7nkH33hDxBM34m
|
||||
*
|
||||
*/
|
||||
elseif($cmd=="blocks"){
|
||||
$height=intval($argv[2]);
|
||||
$limit=intval($argv[3]);
|
||||
if($limit<1) $limit=100;
|
||||
@@ -77,7 +189,16 @@ elseif ($cmd=="current") {
|
||||
echo "$x[height]\t$x[id]\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {php util.php} recheck-blocks Recheck-Blocks
|
||||
* @apiName recheck-blocks
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Recheck all the blocks to make sure the blockchain is correct
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php recheck-blocks
|
||||
*
|
||||
*/
|
||||
elseif($cmd=="recheck-blocks"){
|
||||
$blocks=array();
|
||||
$block=new Block();
|
||||
@@ -96,17 +217,61 @@ elseif($cmd=="recheck-blocks"){
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif($cmd=="peers"){
|
||||
$r=$db->run("SELECT * FROM peers ORDER by reserve ASC LIMIT 100");
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} peers Peers
|
||||
* @apiName peers
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Prints all the peers and their status
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php peers
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* http://35.190.160.142 active
|
||||
* ...
|
||||
* http://aro.master.hashpi.com active
|
||||
*/
|
||||
elseif($cmd=="peers"){
|
||||
$r=$db->run("SELECT * FROM peers ORDER by reserve ASC");
|
||||
$status="active";
|
||||
if($x['reserve']==1) $status="reserve";
|
||||
foreach($r as $x){
|
||||
echo "$x[hostname]\t$x[reserve]\n";
|
||||
echo "$x[hostname]\t$status\n";
|
||||
}
|
||||
|
||||
} elseif($cmd=="mempool"){
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} mempool Mempool
|
||||
* @apiName mempool
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Prints the number of transactions in mempool
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php mempool
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* Mempool size: 12
|
||||
*/
|
||||
elseif($cmd=="mempool"){
|
||||
$res=$db->single("SELECT COUNT(1) from mempool");
|
||||
echo "Mempool size: $res\n";
|
||||
|
||||
} elseif($cmd=="delete-peer"){
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} delete-peer Delete-peer
|
||||
* @apiName delete-peer
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Removes a peer from the peerlist
|
||||
*
|
||||
* @apiParam {text} arg2 Peer's hostname
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php delete-peer http://peer1.arionum.com
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* Peer removed
|
||||
*/
|
||||
elseif($cmd=="delete-peer"){
|
||||
$peer=trim($argv[2]);
|
||||
if(empty($peer)) die("Invalid peer");
|
||||
$db->run("DELETE FROM peers WHERE ip=:ip",array(":ip"=>$peer));
|
||||
@@ -121,7 +286,23 @@ echo "Mempool size: $res\n";
|
||||
} else echo "$x[hostname] ->ok \n";
|
||||
}
|
||||
|
||||
}elseif($cmd=="peers-block"){
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {php util.php} peers-block Peers-Block
|
||||
* @apiName peers-block
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Prints the current height of all the peers
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php peers-block
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* http://peer5.arionum.com 16849
|
||||
* ...
|
||||
* http://peer10.arionum.com 16849
|
||||
*/
|
||||
elseif($cmd=="peers-block"){
|
||||
$r=$db->run("SELECT * FROM peers");
|
||||
foreach($r as $x){
|
||||
$a=peer_post($x['hostname']."/peer.php?q=currentBlock",array(),5);
|
||||
@@ -130,17 +311,85 @@ echo "Mempool size: $res\n";
|
||||
echo "$x[hostname]\t$a[height]\n";
|
||||
|
||||
}
|
||||
}elseif($cmd=="balance"){
|
||||
}
|
||||
|
||||
/**
|
||||
* @api {php util.php} balance Balance
|
||||
* @apiName balance
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Prints the balance of an address or a public key
|
||||
*
|
||||
* @apiParam {text} arg2 address or public_key
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php balance 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* Balance: 2,487
|
||||
*/
|
||||
|
||||
elseif($cmd=="balance"){
|
||||
|
||||
$id=san($argv[2]);
|
||||
$res=$db->single("SELECT balance FROM accounts WHERE id=:id OR public_key=:id2 LIMIT 1",array(":id"=>$id, ":id2"=>$id));
|
||||
|
||||
echo "Balance: ".number_format($res)."\n";
|
||||
}elseif($cmd=="block"){
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} block Block
|
||||
* @apiName block
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Returns a specific block
|
||||
*
|
||||
* @apiParam {text} arg2 block id
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php block 4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* array(9) {
|
||||
* ["id"]=>
|
||||
* string(88) "4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR"
|
||||
* ["generator"]=>
|
||||
* string(88) "5ADfrJUnLefPsaYjMTR4KmvQ79eHo2rYWnKBRCXConYKYJVAw2adtzb38oUG5EnsXEbTct3p7GagT2VVZ9hfVTVn"
|
||||
* ["height"]=>
|
||||
* int(16833)
|
||||
* ["date"]=>
|
||||
* int(1519312385)
|
||||
* ["nonce"]=>
|
||||
* string(41) "EwtJ1EigKrLurlXROuuiozrR6ICervJDF2KFl4qEY"
|
||||
* ["signature"]=>
|
||||
* string(97) "AN1rKpqit8UYv6uvf79GnbjyihCPE1UZu4CGRx7saZ68g396yjHFmzkzuBV69Hcr7TF2egTsEwVsRA3CETiqXVqet58MCM6tu"
|
||||
* ["difficulty"]=>
|
||||
* string(8) "61982809"
|
||||
* ["argon"]=>
|
||||
* string(68) "$SfghIBNSHoOJDlMthVcUtg$WTJMrQWHHqDA6FowzaZJ+O9JC8DPZTjTxNE4Pj/ggwg"
|
||||
* ["transactions"]=>
|
||||
* int(0)
|
||||
* }
|
||||
*/
|
||||
elseif($cmd=="block"){
|
||||
$id=san($argv[2]);
|
||||
$res=$db->row("SELECT * FROM blocks WHERE id=:id OR height=:id2 LIMIT 1",array(":id"=>$id, ":id2"=>$id));
|
||||
|
||||
var_dump($res);
|
||||
}elseif($cmd=="check-address"){
|
||||
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} check-address Check-Address
|
||||
* @apiName check-address
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Checks a specific address for validity
|
||||
*
|
||||
* @apiParam {text} arg2 block id
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php check-address 4khstc1AknzDXg8h2v12rX42vDrzBaai6Rz53mbaBsghYN4DnfPhfG7oLZS24Q92MuusdYmwvDuiZiuHHWgdELLR
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* The address is valid
|
||||
*/
|
||||
elseif($cmd=="check-address"){
|
||||
$dst=trim($argv[2]);
|
||||
$acc=new Account;
|
||||
if(!$acc->valid($dst)) die("Invalid address");
|
||||
@@ -148,6 +397,27 @@ echo "Mempool size: $res\n";
|
||||
if(strlen($dst_b)!=64) die("Invalid address - ".strlen($dst_b)." bytes");
|
||||
|
||||
echo "The address is valid\n";
|
||||
}
|
||||
/**
|
||||
* @api {php util.php} get-address Get-Address
|
||||
* @apiName get-address
|
||||
* @apiGroup UTIL
|
||||
* @apiDescription Converts a public key into an address
|
||||
*
|
||||
* @apiParam {text} arg2 public key
|
||||
*
|
||||
* @apiExample {cli} Example usage:
|
||||
* php util.php get-address PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwQr8cE5s6APWAE1SWAmH6NM1nJTryBURULEsifA2hLVuW5GXFD1XU6s6REG1iPK7qGaRDkGpQwJjDhQKVoSVkSNp
|
||||
*
|
||||
* @apiSuccessExample {text} Success-Response:
|
||||
* 5WuRMXGM7Pf8NqEArVz1NxgSBptkimSpvuSaYC79g1yo3RDQc8TjVtGH5chQWQV7CHbJEuq9DmW5fbmCEW4AghQr
|
||||
*/
|
||||
|
||||
elseif($cmd=='get-address'){
|
||||
|
||||
$public_key=trim($argv2);
|
||||
if(strlen($public_key)<32) die("Invalid public key");
|
||||
print($acc->get_address($public_key));
|
||||
|
||||
} else {
|
||||
echo "Invalid command\n";
|
||||
|
||||
Reference in New Issue
Block a user