123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- <?php
- /**
- * Copyright: Mangrovia Blockchain Solutions S.r.l.
- * Date: 04/01/2019
- */
-
- error_reporting(E_ALL);
- ini_set('display_errors', 1);
-
- $fp = fopen(__DIR__ . '/../locks/lock.txt', 'w') or die ('Cannot create lock file');
- if (! flock($fp, LOCK_EX | LOCK_NB)) {
- echo 'Unable to obtain lock';
- exit(-1);
- }
-
- $conf = parse_ini_file(dirname(__FILE__).'/../client.ini', true);
- $host = $conf['db']['host'] ?? null;
- $db = $conf['db']['name'] ?? null;
- $user = $conf['db']['user'] ?? null;
- $pass = $conf['db']['password'] ?? null;
- $charset = $conf['db']['charset'] ?? null;
- $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
- $options = [
- PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
- PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
- PDO::ATTR_EMULATE_PREPARES => false,
- ];
- try {
- $pdo = new PDO($dsn, $user, $pass, $options);
- } catch (\PDOException $e) {
- throw new \PDOException($e->getMessage(), (int)$e->getCode());
- }
-
- $wallet = new WalletEprosume($pdo, $conf);
-
- // fetch accounts registered in the db
- $stmt = $pdo->prepare('select id,name,sell,buy from meter');
- $stmt->execute();
- $accounts = $stmt->fetchAll();
-
- foreach($accounts as $account) {
- echo PHP_EOL."Account: {$account['name']}".PHP_EOL;
- $wallet->balance($pdo, $account);
- $wallet->updateHistoryDB($pdo, $account);
- }
-
- flock($fp, LOCK_UN);
-
- class WalletEprosume
- {
- public $walletExecutable;
- public $walletConfiguration;
- public $walletAccount;
- public $walletAccountDirectory;
- public $walletCommandUpdatePrices = "admin updatePrices";
- public $walletCommandBalance = "wallet balance";
- public $walletCommandHistory = "wallet history";
- public $walletCommandTransfer = "wallet transfer";
-
- private $conf = [];
-
- public function __construct($pdo=null, $conf) {
- $this->walletExecutable = $conf['wallet']['executable'] ?? null;
- $this->walletConfiguration = $conf['wallet']['configuration'] ?? null;
- $this->walletAccount = $conf['wallet']['account'] ?? null;
- $this->walletAccountDirectory = dirname($conf['wallet']['account']) ?? null;
- if($pdo) {
- // fetch configuration
- $stmt = $pdo->prepare('select conf_key, conf_value from conf');
- $stmt->execute();
- $conf_rows = $stmt->fetchAll();
- foreach($conf_rows as $v) {
- $this->conf[$v['conf_key']] = $v['conf_value'];
- }
- }
- }
-
- public function balance($pdo=null, $account=null)
- {
- $username = $account['name'];
- $id = $account['id'];
- $walletExec = "$this->walletExecutable $this->walletCommandBalance --config $this->walletConfiguration " .
- "--accounts-file $this->walletAccount --of $username 2>/dev/null";
- $type = "";
- $values = ['Meter' => $id, 'PRS' => '' , 'TFT' => ''];
- exec($walletExec, $arrayOutput);
- foreach ($arrayOutput as $line) {
- $parameter = explode(': ', $line);
- if (isset($parameter[1])) {
- $key = $parameter[0];
- $val = $parameter[1];
- if ($key == "Asset") {
- $type = $val;
- } else if ($key == "Balance") {
- $amount = $val;
- $values[$type] = $amount;
- }
- }
- }
- // check if the last registered balance is changed
- $stmt = $pdo->prepare('select * from balances where meter_id = :id order by timestamp desc limit 1');
- $stmt->execute(['id'=>$id]);
- $result = $stmt->fetch();
- if(empty($result) || $result['prs'] != $values['PRS'] || $result['tft'] != $values['TFT']) {
- $stmt = $pdo->prepare('insert into balances ( meter_id, prs, tft) values ( :Meter, :PRS, :TFT ) ');
- $stmt->execute($values);
- $stmt2 = $pdo->prepare('update meter set prs = :PRS, tft = :TFT where id = :Meter');
- $stmt2->execute($values);
- }
-
- /* TOP UP */
- foreach(['prs', 'tft'] as $v) {
- $from = $this->conf['utility_account'] ?? null;
- $limit = $this->conf['topup_'.$v.'_limit'] ?? null;
- $transfer = $this->conf['topup_'.$v.'_transfer'] ?? null;
- $memo = $this->conf['topup_'.$v.'_memo'] ?? "Automatic topup";
- if(!$from || !$limit || !$transfer) {
- continue;
- }
- if($values[strtoupper($v)] < (int)$limit) {
- var_dump("TRANSFER $from, ".$account['name'].", $transfer, $v, $memo");
- $this->transfer($from, $account['name'], $transfer, $v, $memo);
- }
- }
-
- }
-
- public function history($accountFile, $account, $pdo)
- {
- $walletExec = "$this->walletExecutable $this->walletCommandHistory --config $this->walletConfiguration " .
- "--accounts-file $accountFile 2>/dev/null";
-
- exec($walletExec, $arrayOutput);
- $transaction = [];
- $history = [];
-
- // setPrice flag
- $setPriceFlag = $this->conf['utility_account'] != $account['name'];
-
- foreach ($arrayOutput as $line) {
- $parameter = explode(': ', $line);
- if (isset($parameter[1])) {
- $key = $parameter[0];
- $value = $parameter[1];
- switch ($key) {
- case 'Block Number':
- $transaction['Blocknumber'] = $value;
- break;
-
- case 'Memo':
- $readings = json_decode($value, $assoc = TRUE);
- if (is_array($readings)) {
- foreach ($readings as $readingKey => $readingValue) {
- if (is_array($readingValue)) {
- if (!empty($readingValue['value'])) {
- $transaction[$key][$readingKey] = $readingValue['value'];
- }
- } else {
- $transaction[$key][$readingKey] = $readingValue;
- }
- }
- } else if(strlen($value) == 32){
- $transaction['Memo'] = [
- 'txID' => $value
- ];
- } else {
- $transaction['Memo'] = [
- 'Memo' => $value
- ];
- }
- $transaction['MemoHash'] = md5($value);
- break;
-
- default:
- $transaction[$key] = $value;
- break;
- }
- } else {
- $key = preg_replace('/\s/', '', $parameter[0]);
- switch ($key) {
- case '--------HistoryEnd--------':
- case '--------------------':
- // Qui devi salvare i record
- array_push($history, $transaction);
-
- // check if there is a setPrice in history
- if($setPriceFlag && isset($transaction['Asset']) && $transaction['Asset'] == 'TFT' && isset($transaction['Memo']) && count($transaction['Memo']) == 2) {
- if(isset($transaction['Memo']['sellPrice']) && isset($transaction['Memo']['buyPrice']) && isset($transaction['To'])) {
- if($account['sell'] != $transaction['Memo']['sellPrice'] || $account['buy'] != $transaction['Memo']['buyPrice']) {
- $stmt2 = $pdo->prepare("UPDATE meter SET sell = ".$transaction['Memo']['sellPrice'].", buy = ".$transaction['Memo']['buyPrice']." WHERE name = '".$transaction['To']."'");
- $stmt2->execute();
- }
- }
- $setPriceFlag = false;
- }
- $transaction = [];
- break;
- }
- }
- }
-
- if($setPriceFlag) {
- $this->setPrice($account['name'], $account['buy'], $account['sell']);
- }
-
- return $history;
- }
-
- public function status()
- {
-
- }
-
- public function updateHistoryDB($pdo=null, $account=null)
- {
- // check if the file with key exists
- $accountFile = $this->walletAccountDirectory."/".$account['name'].".txt";
- if(!file_exists($accountFile)) {
- echo PHP_EOL."ERROR: File $accountFile is not readable.".PHP_EOL;
- return;
- }
-
- foreach($history=$this->history($accountFile, $account, $pdo) as $block) {
-
- if($block["Type"] != "OperationTypeTransfer" || (!in_array($block["Asset"], ["PRS", "TFT"])) ) {
- continue;
- }
-
- $stmt = $pdo->prepare('select id from blocks where timestamp=:Timestamp and blocknumber=:Blocknumber and wallet_from=:From and wallet_to=:To and asset=:Asset and memo_hash=:MemoHash');
- isset($block['Timestamp']) && $block['Timestamp'] = $this->convertUTCToLocalTime($block['Timestamp']);
- $values=[
- 'Blocknumber'=>$block['Blocknumber'],
- 'Timestamp'=>$block['Timestamp'],
- 'From'=>$block['From'],
- 'To'=>$block['To'],
- 'Asset'=>$block['Asset'],
- 'MemoHash'=>$block['MemoHash']
- ];
- $stmt->execute($values);
- $entry = $stmt->fetch();
- if(empty($entry)) {
- /* memo keys in block table */
- $block_tx_id = null;
- $block_type = 'update_price';
- $block_purchased_sold = null;
- $block_buy_price = null;
- $block_sell_price = null;
- if(!empty($block['Memo'])) {
- $block_tx_id = $block['Memo']['txID'] ?? null;
- $block_purchased_sold = $block['Memo']['energyDiff'] ?? null;
- $block_buy_price = $block['Memo']['buyPrice'] ?? null;
- $block_sell_price = $block['Memo']['sellPrice'] ?? null;
- if($block['Asset'] == 'PRS') {
- $block_type = isset($block['Memo']['txID']) ? 'payment' : 'transfer';
- } else if($block['Asset'] == 'TFT') {
- if(isset($block['Memo']['Memo'])) {
- $block_type = 'transfer';
- } else if(count($block['Memo']) > 2) {
- $block_type = 'measure';
- }
- }
- }
- $stmt = $pdo->prepare('insert into blocks (id, blocknumber,wallet_type,wallet_from,wallet_to,asset,amount,timestamp,memo_hash,tx_id,type,purchased_sold,buy_price,sell_price) ' .
- ' values (null, :Blocknumber,:Type,:From,:To,:Asset,:Amount,:Timestamp,:MemoHash,:TxID,:BlockType,:PurchasedSold,:BuyPrice,:SellPrice) ');
- $values = [
- 'Blocknumber' => '',
- 'From' => '',
- 'To' => '',
- 'Asset' => '',
- 'Amount' => '',
- 'Timestamp' => '',
- 'MemoHash' => null,
- 'TxID' => $block_tx_id,
- 'Type' => '',
- 'BlockType' => $block_type,
- 'PurchasedSold' => $block_purchased_sold,
- 'BuyPrice' => $block_buy_price,
- 'SellPrice' => $block_sell_price,
- ];
-
- foreach (array_keys($values) as $memo_key) {
- if (isset($block[$memo_key])) {
- $values[$memo_key] = $block[$memo_key];
- }
- }
-
- $stmt->execute($values);
- $block_id = $pdo->lastInsertId();
-
- // print_r($block);
-
- if (($block_id) && (!empty($block['Memo']))) {
- /* automatic payments */
- $autopay_operation = null;
- $autopay_txid = null;
- $autopay_energyDiff = 0;
- $autopay_sellPrice = 0;
-
- foreach ($block['Memo'] as $memo_key => $memo_value) {
-
- switch ($memo_key) {
- case 'timestamp_sospendi':
- break;
- default:
- $sql = 'insert into memo (block_id,memo_key,memo_value) values (:block_id,:memo_key,:memo_value)';
- $stmt = $pdo->prepare($sql);
- $stmt->execute(compact('block_id', 'memo_key', 'memo_value'));
- if($account['name'] == $this->conf['utility_account']) {
- if($memo_key == "txID" && $block['Asset'] == "PRS") { // payment
- $autopay_operation = 'delete';
- $autopay_txid = $memo_value;
- }
- }
- if($block['Asset'] == "TFT" && $memo_key == "energyDiff") { // pending payment
- if($memo_value < 0) {
- $autopay_operation = 'pay';
- $autopay_txid = $block['Memo']['txID'] ?? null;
- $autopay_energyDiff = $memo_value;
- $autopay_sellPrice = $block['Memo']['sellPrice'] ?? 0;
- }
- }
-
- }
- }
-
- /*automatic payments */
- if($autopay_operation && $autopay_txid) {
- switch($autopay_operation) {
- case 'delete':
- $sql = 'delete from pending_payments where tx_id = "'.$autopay_txid.'"';
- var_dump($sql);
- $stmt = $pdo->prepare($sql);
- $stmt->execute();
- break;
- case 'pay':
- $sql = 'select * from memo where memo_key = "txID" and memo_value = "'.$autopay_txid.'" and block_id != "'.$block_id.'"';
- var_dump($sql);
- $stmt = $pdo->prepare($sql);
- $stmt->execute();
- $memo_rows = $stmt->fetchAll();
- if(!$memo_rows || empty($memo_rows)) {
- $sql = 'select * from pending_payments where tx_id = "'.$autopay_txid.'"';
- var_dump($sql);
- $stmt = $pdo->prepare($sql);
- $stmt->execute();
- $pending_payments_rows = $stmt->fetchAll();
- if(!$pending_payments_rows || empty($pending_payments_rows)) {
- $from = $this->conf['utility_account'] ?? null;
- if(!$from) {
- break;
- }
- $to = $block['From'];
- $amount = number_format(abs($autopay_energyDiff)*($autopay_sellPrice), 8);
- $asset = 'PRS';
- $memo = $autopay_txid;
- $autopay = $this->transfer($from, $to, $amount, $asset, $memo);
- if($autopay) {
- $sql = 'insert into pending_payments(tx_id) values("'.$autopay_txid.'")';
- var_dump($sql);
- $stmt = $pdo->prepare($sql);
- $stmt->execute();
- }
- }
- }
- break;
- }
- }
-
- }
- }
- }
- }
-
- private function convertUTCToLocalTime($datestring) {
- return (new \DateTime($datestring, new \DateTimeZone("UTC")))->setTimeZone(new \DateTimeZone("Europe/Rome"))->format("Y-m-d H:i:s");
- }
-
- private function transfer($from, $to, $amount, $asset, $memo) {
- if(in_array(null, func_get_args(), true)) {
- return false;
- } else {
- $accountFile = $this->walletAccountDirectory."/".$from.".txt";
- if(!file_exists($accountFile)) {
- return false;
- }
- $asset = strtoupper($asset);
- $memo = str_replace("'", "\'", html_entity_decode($memo, ENT_QUOTES));
- $walletExec = "$this->walletExecutable $this->walletCommandTransfer --accounts-file $accountFile --to $to --asset $asset --amount $amount --memo '$memo' --config $this->walletConfiguration 2>&1";
- var_dump($walletExec);
- $output = system($walletExec);
- return strpos($output, 'Assets correctly transferred', 0) !== false;
- }
- }
-
- private function setPrice($user, $buyPrice, $sellPrice)
- {
- if(in_array(null, func_get_args(), true)) {
- return false;
- } else {
- $walletExec = "$this->walletExecutable $this->walletCommandUpdatePrices --accounts-file $this->walletAccount -b $buyPrice -s $sellPrice -u $user --config $this->walletConfiguration 2>&1";
- var_dump($walletExec);
- $output = system($walletExec);
- return strpos($output, 'Assets correctly transferred', 0) !== false;
- }
- }
-
- }
|