finish parsing transactions from gradido node

This commit is contained in:
Dario Rekowski on RockPI 2020-11-06 14:10:38 +00:00 committed by Ulf Gebhardt
parent 01f0bd5323
commit bd6640388d
No known key found for this signature in database
GPG Key ID: 81308EFE29ABFEBD
21 changed files with 586 additions and 45 deletions

View 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;

View File

@ -0,0 +1,2 @@
INSERT INTO `address_types` (`id`, `name`, `text`) VALUES
(1, 'user main', 'user main address');

View File

@ -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');

View File

@ -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;

View File

@ -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;

View File

@ -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`)

View File

@ -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());

View File

@ -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'];
}

View File

@ -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');
}

View File

@ -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']);
}

View File

@ -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'));

View File

@ -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,
];
}

View File

@ -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

View File

@ -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;
}

View 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;
}
}

View File

@ -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>

View File

@ -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'),

View File

@ -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() ?>

View File

@ -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]) ?>

View File

@ -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 ?>">

View File

@ -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();