79 Commits

Author SHA1 Message Date
admin@arionum.com
d03cd9e9f6 version 2018-12-26 01:12:00 +02:00
admin@arionum.com
f700c3a1c7 Merge branch 'master' of https://github.com/arionum/node
hf recovery
2018-12-25 22:44:33 +02:00
admin@arionum.com
f564e7efa1 hf recovery 2018-12-25 22:44:29 +02:00
arionum
55c2ccc12c Merge pull request #41 from pxgamer/feature/temp-ignore
Add Git ignore file to the tmp directory
2018-12-13 21:23:44 +02:00
pxgamer
0d181f5512 Add Git ignore file to the tmp directory
The sanity process generates a lot of temporary files in the tmp
directory. These display as untracked changes in Git and make it a lot
harder to view only actual changes to the repository.
2018-12-07 11:31:52 +00:00
arionum
cf6811d5c0 Merge pull request #37 from pxgamer/bugfix/public-key-transactions
Add missing public_key to getPendingBalance
2018-11-13 12:21:56 +02:00
pxgamer
d3d20f596b Add missing public_key to getPendingBalance 2018-11-07 11:58:07 +00:00
arionum
54c9d063be Merge pull request #36 from pxgamer/bugfix/public-key-transactions
Add public_key variable where it was undefined
2018-11-05 14:40:22 +02:00
pxgamer
be078f910f Add public_key variable where it was undefined
Previously the public_key variable is being referenced but it is never
set in this API call. This allows the correct functionality to occur
when the public_key query parameter is set.
2018-11-05 11:58:44 +00:00
admin@arionum.com
6252d4e3fe api typo 2018-11-05 12:13:45 +02:00
admin@arionum.com
90fb711d2a 10x sanity lock timeout 2018-11-05 11:47:50 +02:00
arionum
271815e731 Merge pull request #35 from pxgamer/feature/sanity-orphan
Update to use the sanity interval for the lock
2018-11-05 11:45:23 +02:00
admin@arionum.com
1a8b491fba checkAddress API 2018-11-05 11:42:41 +02:00
pxgamer
d6235f4121 Set a sanity interval fallback if it isn't set 2018-10-30 09:18:20 +00:00
pxgamer
dacd9420a1 Standardise the sanity path 2018-10-29 17:49:38 +00:00
pxgamer
7e11df5a28 Update to use the sanity interval for the lock 2018-10-29 17:44:15 +00:00
admin@arionum.com
88f50fcae1 passive peering 2018-10-25 21:11:24 +03:00
arionum
3251f98ebf Merge pull request #34 from pxgamer/feature/config-peers
Add initial peers list to configuration
2018-10-25 20:33:27 +03:00
pxgamer
98dba661b1 Change namespace to Arionum\Node 2018-10-20 18:15:14 +01:00
pxgamer
ca9e95e7af Move loading of new files to the init file 2018-10-20 18:04:33 +01:00
pxgamer
5bbbca15a9 Update the sanity process to use InitialPeers 2018-10-19 10:01:07 +01:00
pxgamer
4c79b7f460 Add InitialPeers class for manging initial peers 2018-10-19 09:58:32 +01:00
pxgamer
5906372fc0 Add initial peers from the peer file 2018-10-19 09:49:53 +01:00
pxgamer
30c76cab5c Add Arionum exception class 2018-10-19 09:30:11 +01:00
pxgamer
e70d422da5 Add peers array to the configuration sample 2018-10-18 23:05:08 +01:00
arionum
754017f634 Merge pull request #33 from pxgamer/feature/api-docs
Add missing API documentation
2018-10-13 21:06:36 +03:00
admin@arionum.com
4aeff314bb ignored file 2018-10-13 21:05:41 +03:00
admin@arionum.com
c25ccfe064 json content 2018-10-13 21:03:24 +03:00
pxgamer
5fbb3c3ac2 Update the API documentation output 2018-10-12 12:11:42 +01:00
pxgamer
d6c6d3420e Add apiDoc comments for the node-info endpoint 2018-10-12 12:01:56 +01:00
pxgamer
e389988bda Update the formatting of the node-info API code 2018-10-12 11:58:08 +01:00
pxgamer
c8a8d3b9d0 Add apiDoc comments for the sanity endpoint 2018-10-12 11:55:24 +01:00
pxgamer
3f42a53991 Update the formatting of the sanity API code 2018-10-12 11:38:20 +01:00
pxgamer
6383aade6e Fix doc numbering typo for getAlias 2018-10-12 11:35:57 +01:00
arionum
17acd5830e Merge pull request #27 from pxgamer/feature/travis
Add a configuration file for Travis CI
2018-10-10 17:40:49 +03:00
arionum
f33402382b Merge pull request #32 from pxgamer/feature/json-headers
Add JSON header setting to the api functions
2018-10-10 17:40:30 +03:00
pxgamer
3ddc0dd90e Add JSON header setting to the api functions 2018-10-08 12:39:16 +01:00
arionum
33587258a8 Merge pull request #31 from pxgamer/feature/blacklist-addresses
Add support for blacklisting addresses
2018-09-14 22:16:33 +03:00
pxgamer
49df2cf71f Add Blacklist check for addresses 2018-09-14 15:49:10 +01:00
pxgamer
975e602088 Blacklist the new Octaex wallet address 2018-09-14 15:46:52 +01:00
pxgamer
6483f377b5 Add Blacklist::checkAddress() method 2018-09-14 15:45:51 +01:00
arionum
843d1d0fef Merge pull request #29 from pxgamer/feature/blacklist-refactor
Refactor the blacklist to a class
2018-09-09 15:52:39 +03:00
admin@arionum.com
91f6e1f5d4 tag 2018-09-09 15:50:17 +03:00
pxgamer
33aa9cb6c5 Merge 'master' into feature/blacklist-refactor 2018-09-06 13:54:45 +01:00
admin@arionum.com
29c27c426e typo 2018-09-06 14:57:52 +03:00
pxgamer
2202811745 Update blacklist checks to use the class 2018-09-06 12:07:17 +01:00
pxgamer
30f35944ea Require the Blaclist class in init.inc 2018-09-06 12:02:10 +01:00
pxgamer
7146cfd3c0 Add current blacklisted public keys 2018-09-06 12:00:42 +01:00
pxgamer
024042abab Add Blacklist class 2018-09-06 12:00:08 +01:00
admin@arionum.com
0b73adb3d8 paranoid and blacklist 2018-09-05 16:06:23 +03:00
Arionum
a03484adee accounts-hash 2018-08-30 01:33:09 +03:00
Arionum
99f17a3e7d util tools 2018-08-30 01:28:57 +03:00
Arionum
3549da461d Merge branch 'master' of https://github.com/arionum/node
Conflicts:
	util.php
2018-08-30 01:28:07 +03:00
Arionum
616dde11ea sync fix 2018-08-30 01:24:39 +03:00
pxgamer
31f5ff0bd1 Remove progress from Travis testing 2018-08-29 00:01:29 +01:00
pxgamer
3cad1162ef Fix local configuration to prevent recursing 2018-08-28 23:57:37 +01:00
pxgamer
7a83f1ab10 Add test Travis configuration 2018-08-28 23:55:27 +01:00
arionum
b974dc4c9a Update util.php 2018-08-27 15:18:40 +03:00
arionum
55a1dc750c Merge pull request #25 from KyleFromOhio/master
FIXED: formatting
2018-08-24 22:56:31 +03:00
Kyle Anderson
4b47d0d88e FIXED: formatting 2018-08-24 12:45:34 -07:00
Arionum
6a6005ca4c tuning 2018-08-19 23:02:06 +03:00
Arionum
9dd74285f7 limit peers per sanity 2018-08-18 01:55:18 +03:00
Arionum
788f438114 alias transactions 2018-08-18 00:42:36 +03:00
Arionum
f3e430fee5 sanity rollback 2018-08-15 14:16:59 +03:00
Arionum
faf8cc05f7 test 2018-08-14 05:35:43 +03:00
Arionum
de732ee7f9 db link 2018-08-14 05:21:00 +03:00
Arionum
74190d40ba filter 2018-08-14 05:16:31 +03:00
Arionum
65e801989d resync check 2018-08-14 02:52:01 +03:00
Arionum
d688423d3e block rechecl restore 2018-08-14 02:39:18 +03:00
Arionum
ffc87d69bf mine logic error 2018-08-14 02:33:07 +03:00
Arionum
2a49e6c70a dif fix 2018-08-13 06:45:59 +03:00
Arionum
6c8bc7b97c argon typo 2018-08-13 05:57:59 +03:00
Arionum
7efb4df493 string 2018-08-13 05:33:29 +03:00
Arionum
beff53e938 80458 2018-08-13 05:15:02 +03:00
Arionum
5ca54479a7 hf extend 2018-08-13 04:56:01 +03:00
Arionum
547cac4afb diff split 2018-08-13 03:31:43 +03:00
Arionum
bc9c945646 faster sanity 2018-08-13 03:09:21 +03:00
Arionum
8be4270e16 20block diff 2018-08-13 03:03:07 +03:00
Arionum
971c385042 difficulty 2018-08-13 03:01:20 +03:00
23 changed files with 1387 additions and 268 deletions

25
.travis.yml Normal file
View File

@@ -0,0 +1,25 @@
dist: trusty
language: php
php:
- 7.2
- nightly
matrix:
allow_failures:
- php: nightly
# This triggers builds to run on the new TravisCI infrastructure.
# See: https://docs.travis-ci.com/user/reference/trusty#Container-based-with-sudo%3A-false
sudo: false
## Cache composer
cache:
directories:
- $HOME/.composer/cache
before_script:
- travis_retry composer update --no-interaction --prefer-dist
script:
- vendor/bin/phpcs -l --standard=psr2 . include

103
api.php
View File

@@ -23,6 +23,8 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE. OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
header('Content-Type: application/json');
/** /**
* @api {get} /api.php 01. Basic Information * @api {get} /api.php 01. Basic Information
@@ -65,7 +67,9 @@ OR OTHER DEALINGS IN THE SOFTWARE.
* } * }
*/ */
require_once("include/init.inc.php"); use Arionum\Blacklist;
require_once __DIR__.'/include/init.inc.php';
error_reporting(0); error_reporting(0);
$ip = san_ip($_SERVER['REMOTE_ADDR']); $ip = san_ip($_SERVER['REMOTE_ADDR']);
$ip = filter_var($ip, FILTER_VALIDATE_IP); $ip = filter_var($ip, FILTER_VALIDATE_IP);
@@ -160,6 +164,7 @@ if ($q == "getAddress") {
*/ */
$account = $data['account']; $account = $data['account'];
$public_key = san($data['public_key'] ?? '');
if (!empty($public_key) && strlen($public_key) < 32) { if (!empty($public_key) && strlen($public_key) < 32) {
api_err("Invalid public key"); api_err("Invalid public key");
} }
@@ -199,6 +204,7 @@ if ($q == "getAddress") {
*/ */
$account = san($data['account']); $account = san($data['account']);
$public_key = san($data['public_key'] ?? '');
if (!empty($public_key) && strlen($public_key) < 32) { if (!empty($public_key) && strlen($public_key) < 32) {
api_err("Invalid public key"); api_err("Invalid public key");
} }
@@ -428,6 +434,11 @@ if ($q == "getAddress") {
if (!$acc->valid_key($public_key)) { if (!$acc->valid_key($public_key)) {
api_err("Invalid public key"); api_err("Invalid public key");
} }
if ($_config['use_official_blacklist']!==false) {
if (Blacklist::checkPublicKey($public_key)) {
api_err("Blacklisted account");
}
}
$private_key = san($data['private_key']); $private_key = san($data['private_key']);
if (!$acc->valid_key($private_key)) { if (!$acc->valid_key($private_key)) {
api_err("Invalid private key"); api_err("Invalid private key");
@@ -528,6 +539,7 @@ if ($q == "getAddress") {
$transaction['id'] = $hash; $transaction['id'] = $hash;
if (!$trx->check($transaction)) { if (!$trx->check($transaction)) {
api_err("Transaction signature failed"); api_err("Transaction signature failed");
} }
@@ -559,6 +571,7 @@ if ($q == "getAddress") {
$trx->add_mempool($transaction, "local"); $trx->add_mempool($transaction, "local");
$hash=escapeshellarg(san($hash));
system("php propagate.php transaction $hash > /dev/null 2>&1 &"); system("php propagate.php transaction $hash > /dev/null 2>&1 &");
api_echo($hash); api_echo($hash);
} elseif ($q == "mempoolSize") { } elseif ($q == "mempoolSize") {
@@ -638,11 +651,12 @@ if ($q == "getAddress") {
* @apiSuccess {boolean} data masternode date * @apiSuccess {boolean} data masternode date
*/ */
$res=$db->run("SELECT * FROM masternode"); $res=$db->run("SELECT * FROM masternode ORDER by public_key ASC");
api_echo($res);
api_echo(["masternodes"=>$res, "hash"=>md5(json_encode($res))]);
} elseif ($q == "getAlias") { } elseif ($q == "getAlias") {
/** /**
* @api {get} /api.php?q=getAlias 189. getAlias * @api {get} /api.php?q=getAlias 19. getAlias
* @apiName getAlias * @apiName getAlias
* @apiGroup API * @apiGroup API
* @apiDescription Returns the alias of an account * @apiDescription Returns the alias of an account
@@ -669,6 +683,87 @@ if ($q == "getAddress") {
$account = san($account); $account = san($account);
api_echo($acc->account2alias($account)); api_echo($acc->account2alias($account));
} elseif ($q === 'sanity') {
/**
* @api {get} /api.php?q=sanity 20. sanity
* @apiName sanity
* @apiGroup API
* @apiDescription Returns details about the node's sanity process.
*
* @apiSuccess {object} data A collection of data about the sanity process.
* @apiSuccess {boolean} data.sanity_running Whether the sanity process is currently running.
* @apiSuccess {number} data.last_sanity The timestamp for the last time the sanity process was run.
* @apiSuccess {boolean} data.sanity_sync Whether the sanity process is currently synchronising.
*/
$sanity = file_exists(__DIR__.'/tmp/sanity-lock');
$lastSanity = (int)$db->single("SELECT val FROM config WHERE cfg='sanity_last'");
$sanitySync = (bool)$db->single("SELECT val FROM config WHERE cfg='sanity_sync'");
api_echo(['sanity_running' => $sanity, 'last_sanity' => $lastSanity, 'sanity_sync' => $sanitySync]);
} elseif ($q === 'node-info') {
/**
* @api {get} /api.php?q=node-info 21. node-info
* @apiName node-info
* @apiGroup API
* @apiDescription Returns details about the node.
*
* @apiSuccess {object} data A collection of data about the node.
* @apiSuccess {string} data.hostname The hostname of the node.
* @apiSuccess {string} data.version The current version of the node.
* @apiSuccess {string} data.dbversion The database schema version for the node.
* @apiSuccess {number} data.accounts The number of accounts known by the node.
* @apiSuccess {number} data.transactions The number of transactions known by the node.
* @apiSuccess {number} data.mempool The number of transactions in the mempool.
* @apiSuccess {number} data.masternodes The number of masternodes known by the node.
* @apiSuccess {number} data.peers The number of valid peers.
*/
$dbVersion = $db->single("SELECT val FROM config WHERE cfg='dbversion'");
$hostname = $db->single("SELECT val FROM config WHERE cfg='hostname'");
$acc = $db->single("SELECT COUNT(1) FROM accounts");
$tr = $db->single("SELECT COUNT(1) FROM transactions");
$masternodes = $db->single("SELECT COUNT(1) FROM masternode");
$mempool = $db->single("SELECT COUNT(1) FROM mempool");
$peers = $db->single("SELECT COUNT(1) FROM peers WHERE blacklisted<UNIX_TIMESTAMP()");
api_echo([
'hostname' => $hostname,
'version' => VERSION,
'dbversion' => $dbVersion,
'accounts' => $acc,
'transactions' => $tr,
'mempool' => $mempool,
'masternodes' => $masternodes,
'peers' => $peers
]);
} elseif ($q === 'checkAddress') {
/**
* @api {get} /api.php?q=checkAddress 22. checkAddress
* @apiName checkAddress
* @apiGroup API
* @apiDescription Checks the validity of an address.
*
* @apiParam {string} account Account id / address
* @apiParam {string} [public_key] Public key
*
* @apiSuccess {boolean} data True if the address is valid, false otherwise.
*/
$address=$data['account'];
$public_key=$data['public_key'];
$acc = new Account();
if (!$acc->valid($address)) {
api_err(false);
}
$dst_b = base58_decode($address);
if (strlen($dst_b) != 64) {
api_err(false);
}
if (!empty($public_key)) {
if($acc->get_address($public_key)!=$address){
api_err(false);
}
}
api_echo(true);
} else { } else {
api_err("Invalid request"); api_err("Invalid request");
} }

View File

@@ -101,6 +101,50 @@ define({ "api": [
"filename": "./api.php", "filename": "./api.php",
"groupTitle": "API" "groupTitle": "API"
}, },
{
"type": "get",
"url": "/api.php?q=checkAddress",
"title": "22. checkAddress",
"name": "checkAddress",
"group": "API",
"description": "<p>Checks the validity of an address.</p>",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "string",
"optional": false,
"field": "account",
"description": "<p>Account id / address</p>"
},
{
"group": "Parameter",
"type": "string",
"optional": true,
"field": "public_key",
"description": "<p>Public key</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "boolean",
"optional": false,
"field": "data",
"description": "<p>True if the address is valid, false otherwise.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "./api.php",
"groupTitle": "API"
},
{ {
"type": "get", "type": "get",
"url": "/api.php?q=checkSignature", "url": "/api.php?q=checkSignature",
@@ -303,7 +347,7 @@ define({ "api": [
{ {
"type": "get", "type": "get",
"url": "/api.php?q=getAlias", "url": "/api.php?q=getAlias",
"title": "189. getAlias", "title": "19. getAlias",
"name": "getAlias", "name": "getAlias",
"group": "API", "group": "API",
"description": "<p>Returns the alias of an account</p>", "description": "<p>Returns the alias of an account</p>",
@@ -1015,6 +1059,86 @@ define({ "api": [
"filename": "./api.php", "filename": "./api.php",
"groupTitle": "API" "groupTitle": "API"
}, },
{
"type": "get",
"url": "/api.php?q=node-info",
"title": "21. node-info",
"name": "node_info",
"group": "API",
"description": "<p>Returns details about the node.</p>",
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "object",
"optional": false,
"field": "data",
"description": "<p>A collection of data about the node.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "data.hostname",
"description": "<p>The hostname of the node.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "data.version",
"description": "<p>The current version of the node.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "data.dbversion",
"description": "<p>The database schema version for the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.accounts",
"description": "<p>The number of accounts known by the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.transactions",
"description": "<p>The number of transactions known by the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.mempool",
"description": "<p>The number of transactions in the mempool.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.masternodes",
"description": "<p>The number of masternodes known by the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.peers",
"description": "<p>The number of valid peers.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "./api.php",
"groupTitle": "API"
},
{ {
"type": "get", "type": "get",
"url": "/api.php?q=randomNumber", "url": "/api.php?q=randomNumber",
@@ -1073,6 +1197,51 @@ define({ "api": [
"filename": "./api.php", "filename": "./api.php",
"groupTitle": "API" "groupTitle": "API"
}, },
{
"type": "get",
"url": "/api.php?q=sanity",
"title": "20. sanity",
"name": "sanity",
"group": "API",
"description": "<p>Returns details about the node's sanity process.</p>",
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "object",
"optional": false,
"field": "data",
"description": "<p>A collection of data about the sanity process.</p>"
},
{
"group": "Success 200",
"type": "boolean",
"optional": false,
"field": "data.sanity_running",
"description": "<p>Whether the sanity process is currently running.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.last_sanity",
"description": "<p>The timestamp for the last time the sanity process was run.</p>"
},
{
"group": "Success 200",
"type": "boolean",
"optional": false,
"field": "data.sanity_sync",
"description": "<p>Whether the sanity process is currently synchronising.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "./api.php",
"groupTitle": "API"
},
{ {
"type": "get", "type": "get",
"url": "/api.php?q=send", "url": "/api.php?q=send",

View File

@@ -101,6 +101,50 @@
"filename": "./api.php", "filename": "./api.php",
"groupTitle": "API" "groupTitle": "API"
}, },
{
"type": "get",
"url": "/api.php?q=checkAddress",
"title": "22. checkAddress",
"name": "checkAddress",
"group": "API",
"description": "<p>Checks the validity of an address.</p>",
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "string",
"optional": false,
"field": "account",
"description": "<p>Account id / address</p>"
},
{
"group": "Parameter",
"type": "string",
"optional": true,
"field": "public_key",
"description": "<p>Public key</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "boolean",
"optional": false,
"field": "data",
"description": "<p>True if the address is valid, false otherwise.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "./api.php",
"groupTitle": "API"
},
{ {
"type": "get", "type": "get",
"url": "/api.php?q=checkSignature", "url": "/api.php?q=checkSignature",
@@ -303,7 +347,7 @@
{ {
"type": "get", "type": "get",
"url": "/api.php?q=getAlias", "url": "/api.php?q=getAlias",
"title": "189. getAlias", "title": "19. getAlias",
"name": "getAlias", "name": "getAlias",
"group": "API", "group": "API",
"description": "<p>Returns the alias of an account</p>", "description": "<p>Returns the alias of an account</p>",
@@ -1015,6 +1059,86 @@
"filename": "./api.php", "filename": "./api.php",
"groupTitle": "API" "groupTitle": "API"
}, },
{
"type": "get",
"url": "/api.php?q=node-info",
"title": "21. node-info",
"name": "node_info",
"group": "API",
"description": "<p>Returns details about the node.</p>",
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "object",
"optional": false,
"field": "data",
"description": "<p>A collection of data about the node.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "data.hostname",
"description": "<p>The hostname of the node.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "data.version",
"description": "<p>The current version of the node.</p>"
},
{
"group": "Success 200",
"type": "string",
"optional": false,
"field": "data.dbversion",
"description": "<p>The database schema version for the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.accounts",
"description": "<p>The number of accounts known by the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.transactions",
"description": "<p>The number of transactions known by the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.mempool",
"description": "<p>The number of transactions in the mempool.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.masternodes",
"description": "<p>The number of masternodes known by the node.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.peers",
"description": "<p>The number of valid peers.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "./api.php",
"groupTitle": "API"
},
{ {
"type": "get", "type": "get",
"url": "/api.php?q=randomNumber", "url": "/api.php?q=randomNumber",
@@ -1073,6 +1197,51 @@
"filename": "./api.php", "filename": "./api.php",
"groupTitle": "API" "groupTitle": "API"
}, },
{
"type": "get",
"url": "/api.php?q=sanity",
"title": "20. sanity",
"name": "sanity",
"group": "API",
"description": "<p>Returns details about the node's sanity process.</p>",
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "object",
"optional": false,
"field": "data",
"description": "<p>A collection of data about the sanity process.</p>"
},
{
"group": "Success 200",
"type": "boolean",
"optional": false,
"field": "data.sanity_running",
"description": "<p>Whether the sanity process is currently running.</p>"
},
{
"group": "Success 200",
"type": "number",
"optional": false,
"field": "data.last_sanity",
"description": "<p>The timestamp for the last time the sanity process was run.</p>"
},
{
"group": "Success 200",
"type": "boolean",
"optional": false,
"field": "data.sanity_sync",
"description": "<p>Whether the sanity process is currently synchronising.</p>"
}
]
}
},
"version": "0.0.0",
"filename": "./api.php",
"groupTitle": "API"
},
{ {
"type": "get", "type": "get",
"url": "/api.php?q=send", "url": "/api.php?q=send",

View File

@@ -7,7 +7,7 @@ define({
"apidoc": "0.3.0", "apidoc": "0.3.0",
"generator": { "generator": {
"name": "apidoc", "name": "apidoc",
"time": "2018-08-05T21:17:14.214Z", "time": "2018-11-05T10:13:13.657Z",
"url": "http://apidocjs.com", "url": "http://apidocjs.com",
"version": "0.17.6" "version": "0.17.6"
} }

View File

@@ -7,7 +7,7 @@
"apidoc": "0.3.0", "apidoc": "0.3.0",
"generator": { "generator": {
"name": "apidoc", "name": "apidoc",
"time": "2018-08-05T21:17:14.214Z", "time": "2018-11-05T10:13:13.657Z",
"url": "http://apidocjs.com", "url": "http://apidocjs.com",
"version": "0.17.6" "version": "0.17.6"
} }

50
include/Blacklist.php Normal file
View File

@@ -0,0 +1,50 @@
<?php
namespace Arionum;
/**
* Class Blacklist
*/
final class Blacklist
{
/**
* The official list of blacklisted public keys
*/
public const PUBLIC_KEYS = [
// phpcs:disable Generic.Files.LineLength
'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCvVQcHHCNLfiP9LmzWhhpCHx39Bhc67P5HMQM9cctEFvcsUdgrkGqy18taz9ZMrAGtq7NhBYpQ4ZTHkKYiZDaSUqQ' => 'Faucet Abuser',
'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCxYDeQHk7Ke66UB2Un3UMmMoJ7RF5vDZXihdEXi8gk8ZBRAi35aFrER2ZLX1mgND7sLFXKETGTjRYjoHcuRNiJN1g' => 'Octaex Exchange',
// phpcs:enable
];
/**
* The official list of blacklisted addresses
*/
public const ADDRESSES = [
// phpcs:disable Generic.Files.LineLength
'xuzyMbEGA1tmx1o7mcxSXf2nXuuV1GtKbA4sAqjcNq2gh3shuhwBT5nJHez9AynCaxpJwL6dpkavmZBA3JkrMkg' => 'Octaex Exchange',
// phpcs:enable
];
/**
* Check if a public key is blacklisted
*
* @param string $publicKey
* @return bool
*/
public static function checkPublicKey(string $publicKey): bool
{
return key_exists($publicKey, static::PUBLIC_KEYS);
}
/**
* Check if an address is blacklisted
*
* @param string $address
* @return bool
*/
public static function checkAddress(string $address): bool
{
return key_exists($address, static::ADDRESSES);
}
}

11
include/Exception.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace Arionum\Node;
/**
* Class Exception
* A custom exception for Arionum error handling.
*/
class Exception extends \Exception
{
}

81
include/InitialPeers.php Normal file
View File

@@ -0,0 +1,81 @@
<?php
namespace Arionum\Node;
/**
* Class InitialPeers
*/
final class InitialPeers
{
public const MINIMUM_PEERS_REQUIRED = 2;
public const PRELOAD_ERROR = 'Unable to retrieve peers from the preload list.';
public const PRELOAD_LIST = 'https://www.arionum.com/peers.txt';
/**
* @var array
*/
private $peerList = [];
/**
* InitialPeers constructor.
* @param array|null $peerList
* @return void
*/
public function __construct(?array $peerList = [])
{
$this->peerList = $peerList;
}
/**
* Retrieve a peer from the initial peer list.
* @return string
* @throws Exception
*/
public function get(): string
{
if (!$this->peerList || count($this->peerList) < self::MINIMUM_PEERS_REQUIRED) {
$this->retrieveFromPreloadList();
}
return $this->selectPeer();
}
/**
* Retrieve all available initial peers.
* @return array
* @throws Exception
*/
public function getAll(): array
{
if (!$this->peerList || count($this->peerList) < self::MINIMUM_PEERS_REQUIRED) {
$this->retrieveFromPreloadList();
}
return $this->peerList;
}
/**
* @return string
*/
private function selectPeer(): string
{
return $this->peerList[array_rand($this->peerList)];
}
/**
* Retrieve a peer from
*
* @return void
* @throws Exception
*/
private function retrieveFromPreloadList(): void
{
$peerList = file(self::PRELOAD_LIST, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (!$peerList || count($peerList) < self::MINIMUM_PEERS_REQUIRED) {
throw new Exception(self::PRELOAD_ERROR);
}
$this->peerList = $peerList;
}
}

View File

@@ -35,8 +35,40 @@ class Account
return 'RncXQuc7S7aWkvTUJSHEFvYoV3ntAf7bfxEHjSiZNBvQV37MzZtg44L7GAV7szZ3uV8qWqikBewa3piZMqzBqm'; return 'RncXQuc7S7aWkvTUJSHEFvYoV3ntAf7bfxEHjSiZNBvQV37MzZtg44L7GAV7szZ3uV8qWqikBewa3piZMqzBqm';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyjKMBY4ihhJ2G25EVezg7KnoCBVbhdvWfqzNA4LC5R7wgu3VNfJgvqkCq9sKKZcCoCpX6Qr9cN882MoXsfGTvZoj') { } elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCyjKMBY4ihhJ2G25EVezg7KnoCBVbhdvWfqzNA4LC5R7wgu3VNfJgvqkCq9sKKZcCoCpX6Qr9cN882MoXsfGTvZoj') {
return 'Rq53oLzpCrb4BdJZ1jqQ2zsixV2ukxVdM4H9uvUhCGJCz1q2wagvuXV4hC6UVwK7HqAt1FenukzhVXgzyG1y32'; return 'Rq53oLzpCrb4BdJZ1jqQ2zsixV2ukxVdM4H9uvUhCGJCz1q2wagvuXV4hC6UVwK7HqAt1FenukzhVXgzyG1y32';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCzZtEj6zAW8WVB6AbDLndbQZrnH2R5Nmpk1sLyHXzqyp4P5cyJAbnUpR5UdG8sBCCuZekWSBHgWNMaGS317vPsVuG'){
// mixed keys badly generated address
return '3CWXXqpzuda85MaPpgYRee8d7a44wzemqztfFfeZDyEysQ15cN6gZNsPT32MHwjrzbENDvkqKtADoCBgVVqXWP2g';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwYhtqidHRVigBiQiun5csb9YnZzcvmSt7aCVS6nH2gYykLr9pQfJHP8bTtYTMkU1WLdmeTkNPGDujYWKjPSGU8XX'){
// broken wallet due to webwallet bug
return '4JstC5anTNMpY2zmUHt2LDmQXsMQvkh7d9qHBjBhRahAsWVTyyS9RPYMRdmcqdVPSDUQsXJfGyPFMn6y6R9M5QQ7';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwoUzVYoaDZGausEDEg5JMtiRQvdmuuv1FKvCxUp6m8iMJhKbohtH75wXPBgi4wYPMSUw4himHeJ3qnDpAQnKSsJU'){
// stolen coins hf recovery
return '4VLRngC3U24YdusKQ4rGfCX4DDfBUcNemH419wUS5xe2uUf3ku1CXq6RCfGoiZvDK61upmLfrb64YWubyh5eUG4Y';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCvgAVPik2t9yfM63rDCy13opmvejvMXadRb6qKjEoaiFkGCJHKBUSzggaEtgyDVkRk7ajREQjRrN6J4EcoXTzGM3p'){
// stolen coins hf recovery
return 'SBWPS7Yu4X4ZQFY9n27bkBL5AnDRveUBbfbZWwhEN1tWZnTCEc8kvx7ddfoaqhjw7tw8rQULk2fEgSB1r2vWqKp';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCz1Adkpo6MRTogSUKLtEh5NKo1Y8sumnNKqhRW8w2bZtVfMT4sfbStg8ycqtmQNDztvUE39MVHnXmCDtpmv9KKdQN'){
// stolen coins hf recovery
return 'reMoRxfiUxtoj7RD1aDH5yNfeuXEyTj2XiHaUBdVUhk8Wt5f4VLWrqge6J5yE9BGkVLFPqfS6ZYvj4ocWhbZhru';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCxXrhv7wkhX4R2YjyRNfssf15wTksz5Ev4FFGfCmhcUL7kt5aXRvh6xknQf5HHzDo4GsG523wBYcFhiAkmBL1kkUo'){
// stolen coins hf recovery
return '3goaif939N4xy5ThT7iq2GhBgwjrS4buhhTtTQkXrzarKcsYvyg5PU8KVgzrSfgFfhnZGNx9WseaR2JSUpYn1Vch';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCzhTJ5G37ijQcgdzUsMMVyAPFaxLCyssQjqYF1g1Zsr3XkzYux3Dt75y3DRmXmx6wiNTf7uKxAGFaQA7qao7TXp9j'){
// stolen coins hf recovery
return 'LtjGjTTurwLNZLbexAbusCRS5SNYhFydMuFdPTaYFRD3WoL2q67tidsrd7qnX8czmTBhrDyrdheP5gCwCbAHBBd';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCwrgAsdSZtv9e4Ldw2mzg7HwQMHzG1FFVzoRtENwDRZxhRTwSGYU4oUXVLzNWNqpRZ6iEZXenxUANScwr7yDET7xA'){
// stolen coins hf recovery
return 'aSpfMMbxA8U1rMqBgYoQtXhUyAKyhBJHY17CEW4V3ttgRsvpuZ1Dg3xYc1rcMeKnP2gT2sxnn7vHpmLAVVPQv7w';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCzPi4ZmDK5E7vNVz14AiJmvcT9UbxXDDWzNVYt973Sqgt6p6BQtuqkJ3X3UM92mbjxVLg3xzmhZricuUSx5J811nW'){
// stolen coins hf recovery
return '98MsWpiv3fcutf4Mm94wYKZeeS556EAvMWEBLc12y5nf5QzNtD6hDfCuWcJMUr9Q9qmbj8kS326EGuiiTW7YJDo';
} elseif ($hash == 'PZ8Tyr4Nx8MHsRAGMpZmZ6TWY63dXWSCz9iKvAxdReMiDYmBWJb3GnjeTnNLwE8y7fuyBwFDbRLpECwnscbXSLGXMmvPMbMMRYSnnc7aTyLJBzw7tqxGNw4K'){
// stolen coins hf recovery
return '2xQGMH8qQuaTeKSYya5wYPWA9dgqiKBBDSeDWu1aUuBhKi8LnsukknqcUDRdzS7VVeC7aezK6Azhkx6L7H24pUjo';
} }
// hashes 9 times in sha512 (binary) and encodes in base58 // hashes 9 times in sha512 (binary) and encodes in base58
for ($i = 0; $i < 9; for ($i = 0; $i < 9;
$i++) { $i++) {
@@ -115,12 +147,16 @@ class Account
} }
//check if an account already has an alias //check if an account already has an alias
public function has_alias($public_key){ public function has_alias($public_key)
{
global $db; global $db;
$public_key=san($public_key); $public_key=san($public_key);
$res=$db->single("SELECT COUNT(1) FROM accounts WHERE public_key=:public_key AND alias IS NOT NULL", [":public_key"=>$public_key]); $res=$db->single("SELECT COUNT(1) FROM accounts WHERE public_key=:public_key AND alias IS NOT NULL", [":public_key"=>$public_key]);
if($res!=0) return true; if ($res!=0) {
else return false; return true;
} else {
return false;
}
} }
//check alias validity //check alias validity
@@ -144,7 +180,8 @@ class Account
} }
//returns the account of an alias //returns the account of an alias
public function alias2account($alias){ public function alias2account($alias)
{
global $db; global $db;
$alias=strtoupper($alias); $alias=strtoupper($alias);
$res=$db->single("SELECT id FROM accounts WHERE alias=:alias LIMIT 1", [":alias"=>$alias]); $res=$db->single("SELECT id FROM accounts WHERE alias=:alias LIMIT 1", [":alias"=>$alias]);
@@ -152,7 +189,8 @@ class Account
} }
//returns the alias of an account //returns the alias of an account
public function account2alias($id){ public function account2alias($id)
{
global $db; global $db;
$id=san($id); $id=san($id);
$res=$db->single("SELECT alias FROM accounts WHERE id=:id LIMIT 1", [":id"=>$id]); $res=$db->single("SELECT alias FROM accounts WHERE id=:id LIMIT 1", [":id"=>$id]);
@@ -212,13 +250,14 @@ class Account
$block = new Block(); $block = new Block();
$current = $block->current(); $current = $block->current();
$public_key = $this->public_key($id); $public_key = $this->public_key($id);
$alias = $this->account2alias($id);
$limit = intval($limit); $limit = intval($limit);
if ($limit > 100 || $limit < 1) { if ($limit > 100 || $limit < 1) {
$limit = 100; $limit = 100;
} }
$res = $db->run( $res = $db->run(
"SELECT * FROM transactions WHERE dst=:dst or public_key=:src ORDER by height DESC LIMIT :limit", "SELECT * FROM transactions WHERE dst=:dst or public_key=:src or dst=:alias ORDER by height DESC LIMIT :limit",
[":src" => $public_key, ":dst" => $id, ":limit" => $limit] [":src" => $public_key, ":dst" => $id, ":limit" => $limit, ":alias"=>$alias]
); );
$transactions = []; $transactions = [];
@@ -299,11 +338,13 @@ class Account
return $res; return $res;
} }
public function get_masternode($public_key){ public function get_masternode($public_key)
{
global $db; global $db;
$res = $db->row("SELECT * FROM masternode WHERE public_key=:public_key", [":public_key" => $public_key]); $res = $db->row("SELECT * FROM masternode WHERE public_key=:public_key", [":public_key" => $public_key]);
if(empty($res['public_key'])) return false; if (empty($res['public_key'])) {
return false;
}
return $res; return $res;
} }
} }

View File

@@ -43,7 +43,7 @@ class Block
$msg = ''; $msg = '';
if($height>=80460){ if ($height>=80458) {
//reward the masternode //reward the masternode
$mn_winner=$db->single( $mn_winner=$db->single(
@@ -58,7 +58,6 @@ class Block
$mn_reward=number_format($mn_reward, 8, ".", ""); $mn_reward=number_format($mn_reward, 8, ".", "");
_log("MN Reward: $mn_reward", 2); _log("MN Reward: $mn_reward", 2);
} }
} }
@@ -115,9 +114,15 @@ class Block
} }
// insert the reward transaction in the db // insert the reward transaction in the db
$trx->add($hash, $height, $transaction); $res=$trx->add($hash, $height, $transaction);
if ($res == false) {
if($mn_winner!==false){ // rollback and exit if it fails
_log("Reward DB insert failed");
$db->rollback();
$db->exec("UNLOCK TABLES");
return false;
}
if ($mn_winner!==false&&$height>=80458&&$mn_reward>0) {
$db->run("UPDATE accounts SET balance=balance+:bal WHERE public_key=:pub", [":pub"=>$mn_winner, ":bal"=>$mn_reward]); $db->run("UPDATE accounts SET balance=balance+:bal WHERE public_key=:pub", [":pub"=>$mn_winner, ":bal"=>$mn_reward]);
$bind = [ $bind = [
":id" => hex2coin(hash("sha512", "mn".$hash.$height.$mn_winner)), ":id" => hex2coin(hash("sha512", "mn".$hash.$height.$mn_winner)),
@@ -136,14 +141,30 @@ if($mn_winner!==false){
"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", "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 $bind
); );
$this->reset_fails_masternodes($mn_winner, $height, $hash); if ($res != 1) {
// rollback and exit if it fails
_log("Masternode reward DB insert failed");
$db->rollback();
$db->exec("UNLOCK TABLES");
return false;
}
$res=$this->reset_fails_masternodes($mn_winner, $height, $hash);
if (!$res) {
// rollback and exit if it fails
_log("Masternode log DB insert failed");
$db->rollback();
$db->exec("UNLOCK TABLES");
return false;
}
$this->do_hard_forks($height, $hash);
} }
// parse the block's transactions and insert them to db // parse the block's transactions and insert them to db
$res = $this->parse_block($hash, $height, $data, false, $bootstrapping); $res = $this->parse_block($hash, $height, $data, false, $bootstrapping);
if (($height-1)%3==2 && $height>=80000&&$height<80460) { if (($height-1)%3==2 && $height>=80000&&$height<80458) {
$this->blacklist_masternodes(); $this->blacklist_masternodes();
$this->reset_fails_masternodes($public_key, $height, $hash); $this->reset_fails_masternodes($public_key, $height, $hash);
} }
@@ -158,17 +179,92 @@ $this->reset_fails_masternodes($mn_winner, $height, $hash);
return true; return true;
} }
public function do_hard_forks($height, $block)
{
global $db;
if ($height==126215) {
// compromised masternodes are being removed
$mns=['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',
];
foreach ($mns as $mn) {
$db->run("DELETE FROM masternode WHERE public_key=:p", [":p"=>$mn]);
}
// their locked coins are added to dev's safewallet
$id=hex2coin(hash("sha512", "hf".$block.$height.'compromised-masternodes'));
$res=$db->run(
"INSERT into transactions SET id=:id, block=:block, height=:height, dst=:dst, val=4700000, fee=0, signature=:sig, version=0, message=:msg, date=:date, public_key=:public_key",
[":id"=>$id, ":block"=>$block, ":height"=>$height, ":dst"=>'4kWXV4HMuogUcjZBEzmmQdtc1dHzta6VykhCV1HWyEXK7kRWEMJLNoMWbuDwFMTfBrq5a9VthkZfmkMkamTfwRBP', ":sig"=>$id, ":msg"=>'compromised-masternodes-hf', ":date"=>time(), ":public_key"=>'4kWXV4HMuogUcjZBEzmmQdtc1dHzta6VykhCV1HWyEXK7kRWEMJLNoMWbuDwFMTfBrq5a9VthkZfmkMkamTfwRBP']
);
$db->run("UPDATE accounts SET balance=balance+4700000 where id='4kWXV4HMuogUcjZBEzmmQdtc1dHzta6VykhCV1HWyEXK7kRWEMJLNoMWbuDwFMTfBrq5a9VthkZfmkMkamTfwRBP' LIMIT 1");
}
}
// resets the number of fails when winning a block and marks it with a transaction // resets the number of fails when winning a block and marks it with a transaction
public function reset_fails_masternodes($public_key, $height, $hash) public function reset_fails_masternodes($public_key, $height, $hash)
{ {
global $db; global $db;
$res=$this->masternode_log($public_key, $height, $hash); $res=$this->masternode_log($public_key, $height, $hash);
if ($res===5) {
return false;
}
if ($res) { if ($res) {
$db->run("UPDATE masternode SET last_won=:last_won,fails=0 WHERE public_key=:public_key", [":public_key"=>$public_key, ":last_won"=>$height]); $rez=$db->run("UPDATE masternode SET last_won=:last_won,fails=0 WHERE public_key=:public_key", [":public_key"=>$public_key, ":last_won"=>$height]);
if ($rez!=1) {
return false;
} }
} }
return true;
}
//logs the current masternode status //logs the current masternode status
public function masternode_log($public_key, $height, $hash) public function masternode_log($public_key, $height, $hash)
@@ -184,12 +280,15 @@ $this->reset_fails_masternodes($mn_winner, $height, $hash);
$id = hex2coin(hash("sha512", "resetfails-$hash-$height-$public_key")); $id = hex2coin(hash("sha512", "resetfails-$hash-$height-$public_key"));
$msg="$mn[blacklist],$mn[last_won],$mn[fails]"; $msg="$mn[blacklist],$mn[last_won],$mn[fails]";
$db->run( $res=$db->run(
"INSERT into transactions SET id=:id, block=:block, height=:height, dst=:dst, val=0, fee=0, signature=:sig, version=111, message=:msg, date=:date, public_key=:public_key", "INSERT into transactions SET id=:id, block=:block, height=:height, dst=:dst, val=0, fee=0, signature=:sig, version=111, message=:msg, date=:date, public_key=:public_key",
[":id"=>$id, ":block"=>$hash, ":height"=>$height, ":dst"=>$hash, ":sig"=>$hash, ":msg"=>$msg, ":date"=>time(), ":public_key"=>$public_key] [":id"=>$id, ":block"=>$hash, ":height"=>$height, ":dst"=>$hash, ":sig"=>$hash, ":msg"=>$msg, ":date"=>time(), ":public_key"=>$public_key]
); );
if ($res!=1) {
return 5;
}
return true; return true;
} }
@@ -229,8 +328,8 @@ $this->reset_fails_masternodes($mn_winner, $height, $hash);
$height = $current['height']; $height = $current['height'];
if ($height == 10801) { if ($height == 10801||($height>=80456&&$height<80460)) {
return 5555555555; //hard fork 10900 resistance, force new difficulty return "5555555555"; //hard fork 10900 resistance, force new difficulty
} }
// last 20 blocks used to check the block times // last 20 blocks used to check the block times
@@ -247,7 +346,7 @@ $this->reset_fails_masternodes($mn_winner, $height, $hash);
// before mnn hf // before mnn hf
if ($height<80000) { if ($height<80000) {
// elapsed time between the last 20 blocks // elapsed time between the last 20 blocks
$first = $db->row("SELECT `date` FROM blocks ORDER by height DESC LIMIT $limit,1"); $first = $db->row("SELECT `date` FROM blocks ORDER by height DESC LIMIT :limit,1", [":limit"=>$limit]);
$time = $current['date'] - $first['date']; $time = $current['date'] - $first['date'];
// avg block time // avg block time
@@ -265,6 +364,32 @@ $this->reset_fails_masternodes($mn_winner, $height, $hash);
// keep current difficulty // keep current difficulty
$dif = $current['difficulty']; $dif = $current['difficulty'];
} }
} elseif ($height>=80458) {
$type=$height%2;
$current=$db->row("SELECT difficulty from blocks WHERE height<=:h ORDER by height DESC LIMIT 1,1", [":h"=>$height]);
$blks=0;
$total_time=0;
$blk = $db->run("SELECT `date`, height FROM blocks WHERE height<=:h ORDER by height DESC LIMIT 20", [":h"=>$height]);
for ($i=0;$i<19;$i++) {
$ctype=$blk[$i+1]['height']%2;
$time=$blk[$i]['date']-$blk[$i+1]['date'];
if ($type!=$ctype) {
continue;
}
$blks++;
$total_time+=$time;
}
$result=ceil($total_time/$blks);
_log("Block time: $result", 3);
if ($result > 260) {
$dif = bcmul($current['difficulty'], 1.05);
} elseif ($result < 220) {
// if lower, decrease by 5%
$dif = bcmul($current['difficulty'], 0.95);
} else {
// keep current difficulty
$dif = $current['difficulty'];
}
} else { } else {
// hardfork 80000, fix difficulty targetting // hardfork 80000, fix difficulty targetting
@@ -432,7 +557,7 @@ $this->reset_fails_masternodes($mn_winner, $height, $hash);
// reward transaction and signature // reward transaction and signature
$reward = $this->reward($height, $data); $reward = $this->reward($height, $data);
if($height>=80460){ if ($height>=80458) {
//reward the masternode //reward the masternode
global $db; global $db;
$mn_winner=$db->single( $mn_winner=$db->single(
@@ -447,7 +572,6 @@ if($height>=80460){
$mn_reward=number_format($mn_reward, 8, ".", ""); $mn_reward=number_format($mn_reward, 8, ".", "");
_log("MN Reward: $mn_reward", 2); _log("MN Reward: $mn_reward", 2);
} }
} }
$msg = ''; $msg = '';
@@ -504,14 +628,16 @@ if($height>=80460){
if ($current['height']>=80500) { if ($current['height']>=80500) {
$total_time-=360; $total_time-=360;
$tem=floor($total_time/120)+1; $tem=floor($total_time/120)+1;
if($tem>5) $tem=5; if ($tem>5) {
$tem=5;
}
} else { } else {
$tem=floor($total_time/600); $tem=floor($total_time/600);
} }
_log("We have masternodes to blacklist - $tem", 2); _log("We have masternodes to blacklist - $tem", 2);
$ban=$db->run( $ban=$db->run(
"SELECT public_key, blacklist, fails, last_won FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 0,$tem", "SELECT public_key, blacklist, fails, last_won FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 0,:limit",
[":current"=>$last['height'], ":start"=>$last['height']-360] [":current"=>$last['height'], ":start"=>$last['height']-360, ":limit"=>$tem]
); );
_log(json_encode($ban)); _log(json_encode($ban));
$i=0; $i=0;
@@ -519,7 +645,9 @@ if($height>=80460){
$this->masternode_log($b['public_key'], $current['height'], $current['id']); $this->masternode_log($b['public_key'], $current['height'], $current['id']);
_log("Blacklisting masternode - $i $b[public_key]", 2); _log("Blacklisting masternode - $i $b[public_key]", 2);
$btime=10; $btime=10;
if($current['height']>83000) $btime=360; if ($current['height']>83000) {
$btime=360;
}
$db->run("UPDATE masternode SET fails=fails+1, blacklist=:blacklist WHERE public_key=:public_key", [":public_key"=>$b['public_key'], ":blacklist"=> $current['height']+(($b['fails']+1)*$btime)]); $db->run("UPDATE masternode SET fails=fails+1, blacklist=:blacklist WHERE public_key=:public_key", [":public_key"=>$b['public_key'], ":blacklist"=> $current['height']+(($b['fails']+1)*$btime)]);
$i++; $i++;
} }
@@ -566,8 +694,7 @@ if($height>=80460){
_log("Block below 10800, using 16MB argon", 2); _log("Block below 10800, using 16MB argon", 2);
$argon = '$argon2i$v=19$m=16384,t=4,p=4'.$argon; $argon = '$argon2i$v=19$m=16384,t=4,p=4'.$argon;
} }
} elseif ($current_height>=80458) {
} elseif($current_height>=80460){
if ($current_height%2==0) { if ($current_height%2==0) {
// cpu mining // cpu mining
_log("CPU Mining - $current_height", 2); _log("CPU Mining - $current_height", 2);
@@ -577,7 +704,6 @@ if($height>=80460){
_log("GPU Mining - $current_height", 2); _log("GPU Mining - $current_height", 2);
$argon = '$argon2i$v=19$m=16384,t=4,p=4'.$argon; $argon = '$argon2i$v=19$m=16384,t=4,p=4'.$argon;
} }
} else { } else {
_log("Block > 80000 - $current_height", 2); _log("Block > 80000 - $current_height", 2);
if ($current_height%3==0) { if ($current_height%3==0) {
@@ -629,19 +755,18 @@ if($height>=80460){
$total_time=$time-$last_time; $total_time=$time-$last_time;
$total_time-=360; $total_time-=360;
$tem=floor($total_time/120)+1; $tem=floor($total_time/120)+1;
} else { } else {
$tem=floor(($time-$last_time)/600); $tem=floor(($time-$last_time)/600);
} }
$winner=$db->single( $winner=$db->single(
"SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT $tem,1", "SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT :tem,1",
[":current"=>$current_height, ":start"=>$current_height-360] [":current"=>$current_height, ":start"=>$current_height-360, ":tem"=>$tem]
); );
_log("Moving to the next masternode - $tem - $winner", 1); _log("Moving to the next masternode - $tem - $winner", 1);
// if all masternodes are dead, give the block to gpu // if all masternodes are dead, give the block to gpu
if ($winner===false||($tem>=5&&$current_height>=80500)) { if ($winner===false||($tem>=5&&$current_height>=80500)) {
_log("All masternodes failed, giving the block to gpu", 1); _log("All masternodes failed, giving the block to gpu", 1);
$argon = '$argon2i$v=19$m=16384,t=1,p=1'.$argon; $argon = '$argon2i$v=19$m=16384,t=4,p=4'.$argon;
} elseif ($winner==$public_key) { } elseif ($winner==$public_key) {
return true; return true;
} else { } else {
@@ -706,6 +831,7 @@ if($height>=80460){
global $db; global $db;
// data must be array // data must be array
if ($data === false) { if ($data === false) {
_log("Block data is false", 3);
return false; return false;
} }
$acc = new Account(); $acc = new Account();
@@ -718,6 +844,7 @@ if($height>=80460){
// check if the number of transactions is not bigger than current block size // check if the number of transactions is not bigger than current block size
$max = $this->max_transactions(); $max = $this->max_transactions();
if (count($data) > $max) { if (count($data) > $max) {
_log("Too many transactions in block", 3);
return false; return false;
} }
@@ -732,6 +859,7 @@ if($height>=80460){
if (!$bootstrapping) { if (!$bootstrapping) {
//validate the transaction //validate the transaction
if (!$trx->check($x, $height)) { if (!$trx->check($x, $height)) {
_log("Transaction check failed - $x[id]", 3);
return false; return false;
} }
if ($x['version']>=100&&$x['version']<110) { if ($x['version']>=100&&$x['version']<110) {
@@ -744,6 +872,7 @@ if($height>=80460){
// check if the transaction is already on the blockchain // check if the transaction is already on the blockchain
if ($db->single("SELECT COUNT(1) FROM transactions WHERE id=:id", [":id" => $x['id']]) > 0) { if ($db->single("SELECT COUNT(1) FROM transactions WHERE id=:id", [":id" => $x['id']]) > 0) {
_log("Transaction already on the blockchain - $x[id]", 3);
return false; return false;
} }
} }
@@ -762,6 +891,7 @@ if($height>=80460){
[":id" => $id, ":balance" => $bal] [":id" => $id, ":balance" => $bal]
); );
if ($res == 0) { if ($res == 0) {
_log("Not enough balance for transaction - $id", 3);
return false; // not enough balance for the transactions return false; // not enough balance for the transactions
} }
} }
@@ -839,12 +969,14 @@ if($height>=80460){
foreach ($r as $x) { foreach ($r as $x) {
$res = $trx->reverse($x['id']); $res = $trx->reverse($x['id']);
if ($res === false) { if ($res === false) {
_log("A transaction could not be reversed. Delete block failed.");
$db->rollback(); $db->rollback();
$db->exec("UNLOCK TABLES"); $db->exec("UNLOCK TABLES");
return false; return false;
} }
$res = $db->run("DELETE FROM blocks WHERE id=:id", [":id" => $x['id']]); $res = $db->run("DELETE FROM blocks WHERE id=:id", [":id" => $x['id']]);
if ($res != 1) { if ($res != 1) {
_log("Delete block failed.");
$db->rollback(); $db->rollback();
$db->exec("UNLOCK TABLES"); $db->exec("UNLOCK TABLES");
return false; return false;

View File

@@ -38,6 +38,10 @@ $_config['allowed_hosts'] = [
'127.0.0.1', '127.0.0.1',
]; ];
// Disable transactions and block repropagation
$_config['disable_repropagation'] = false;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Peer Configuration | Peer Configuration
@@ -50,6 +54,41 @@ $_config['transaction_propagation_peers'] = 5;
// How many new peers to check from each peer // How many new peers to check from each peer
$_config['max_test_peers'] = 5; $_config['max_test_peers'] = 5;
// The initial peers to sync from in sanity
$_config['initial_peer_list'] = [
'http://peer1.arionum.com',
'http://peer2.arionum.com',
'http://peer3.arionum.com',
'http://peer4.arionum.com',
'http://peer5.arionum.com',
'http://peer6.arionum.com',
'http://peer7.arionum.com',
'http://peer8.arionum.com',
'http://peer9.arionum.com',
'http://peer10.arionum.com',
'http://peer11.arionum.com',
'http://peer12.arionum.com',
'http://peer13.arionum.com',
'http://peer14.arionum.com',
'http://peer15.arionum.com',
'http://peer16.arionum.com',
'http://peer17.arionum.com',
'http://peer18.arionum.com',
'http://peer19.arionum.com',
'http://peer20.arionum.com',
'http://peer21.arionum.com',
'http://peer22.arionum.com',
'http://peer23.arionum.com',
'http://peer24.arionum.com',
'http://peer25.arionum.com',
'http://peer26.arionum.com',
'http://peer27.arionum.com',
];
// does not peer with any of the peers. Uses the seed peers and syncs only from those peers. Requires a cronjob on sanity.php
$_config['passive_peering'] = false;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Mempool Configuration | Mempool Configuration
@@ -65,6 +104,9 @@ $_config['max_mempool_rebroadcast'] = 5000;
// The number of blocks between rebroadcasting transactions // The number of blocks between rebroadcasting transactions
$_config['sanity_rebroadcast_height'] = 30; $_config['sanity_rebroadcast_height'] = 30;
// Block accepting transfers from addresses blacklisted by the Arionum devs
$_config['use_official_blacklist'] = true;
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Sanity Configuration | Sanity Configuration

View File

@@ -24,6 +24,10 @@ function san_host($a)
function api_err($data) function api_err($data)
{ {
global $_config; global $_config;
if (!headers_sent()) {
header('Content-Type: application/json');
}
echo json_encode(["status" => "error", "data" => $data, "coin" => $_config['coin']]); echo json_encode(["status" => "error", "data" => $data, "coin" => $_config['coin']]);
exit; exit;
} }
@@ -32,6 +36,10 @@ function api_err($data)
function api_echo($data) function api_echo($data)
{ {
global $_config; global $_config;
if (!headers_sent()) {
header('Content-Type: application/json');
}
echo json_encode(["status" => "ok", "data" => $data, "coin" => $_config['coin']]); echo json_encode(["status" => "ok", "data" => $data, "coin" => $_config['coin']]);
exit; exit;
} }
@@ -39,6 +47,10 @@ function api_echo($data)
// log function, shows only in cli atm // log function, shows only in cli atm
function _log($data, $verbosity = 0) function _log($data, $verbosity = 0)
{ {
global $_config;
if ($_config['log_verbosity'] < $verbosity) {
return;
}
$date = date("[Y-m-d H:i:s]"); $date = date("[Y-m-d H:i:s]");
$trace = debug_backtrace(); $trace = debug_backtrace();
$loc = count($trace) - 1; $loc = count($trace) - 1;
@@ -56,7 +68,6 @@ function _log($data, $verbosity = 0)
if (php_sapi_name() === 'cli') { if (php_sapi_name() === 'cli') {
echo $res; echo $res;
} }
global $_config;
if ($_config['enable_logging'] == true && $_config['log_verbosity'] >= $verbosity) { if ($_config['enable_logging'] == true && $_config['log_verbosity'] >= $verbosity) {
@file_put_contents($_config['log_file'], $res, FILE_APPEND); @file_put_contents($_config['log_file'], $res, FILE_APPEND);
} }

View File

@@ -1,6 +1,6 @@
<?php <?php
// ARO version // ARO version
define("VERSION", "0.4.2"); define("VERSION", "0.4.4");
// Amsterdam timezone by default, should probably be moved to config // Amsterdam timezone by default, should probably be moved to config
date_default_timezone_set("UTC"); date_default_timezone_set("UTC");
@@ -13,12 +13,15 @@ if (php_sapi_name() !== 'cli' && substr_count($_SERVER['PHP_SELF'], "/") > 1) {
die("This application should only be run in the main directory /"); die("This application should only be run in the main directory /");
} }
require_once("include/config.inc.php"); require_once __DIR__.'/Exception.php';
require_once("include/db.inc.php"); require_once __DIR__.'/config.inc.php';
require_once("include/functions.inc.php"); require_once __DIR__.'/db.inc.php';
require_once("include/block.inc.php"); require_once __DIR__.'/functions.inc.php';
require_once("include/account.inc.php"); require_once __DIR__.'/Blacklist.php';
require_once("include/transaction.inc.php"); require_once __DIR__.'/InitialPeers.php';
require_once __DIR__.'/block.inc.php';
require_once __DIR__.'/account.inc.php';
require_once __DIR__.'/transaction.inc.php';
if ($_config['db_pass'] == "ENTER-DB-PASS") { if ($_config['db_pass'] == "ENTER-DB-PASS") {
die("Please update your config file and set your db password"); die("Please update your config file and set your db password");
@@ -74,7 +77,7 @@ if (file_exists("tmp/db-update")) {
$res = unlink("tmp/db-update"); $res = unlink("tmp/db-update");
if ($res) { if ($res) {
echo "Updating db schema! Please refresh!\n"; echo "Updating db schema! Please refresh!\n";
require_once("include/schema.inc.php"); require_once __DIR__.'/schema.inc.php';
exit; exit;
} }
echo "Could not access the tmp/db-update file. Please give full permissions to this file\n"; echo "Could not access the tmp/db-update file. Please give full permissions to this file\n";

View File

@@ -164,7 +164,10 @@ if ($dbversion == 8) {
ADD KEY `height` (`height`);"); ADD KEY `height` (`height`);");
$dbversion++; $dbversion++;
} }
if ($dbversion = 9) {
//dev only
$dbversion++;
}
// update the db version to the latest one // update the db version to the latest one

View File

@@ -1,59 +1,83 @@
<?php <?php
use Arionum\Blacklist;
class Transaction class Transaction
{ {
// reverse and remove all transactions from a block // reverse and remove all transactions from a block
public function reverse($block) public function reverse($block)
{ {
global $db; global $db;
$acc = new Account(); $acc = new Account();
$r = $db->run("SELECT * FROM transactions WHERE block=:block ORDER by `version` ASC", [":block" => $block]); $r = $db->run("SELECT * FROM transactions WHERE block=:block ORDER by `version` ASC", [":block" => $block]);
foreach ($r as $x) { foreach ($r as $x) {
_log("Reversing transaction $x[id]", 4);
if (empty($x['src'])) { if (empty($x['src'])) {
$x['src'] = $acc->get_address($x['public_key']); $x['src'] = $acc->get_address($x['public_key']);
} }
if ($x['version'] == 2) { if ($x['version'] == 2) {
// payment sent to alias // payment sent to alias
$db->run( $rez=$db->run(
"UPDATE accounts SET balance=balance-:val WHERE alias=:alias", "UPDATE accounts SET balance=balance-:val WHERE alias=:alias",
[":alias" => $x['dst'], ":val" => $x['val']] [":alias" => $x['dst'], ":val" => $x['val']]
); );
if ($rez!=1) {
_log("Update alias balance minus failed", 3);
return false;
}
} else { } else {
// other type of transactions // other type of transactions
if($x['version']!=100) { $db->run( if ($x['version']!=100&&$x['version']<111) {
$rez=$db->run(
"UPDATE accounts SET balance=balance-:val WHERE id=:id", "UPDATE accounts SET balance=balance-:val WHERE id=:id",
[":id" => $x['dst'], ":val" => $x['val']] [":id" => $x['dst'], ":val" => $x['val']]
); );
if ($rez!=1) {
_log("Update accounts balance minus failed", 3);
return false;
}
} }
} }
// on version 0 / reward transaction, don't credit anyone // on version 0 / reward transaction, don't credit anyone
if ($x['version'] > 0) { if ($x['version'] > 0 && $x['version']<111) {
$db->run( $rez=$db->run(
"UPDATE accounts SET balance=balance+:val WHERE id=:id", "UPDATE accounts SET balance=balance+:val WHERE id=:id",
[":id" => $x['src'], ":val" => $x['val'] + $x['fee']] [":id" => $x['src'], ":val" => $x['val'] + $x['fee']]
); );
if ($rez!=1) {
_log("Update account balance plus failed", 3);
return false;
}
} }
// removing the alias if the alias transaction is reversed // removing the alias if the alias transaction is reversed
if ($x['version']==3) { if ($x['version']==3) {
$db->run( $rez=$db->run(
"UPDATE accounts SET alias=NULL WHERE id=:id", "UPDATE accounts SET alias=NULL WHERE id=:id",
[":id" => $x['src']] [":id" => $x['src']]
); );
if ($rez!=1) {
_log("Clear alias failed", 3);
return false;
}
} }
if ($x['version']>=100&&$x['version']<110&&$x['height']>=80000) { if ($x['version']>=100&&$x['version']<110&&$x['height']>=80000) {
if ($x['version']==100) { if ($x['version']==100) {
$db->run("DELETE FROM masternode WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); $rez=$db->run("DELETE FROM masternode WHERE public_key=:public_key", [':public_key'=>$x['public_key']]);
if ($rez!=1) {
_log("Delete from masternode failed", 3);
return false;
}
} elseif ($x['version']==101) { } elseif ($x['version']==101) {
$db->run( $rez=$db->run(
"UPDATE masternode SET status=1 WHERE public_key=:public_key", "UPDATE masternode SET status=1 WHERE public_key=:public_key",
[':public_key'=>$x['public_key']] [':public_key'=>$x['public_key']]
); );
} elseif ($x['version']==102) { } elseif ($x['version']==102) {
$db->run("UPDATE masternode SET status=0 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); $rez=$db->run("UPDATE masternode SET status=0 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]);
} elseif ($x['version']==103) { } elseif ($x['version']==103) {
$mnt=$db->row("SELECT height, `message` FROM transactions WHERE version=100 AND public_key=:public_key ORDER by height DESC LIMIT 1", [":public_key"=>$x['public_key']]); $mnt=$db->row("SELECT height, `message` FROM transactions WHERE version=100 AND public_key=:public_key ORDER by height DESC LIMIT 1", [":public_key"=>$x['public_key']]);
$vers=$db->single( $vers=$db->single(
@@ -67,21 +91,34 @@ class Transaction
$status=0; $status=0;
} }
$db->run( $rez=$db->run(
"INSERT into masternode SET `public_key`=:public_key, `height`=:height, `ip`=:ip, `status`=:status", "INSERT into masternode SET `public_key`=:public_key, `height`=:height, `ip`=:ip, `status`=:status",
[":public_key"=>$x['public_key'], ":height"=>$mnt['height'], ":ip"=>$mnt['message'], ":status"=>$status] [":public_key"=>$x['public_key'], ":height"=>$mnt['height'], ":ip"=>$mnt['message'], ":status"=>$status]
); );
$db->run("UPDATE accounts SET balance=balance-100000 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]); if ($rez!=1) {
_log("Insert into masternode failed", 3);
return false;
}
$rez=$db->run("UPDATE accounts SET balance=balance-100000 WHERE public_key=:public_key", [':public_key'=>$x['public_key']]);
if ($rez!=1) {
_log("Update masternode balance failed", 3);
return false;
}
} }
} }
// internal masternode history // internal masternode history
if ($x['version']==111) { if ($x['version']==111) {
_log("Masternode reverse: $x[message]", 4);
$m=explode(",", $x['message']); $m=explode(",", $x['message']);
$db->run( $rez=$db->run(
"UPDATE masternode SET fails=:fails, blacklist=:blacklist, last_won=:last_won WHERE public_key=:public_key", "UPDATE masternode SET fails=:fails, blacklist=:blacklist, last_won=:last_won WHERE public_key=:public_key",
[":public_key"=>$x['public_key'], ":blacklist"=> $m[0], ":fails"=>$m[2], ":last_won"=>$m[1]] [":public_key"=>$x['public_key'], ":blacklist"=> $m[0], ":fails"=>$m[2], ":last_won"=>$m[1]]
); );
if ($rez!=1) {
_log("Update masternode log failed", 3);
return false;
}
} }
// add the transactions to mempool // add the transactions to mempool
@@ -90,6 +127,7 @@ class Transaction
} }
$res = $db->run("DELETE FROM transactions WHERE id=:id", [":id" => $x['id']]); $res = $db->run("DELETE FROM transactions WHERE id=:id", [":id" => $x['id']]);
if ($res != 1) { if ($res != 1) {
_log("Delete transaction failed", 3);
return false; return false;
} }
} }
@@ -182,10 +220,17 @@ class Transaction
public function add_mempool($x, $peer = "") public function add_mempool($x, $peer = "")
{ {
global $db; global $db;
global $_config;
$block = new Block(); $block = new Block();
if ($x['version']>110) { if ($x['version']>110) {
return true; return true;
} }
if ($_config['use_official_blacklist']!==false) {
if (Blacklist::checkPublicKey($x['public_key']) || Blacklist::checkAddress($x['src'])) {
return true;
}
}
$current = $block->current(); $current = $block->current();
$height = $current['height']; $height = $current['height'];
$x['id'] = san($x['id']); $x['id'] = san($x['id']);
@@ -378,6 +423,11 @@ class Transaction
_log("The Masternode IP is invalid", 3); _log("The Masternode IP is invalid", 3);
return false; return false;
} }
global $db;
$existing=$db->single("SELECT COUNT(1) FROM masternode WHERE public_key=:id or ip=:ip", ["id"=>$x['public_key'], ":ip"=>$message]);
if ($existing!=0) {
return false;
}
} }

View File

@@ -23,7 +23,7 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE. OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
require_once("include/init.inc.php"); require_once __DIR__.'/include/init.inc.php';
$block = new Block(); $block = new Block();
$acc = new Account(); $acc = new Account();
set_time_limit(360); set_time_limit(360);
@@ -56,10 +56,17 @@ if ($q == "info") {
$argon_threads=1; $argon_threads=1;
$argon_time=1; $argon_time=1;
} }
} elseif($current_height>=80460&&$current_height%2==0){ } elseif($current_height>=80458){
if($current_height%2==0){
$argon_mem=524288; $argon_mem=524288;
$argon_threads=1; $argon_threads=1;
$argon_time=1; $argon_time=1;
} else {
$argon_mem=16384;
$argon_threads=4;
$argon_time=4;
}
} else { } else {
@@ -73,7 +80,7 @@ if ($q == "info") {
"SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 1", "SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 1",
[":current"=>$current_height, ":start"=>$current_height-360] [":current"=>$current_height, ":start"=>$current_height-360]
); );
$recommendation="pause"; //$recommendation="pause";
if ($winner===false) { if ($winner===false) {
$recommendation="mine"; $recommendation="mine";
} }
@@ -111,6 +118,7 @@ if ($q == "info") {
if ($res) { if ($res) {
//if the new block is generated, propagate it to all peers in background //if the new block is generated, propagate it to all peers in background
$current = $block->current(); $current = $block->current();
$current['id']=escapeshellarg(san($current['id']));
system("php propagate.php block $current[id] > /dev/null 2>&1 &"); system("php propagate.php block $current[id] > /dev/null 2>&1 &");
api_echo("accepted"); api_echo("accepted");
} }
@@ -186,6 +194,7 @@ if ($q == "info") {
if ($res) { if ($res) {
//if the new block is generated, propagate it to all peers in background //if the new block is generated, propagate it to all peers in background
$current = $block->current(); $current = $block->current();
$current['id']=escapeshellarg(san($current['id']));
system("php propagate.php block $current[id] > /dev/null 2>&1 &"); system("php propagate.php block $current[id] > /dev/null 2>&1 &");
api_echo("accepted"); api_echo("accepted");
} else { } else {

View File

@@ -23,7 +23,9 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE. OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
require_once("include/init.inc.php"); require_once __DIR__.'/include/init.inc.php';
header('Content-Type: application/json');
$trx = new Transaction(); $trx = new Transaction();
$block = new Block(); $block = new Block();
$q = $_GET['q']; $q = $_GET['q'];
@@ -150,6 +152,7 @@ if ($q == "peer") {
// rebroadcast the transaction to some peers unless the transaction is smaller than the average size of transactions in mempool - protect against garbage data flooding // rebroadcast the transaction to some peers unless the transaction is smaller than the average size of transactions in mempool - protect against garbage data flooding
$res = $db->row("SELECT COUNT(1) as c, sum(val) as v FROM mempool ", [":src" => $data['src']]); $res = $db->row("SELECT COUNT(1) as c, sum(val) as v FROM mempool ", [":src" => $data['src']]);
if ($res['c'] < $_config['max_mempool_rebroadcast'] && $res['v'] / $res['c'] < $data['val']) { if ($res['c'] < $_config['max_mempool_rebroadcast'] && $res['v'] / $res['c'] < $data['val']) {
$data['id']=escapeshellarg(san($data['id']));
system("php propagate.php transaction '$data[id]' > /dev/null 2>&1 &"); system("php propagate.php transaction '$data[id]' > /dev/null 2>&1 &");
} }
api_echo("transaction-ok"); api_echo("transaction-ok");
@@ -185,6 +188,7 @@ if ($q == "peer") {
if ($accept_new) { if ($accept_new) {
// if the new block is accepted, run a microsanity to sync it // if the new block is accepted, run a microsanity to sync it
_log('['.$ip."] Starting microsanity - $data[height]"); _log('['.$ip."] Starting microsanity - $data[height]");
$ip=escapeshellarg($ip);
system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &"); system("php sanity.php microsanity '$ip' > /dev/null 2>&1 &");
api_echo("microsanity"); api_echo("microsanity");
} else { } else {
@@ -200,7 +204,7 @@ if ($q == "peer") {
if (!$pr) { if (!$pr) {
api_err("block-too-old"); api_err("block-too-old");
} }
$peer_host = base58_encode($pr['hostname']); $peer_host = escapeshellcmd(base58_encode($pr['hostname']));
$pr['ip'] = escapeshellcmd(san_ip($pr['ip'])); $pr['ip'] = escapeshellcmd(san_ip($pr['ip']));
system("php propagate.php block current '$peer_host' '$pr[ip]' > /dev/null 2>&1 &"); system("php propagate.php block current '$peer_host' '$pr[ip]' > /dev/null 2>&1 &");
_log('['.$ip."] block too old, sending our current block - $data[height]"); _log('['.$ip."] block too old, sending our current block - $data[height]");
@@ -243,6 +247,7 @@ if ($q == "peer") {
_log('['.$ip."] block ok, repropagating - $data[height]"); _log('['.$ip."] block ok, repropagating - $data[height]");
// send it to all our peers // send it to all our peers
$data['id']=escapeshellcmd(san($data['id']));
system("php propagate.php block '$data[id]' all all linear > /dev/null 2>&1 &"); system("php propagate.php block '$data[id]' all all linear > /dev/null 2>&1 &");
api_echo("block-ok"); api_echo("block-ok");
} // return the current block, used in syncing } // return the current block, used in syncing

View File

@@ -24,7 +24,7 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE. OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
set_time_limit(360); set_time_limit(360);
require_once("include/init.inc.php"); require_once __DIR__.'/include/init.inc.php';
$block = new Block(); $block = new Block();
$type = san($argv[1]); $type = san($argv[1]);
@@ -69,9 +69,13 @@ if ((empty($peer) || $peer == 'all') && $type == "block") {
foreach ($r as $x) { foreach ($r as $x) {
if($x['hostname']==$_config['hostname']) continue; if($x['hostname']==$_config['hostname']) continue;
// encode the hostname in base58 and sanitize the IP to avoid any second order shell injections // encode the hostname in base58 and sanitize the IP to avoid any second order shell injections
$host = base58_encode($x['hostname']); $host = escapeshellcmd(base58_encode($x['hostname']));
$ip = filter_var($x['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE); $ip = escapeshellcmd(filter_var($x['ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE));
// fork a new process to send the blocks async // fork a new process to send the blocks async
$type=escapeshellcmd(san($type));
$id=escapeshellcmd(san($id));
if ($debug) { if ($debug) {
system("php propagate.php '$type' '$id' '$host' '$ip' debug"); system("php propagate.php '$type' '$id' '$host' '$ip' debug");
} elseif ($linear) { } elseif ($linear) {
@@ -166,7 +170,8 @@ if ($type == "transaction") {
if ($data['peer'] == "local") { if ($data['peer'] == "local") {
$r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP()"); $r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP()");
} else { } else {
$r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 ORDER by RAND() LIMIT ".intval($_config['transaction_propagation_peers']));
$r = $db->run("SELECT hostname FROM peers WHERE blacklisted < UNIX_TIMESTAMP() AND reserve=0 ORDER by RAND() LIMIT :limit",["limit"=>intval($_config['transaction_propagation_peers'])]);
} }
foreach ($r as $x) { foreach ($r as $x) {
$res = peer_post($x['hostname']."/peer.php?q=submitTransaction", $data); $res = peer_post($x['hostname']."/peer.php?q=submitTransaction", $data);

View File

@@ -23,6 +23,9 @@ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE. OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
const SANITY_LOCK_PATH = __DIR__.'/tmp/sanity-lock';
set_time_limit(0); set_time_limit(0);
error_reporting(0); error_reporting(0);
@@ -31,8 +34,10 @@ if (php_sapi_name() !== 'cli') {
die("This should only be run as cli"); die("This should only be run as cli");
} }
require_once __DIR__.'/include/init.inc.php';
// make sure there's only a single sanity process running at the same time // make sure there's only a single sanity process running at the same time
if (file_exists("tmp/sanity-lock")) { if (file_exists(SANITY_LOCK_PATH)) {
$ignore_lock = false; $ignore_lock = false;
if ($argv[1] == "force") { if ($argv[1] == "force") {
$res = intval(shell_exec("ps aux|grep sanity.php|grep -v grep|wc -l")); $res = intval(shell_exec("ps aux|grep sanity.php|grep -v grep|wc -l"));
@@ -40,17 +45,20 @@ if (file_exists("tmp/sanity-lock")) {
$ignore_lock = true; $ignore_lock = true;
} }
} }
$pid_time = filemtime("tmp/sanity-lock"); $pid_time = filemtime(SANITY_LOCK_PATH);
// if the process died, restart after 1day
if (time() - $pid_time > 86400) { // If the process died, restart after 10 times the sanity interval
@unlink("tmp/sanity-lock"); if (time() - $pid_time > ($_config['sanity_interval'] ?? 900 * 10)) {
@unlink(SANITY_LOCK_PATH);
} }
if (!$ignore_lock) { if (!$ignore_lock) {
die("Sanity lock in place"); die("Sanity lock in place".PHP_EOL);
} }
} }
// set the new sanity lock // set the new sanity lock
$lock = fopen("tmp/sanity-lock", "w"); $lock = fopen(SANITY_LOCK_PATH, "w");
fclose($lock); fclose($lock);
$arg = trim($argv[1]); $arg = trim($argv[1]);
$arg2 = trim($argv[2]); $arg2 = trim($argv[2]);
@@ -60,13 +68,15 @@ if ($arg != "microsanity") {
sleep(3); sleep(3);
} }
if ($argv[1]=="dev") {
require_once("include/init.inc.php"); error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT & ~E_NOTICE);
ini_set("display_errors", "on");
}
// the sanity can't run without the schema being installed // the sanity can't run without the schema being installed
if ($_config['dbversion'] < 2) { if ($_config['dbversion'] < 2) {
die("DB schema not created"); die("DB schema not created");
@unlink("tmp/sanity-lock"); @unlink(SANITY_LOCK_PATH);
exit; exit;
} }
@@ -76,6 +86,11 @@ $block = new Block();
$acc = new Account(); $acc = new Account();
$current = $block->current(); $current = $block->current();
// bootstrapping the initial sync // bootstrapping the initial sync
if ($current['height']==1) { if ($current['height']==1) {
echo "Bootstrapping!\n"; echo "Bootstrapping!\n";
@@ -224,7 +239,7 @@ if ($arg == "microsanity" && !empty($arg2)) {
_log("Synced block from $host - $b[height] $b[difficulty]"); _log("Synced block from $host - $b[height] $b[difficulty]");
} while (0); } while (0);
@unlink("tmp/sanity-lock"); @unlink(SANITY_LOCK_PATH);
exit; exit;
} }
@@ -248,8 +263,8 @@ $total_active_peers = 0;
// checking peers // checking peers
// delete the dead peers // delete the dead peers
$db->run("DELETE from peers WHERE fails>100 OR stuckfail>200"); $db->run("DELETE from peers WHERE fails>100 OR stuckfail>100");
$r = $db->run("SELECT id,hostname,stuckfail,fails FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP()"); $r = $db->run("SELECT id,hostname,stuckfail,fails FROM peers WHERE reserve=0 AND blacklisted<UNIX_TIMESTAMP() LIMIT 50");
$total_peers = count($r); $total_peers = count($r);
@@ -257,16 +272,20 @@ $peered = [];
// if we have no peers, get the seed list from the official site // if we have no peers, get the seed list from the official site
if ($total_peers == 0 && $_config['testnet'] == false) { if ($total_peers == 0 && $_config['testnet'] == false) {
$i = 0; $i = 0;
echo "No peers found. Attempting to get peers from arionum.com\n"; echo 'No peers found. Attempting to get peers from the initial list.'.PHP_EOL;
$f = file("https://www.arionum.com/peers.txt");
shuffle($f); $initialPeers = new \Arionum\Node\InitialPeers($_config['initial_peer_list'] ?? []);
// we can't connect to arionum.com
if (count($f) < 2) { try {
@unlink("tmp/sanity-lock"); $peers = $initialPeers->getAll();
die("Could not connect to arionum.com! Will try later!\n"); } catch (\Arionum\Node\Exception $e) {
@unlink(SANITY_LOCK_PATH);
die($e->getMessage().PHP_EOL);
} }
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. foreach ($peers 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(san_host($peer)); $peer = trim(san_host($peer));
$bad_peers = ["127.", "localhost", "10.", "192.168.","172.16.","172.17.","172.18.","172.19.","172.20.","172.21.","172.22.","172.23.","172.24.","172.25.","172.26.","172.27.","172.28.","172.29.","172.30.","172.31."]; $bad_peers = ["127.", "localhost", "10.", "192.168.","172.16.","172.17.","172.18.","172.19.","172.20.","172.21.","172.22.","172.23.","172.24.","172.25.","172.26.","172.27.","172.28.","172.29.","172.30.","172.31."];
@@ -288,7 +307,15 @@ if ($total_peers == 0 && $_config['testnet'] == false) {
continue; continue;
} }
$peered[$pid] = 1; $peered[$pid] = 1;
if($_config['passive_peering'] == true){
// does not peer, just add it to DB in passive mode
$db->run("INSERT into peers set hostname=:hostname, ping=0, reserve=0,ip=:ip",[":hostname"=>$peer, ":ip"=>md5($peer)]);
$res=true;
} else {
// forces the other node to peer with us.
$res = peer_post($peer."/peer.php?q=peer", ["hostname" => $_config['hostname'], "repeer" => 1]); $res = peer_post($peer."/peer.php?q=peer", ["hostname" => $_config['hostname'], "repeer" => 1]);
}
if ($res !== false) { if ($res !== false) {
$i++; $i++;
echo "Peering OK - $peer\n"; echo "Peering OK - $peer\n";
@@ -304,17 +331,18 @@ if ($total_peers == 0 && $_config['testnet'] == false) {
$total_peers = count($r); $total_peers = count($r);
if ($total_peers == 0) { if ($total_peers == 0) {
// something went wrong, could not add any peers -> exit // something went wrong, could not add any peers -> exit
@unlink("tmp/sanity-lock"); @unlink(SANITY_LOCK_PATH);
die("Could not peer to any peers! Please check internet connectivity!\n"); die("Could not peer to any peers! Please check internet connectivity!\n");
} }
} }
// contact all the active peers // contact all the active peers
$i = 0;
foreach ($r as $x) { foreach ($r as $x) {
_log("Contacting peer $x[hostname]"); _log("Contacting peer $x[hostname]");
$url = $x['hostname']."/peer.php?q="; $url = $x['hostname']."/peer.php?q=";
// get their peers list // get their peers list
if($_config['get_more_peers']==true){ if ($_config['get_more_peers']==true && $_config['passive_peering']!=true) {
$data = peer_post($url."getPeers", [], 5); $data = peer_post($url."getPeers", [], 5);
if ($data === false) { if ($data === false) {
_log("Peer $x[hostname] unresponsive"); _log("Peer $x[hostname] unresponsive");
@@ -325,7 +353,6 @@ if($_config['get_more_peers']==true){
); );
continue; continue;
} }
$i = 0;
foreach ($data as $peer) { foreach ($data as $peer) {
// store the hostname as md5 hash, for easier checking // store the hostname as md5 hash, for easier checking
$peer['hostname'] = san_host($peer['hostname']); $peer['hostname'] = san_host($peer['hostname']);
@@ -441,7 +468,7 @@ echo "Most common: $most_common\n";
echo "Most common block: $most_common_size\n"; echo "Most common block: $most_common_size\n";
echo "Max height: $largest_height\n"; echo "Max height: $largest_height\n";
echo "Current block: $current[height]\n"; echo "Current block: $current[height]\n";
$block_parse_failed=false;
// if we're not on the largest height // if we're not on the largest height
if ($current['height'] < $largest_height && $largest_height > 1) { if ($current['height'] < $largest_height && $largest_height > 1) {
// start sanity sync / block all other transactions/blocks // start sanity sync / block all other transactions/blocks
@@ -475,17 +502,17 @@ if ($current['height'] < $largest_height && $largest_height > 1) {
break; break;
} }
} elseif ($data['id'] != $current['id'] && $data['id'] != $most_common) { } elseif ($data['id'] != $current['id'] && $data['id'] != $most_common) {
//if we're not on the same blockchain and also it's not the most common, verify all the blocks on on this blockchain starting at current-10 until current //if we're not on the same blockchain and also it's not the most common, verify all the blocks on on this blockchain starting at current-30 until current
$invalid = false; $invalid = false;
$last_good = $current['height']; $last_good = $current['height'];
for ($i = $current['height'] - 10; $i < $current['height']; $i++) { for ($i = $current['height'] - 30; $i < $current['height']; $i++) {
$data = peer_post($url."getBlock", ["height" => $i]); $data = peer_post($url."getBlock", ["height" => $i]);
if ($data === false) { if ($data === false) {
$invalid = true; $invalid = true;
break; break;
} }
$ext = $block->get($i); $ext = $block->get($i);
if ($i == $current['height'] - 10 && $ext['id'] != $data['id']) { if ($i == $current['height'] - 30 && $ext['id'] != $data['id']) {
$invalid = true; $invalid = true;
break; break;
} }
@@ -494,7 +521,7 @@ if ($current['height'] < $largest_height && $largest_height > 1) {
$last_good = $i; $last_good = $i;
} }
} }
if ($last_good==$current['height']-1&&$last_good%3==2) { if ($last_good==$current['height']-1) {
$block->pop(1); $block->pop(1);
} }
// if last 10 blocks are good, verify all the blocks // if last 10 blocks are good, verify all the blocks
@@ -510,7 +537,7 @@ if ($current['height'] < $largest_height && $largest_height > 1) {
} }
// check if the block mining data is correct // check if the block mining data is correct
for ($i = $last_good + 1; $i <= $largest_height; $i++) { for ($i = $last_good + 1; $i <= $largest_height; $i++) {
if (($i-1)%3==2) { if (($i-1)%3==2&&$cblock[$i - 1]['height']<80458) {
continue; continue;
} }
if (!$block->mine( if (!$block->mine(
@@ -553,6 +580,7 @@ if ($current['height'] < $largest_height && $largest_height > 1) {
$b['height'] = san($b['height']); $b['height'] = san($b['height']);
if (!$block->check($b)) { if (!$block->check($b)) {
$block_parse_failed=true;
_log("Block check: could not add block - $b[id] - $b[height]"); _log("Block check: could not add block - $b[id] - $b[height]");
$good_peer = false; $good_peer = false;
break; break;
@@ -569,6 +597,7 @@ if ($current['height'] < $largest_height && $largest_height > 1) {
$b['argon'] $b['argon']
); );
if (!$res) { if (!$res) {
$block_parse_failed=true;
_log("Block add: could not add block - $b[id] - $b[height]"); _log("Block add: could not add block - $b[id] - $b[height]");
$good_peer = false; $good_peer = false;
break; break;
@@ -585,6 +614,70 @@ if ($current['height'] < $largest_height && $largest_height > 1) {
break; break;
} }
} }
$resyncing=false;
if ($block_parse_failed==true&&$current['date']<time()-(3600*24)) {
_log("Rechecking reward transactions");
$current = $block->current();
$rwpb=$db->single("SELECT COUNT(1) FROM transactions WHERE version=0 AND message=''");
if ($rwpb!=$current['height']) {
$failed=$db->single("SELECT blocks.height FROM blocks LEFT JOIN transactions ON transactions.block=blocks.id and transactions.version=0 and transactions.message='' WHERE transactions.height is NULL ORDER by blocks.height ASC LIMIT 1");
if ($failed>1) {
_log("Found failed block - $faield");
$block->delete($failed);
$block_parse_failed==false;
}
}
}
if ($block_parse_failed==true||$argv[1]=="resync") {
$last_resync=$db->single("SELECT val FROM config WHERE cfg='last_resync'");
if ($last_resync<time()-(3600*24)||$argv[1]=="resync") {
if ($current['date']<time()-(3600*72)||$argv[1]=="resync") {
$to_remove=3000;
if (intval($argv[2])>0) {
$to_remove=intval($argv[2]);
}
_log("Removing $to_remove blocks, the blockchain is stale.");
$block->pop(to_remove);
$resyncing=true;
} elseif ($current['date']<time()-(3600*24)) {
_log("Removing 200 blocks, the blockchain is stale.");
$block->pop(200);
$resyncing=true;
}
if ($resyncing==true) {
_log("Resyncing accounts");
$db->run("INSERT into config SET val=UNIX_TIMESTAMP(), cfg='last_resync' ON DUPLICATE KEY UPDATE val=UNIX_TIMESTAMP()");
$db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE");
$r=$db->run("SELECT * FROM accounts");
foreach ($r as $x) {
$alias=$x['alias'];
if (empty($alias)) {
$alias="A";
}
$rec=$db->single("SELECT SUM(val) FROM transactions WHERE (dst=:id or dst=:alias) AND (height<80000 OR (version!=100 AND version!=103)) and version<111", [":id"=>$x['id'], ":alias"=>$alias]);
$spent=$db->single("SELECT SUM(val+fee) FROM transactions WHERE public_key=:pub AND version>0", [":pub"=>$x['public_key']]);
if ($spent==false) {
$spent=0;
}
$balance=round(($rec-$spent), 8);
if ($x['balance']!=$balance) {
// echo "rec: $rec, spent: $spent, bal: $x[balance], should be: $balance - $x[id] $x[public_key]\n";
if (trim($argv[2])!="check") {
$db->run("UPDATE accounts SET balance=:bal WHERE id=:id", [":id"=>$x['id'], ":bal"=>$balance]);
}
}
}
$current = $block->current();
$db->run("DELETE FROM masternode WHERE height>:h", [":h"=>$current['height']]);
$db->exec("UNLOCK TABLES");
}
}
}
$db->run("UPDATE config SET val=0 WHERE cfg='sanity_sync'", [":time" => $t]); $db->run("UPDATE config SET val=0 WHERE cfg='sanity_sync'", [":time" => $t]);
} }
@@ -594,14 +687,14 @@ $db->run("DELETE FROM `mempool` WHERE `date` < UNIX_TIMESTAMP()-(3600*24*14)");
//rebroadcasting local transactions //rebroadcasting local transactions
if ($_config['sanity_rebroadcast_locals'] == true) { if ($_config['sanity_rebroadcast_locals'] == true && $_config['disable_repropagation'] == false) {
$r = $db->run( $r = $db->run(
"SELECT id FROM mempool WHERE height>=:current and peer='local' order by `height` asc LIMIT 20", "SELECT id FROM mempool WHERE height>=:current and peer='local' order by `height` asc LIMIT 20",
[":current" => $current['height']] [":current" => $current['height']]
); );
_log("Rebroadcasting local transactions - ".count($r)); _log("Rebroadcasting local transactions - ".count($r));
foreach ($r as $x) { foreach ($r as $x) {
$x['id'] = san($x['id']); $x['id'] = escapeshellarg(san($x['id'])); // i know it's redundant due to san(), but some people are too scared of any exec
system("php propagate.php transaction $x[id] > /dev/null 2>&1 &"); system("php propagate.php transaction $x[id] > /dev/null 2>&1 &");
$db->run( $db->run(
"UPDATE mempool SET height=:current WHERE id=:id", "UPDATE mempool SET height=:current WHERE id=:id",
@@ -611,6 +704,7 @@ if ($_config['sanity_rebroadcast_locals'] == true) {
} }
//rebroadcasting transactions //rebroadcasting transactions
if ($_config['disable_repropagation'] == false) {
$forgotten = $current['height'] - $_config['sanity_rebroadcast_height']; $forgotten = $current['height'] - $_config['sanity_rebroadcast_height'];
$r = $db->run( $r = $db->run(
"SELECT id FROM mempool WHERE height<:forgotten ORDER by val DESC LIMIT 10", "SELECT id FROM mempool WHERE height<:forgotten ORDER by val DESC LIMIT 10",
@@ -620,11 +714,11 @@ $r = $db->run(
_log("Rebroadcasting external transactions - ".count($r)); _log("Rebroadcasting external transactions - ".count($r));
foreach ($r as $x) { foreach ($r as $x) {
$x['id'] = san($x['id']); $x['id'] = escapeshellarg(san($x['id'])); // i know it's redundant due to san(), but some people are too scared of any exec
system("php propagate.php transaction $x[id] > /dev/null 2>&1 &"); system("php propagate.php transaction $x[id] > /dev/null 2>&1 &");
$db->run("UPDATE mempool SET height=:current WHERE id=:id", [":id" => $x['id'], ":current" => $current['height']]); $db->run("UPDATE mempool SET height=:current WHERE id=:id", [":id" => $x['id'], ":current" => $current['height']]);
} }
}
//add new peers if there aren't enough active //add new peers if there aren't enough active
if ($total_peers < $_config['max_peers'] * 0.7) { if ($total_peers < $_config['max_peers'] * 0.7) {
@@ -633,7 +727,7 @@ if ($total_peers < $_config['max_peers'] * 0.7) {
} }
//random peer check //random peer check
$r = $db->run("SELECT * FROM peers WHERE blacklisted<UNIX_TIMESTAMP() and reserve=1 LIMIT ".$_config['max_test_peers']); $r = $db->run("SELECT * FROM peers WHERE blacklisted<UNIX_TIMESTAMP() and reserve=1 LIMIT :limit", [":limit"=>intval($_config['max_test_peers'])]);
foreach ($r as $x) { foreach ($r as $x) {
$url = $x['hostname']."/peer.php?q="; $url = $x['hostname']."/peer.php?q=";
$data = peer_post($url."ping", [], 5); $data = peer_post($url."ping", [], 5);
@@ -665,7 +759,7 @@ foreach ($f as $x) {
//recheck the last blocks //recheck the last blocks
if ($_config['sanity_recheck_blocks'] > 0 && $_config['testnet'] == false&&1==2) { if ($_config['sanity_recheck_blocks'] > 0 && $_config['testnet'] == false) {
_log("Rechecking blocks"); _log("Rechecking blocks");
$blocks = []; $blocks = [];
$all_blocks_ok = true; $all_blocks_ok = true;
@@ -710,4 +804,4 @@ if ($_config['sanity_recheck_blocks'] > 0 && $_config['testnet'] == false&&1==2)
_log("Finishing sanity"); _log("Finishing sanity");
@unlink("tmp/sanity-lock"); @unlink(SANITY_LOCK_PATH);

3
tmp/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*
!.gitignore
!db-update

View File

@@ -1 +1 @@
4.0.1 4.0.2

135
util.php
View File

@@ -29,7 +29,7 @@ if (php_sapi_name() !== 'cli') {
die("This should only be run as cli"); die("This should only be run as cli");
} }
require_once("include/init.inc.php"); require_once __DIR__.'/include/init.inc.php';
$cmd = trim($argv[1]); $cmd = trim($argv[1]);
/** /**
@@ -43,6 +43,10 @@ $cmd = trim($argv[1]);
*/ */
if ($cmd == 'clean') { if ($cmd == 'clean') {
if (file_exists("tmp/sanity-lock")) {
die("Sanity running. Wait for it to finish");
}
touch("tmp/sanity-lock");
$db->run("SET foreign_key_checks=0;"); $db->run("SET foreign_key_checks=0;");
$tables = ["accounts", "transactions", "mempool", "masternode","blocks"]; $tables = ["accounts", "transactions", "mempool", "masternode","blocks"];
foreach ($tables as $table) { foreach ($tables as $table) {
@@ -51,6 +55,7 @@ if ($cmd == 'clean') {
$db->run("SET foreign_key_checks=1;"); $db->run("SET foreign_key_checks=1;");
echo "\n The database has been cleared\n"; echo "\n The database has been cleared\n";
unlink("tmp/sanity-lock");
} /** } /**
* @api {php util.php} pop Pop * @api {php util.php} pop Pop
* @apiName pop * @apiName pop
@@ -64,9 +69,14 @@ if ($cmd == 'clean') {
*/ */
elseif ($cmd == 'pop') { elseif ($cmd == 'pop') {
if (file_exists("tmp/sanity-lock")) {
die("Sanity running. Wait for it to finish");
}
touch("tmp/sanity-lock");
$no = intval($argv[2]); $no = intval($argv[2]);
$block = new Block(); $block = new Block();
$block->pop($no); $block->pop($no);
unlink("tmp/sanity-lock");
} /** } /**
* @api {php util.php} block-time Block-time * @api {php util.php} block-time Block-time
* @apiName block-time * @apiName block-time
@@ -93,7 +103,7 @@ elseif ($cmd == 'block-time') {
} }
$time = $t - $x['date']; $time = $t - $x['date'];
$t = $x['date']; $t = $x['date'];
echo "$x[height] -> $time\n"; echo "$x[height]\t\t$time\t\t$x[difficulty]\n";
$end = $x['date']; $end = $x['date'];
} }
echo "Average block time: ".ceil(($start - $end) / 100)." seconds\n"; echo "Average block time: ".ceil(($start - $end) / 100)." seconds\n";
@@ -183,7 +193,7 @@ elseif ($cmd == "blocks") {
if ($limit < 1) { if ($limit < 1) {
$limit = 100; $limit = 100;
} }
$r = $db->run("SELECT * FROM blocks WHERE height>:height ORDER by height ASC LIMIT $limit", [":height" => $height]); $r = $db->run("SELECT * FROM blocks WHERE height>:height ORDER by height ASC LIMIT :limit", [":height" => $height, ":limit"=>$limit]);
foreach ($r as $x) { foreach ($r as $x) {
echo "$x[height]\t$x[id]\n"; echo "$x[height]\t$x[id]\n";
} }
@@ -443,31 +453,142 @@ elseif ($cmd == 'get-address') {
* php util.php clean-blacklist * php util.php clean-blacklist
* *
*/ */
} elseif ($cmd == 'clean-blacklist') { } elseif ($cmd == 'clean-blacklist') {
$db->run("UPDATE peers SET blacklisted=0, fails=0, stuckfail=0"); $db->run("UPDATE peers SET blacklisted=0, fails=0, stuckfail=0");
echo "All the peers have been removed from the blacklist\n"; echo "All the peers have been removed from the blacklist\n";
} elseif ($cmd == 'resync-accounts') { } elseif ($cmd == 'resync-accounts') {
// resyncs the balance on all accounts // resyncs the balance on all accounts
if (file_exists("tmp/sanity-lock")) {
die("Sanity running. Wait for it to finish");
}
touch("tmp/sanity-lock");
// lock table to avoid race conditions on blocks // lock table to avoid race conditions on blocks
$db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE"); $db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE");
$r=$db->run("SELECT * FROM accounts"); $r=$db->run("SELECT * FROM accounts");
foreach ($r as $x) { foreach ($r as $x) {
$alias=$x['alias']; $alias=$x['alias'];
if(empty($alias)) $alias="A"; if (empty($alias)) {
$alias="A";
}
$rec=$db->single("SELECT SUM(val) FROM transactions WHERE (dst=:id or dst=:alias) AND (height<80000 OR (version!=100 AND version!=103)) and version<111", [":id"=>$x['id'], ":alias"=>$alias]); $rec=$db->single("SELECT SUM(val) FROM transactions WHERE (dst=:id or dst=:alias) AND (height<80000 OR (version!=100 AND version!=103)) and version<111", [":id"=>$x['id'], ":alias"=>$alias]);
$spent=$db->single("SELECT SUM(val+fee) FROM transactions WHERE public_key=:pub AND version>0", [":pub"=>$x['public_key']]); $spent=$db->single("SELECT SUM(val+fee) FROM transactions WHERE public_key=:pub AND version>0", [":pub"=>$x['public_key']]);
if($spent==false) $spent=0; if ($spent==false) {
$spent=0;
}
$balance=round(($rec-$spent), 8); $balance=round(($rec-$spent), 8);
if ($x['balance']!=$balance) { if ($x['balance']!=$balance) {
echo "rec: $rec, spent: $spent, bal: $x[balance], should be: $balance - $x[id] $x[public_key]\n"; echo "rec: $rec, spent: $spent, bal: $x[balance], should be: $balance - $x[id] $x[public_key]\n";
if (trim($argv[2])!="check") {
$db->run("UPDATE accounts SET balance=:bal WHERE id=:id", [":id"=>$x['id'], ":bal"=>$balance]); $db->run("UPDATE accounts SET balance=:bal WHERE id=:id", [":id"=>$x['id'], ":bal"=>$balance]);
} }
} }
}
$db->exec("UNLOCK TABLES"); $db->exec("UNLOCK TABLES");
echo "All done"; echo "All done";
unlink("tmp/sanity-lock");
} elseif ($cmd=="compare-blocks") {
$block=new Block();
$current=$block->current();
$peer=trim($argv[2]);
$limit=intval($argv[3]);
if ($limit==0) {
$limit=5000;
}
for ($i=$current['height']-$limit;$i<=$current['height'];$i++) {
$data=peer_post($peer."/peer.php?q=getBlock", ["height" => $i]);
if ($data==false) {
continue;
}
$our=$block->export(false, $i);
if ($data!=$our) {
echo "Failed block -> $i\n";
if ($argv[4]=="dump") {
echo "\n\n ---- Internal ----\n\n";
var_dump($our);
echo "\n\n ---- External ----\n\n";
var_dump($data);
}
}
}
} elseif ($cmd=='compare-accounts') {
$peer=trim($argv[2]);
$r=$db->run("SELECT id,balance FROM accounts");
foreach ($r as $x) {
$data=peer_post($peer."/api.php?q=getBalance", ["account" => $x['id']]);
if ($data==false) {
continue;
}
if ($data!=$x['balance']) {
echo "$x[id]\t\t$x[balance]\t$data\n";
}
}
} elseif ($cmd=='masternode-hash') {
$res=$db->run("SELECT * FROM masternode ORDER by public_key ASC");
$block=new Block();
$current=$block->current();
echo "Height:\t\t$current[height]\n";
echo "Hash:\t\t".md5(json_encode($res))."\n\n";
} elseif ($cmd=='accounts-hash') {
$res=$db->run("SELECT * FROM accounts ORDER by id ASC");
$block=new Block();
$current=$block->current();
echo "Height:\t\t$current[height]\n";
echo "Hash:\t\t".md5(json_encode($res))."\n\n";
} elseif ($cmd == "version") {
echo "\n\n".VERSION."\n\n";
} elseif ($cmd == "sendblock"){
$peer=trim($argv[3]);
if (!filter_var($peer, FILTER_VALIDATE_URL)) {
die("Invalid peer hostname");
}
$peer = filter_var($peer, FILTER_SANITIZE_URL);
$height=intval($argv[2]);
$block=new Block();
$data = $block->export("", $height);
if($data===false){
die("Could not find this block");
}
$response = peer_post($peer."/peer.php?q=submitBlock", $data, 60, true);
var_dump($response);
}elseif ($cmd == "recheck-external-blocks") {
$peer=trim($argv[2]);
if (!filter_var($peer, FILTER_VALIDATE_URL)) {
die("Invalid peer hostname");
}
$peer = filter_var($peer, FILTER_SANITIZE_URL);
$blocks = [];
$block = new Block();
$height=intval($argv[3]);
$last=peer_post($peer."/peer.php?q=currentBlock");
$b=peer_post($peer."/peer.php?q=getBlock",["height"=>$height]);
for ($i = $height+1; $i <= $last['height']; $i++) {
$c=peer_post($peer."/peer.php?q=getBlock",["height"=>$i]);
if (!$block->mine(
$c['public_key'],
$c['nonce'],
$c['argon'],
$c['difficulty'],
$b['id'],
$b['height'],
$c['date']
)) {
print("Invalid block detected. $c[height] - $c[id]\n");
break;
}
echo "Block $i -> ok\n";
$b=$c;
}
} else { } else {