From 4dc4451b2f48546fc774229eb20e8c95263ec5f3 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 23 Sep 2024 19:11:00 +0200 Subject: [PATCH] adjustments --- .../apis/dltConnector/DltConnectorClient.ts | 28 +++++-- backend/src/graphql/resolver/UserResolver.ts | 5 +- .../tasks/sendTransactionsToDltConnector.ts | 84 ++++++++++++------- .../DltTransaction.ts | 36 ++++++++ .../0087-add_dlt_users_table/DltUser.ts | 3 + database/entity/DltTransaction.ts | 2 +- .../migrations/0087-add_dlt_users_table.ts | 27 ++++-- dlt-connector/src/client/GradidoNode.ts | 2 +- .../src/graphql/input/TransactionDraft.ts | 8 +- dlt-connector/src/index.ts | 16 +++- .../sendToIota/CreationTransaction.role.ts | 1 + .../sendToIota/TransferTransaction.role.ts | 1 + .../logging/TransactionDraftLogging.view.ts | 1 - 13 files changed, 161 insertions(+), 53 deletions(-) create mode 100644 database/entity/0087-add_dlt_users_table/DltTransaction.ts diff --git a/backend/src/apis/dltConnector/DltConnectorClient.ts b/backend/src/apis/dltConnector/DltConnectorClient.ts index 4737d95bc..75e9b2544 100644 --- a/backend/src/apis/dltConnector/DltConnectorClient.ts +++ b/backend/src/apis/dltConnector/DltConnectorClient.ts @@ -13,13 +13,18 @@ import { UserAccountDraft } from './model/UserAccountDraft' import { UserIdentifier } from './model/UserIdentifier' const sendTransaction = gql` - mutation ($input: TransactionInput!) { + mutation ($input: TransactionDraft!) { sendTransaction(data: $input) { error { message name } succeed + recipe { + createdAt + type + messageIdHex + } } } ` @@ -32,6 +37,11 @@ const registerAddress = gql` name } succeed + recipe { + createdAt + type + messageIdHex + } } } ` @@ -126,7 +136,6 @@ export class DltConnectorClient { amount: amountString, type: typeString, createdAt: transaction.balanceDate.toISOString(), - backendTransactionId: transaction.id, targetDate: transaction.creationDate?.toISOString(), }, } @@ -142,9 +151,14 @@ export class DltConnectorClient { if (result.error) { throw new Error(result.error.message) } + console.log(result) return result } catch (e) { - throw new LogError('Error send sending transaction to dlt-connector: ', e) + if (e instanceof Error) { + throw new LogError(`from dlt-connector: ${e.message}`) + } else { + throw new LogError('Exception sending transfer transaction to dlt-connector', e) + } } } @@ -172,11 +186,15 @@ export class DltConnectorClient { result, }) if (result.error) { - logger.error('Error sending register address transaction to dlt-connector', result.error) + throw new Error(result.error.message) } return result } catch (e) { - logger.error('Exception sending register address transaction to dlt-connector', e) + if (e instanceof Error) { + throw new LogError(`from dlt-connector: ${e.message}`) + } else { + throw new LogError('Exception sending register address transaction to dlt-connector', e) + } } } } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 6ddd15705..9dbbba1f1 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -66,7 +66,10 @@ import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' import { communityDbUser } from '@/util/communityUser' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { InterruptiveSleepManager, TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY } from '@/util/InterruptiveSleepManager' +import { + InterruptiveSleepManager, + TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY, +} from '@/util/InterruptiveSleepManager' import { getTimeDurationObject, printTimeDuration } from '@/util/time' import random from 'random-bigint' diff --git a/backend/src/tasks/sendTransactionsToDltConnector.ts b/backend/src/tasks/sendTransactionsToDltConnector.ts index 26535e082..62c7c5ad7 100644 --- a/backend/src/tasks/sendTransactionsToDltConnector.ts +++ b/backend/src/tasks/sendTransactionsToDltConnector.ts @@ -33,31 +33,60 @@ export async function sendTransactionsToDltConnector(): Promise { while (true) { const pendingTransaction = await findNextPendingTransaction() if (pendingTransaction instanceof User) { - const result = await dltConnector.registerAddress(pendingTransaction) - if (result?.succeed && result.recipe) { - const dltUser = DltUser.create() - dltUser.userId = pendingTransaction.id - dltUser.messageId = result.recipe.messageIdHex - // wait until saved, necessary before next call to findNextPendingTransaction - await DltUser.save(dltUser) - logger.info('store dltUser: messageId=%s in dltTx=%d', dltUser.messageId, dltUser.id) + const dltUser = DltUser.create() + dltUser.userId = pendingTransaction.id + try { + const result = await dltConnector.registerAddress(pendingTransaction) + if (result?.succeed && result.recipe) { + dltUser.messageId = result.recipe.messageIdHex + } + } catch (e) { + if (e instanceof Error) { + dltUser.error = e.message + } else if (typeof e === 'string') { + dltUser.error = e + } + } + // wait until saved, necessary before next call to findNextPendingTransaction + await DltUser.save(dltUser) + if (dltUser.messageId) { + logger.info('store dltUser: messageId=%s, id=%d', dltUser.messageId, dltUser.id) + } else { + logger.error('store dltUser with error: id=%d, error=%s', dltUser.id, dltUser.error) } } else if (pendingTransaction instanceof Transaction) { - const result = await dltConnector.transmitTransaction(pendingTransaction) - if (result?.succeed && result.recipe) { - const dltTransaction = DltTransaction.create() - dltTransaction.transactionId = pendingTransaction.id - dltTransaction.messageId = result.recipe.messageIdHex - // wait until saved, necessary before next call to findNextPendingTransaction - await DltTransaction.save(dltTransaction) + const dltTransaction = DltTransaction.create() + dltTransaction.transactionId = pendingTransaction.id + try { + const result = await dltConnector.transmitTransaction(pendingTransaction) + if (result?.succeed && result.recipe) { + dltTransaction.messageId = result.recipe.messageIdHex + } else { + dltTransaction.error = 'skipped' + } + } catch (e) { + if (e instanceof Error) { + dltTransaction.error = e.message + } else if (typeof e === 'string') { + dltTransaction.error = e + } + } + // wait until saved, necessary before next call to findNextPendingTransaction + await DltTransaction.save(dltTransaction) + if (dltTransaction.messageId) { logger.info( - 'store dltTransaction: messageId=%s in dltTx=%d', + 'store dltTransaction: messageId=%s, id=%d', dltTransaction.messageId, dltTransaction.id, ) + } else { + logger.error( + 'store dltTransaction with error: id=%d, error=%s', + dltTransaction.id, + dltTransaction.error, + ) } } else { - // nothing to do, break inner loop and sleep until new work has arrived break } } @@ -72,22 +101,21 @@ export async function sendTransactionsToDltConnector(): Promise { } async function findNextPendingTransaction(): Promise { - const lastTransactionPromise: Promise = Transaction.createQueryBuilder() - .select() - .leftJoin(DltTransaction, 'dltTransaction', 'transaction.id = dltTransaction.transactionId') - .where('dltTransaction.transactionId IS NULL') + const lastTransactionPromise: Promise = Transaction.createQueryBuilder() + .leftJoin(DltTransaction, 'dltTransaction', 'Transaction.id = dltTransaction.transactionId') + .where('dltTransaction.transaction_id IS NULL') // eslint-disable-next-line camelcase - .orderBy({ balance_date: 'ASC', id: 'ASC' }) + .orderBy({ balance_date: 'ASC', Transaction_id: 'ASC' }) .limit(1) - .getRawOne() + .getOne() - const lastUserPromise: Promise = User.createQueryBuilder() - .leftJoin(DltUser, 'dltUser', 'user.id = dltUser.userId') - .where('dltUser.userId IS NULL') + const lastUserPromise: Promise = User.createQueryBuilder() + .leftJoin(DltUser, 'dltUser', 'User.id = dltUser.userId') + .where('dltUser.user_id IS NULL') // eslint-disable-next-line camelcase - .orderBy({ created_at: 'ASC', id: 'ASC' }) + .orderBy({ User_created_at: 'ASC', User_id: 'ASC' }) .limit(1) - .getRawOne() + .getOne() const results = await Promise.all([lastTransactionPromise, lastUserPromise]) if (results[0] && results[1]) { diff --git a/database/entity/0087-add_dlt_users_table/DltTransaction.ts b/database/entity/0087-add_dlt_users_table/DltTransaction.ts new file mode 100644 index 000000000..653077bac --- /dev/null +++ b/database/entity/0087-add_dlt_users_table/DltTransaction.ts @@ -0,0 +1,36 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm' +import { Transaction } from '../Transaction' + +@Entity('dlt_transactions', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class DltTransaction extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: false }) + transactionId: number + + @Column({ + name: 'message_id', + length: 64, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + messageId: string + + @Column({ name: 'verified', type: 'bool', nullable: false, default: false }) + verified: boolean + + @Column({ name: 'created_at', default: () => 'CURRENT_TIMESTAMP(3)', nullable: false }) + createdAt: Date + + @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) + verifiedAt: Date | null + + @Column({ name: 'error', type: 'text', nullable: true }) + error: string | null + + @OneToOne(() => Transaction, (transaction) => transaction.dltTransaction) + @JoinColumn({ name: 'transaction_id' }) + transaction?: Transaction | null +} diff --git a/database/entity/0087-add_dlt_users_table/DltUser.ts b/database/entity/0087-add_dlt_users_table/DltUser.ts index ca916e128..483437d58 100644 --- a/database/entity/0087-add_dlt_users_table/DltUser.ts +++ b/database/entity/0087-add_dlt_users_table/DltUser.ts @@ -27,6 +27,9 @@ export class DltUser extends BaseEntity { @Column({ name: 'verified_at', nullable: true, default: null, type: 'datetime' }) verifiedAt: Date | null + @Column({ name: 'error', type: 'text', nullable: true }) + error: string | null + @OneToOne(() => User, (user) => user.dltUser) @JoinColumn({ name: 'user_id' }) user?: User | null diff --git a/database/entity/DltTransaction.ts b/database/entity/DltTransaction.ts index d9c03306c..31c21d583 100644 --- a/database/entity/DltTransaction.ts +++ b/database/entity/DltTransaction.ts @@ -1 +1 @@ -export { DltTransaction } from './0070-add_dlt_transactions_table/DltTransaction' +export { DltTransaction } from './0087-add_dlt_users_table/DltTransaction' diff --git a/database/migrations/0087-add_dlt_users_table.ts b/database/migrations/0087-add_dlt_users_table.ts index fdb310c67..95f5c2ca2 100644 --- a/database/migrations/0087-add_dlt_users_table.ts +++ b/database/migrations/0087-add_dlt_users_table.ts @@ -3,17 +3,28 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { await queryFn(` - CREATE TABLE dlt_users ( - id int unsigned NOT NULL AUTO_INCREMENT, - user_id int(10) unsigned NOT NULL, - message_id varchar(64) NULL DEFAULT NULL, - verified tinyint(4) NOT NULL DEFAULT 0, - created_at datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), - verified_at datetime(3), + CREATE TABLE \`dlt_users\` ( + \`id\` int unsigned NOT NULL AUTO_INCREMENT, + \`user_id\` int(10) unsigned NOT NULL, + \`message_id\` varchar(64) NULL DEFAULT NULL, + \`verified\` tinyint(4) NOT NULL DEFAULT 0, + \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + \`verified_at\` datetime(3), + \`error\` text NULL DEFAULT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) + + await queryFn( + 'ALTER TABLE `dlt_transactions` RENAME COLUMN `transactions_id` TO `transaction_id`;', + ) + await queryFn('ALTER TABLE `dlt_transactions` ADD COLUMN `error` text NULL DEFAULT NULL;') } export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(`DROP TABLE dlt_users;`) + await queryFn(`DROP TABLE \`dlt_users\`;`) + + await queryFn( + 'ALTER TABLE `dlt_transactions` RENAME COLUMN `transaction_id` TO `transactions_id`;', + ) + await queryFn('ALTER TABLE `dlt_transactions` DROP COLUMN `error`;') } diff --git a/dlt-connector/src/client/GradidoNode.ts b/dlt-connector/src/client/GradidoNode.ts index 92a211768..a33e5adc2 100644 --- a/dlt-connector/src/client/GradidoNode.ts +++ b/dlt-connector/src/client/GradidoNode.ts @@ -6,7 +6,7 @@ import { JsonRpcEitherResponse } from 'jsonrpc-ts-client/dist/types/utils/jsonrp import { CONFIG } from '@/config' import { logger } from '@/logging/logger' import { LogError } from '@/server/LogError' -import { confirmedTransactionFromBase64, getEnumValue } from '@/utils/typeConverter' +import { confirmedTransactionFromBase64 } from '@/utils/typeConverter' const client = new JsonRpcClient({ url: CONFIG.NODE_SERVER_URL, diff --git a/dlt-connector/src/graphql/input/TransactionDraft.ts b/dlt-connector/src/graphql/input/TransactionDraft.ts index 59e1ecafd..d1fa48c3c 100755 --- a/dlt-connector/src/graphql/input/TransactionDraft.ts +++ b/dlt-connector/src/graphql/input/TransactionDraft.ts @@ -1,8 +1,8 @@ // https://www.npmjs.com/package/@apollo/protobufjs import { InputTransactionType } from '@enum/InputTransactionType' import { isValidDateString, isValidNumberString } from '@validator/DateString' -import { IsEnum, IsObject, IsPositive, ValidateNested } from 'class-validator' -import { InputType, Field, Int } from 'type-graphql' +import { IsEnum, IsObject, ValidateNested } from 'class-validator' +import { InputType, Field } from 'type-graphql' import { UserIdentifier } from './UserIdentifier' @@ -18,10 +18,6 @@ export class TransactionDraft { @ValidateNested() linkedUser: UserIdentifier - @Field(() => Int) - @IsPositive() - backendTransactionId: number - @Field(() => String) @isValidNumberString() amount: string diff --git a/dlt-connector/src/index.ts b/dlt-connector/src/index.ts index c025296fd..ac5366127 100644 --- a/dlt-connector/src/index.ts +++ b/dlt-connector/src/index.ts @@ -72,9 +72,21 @@ async function main() { const communityDraft = await backend.getHomeCommunityDraft() KeyPairCacheManager.getInstance().setHomeCommunityUUID(communityDraft.uuid) + logger.info('home community topic: %s', uuid4ToHash(communityDraft.uuid).convertToHex()) + logger.info('gradido node server: %s', CONFIG.NODE_SERVER_URL) // ask gradido node if community blockchain was created - const firstTransaction = await getTransaction(1, uuid4ToHash(communityDraft.uuid).convertToHex()) - if (!firstTransaction) { + try { + const firstTransaction = await getTransaction( + 1, + uuid4ToHash(communityDraft.uuid).convertToHex(), + ) + if (!firstTransaction) { + // if not exist, create community root transaction + await SendToIotaContext(communityDraft) + } + } catch (e) { + // eslint-disable-next-line no-console + // console.log('error requesting gradido node: ', e) // if not exist, create community root transaction await SendToIotaContext(communityDraft) } diff --git a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts index 0e80e19a4..b7a074a7a 100644 --- a/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/CreationTransaction.role.ts @@ -29,6 +29,7 @@ export class CreationTransactionRole extends AbstractTransactionRole { } builder .setCreatedAt(new Date(this.self.createdAt)) + .setMemo('dummy memo for creation') .setTransactionCreation( new TransferAmount(recipientKeyPair.getPublicKey(), this.self.amount.toString()), new Date(this.self.targetDate), diff --git a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts index c26f8c61f..e0749f002 100644 --- a/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToIota/TransferTransaction.role.ts @@ -26,6 +26,7 @@ export class TransferTransactionRole extends AbstractTransactionRole { const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser) builder .setCreatedAt(new Date(this.self.createdAt)) + .setMemo('dummy memo for transfer') .setTransactionTransfer( new TransferAmount(senderKeyPair.getPublicKey(), this.self.amount.toString()), recipientKeyPair.getPublicKey(), diff --git a/dlt-connector/src/logging/TransactionDraftLogging.view.ts b/dlt-connector/src/logging/TransactionDraftLogging.view.ts index 655a9ab9e..b68f6d746 100644 --- a/dlt-connector/src/logging/TransactionDraftLogging.view.ts +++ b/dlt-connector/src/logging/TransactionDraftLogging.view.ts @@ -15,7 +15,6 @@ export class TransactionDraftLoggingView extends AbstractLoggingView { return { user: new UserIdentifierLoggingView(this.self.user).toJSON(), linkedUser: new UserIdentifierLoggingView(this.self.linkedUser).toJSON(), - backendTransactionId: this.self.backendTransactionId, amount: Number(this.self.amount), type: getEnumValue(InputTransactionType, this.self.type), createdAt: this.self.createdAt,