mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
finish parsing transactions from gradido node
This commit is contained in:
parent
01f0bd5323
commit
bd6640388d
7
skeema/gradido_community/address_types.sql
Normal file
7
skeema/gradido_community/address_types.sql
Normal file
@ -0,0 +1,7 @@
|
||||
CREATE TABLE `address_types` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`text` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
2
skeema/gradido_community/insert/address_types.sql
Normal file
2
skeema/gradido_community/insert/address_types.sql
Normal file
@ -0,0 +1,2 @@
|
||||
INSERT INTO `address_types` (`id`, `name`, `text`) VALUES
|
||||
(1, 'user main', 'user main address');
|
||||
@ -1,9 +1,10 @@
|
||||
INSERT INTO `transaction_types` (`id`, `name`, `text`) VALUES
|
||||
(1, 'group create', 'create a new group, trigger creation of new hedera topic and new blockchain on node server'),
|
||||
(2, 'group add member', 'add user to a group or move if he was already in a group'),
|
||||
(3, 'creation', 'create new gradidos for member and also for group (in development)'),
|
||||
(4, 'transfer', 'send gradidos from one member to another, also cross group transfer'),
|
||||
(5, 'hedera topic create', 'create new topic on hedera'),
|
||||
(6, 'hedera topic send message', 'send consensus message over hedera topic'),
|
||||
(7, 'hedera account create', 'create new account on hedera for holding some founds with unencrypted keys');
|
||||
(1, 'creation', 'create new gradidos for member and also for group (in development)'),
|
||||
(2, 'transfer', 'send gradidos from one member to another, also cross group transfer'),
|
||||
(3, 'group create', 'create a new group, trigger creation of new hedera topic and new blockchain on node server'),
|
||||
(4, 'group add member', 'add user to a group or move if he was already in a group'),
|
||||
(5, 'group remove member', 'remove user from group, maybe he was moved elsewhere'),
|
||||
(6, 'hedera topic create', 'create new topic on hedera'),
|
||||
(7, 'hedera topic send message', 'send consensus message over hedera topic'),
|
||||
(8, 'hedera account create', 'create new account on hedera for holding some founds with unencrypted keys');
|
||||
|
||||
|
||||
@ -3,5 +3,6 @@ CREATE TABLE `state_group_addresses` (
|
||||
`group_id` int(10) unsigned NOT NULL,
|
||||
`public_key` binary(32) NOT NULL,
|
||||
`address_type_id` int(10) unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE(`public_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@ -2,6 +2,7 @@ CREATE TABLE `transaction_group_addaddress` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`transaction_id` int(10) unsigned NOT NULL,
|
||||
`address_type_id` int(10) unsigned NOT NULL,
|
||||
`remove_from_group` BOOLEAN DEFAULT FALSE,
|
||||
`public_key` binary(32) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
CREATE TABLE `transaction_send_coins` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`transaction_id` int(10) unsigned NOT NULL,
|
||||
`state_user_id` int(10) unsigned NOT NULL,
|
||||
`sender_public_key` binary(32) NOT NULL,
|
||||
`state_user_id` int(10) unsigned DEFAULT 0,
|
||||
`receiver_public_key` binary(32) NOT NULL,
|
||||
`receiver_user_id` int(10) unsigned NOT NULL,
|
||||
`receiver_user_id` int(10) unsigned DEFAULT 0,
|
||||
`amount` bigint(20) NOT NULL,
|
||||
`sender_final_balance` bigint(20) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Controller\AppController;
|
||||
use Cake\I18n\Number;
|
||||
|
||||
/**
|
||||
* AddressTypes Controller
|
||||
@ -35,7 +34,7 @@ class AddressTypesController extends AppController
|
||||
public function view($id = null)
|
||||
{
|
||||
$addressType = $this->AddressTypes->get($id, [
|
||||
'contain' => ['StateGroupAddresses', 'TransactionGroupAddaddress']
|
||||
'contain' => ['StateGroupAddresses', 'TransactionGroupAddaddress'],
|
||||
]);
|
||||
|
||||
$this->set('addressType', $addressType);
|
||||
@ -71,7 +70,7 @@ class AddressTypesController extends AppController
|
||||
public function edit($id = null)
|
||||
{
|
||||
$addressType = $this->AddressTypes->get($id, [
|
||||
'contain' => []
|
||||
'contain' => [],
|
||||
]);
|
||||
if ($this->request->is(['patch', 'post', 'put'])) {
|
||||
$addressType = $this->AddressTypes->patchEntity($addressType, $this->request->getData());
|
||||
|
||||
@ -41,7 +41,11 @@ class JsonRpcRequestClientComponent extends Component
|
||||
public function sendRequest($message) {
|
||||
$http = new Client();
|
||||
|
||||
$response = $http->post($this->getGradidoNodeUrl(), $message, ['type' => 'json']);
|
||||
try {
|
||||
$response = $http->post($this->pickGradidoNodeUrl(), $message, ['type' => 'json']);
|
||||
} catch(Exception $e) {
|
||||
return ['state' => 'error', 'type' => 'http exception', 'details' => $e->getMessage()];
|
||||
}
|
||||
$responseStatus = $response->getStatusCode();
|
||||
if($responseStatus != 200) {
|
||||
return ['state' => 'error', 'type' => 'request error', 'msg' => 'server response status code isn\'t 200', 'details' => $responseStatus];
|
||||
@ -59,10 +63,11 @@ class JsonRpcRequestClientComponent extends Component
|
||||
//return ['state' => 'success', 'data' => $json];
|
||||
}
|
||||
|
||||
static public function getGradidoNodeUrl()
|
||||
static public function pickGradidoNodeUrl()
|
||||
{
|
||||
$gradidoNode = Configure::read('GradidoNode');
|
||||
return $gradidoNode['host'] . ':' . $gradidoNode['port'];
|
||||
$gradidoNodes = Configure::read('GradidoNode');
|
||||
$i = rand(0, count($gradidoNodes)-1);
|
||||
return $gradidoNodes[$i]['host'] . ':' . $gradidoNodes[$i]['port'];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ class ErrorController extends AppController
|
||||
public function beforeRender(Event $event)
|
||||
{
|
||||
parent::beforeRender($event);
|
||||
|
||||
$this->RequestHandler->renderAs($this, 'json');
|
||||
$this->viewBuilder()->setTemplatePath('Error');
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ use Cake\Core\Configure;
|
||||
|
||||
use Model\Transactions\TransactionTransfer;
|
||||
use Model\Transactions\Transaction;
|
||||
use Model\Transactions\Record;
|
||||
/*!
|
||||
* @author: Dario Rekowski#
|
||||
*
|
||||
@ -24,6 +25,7 @@ class JsonRequestHandlerController extends AppController {
|
||||
{
|
||||
parent::initialize();
|
||||
$this->loadComponent('JsonRequestClient');
|
||||
$this->loadComponent('JsonRpcRequestClient');
|
||||
//$this->Auth->allow(['add', 'edit']);
|
||||
$this->Auth->allow('index');
|
||||
}
|
||||
@ -69,6 +71,45 @@ class JsonRequestHandlerController extends AppController {
|
||||
// Called from login server like a cron job every 10 minutes or after sending transaction to hedera
|
||||
private function updateReadNode()
|
||||
{
|
||||
$this->autoRender = false;
|
||||
$response = $this->response->withType('application/json');
|
||||
|
||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||
$last_transaction = $transactionsTable->find('all')->order(['id' => 'DESC'])->first();
|
||||
$group_alias = Configure::read('GroupAlias');
|
||||
$result = $this->JsonRpcRequestClient->request('getTransactions', ['groupAlias' => $group_alias, 'lastKnownSequenceNumber' => $last_transaction->id]);
|
||||
if(isset($result['state']) && $result['state'] == 'error') {
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'jsonrpc error', 'details' => $result]);
|
||||
}
|
||||
$part_count = -1;
|
||||
$temp_record = new Record;
|
||||
$errors = [];
|
||||
foreach($result as $_record) {
|
||||
$parse_result = $temp_record->parseRecord($_record);
|
||||
if($parse_result == true) {
|
||||
$sequenceNumber = $temp_record->getSequenceNumber();
|
||||
if($part_count == -1) {
|
||||
$part_count = $temp_record->getPartCount();
|
||||
}
|
||||
$part_count--;
|
||||
|
||||
if($part_count == 0) {
|
||||
$finalize_result = $temp_record->finalize();
|
||||
if($finalize_result != true) {
|
||||
$errors[] = ['msg' => 'error in finalize', 'record' => $_record, 'details' => $finalize_result, 'sequenceNumber' => $sequenceNumber];
|
||||
}
|
||||
$temp_record = new Record;
|
||||
$part_count = -1;
|
||||
}
|
||||
} else {
|
||||
$temp_record = new Record;
|
||||
$part_count = -1;
|
||||
$errors[] = ['msg' => 'error in parse record', 'record' => $_record, 'details' => $parse_result];
|
||||
}
|
||||
}
|
||||
if(count($errors)) {
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'error in parsing records', 'details' => $errors]);
|
||||
}
|
||||
return $this->returnJson(['state' => 'success']);
|
||||
}
|
||||
|
||||
|
||||
@ -170,17 +170,22 @@ class StateBalancesController extends AppController
|
||||
foreach ($transferTransactions as $sendCoins) {
|
||||
$type = '';
|
||||
$otherUser = null;
|
||||
$other_user_public = '';
|
||||
if ($sendCoins->state_user_id == $user['id']) {
|
||||
$type = 'send';
|
||||
|
||||
if(isset($involvedUserIndices[$sendCoins->receiver_user_id])) {
|
||||
$otherUser = $involvedUserIndices[$sendCoins->receiver_user_id];
|
||||
}
|
||||
$other_user_public = bin2hex(stream_get_contents($sendCoins->receiver_public_key));
|
||||
} else if ($sendCoins->receiver_user_id == $user['id']) {
|
||||
$type = 'receive';
|
||||
if(isset($involvedUserIndices[$sendCoins->state_user_id])) {
|
||||
$otherUser = $involvedUserIndices[$sendCoins->state_user_id];
|
||||
}
|
||||
if($sendCoins->sender_public_key) {
|
||||
$other_user_public = bin2hex(stream_get_contents($sendCoins->sender_public_key));
|
||||
}
|
||||
}
|
||||
if(null == $otherUser) {
|
||||
$otherUser = $this->StateBalances->StateUsers->newEntity();
|
||||
@ -192,7 +197,8 @@ class StateBalancesController extends AppController
|
||||
'transaction_id' => $sendCoins->transaction_id,
|
||||
'date' => $sendCoins->transaction->received,
|
||||
'balance' => $sendCoins->amount,
|
||||
'memo' => $sendCoins->transaction->memo
|
||||
'memo' => $sendCoins->transaction->memo,
|
||||
'pubkey' => $other_user_public
|
||||
]);
|
||||
}
|
||||
uasort($transactions, array($this, 'sortTransactions'));
|
||||
|
||||
@ -8,7 +8,7 @@ use Cake\ORM\Entity;
|
||||
*
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string|null $text
|
||||
* @property string $text
|
||||
*
|
||||
* @property \App\Model\Entity\StateGroupAddress[] $state_group_addresses
|
||||
* @property \App\Model\Entity\TransactionGroupAddaddres[] $transaction_group_addaddress
|
||||
@ -28,6 +28,6 @@ class AddressType extends Entity
|
||||
'name' => true,
|
||||
'text' => true,
|
||||
'state_group_addresses' => true,
|
||||
'transaction_group_addaddress' => true
|
||||
'transaction_group_addaddress' => true,
|
||||
];
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ class TransactionGroupAddaddres extends Entity
|
||||
protected $_accessible = [
|
||||
'transaction_id' => true,
|
||||
'address_type_id' => true,
|
||||
'remove_from_group' => true,
|
||||
'public_key' => true,
|
||||
'transaction' => true,
|
||||
'address_type' => true
|
||||
|
||||
@ -38,10 +38,10 @@ class AddressTypesTable extends Table
|
||||
$this->setPrimaryKey('id');
|
||||
|
||||
$this->hasMany('StateGroupAddresses', [
|
||||
'foreignKey' => 'address_type_id'
|
||||
'foreignKey' => 'address_type_id',
|
||||
]);
|
||||
$this->hasMany('TransactionGroupAddaddress', [
|
||||
'foreignKey' => 'address_type_id'
|
||||
'foreignKey' => 'address_type_id',
|
||||
]);
|
||||
}
|
||||
|
||||
@ -54,19 +54,20 @@ class AddressTypesTable extends Table
|
||||
public function validationDefault(Validator $validator)
|
||||
{
|
||||
$validator
|
||||
->integer('id')
|
||||
->nonNegativeInteger('id')
|
||||
->allowEmptyString('id', null, 'create');
|
||||
|
||||
$validator
|
||||
->scalar('name')
|
||||
->maxLength('name', 25)
|
||||
->maxLength('name', 45)
|
||||
->requirePresence('name', 'create')
|
||||
->notEmptyString('name');
|
||||
|
||||
$validator
|
||||
->scalar('text')
|
||||
->maxLength('text', 255)
|
||||
->allowEmptyString('text');
|
||||
->requirePresence('text', 'create')
|
||||
->notEmptyString('text');
|
||||
|
||||
return $validator;
|
||||
}
|
||||
|
||||
471
src/Model/Transactions/Record.php
Normal file
471
src/Model/Transactions/Record.php
Normal file
@ -0,0 +1,471 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Model\Transactions;
|
||||
use Cake\I18n\Time;
|
||||
use Cake\ORM\TableRegistry;
|
||||
|
||||
/*
|
||||
* @author: Dario Rekowski
|
||||
*
|
||||
* @date: 2020-11-05
|
||||
*
|
||||
* @brief: Class for reading records from gradido node (pauls json dump format) and translate into community server transaction db format
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
class Signature
|
||||
{
|
||||
private $signature;
|
||||
private $publicKey;
|
||||
|
||||
public function __construct($signature, $pubkey)
|
||||
{
|
||||
$this->signature = $signature;
|
||||
$this->publicKey = $pubkey;
|
||||
}
|
||||
|
||||
public function finalize($transactionId)
|
||||
{
|
||||
$signaturesTable = TableRegistry::getTableLocator()->get('TransactionSignatures');
|
||||
$entity = $signaturesTable->newEntity();
|
||||
$entity->transaction_id = $transactionId;
|
||||
if(count($this->signature) != 128) {
|
||||
return ['state' => 'error', 'msg' => 'invalid signature size', 'details' => count($this->signature)];
|
||||
}
|
||||
if(count($this->publicKey) != 64) {
|
||||
return ['state' => 'error', 'msg' => 'invalid pubkey size', 'details' => count($this->publicKey)];
|
||||
}
|
||||
if(!preg_match('/^[0-9a-fA-F]*$/', $this->signature)) {
|
||||
return ['state' => 'error', 'msg' => 'signature isn\'t in hex format'];
|
||||
}
|
||||
if(!preg_match('/^[0-9a-fA-F]*$/', $this->publicKey)) {
|
||||
return ['state' => 'error', 'msg' => 'publicKey isn\'t in hex format'];
|
||||
}
|
||||
$entity->signature = hex2bin($this->signature);
|
||||
$entity->pubkey = hex2bin($this->publicKey);
|
||||
|
||||
if(!$signaturesTable->save($entity)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving signature', 'details' => $entity->getErrors()];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ManageNodeGroupAdd
|
||||
{
|
||||
/*
|
||||
"add_user": {
|
||||
"user\": " << user << ",
|
||||
},
|
||||
OR
|
||||
|
||||
"move_user_inbound|move_user_outbound": {
|
||||
"user": " << user << ",
|
||||
"other_group": " << other_group << ",
|
||||
"paired_transaction_id": {
|
||||
"seconds": << ts.seconds <<,
|
||||
"nanos": << ts.nanos
|
||||
}
|
||||
},
|
||||
|
||||
*/
|
||||
|
||||
private $user_pubkey;
|
||||
private $other_group = '';
|
||||
private $remove_from_group = false;
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->user_pubkey = $data['user'];
|
||||
if(isset($data['other_group'])) {
|
||||
$this->other_group = $data['other_group'];
|
||||
}
|
||||
}
|
||||
|
||||
public function finalize($transactionId, $received)
|
||||
{
|
||||
$transactionGroupAddadressTable = TableRegistry::getTableLocator()->get('TransactionGroupAddaddress');
|
||||
$stateGroupAddresses = TableRegistry::getTableLocator()->get('StateGroupAddresses');
|
||||
$transactionGroupEntity = $transactionGroupAddadressTable->newEntity();
|
||||
$transactionGroupEntity->transaction_id = $transactionId;
|
||||
if(count($this->user_pubkey) != 64) {
|
||||
return ['state' => 'error', 'msg' => 'invalid size user pubkey', 'details' => count($this->user_pubkey)];
|
||||
}
|
||||
if(!preg_match('/^[0-9a-fA-F]*$/', $this->user_pubkey)) {
|
||||
return ['state' => 'error', 'msg' => 'user_pubkey isn\'t in hex format'];
|
||||
}
|
||||
|
||||
$transactionGroupEntity->public_key = hex2bin($this->user_pubkey);
|
||||
$transactionGroupEntity->remove_from_group = $this->remove_from_group;
|
||||
if(!$transactionGroupAddadressTable->save($transactionGroupEntity)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving TransactionGroupAddaddress Entity', 'details' => $transactionGroupEntity->getErrors()];
|
||||
}
|
||||
$userPubkeyBin = hex2bin($this->user_pubkey);
|
||||
if($this->remove_from_group) {
|
||||
$stateGroup_query = $stateGroupAddresses->find('all')->where(['public_key' => hex2bin($this->user_pubkey)]);
|
||||
if(!$stateGroup_query->isEmpty()) {
|
||||
$stateGroupAddresses->delete($stateGroup_query->first());
|
||||
}
|
||||
} else {
|
||||
$stateGroupAddressesEntity = $stateGroupAddresses->newEntity();
|
||||
$stateGroupAddressesEntity->group_id = 1;
|
||||
$stateGroupAddressesEntity->public_key = $userPubkeyBin;
|
||||
$stateGroupAddressesEntity->address_type_id = 1;
|
||||
if(!$stateGroupAddresses->save($stateGroupAddressesEntity)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving state group addresses entity', 'details' => $stateGroupAddressesEntity->getErrors()];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setRemoveFromGroup($removeFromGroup) {
|
||||
$this->remove_from_group = $removeFromGroup;
|
||||
}
|
||||
}
|
||||
|
||||
class GradidoModifieUserBalance
|
||||
{
|
||||
|
||||
public function getUserId($userPublicKey)
|
||||
{
|
||||
$stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers');
|
||||
$stateUser = $stateUsersTable->find('all')->where(['public_key' => hex2bin($userPublicKey)]);
|
||||
if($stateUser->isEmpty()) {
|
||||
return ['state' => 'error', 'msg' => 'couldn\'t find user via public key'];
|
||||
}
|
||||
return $stateUser->first()->id;
|
||||
}
|
||||
|
||||
public function updateBalance($newBalance, $recordDate, $userId)
|
||||
{
|
||||
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||
$stateBalanceQuery = $stateBalancesTable->find('all')->where(['state_user_id' => $userId]);
|
||||
$entity = null;
|
||||
|
||||
if(!$stateBalanceQuery->isEmpty()) {
|
||||
$entity = $stateBalanceQuery->first();
|
||||
if($entity->record_date != NULL && $entity->record_date > $recordDate) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$entity = $stateBalancesTable->newEntity();
|
||||
$entity->state_user_id = $userId;
|
||||
}
|
||||
$entity->record_date = $recordDate;
|
||||
$entity->amount = $newBalance;
|
||||
if(!$stateBalancesTable->save($entity)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving state balance', 'details' => $entity->getErrors()];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class GradidoCreation extends GradidoModifieUserBalance
|
||||
{
|
||||
/*
|
||||
* "gradido_creation": {
|
||||
"user": " << user << ",
|
||||
"new_balance": << v.new_balance << ,
|
||||
"prev_transfer_rec_num": << v.prev_transfer_rec_num <<,
|
||||
"amount": << v.amount <<
|
||||
}
|
||||
*/
|
||||
private $userPubkey;
|
||||
private $amount;
|
||||
private $targetDate; // seems currently not in node server implementet, use hedera date until it is implemented
|
||||
private $new_balance;
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->userPubkey = $data['user'];
|
||||
$this->amount = $data['amount'];
|
||||
$this->new_balance = $data['new_balance'];
|
||||
//$this->targetDate = $received;
|
||||
}
|
||||
|
||||
public function finalize($transactionId, $received)
|
||||
{
|
||||
// TODO: don't use, after node server transmit correct date
|
||||
$this->targetDate = $received;
|
||||
|
||||
$transactionCreationTable = TableRegistry::getTableLocator()->get('TransactionCreations');
|
||||
|
||||
|
||||
$state_user_id = $this->getUserId($this->userPubkey);
|
||||
if(!is_int($state_user_id)) {
|
||||
return $state_user_id;
|
||||
}
|
||||
|
||||
$entity = $transactionCreationTable->newEntity();
|
||||
$entity->transaction_id = $transactionId;
|
||||
$entity->amount = $this->amount;
|
||||
$entity->target_date = $this->targetDate;
|
||||
$entity->state_user_id = $state_user_id;
|
||||
|
||||
if(!$transactionCreationTable->save($entity)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving create transaction', 'details' => $entity->getErrors()];
|
||||
}
|
||||
|
||||
$balance_result = $this->updateBalance($this->new_balance, $received, $state_user_id);
|
||||
if(is_array($balance_result)) {
|
||||
return $balance_result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class GradidoTransfer extends GradidoModifieUserBalance
|
||||
{
|
||||
/*
|
||||
"local_transfer|inbound_transfer|outbound_transfer": {
|
||||
"sender": {
|
||||
"user": " << sender << ",
|
||||
"new_balance": << tt.sender.new_balance << ,
|
||||
"prev_transfer_rec_num": << tt.sender.prev_transfer_rec_num <<
|
||||
},
|
||||
"receiver": {
|
||||
"user": " << receiver << ",
|
||||
"new_balance": << tt.receiver.new_balance << ,
|
||||
"prev_transfer_rec_num": << tt.receiver.prev_transfer_rec_num <<
|
||||
},
|
||||
"amount": << tt.amount <<
|
||||
},
|
||||
* */
|
||||
private $amount;
|
||||
private $sender_new_balance;
|
||||
private $sender_pubkey;
|
||||
|
||||
private $receiver_pubkey;
|
||||
private $receiver_new_balance;
|
||||
|
||||
public function __construct($data)
|
||||
{
|
||||
$this->amount = $data['amount'];
|
||||
|
||||
$sender = $data['sender'];
|
||||
$this->sender_pubkey = $sender['user'];
|
||||
$this->sender_new_balance = $sender['new_balance'];
|
||||
|
||||
$receiver = $data['receiver'];
|
||||
$this->receiver_pubkey = $receiver['user'];
|
||||
$this->receiver_new_balance = $receiver['new_balance'];
|
||||
|
||||
}
|
||||
|
||||
public function finalize($transactionId, $received)
|
||||
{
|
||||
$transactionTransferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins');
|
||||
if(count($this->sender_pubkey) != 64) {
|
||||
return ['state' => 'error', 'msg' => 'invalid size sender pubkey', 'details' => count($this->user_pubkey)];
|
||||
}
|
||||
if(!preg_match('/^[0-9a-fA-F]*$/', $this->sender_pubkey)) {
|
||||
return ['state' => 'error', 'msg' => 'sender_pubkey isn\'t in hex format'];
|
||||
}
|
||||
if(count($this->receiver_pubkey) != 64) {
|
||||
return ['state' => 'error', 'msg' => 'invalid size receiver pubkey', 'details' => count($this->user_pubkey)];
|
||||
}
|
||||
if(!preg_match('/^[0-9a-fA-F]*$/', $this->receiver_pubkey)) {
|
||||
return ['state' => 'error', 'msg' => 'receiver_pubkey isn\'t in hex format'];
|
||||
}
|
||||
|
||||
$sender_id = $this->getUserId($this->sender_pubkey);
|
||||
$receiver_id = $this->getUserId($this->receiver_pubkey);
|
||||
if(is_array($sender_id) && is_array($receiver_id)) {
|
||||
return ['state' => 'error', 'msg' => 'neither sender or receiver known'];
|
||||
}
|
||||
$transferEntity = $transactionTransferTable->newEntity();
|
||||
$transferEntity->transaction_id = $transactionId;
|
||||
$transferEntity->sender_public_key = hex2bin($this->sender_pubkey);
|
||||
$transferEntity->receiver_public_key = hex2bin($this->receiver_pubkey);
|
||||
$transferEntity->amount = $this->amount;
|
||||
$transferEntity->sender_final_balance = $this->sender_new_balance;
|
||||
|
||||
if(is_int($sender_id) && $sender_id > 0) {
|
||||
$transferEntity->state_user_id = $sender_id;
|
||||
$balance_result = $this->updateBalance($this->sender_new_balance, $received, $sender_id);
|
||||
if(is_array($balance_result)) {
|
||||
return $balance_result;
|
||||
}
|
||||
}
|
||||
if(is_int($receiver_id) && $receiver_id > 0) {
|
||||
$transferEntity->receiver_user_id = $receiver_id;
|
||||
$balance_result = $this->updateBalance($this->receiver_new_balance, $received, $receiver_id);
|
||||
if(is_array($balance_result)) {
|
||||
return $balance_result;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$transactionTransferTable->save($transferEntity)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving transaction send coins entity', 'details' => $transferEntity->getErrors()];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class Record
|
||||
{
|
||||
private $sequenceNumber = 0;
|
||||
private $transactionType = '';
|
||||
private $memo = '';
|
||||
private $signatures = [];
|
||||
private $received;
|
||||
private $transactionObj = null;
|
||||
private $result;
|
||||
private $partCount = 0;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function parseRecord($json) {
|
||||
switch($json['record_type']) {
|
||||
case 'GRADIDO_TRANSACTION':
|
||||
return $this->parseTransaction($json['transaction']);
|
||||
case 'MEMO':
|
||||
$this->memo = $json['memo'];
|
||||
return true;
|
||||
case 'SIGNATURES':
|
||||
return $this->parseSignatures($json['signature']);
|
||||
case 'STRUCTURALLY_BAD_MESSAGE':
|
||||
case 'RAW_MESSAGE':
|
||||
case 'BLANK':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief save data parts in db
|
||||
*/
|
||||
public function finalize()
|
||||
{
|
||||
$transactionTypesTable = TableRegistry::getTableLocator()->get('TransactionTypes');
|
||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||
|
||||
$transactionTypeName = $this->nodeTransactionTypeToDBTransactionType($this->transactionType);
|
||||
$transactionTypeResults = $transactionTypesTable->find('all')->where(['name' => $transactionTypeName]);
|
||||
if($transactionTypeResults->isEmpty()) {
|
||||
return [
|
||||
'state' => 'error', 'msg' => 'transaction type not found',
|
||||
'details' => ['nodeType' => $this->transactionType, 'dbType' => $transactionTypeName]
|
||||
];
|
||||
}
|
||||
if(!$this->transactionObj) {
|
||||
return ['state' => 'error', 'msg' => 'transaction obj is null'];
|
||||
}
|
||||
if($this->sequenceNumber <= 0) {
|
||||
return ['state' => 'error', 'msg' => 'sequence number invalid', 'details' => $this->sequenceNumber];
|
||||
}
|
||||
$transactionExistResult = $transactionsTable->find('all')->where(['id' => $this->sequenceNumber]);
|
||||
if(!$transactionExistResult->isEmpty()) {
|
||||
return ['state' => 'warning', 'msg' => 'transaction already exist in db', 'details' => $this->sequenceNumber];
|
||||
}
|
||||
$newTransaction = $transactionsTable->newEntity();
|
||||
$newTransaction->id = $this->sequenceNumber;
|
||||
$newTransaction->transaction_type_id = $transactionTypeResults->first()->id;
|
||||
$newTransaction->memo = $this->memo;
|
||||
$newTransaction->received = $this->received;
|
||||
|
||||
if(!$transactionsTable->save($newTransaction)) {
|
||||
return ['state' => 'error', 'msg' => 'error saving transaction', 'details' => $newTransaction->getErrors()];
|
||||
}
|
||||
foreach($this->signatures as $sign) {
|
||||
$sign_result = $sign->finalize($this->sequenceNumber);
|
||||
iF($sign_result != true) {
|
||||
return ['state' => 'error', 'msg', 'error finalizing signature', 'details' => $sign_result];
|
||||
}
|
||||
}
|
||||
$transaction_obj_result = $this->transactionObj->finalize($newTransaction->id, $this->received);
|
||||
if($transaction_obj_result != true) {
|
||||
return ['state' => 'error', 'msg' => 'error finalizing transaction object', 'details' => $transaction_obj_result];
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private function nodeTransactionTypeToDBTransactionType($nodeTransactionType)
|
||||
{
|
||||
switch($nodeTransactionType) {
|
||||
case 'GRADIDO_CREATION':
|
||||
return 'creation';
|
||||
|
||||
case 'MOVE_USER_INBOUND':
|
||||
case 'ADD_USER':
|
||||
return 'group add member';
|
||||
|
||||
case 'MOVE_USER_OUTBOUND':
|
||||
return 'group remove member';
|
||||
|
||||
case 'LOCAL_TRANSFER':
|
||||
case 'INBOUND_TRANSFER':
|
||||
case 'OUTBOUND_TRANSFER':
|
||||
return 'transfer';
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
private function parseSignatures($signaturesArray)
|
||||
{
|
||||
foreach($signaturesArray as $sign) {
|
||||
$this->signatures[] = new Signature($sign['signature'], $sign['pubkey']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function parseTransaction($data)
|
||||
{
|
||||
$this->transactionType = $data['transaction_type'];
|
||||
$sign = $data['signature'];
|
||||
$this->signatures[] = new Signature($sign['signature'], $sign['pubkey']);
|
||||
|
||||
$hedera = $data['hedera_transaction'];
|
||||
$this->sequenceNumber = $hedera['sequenceNumber'];
|
||||
$this->received = Time::createFromTimestamp($hedera['consensusTimestamp']['seconds']);
|
||||
|
||||
$field_index = '';
|
||||
$class_name = '';
|
||||
|
||||
$removeFromGroup = false;
|
||||
switch($this->transactionType)
|
||||
{
|
||||
case 'GRADIDO_CREATION': $field_index = 'gradido_creation'; $class_name = 'GradidoCreation'; break;
|
||||
case 'ADD_USER': $field_index = 'add_user'; $class_name = 'ManageNodeGroupAdd'; break;
|
||||
case 'MOVE_USER_INBOUND': $field_index = 'move_user_inbound'; $class_name = 'ManageNodeGroupAdd'; break;
|
||||
case 'MOVE_USER_OUTBOUND': $field_index = 'move_user_outbound'; $class_name = 'ManageNodeGroupAdd'; $removeFromGroup = true; break;
|
||||
case 'LOCAL_TRANSFER': $field_index = 'local_transfer'; $class_name = 'GradidoTransfer'; break;
|
||||
case 'INBOUND_TRANSFER': $field_index = 'inbound_transfer'; $class_name = 'GradidoTransfer'; break;
|
||||
case 'OUTBOUND_TRANSFER': $field_index = 'outbound_transfer'; $class_name = 'GradidoTransfer'; break;
|
||||
}
|
||||
if($class_name == '' || $field_index == '') {
|
||||
return ['state' => 'error', 'msg' => 'node transaction type unknown', 'details' => $this->transactionType];
|
||||
}
|
||||
$this->transactionObj = new $class_name($data[$field_index]);
|
||||
if($class_name == 'ManageNodeGroupAdd') {
|
||||
$this->transactionObj->setRemoveFromGroup($removeFromGroup);
|
||||
}
|
||||
|
||||
$this->result = $data['result'];
|
||||
$this->partCount = intval($data['parts']);
|
||||
$this->memo = $data['memo'];
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getSequenceNumber() {
|
||||
return $this->sequenceNumber;
|
||||
}
|
||||
public function getPartCount() {
|
||||
return $this->partCount;
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,8 +4,8 @@
|
||||
* @var \App\Model\Entity\AddressType $addressType
|
||||
*/
|
||||
?>
|
||||
<nav id="actions-sidebar">
|
||||
<ul class="nav-horizontal nav-smaller">
|
||||
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||
<ul class="side-nav">
|
||||
<li class="heading"><?= __('Actions') ?></li>
|
||||
<li><?= $this->Html->link(__('List Address Types'), ['action' => 'index']) ?></li>
|
||||
<li><?= $this->Html->link(__('List State Group Addresses'), ['controller' => 'StateGroupAddresses', 'action' => 'index']) ?></li>
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
* @var \App\Model\Entity\AddressType $addressType
|
||||
*/
|
||||
?>
|
||||
<nav id="actions-sidebar">
|
||||
<ul class="nav-horizontal nav-smaller">
|
||||
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||
<ul class="side-nav">
|
||||
<li class="heading"><?= __('Actions') ?></li>
|
||||
<li><?= $this->Form->postLink(
|
||||
__('Delete'),
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
* @var \App\Model\Entity\AddressType[]|\Cake\Collection\CollectionInterface $addressTypes
|
||||
*/
|
||||
?>
|
||||
<nav id="actions-sidebar">
|
||||
<ul class="nav-horizontal nav-smaller">
|
||||
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||
<ul class="side-nav">
|
||||
<li class="heading"><?= __('Actions') ?></li>
|
||||
<li><?= $this->Html->link(__('New Address Type'), ['action' => 'add']) ?></li>
|
||||
<li><?= $this->Html->link(__('List State Group Addresses'), ['controller' => 'StateGroupAddresses', 'action' => 'index']) ?></li>
|
||||
@ -40,8 +40,8 @@
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<ul class="nav-horizontal">
|
||||
<div class="paginator">
|
||||
<ul class="pagination">
|
||||
<?= $this->Paginator->first('<< ' . __('first')) ?>
|
||||
<?= $this->Paginator->prev('< ' . __('previous')) ?>
|
||||
<?= $this->Paginator->numbers() ?>
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
* @var \App\Model\Entity\AddressType $addressType
|
||||
*/
|
||||
?>
|
||||
<nav id="actions-sidebar">
|
||||
<ul class="nav-horizontal nav-smaller">
|
||||
<nav class="large-3 medium-4 columns" id="actions-sidebar">
|
||||
<ul class="side-nav">
|
||||
<li class="heading"><?= __('Actions') ?></li>
|
||||
<li><?= $this->Html->link(__('Edit Address Type'), ['action' => 'edit', $addressType->id]) ?> </li>
|
||||
<li><?= $this->Form->postLink(__('Delete Address Type'), ['action' => 'delete', $addressType->id], ['confirm' => __('Are you sure you want to delete # {0}?', $addressType->id)]) ?> </li>
|
||||
@ -39,7 +39,7 @@
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<th scope="col"><?= __('Id') ?></th>
|
||||
<th scope="col"><?= __('State Group Id') ?></th>
|
||||
<th scope="col"><?= __('Group Id') ?></th>
|
||||
<th scope="col"><?= __('Public Key') ?></th>
|
||||
<th scope="col"><?= __('Address Type Id') ?></th>
|
||||
<th scope="col" class="actions"><?= __('Actions') ?></th>
|
||||
@ -47,7 +47,7 @@
|
||||
<?php foreach ($addressType->state_group_addresses as $stateGroupAddresses): ?>
|
||||
<tr>
|
||||
<td><?= h($stateGroupAddresses->id) ?></td>
|
||||
<td><?= h($stateGroupAddresses->state_group_id) ?></td>
|
||||
<td><?= h($stateGroupAddresses->group_id) ?></td>
|
||||
<td><?= h($stateGroupAddresses->public_key) ?></td>
|
||||
<td><?= h($stateGroupAddresses->address_type_id) ?></td>
|
||||
<td class="actions">
|
||||
@ -68,6 +68,7 @@
|
||||
<th scope="col"><?= __('Id') ?></th>
|
||||
<th scope="col"><?= __('Transaction Id') ?></th>
|
||||
<th scope="col"><?= __('Address Type Id') ?></th>
|
||||
<th scope="col"><?= __('Remove From Group') ?></th>
|
||||
<th scope="col"><?= __('Public Key') ?></th>
|
||||
<th scope="col" class="actions"><?= __('Actions') ?></th>
|
||||
</tr>
|
||||
@ -76,6 +77,7 @@
|
||||
<td><?= h($transactionGroupAddaddress->id) ?></td>
|
||||
<td><?= h($transactionGroupAddaddress->transaction_id) ?></td>
|
||||
<td><?= h($transactionGroupAddaddress->address_type_id) ?></td>
|
||||
<td><?= h($transactionGroupAddaddress->remove_from_group) ?></td>
|
||||
<td><?= h($transactionGroupAddaddress->public_key) ?></td>
|
||||
<td class="actions">
|
||||
<?= $this->Html->link(__('View'), ['controller' => 'TransactionGroupAddaddress', 'action' => 'view', $transactionGroupAddaddress->id]) ?>
|
||||
|
||||
@ -58,8 +58,10 @@ $this->assign('header', $header);
|
||||
<a href="mailto:<?= $transaction['email'] ?>" title="<?= $transaction['email'] ?>">
|
||||
<small class="tx-email"><?= $transaction['name'] ?></small>
|
||||
</a>
|
||||
<?php else : ?>
|
||||
<?php elseif(isset($transaction['name']) && $transaction['name'] != '') : ?>
|
||||
<small class="tx-email"><?= $transaction['name'] ?></small>
|
||||
<?php else : ?>
|
||||
<small class="tx-email"><?= $transaction['pubkey'] ?></small>
|
||||
<?php endif; ?>
|
||||
<!-- noch ungeklärt - icon ist nicht aligned -->
|
||||
<div class="cell-icon <?= $cellColorClass ?>">
|
||||
|
||||
@ -15,15 +15,15 @@ class AddressTypesFixture extends TestFixture
|
||||
*/
|
||||
// @codingStandardsIgnoreStart
|
||||
public $fields = [
|
||||
'id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
|
||||
'name' => ['type' => 'string', 'length' => 25, 'null' => false, 'default' => null, 'collate' => 'utf8_bin', 'comment' => '', 'precision' => null, 'fixed' => null],
|
||||
'text' => ['type' => 'string', 'length' => 255, 'null' => true, 'default' => null, 'collate' => 'utf8_bin', 'comment' => '', 'precision' => null, 'fixed' => null],
|
||||
'id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null],
|
||||
'name' => ['type' => 'string', 'length' => 45, 'null' => false, 'default' => null, 'collate' => 'utf8mb4_unicode_ci', 'comment' => '', 'precision' => null, 'fixed' => null],
|
||||
'text' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'collate' => 'utf8mb4_unicode_ci', 'comment' => '', 'precision' => null, 'fixed' => null],
|
||||
'_constraints' => [
|
||||
'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []],
|
||||
],
|
||||
'_options' => [
|
||||
'engine' => 'InnoDB',
|
||||
'collation' => 'utf8_bin'
|
||||
'collation' => 'utf8mb4_unicode_ci'
|
||||
],
|
||||
];
|
||||
// @codingStandardsIgnoreEnd
|
||||
@ -37,8 +37,8 @@ class AddressTypesFixture extends TestFixture
|
||||
$this->records = [
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => 'Lorem ipsum dolor sit a',
|
||||
'text' => 'Lorem ipsum dolor sit amet'
|
||||
'name' => 'Lorem ipsum dolor sit amet',
|
||||
'text' => 'Lorem ipsum dolor sit amet',
|
||||
],
|
||||
];
|
||||
parent::init();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user