20 Commits

Author SHA1 Message Date
Arionum
984aedc940 version 2018-08-13 02:51:49 +03:00
Arionum
e59bb416b4 80460 hard fork 2018-08-13 02:36:59 +03:00
Arionum
57d2257c43 80460 hf 2018-08-13 02:36:20 +03:00
Arionum
8c32d1c71b 80500 hf mn 2018-08-12 21:39:38 +03:00
Arionum
b5110bf01f protection 2018-08-12 16:47:52 +03:00
Arionum
0567899edd temp fix 2018-08-12 05:44:03 +03:00
Arionum
66b1221e22 blacklist time 83000 2018-08-12 01:47:56 +03:00
Arionum
9e9c12fbbb accounts resync option 2018-08-11 23:00:33 +03:00
Arionum
c5002508d6 internal transaction 2018-08-10 22:19:22 +03:00
Arionum
fbc48921f3 mn fix 2018-08-10 21:49:34 +03:00
Arionum
07dcebd895 limit peers 2018-08-10 18:19:19 +03:00
arionum
6651ff54fc Update db-update 2018-08-09 15:32:09 +03:00
Arionum
38745111ef Merge branch 'master' of https://github.com/arionum/node 2018-08-07 22:36:19 +03:00
Arionum
c83895d384 homepage version 2018-08-07 22:36:04 +03:00
arionum
62cc290b50 Update README.md 2018-08-07 18:19:17 +03:00
Arionum
dab6648ae8 log fix 2018-08-07 18:09:26 +03:00
arionum
5c476be954 Merge pull request #23 from pxgamer/feature/config-formatting
Beautify the sample configuration with sections
2018-08-07 15:57:17 +03:00
pxgamer
0d5f79fc20 Beautify the sample configuration with sections 2018-08-07 11:38:47 +01:00
arionum
5fc167cfbf Update README.md 2018-08-07 13:12:32 +03:00
arionum
5f4b6d9d51 Rename config.inc.php to config-sample.inc.php 2018-08-07 13:11:09 +03:00
12 changed files with 276 additions and 71 deletions

View File

@@ -5,11 +5,11 @@ The Arionum (ARO) cryptocurrency node.
## Install ## Install
**Hardware Requirements:** **Hardware Requirements:**
```
2GB RAM 2GB RAM
1 CPU Core 1 CPU Core
50GB DISK 50GB DISK
```
**Requirements:** **Requirements:**
- PHP 7.2 - PHP 7.2
@@ -19,7 +19,7 @@ The Arionum (ARO) cryptocurrency node.
- MySQL/MariaDB - MySQL/MariaDB
1. Install MySQL or MariaDB and create a database and a user. 1. Install MySQL or MariaDB and create a database and a user.
2. Edit `include/config.inc.php` and set the DB login data 2. Rename `include/config-sample.inc.php` to `include/config.inc.php` and set the DB login data
3. Change permissions to tmp and `tmp/db-update` to 777 (`chmod 777 tmp -R`) 3. Change permissions to tmp and `tmp/db-update` to 777 (`chmod 777 tmp -R`)
4. Access the http://ip-or-domain and refresh once 4. Access the http://ip-or-domain and refresh once

View File

@@ -24,7 +24,7 @@ class Block
// create the block data and check it against the signature // create the block data and check it against the signature
$info = "{$generator}-{$height}-{$date}-{$nonce}-{$json}-{$difficulty}-{$argon}"; $info = "{$generator}-{$height}-{$date}-{$nonce}-{$json}-{$difficulty}-{$argon}";
_log($info,3); // _log($info,3);
if (!$bootstrapping) { if (!$bootstrapping) {
if (!$acc->check_signature($info, $signature, $public_key)) { if (!$acc->check_signature($info, $signature, $public_key)) {
_log("Block signature check failed"); _log("Block signature check failed");
@@ -37,12 +37,33 @@ class Block
} }
} }
// 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, masternode WRITE, peers write, config WRITE");
$reward = $this->reward($height, $data); $reward = $this->reward($height, $data);
$msg = ''; $msg = '';
if($height>=80460){
//reward the masternode
$mn_winner=$db->single(
"SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 1",
[":current"=>$height, ":start"=>$height-360]
);
_log("MN Winner: $mn_winner",2);
if($mn_winner!==false){
$mn_reward=round(0.33*$reward,8);
$reward=round($reward-$mn_reward,8);
$reward=number_format($reward,8,".","");
$mn_reward=number_format($mn_reward,8,".","");
_log("MN Reward: $mn_reward",2);
}
}
// the reward transaction // the reward transaction
$transaction = [ $transaction = [
"src" => $generator, "src" => $generator,
@@ -68,6 +89,8 @@ class Block
// insert the block into the db // insert the block into the db
$db->beginTransaction(); $db->beginTransaction();
$total = count($data); $total = count($data);
$bind = [ $bind = [
":id" => $hash, ":id" => $hash,
":generator" => $generator, ":generator" => $generator,
@@ -94,10 +117,33 @@ class Block
// insert the reward transaction in the db // insert the reward transaction in the db
$trx->add($hash, $height, $transaction); $trx->add($hash, $height, $transaction);
if($mn_winner!==false){
$db->run("UPDATE accounts SET balance=balance+:bal WHERE public_key=:pub",[":pub"=>$mn_winner, ":bal"=>$mn_reward]);
$bind = [
":id" => hex2coin(hash("sha512", "mn".$hash.$height.$mn_winner)),
":public_key" => $public_key,
":height" => $height,
":block" => $hash,
":dst" => $acc->get_address($mn_winner),
":val" => $mn_reward,
":fee" => 0,
":signature" => $reward_signature,
":version" => 0,
":date" => $date,
":message" => 'masternode',
];
$res = $db->run(
"INSERT into transactions SET id=:id, public_key=:public_key, block=:block, height=:height, dst=:dst, val=:val, fee=:fee, signature=:signature, version=:version, message=:message, `date`=:date",
$bind
);
$this->reset_fails_masternodes($mn_winner, $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) { if (($height-1)%3==2 && $height>=80000&&$height<80460) {
$this->blacklist_masternodes(); $this->blacklist_masternodes();
$this->reset_fails_masternodes($public_key, $height, $hash); $this->reset_fails_masternodes($public_key, $height, $hash);
} }
@@ -385,6 +431,25 @@ class Block
// reward transaction and signature // reward transaction and signature
$reward = $this->reward($height, $data); $reward = $this->reward($height, $data);
if($height>=80460){
//reward the masternode
global $db;
$mn_winner=$db->single(
"SELECT public_key FROM masternode WHERE status=1 AND blacklist<:current AND height<:start ORDER by last_won ASC, public_key ASC LIMIT 1",
[":current"=>$height, ":start"=>$height-360]
);
_log("MN Winner: $mn_winner",2);
if($mn_winner!==false){
$mn_reward=round(0.33*$reward,8);
$reward=round($reward-$mn_reward,8);
$reward=number_format($reward,8,".","");
$mn_reward=number_format($mn_reward,8,".","");
_log("MN Reward: $mn_reward",2);
}
}
$msg = ''; $msg = '';
$transaction = [ $transaction = [
"src" => $generator, "src" => $generator,
@@ -430,10 +495,19 @@ class Block
$last=$this->get($current['height']-1); $last=$this->get($current['height']-1);
$total_time=$current['date']-$last['date']; $total_time=$current['date']-$last['date'];
_log("blacklist total time $total_time"); _log("blacklist total time $total_time");
if ($total_time<=600) { if ($total_time<=600&&$current['height']<80500) {
return; return;
} }
if($current['height']>=80500&&$total_time<360){
return false;
}
if($current['height']>=80500){
$total_time-=360;
$tem=floor($total_time/120)+1;
if($tem>5) $tem=5;
} 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,$tem",
@@ -444,7 +518,9 @@ class Block
foreach ($ban as $b) { foreach ($ban as $b) {
$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);
$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)*10)]); $btime=10;
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)]);
$i++; $i++;
} }
} }
@@ -490,6 +566,18 @@ class Block
_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>=80460){
if ($current_height%2==0) {
// cpu mining
_log("CPU Mining - $current_height", 2);
$argon = '$argon2i$v=19$m=524288,t=1,p=1'.$argon;
} else {
// gpu mining
_log("GPU Mining - $current_height", 2);
$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) {
@@ -535,17 +623,23 @@ class Block
} }
// if 10 mins have passed, try to give the block to the next masternode and do this every 10mins // if 10 mins have passed, try to give the block to the next masternode and do this every 10mins
_log("Last block time: $last_time, difference: ".($time-$last_time), 3); _log("Last block time: $last_time, difference: ".($time-$last_time), 3);
if ($time-$last_time>600) { if (($time-$last_time>600&&$current_height<80500)||($time-$last_time>360&&$current_height>=80500)) {
_log("Current public_key $public_key", 3); _log("Current public_key $public_key", 3);
$tem=floor(($time-$last_time)/600); if($current_height>=80500){
$total_time=$time-$last_time;
$total_time-=360;
$tem=floor($total_time/120)+1;
} else {
$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]
); );
_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) { 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=1,p=1'.$argon;
} elseif ($winner==$public_key) { } elseif ($winner==$public_key) {
@@ -863,7 +957,7 @@ class Block
// the reward transaction always has version 0 // the reward transaction always has version 0
$gen = $db->row( $gen = $db->row(
"SELECT public_key, signature FROM transactions WHERE version=0 AND block=:block", "SELECT public_key, signature FROM transactions WHERE version=0 AND block=:block AND message=''",
[":block" => $block['id']] [":block" => $block['id']]
); );
$block['public_key'] = $gen['public_key']; $block['public_key'] = $gen['public_key'];

114
include/config-sample.inc.php Executable file
View File

@@ -0,0 +1,114 @@
<?php
/*
|--------------------------------------------------------------------------
| Database Configuration
|--------------------------------------------------------------------------
*/
// The database DSN
$_config['db_connect'] = 'mysql:host=localhost;dbname=ENTER-DB-NAME';
// The database username
$_config['db_user'] = 'ENTER-DB-USER';
// The database password
$_config['db_pass'] = 'ENTER-DB-PASS';
/*
|--------------------------------------------------------------------------
| General Configuration
|--------------------------------------------------------------------------
*/
// Maximum number of connected peers
$_config['max_peers'] = 30;
// Enable testnet mode for development
$_config['testnet'] = false;
// To avoid any problems if other clones are made
$_config['coin'] = 'arionum';
// Allow others to connect to the node api (if set to false, only the below 'allowed_hosts' are allowed)
$_config['public_api'] = true;
// Hosts that are allowed to mine on this node
$_config['allowed_hosts'] = [
'127.0.0.1',
];
/*
|--------------------------------------------------------------------------
| Peer Configuration
|--------------------------------------------------------------------------
*/
// The number of peers to send each new transaction to
$_config['transaction_propagation_peers'] = 5;
// How many new peers to check from each peer
$_config['max_test_peers'] = 5;
/*
|--------------------------------------------------------------------------
| Mempool Configuration
|--------------------------------------------------------------------------
*/
// The maximum transactions to accept from a single peer
$_config['peer_max_mempool'] = 100;
// The maximum number of mempool transactions to be rebroadcasted
$_config['max_mempool_rebroadcast'] = 5000;
// The number of blocks between rebroadcasting transactions
$_config['sanity_rebroadcast_height'] = 30;
/*
|--------------------------------------------------------------------------
| Sanity Configuration
|--------------------------------------------------------------------------
*/
// Recheck the last blocks on sanity
$_config['sanity_recheck_blocks'] = 10;
// The interval to run the sanity in seconds
$_config['sanity_interval'] = 900;
// Enable setting a new hostname (should be used only if you want to change the hostname)
$_config['allow_hostname_change'] = false;
// Rebroadcast local transactions when running sanity
$_config['sanity_rebroadcast_locals'] = true;
// Get more peers?
$_config['get_more_peers']=true;
/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
*/
// Enable log output to the specified file
$_config['enable_logging'] = false;
// The specified file to write to (this should not be publicly visible)
$_config['log_file'] = '/var/log/aro.log';
// Log verbosity (default 0, maximum 3)
$_config['log_verbosity'] = 0;
/*
|--------------------------------------------------------------------------
| Masternode Configuration
|--------------------------------------------------------------------------
*/
// Enable this node as a masternode
$_config['masternode'] = false;
// The public key for the masternode
$_config['masternode_public_key'] = '';

View File

@@ -1,44 +0,0 @@
<?php
// Database connection
$_config['db_connect']="mysql:host=localhost;dbname=ENTER-DB-NAME";
$_config['db_user']="ENTER-DB-USER";
$_config['db_pass']="ENTER-DB-PASS";
// Maximum number of connected peers
$_config['max_peers']=30;
// Testnet, used for development
$_config['testnet']=false;
// To avoid any problems if other clones are made
$_config['coin']="arionum";
// maximum transactions accepted from a single peer
$_config['peer_max_mempool']=100;
// maximum mempool transactions to be rebroadcasted
$_config['max_mempool_rebroadcast']=5000;
// after how many blocks should the transactions be rebroadcasted
$_config['sanity_rebroadcast_height']=30;
// each new received transaction is sent to X peers
$_config['transaction_propagation_peers']=5;
// how many new peers to check from each peer.
$_config['max_test_peers']=5;
// recheck the last blocks on sanity
$_config['sanity_recheck_blocks']=10;
// allow others to connect to node api. If set to false, only allowed_hosts are allowed
$_config['public_api']=true;
// hosts allowed to mine on this node
$_config['allowed_hosts']=array("127.0.0.1");
// sanity is run every X seconds
$_config['sanity_interval']=900;
// accept the setting of new hostnames / should be used only if you want to change the hostname
$_config['allow_hostname_change']=false;
// rebroadcast local transactions on each sanity
$_config['sanity_rebroadcast_locals']=true;
// write logs to file
$_config['enable_logging']=false;
// log file, should not be publicly viewable
$_config['log_file']="/var/log/aro.log";
//log verbosity, default 0, maximum 3
$_config['log_verbosity']=0;
//will this run as a masternode?
$_config['masternode']=false;
//masternode public key
$_config['masternode_public_key']="";

View File

@@ -1,6 +1,6 @@
<?php <?php
// ARO version // ARO version
define("VERSION", "0.4.1"); define("VERSION", "0.4.2");
// Amsterdam timezone by default, should probably be moved to config // Amsterdam timezone by default, should probably be moved to config
date_default_timezone_set("UTC"); date_default_timezone_set("UTC");
@@ -71,9 +71,6 @@ if (file_exists("tmp/db-update")) {
if($ram<1700000) { if($ram<1700000) {
die("The node requires at least 2 GB of RAM"); die("The node requires at least 2 GB of RAM");
} }
if($_config['masternode']==true && $ram<7000000){
die("The masternode require at least 8GB of RAM");
}
$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";

View File

@@ -20,11 +20,14 @@ class Transaction
); );
} else { } else {
// other type of transactions // other type of transactions
$db->run(
if($x['version']!=100) { $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']]
); );
} }
}
// 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) {
$db->run( $db->run(
@@ -82,7 +85,7 @@ class Transaction
} }
// add the transactions to mempool // add the transactions to mempool
if ($x['version'] > 0 && $x['version']<=1000) { if ($x['version'] > 0 && $x['version']<=110) {
$this->add_mempool($x); $this->add_mempool($x);
} }
$res = $db->run("DELETE FROM transactions WHERE id=:id", [":id" => $x['id']]); $res = $db->run("DELETE FROM transactions WHERE id=:id", [":id" => $x['id']]);

View File

@@ -185,6 +185,10 @@ $current = $block->current();
background-color: #209cee; background-color: #209cee;
color: #fff; color: #fff;
} }
.tag:not(body).is-danger {
background-color: #f48f42;
color: #fff;
}
.tag:not(body).is-success { .tag:not(body).is-success {
background-color: #23d160; background-color: #23d160;
@@ -292,12 +296,20 @@ $current = $block->current();
<span class="tag is-light"><?= $current['height']; ?></span> <span class="tag is-light"><?= $current['height']; ?></span>
</div> </div>
</div> </div>
<div class="control">
<div class="tags has-addons">
<strong class="tag is-danger">Version</strong>
<span class="tag is-light"><?= VERSION; ?></span>
</div>
</div>
<div class="control"> <div class="control">
<div class="tags has-addons"> <div class="tags has-addons">
<strong class="tag is-info">Public API</strong> <strong class="tag is-info">Public API</strong>
<span class="tag is-light"><?= ($_config['public_api']) ? 'yes' : 'no'; ?></span> <span class="tag is-light"><?= ($_config['public_api']) ? 'yes' : 'no'; ?></span>
</div> </div>
</div> </div>
<div class="control"> <div class="control">
<a class="tags is-dark" href="./doc/" target="_blank"> <a class="tags is-dark" href="./doc/" target="_blank">
<strong class="tag is-info">Documentation</strong> <strong class="tag is-info">Documentation</strong>

View File

@@ -56,6 +56,12 @@ if ($q == "info") {
$argon_threads=1; $argon_threads=1;
$argon_time=1; $argon_time=1;
} }
} elseif($current_height>=80460&&$current_height%2==0){
$argon_mem=524288;
$argon_threads=1;
$argon_time=1;
} else { } else {
if ($current_height%3==0) { if ($current_height%3==0) {
$argon_mem=524288; $argon_mem=524288;

View File

@@ -252,7 +252,6 @@ elseif ($q == "currentBlock") {
} // return a specific block, used in syncing } // return a specific block, used in syncing
elseif ($q == "getBlock") { elseif ($q == "getBlock") {
$height = intval($data['height']); $height = intval($data['height']);
$export = $block->export("", $height); $export = $block->export("", $height);
if (!$export) { if (!$export) {
api_err("invalid-block"); api_err("invalid-block");

View File

@@ -314,6 +314,7 @@ 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){
$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");
@@ -324,7 +325,6 @@ foreach ($r as $x) {
); );
continue; continue;
} }
$i = 0; $i = 0;
foreach ($data as $peer) { foreach ($data as $peer) {
// store the hostname as md5 hash, for easier checking // store the hostname as md5 hash, for easier checking
@@ -371,7 +371,7 @@ foreach ($r as $x) {
} }
} }
} }
}
// get the current block and check it's blockchain // get the current block and check it's blockchain
$data = peer_post($url."currentBlock", [], 5); $data = peer_post($url."currentBlock", [], 5);
@@ -665,7 +665,7 @@ foreach ($f as $x) {
//recheck the last blocks //recheck the last blocks
if ($_config['sanity_recheck_blocks'] > 0 && $_config['testnet'] == false) { if ($_config['sanity_recheck_blocks'] > 0 && $_config['testnet'] == false&&1==2) {
_log("Rechecking blocks"); _log("Rechecking blocks");
$blocks = []; $blocks = [];
$all_blocks_ok = true; $all_blocks_ok = true;

View File

@@ -0,0 +1 @@
4.0.1

View File

@@ -447,6 +447,29 @@ elseif ($cmd == 'get-address') {
} 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'){
// resyncs the balance on all accounts
// lock table to avoid race conditions on blocks
$db->exec("LOCK TABLES blocks WRITE, accounts WRITE, transactions WRITE, mempool WRITE");
$r=$db->run("SELECT * FROM accounts");
foreach($r as $x){
$alias=$x['alias'];
if(empty($alias)) $alias="A";
$rec=$db->single("SELECT SUM(val) FROM transactions WHERE (dst=:id or dst=:alias) AND (height<80000 OR (version!=100 AND version!=103)) and version<111",[":id"=>$x['id'], ":alias"=>$alias]);
$spent=$db->single("SELECT SUM(val+fee) FROM transactions WHERE public_key=:pub AND version>0",[":pub"=>$x['public_key']]);
if($spent==false) $spent=0;
$balance=round(($rec-$spent),8);
if($x['balance']!=$balance){
echo "rec: $rec, spent: $spent, bal: $x[balance], should be: $balance - $x[id] $x[public_key]\n";
$db->run("UPDATE accounts SET balance=:bal WHERE id=:id",[":id"=>$x['id'], ":bal"=>$balance]);
}
}
$db->exec("UNLOCK TABLES");
echo "All done";
} else { } else {
echo "Invalid command\n"; echo "Invalid command\n";
} }