adjustments

This commit is contained in:
einhornimmond 2024-09-23 19:11:00 +02:00
parent e1cc58381e
commit 4dc4451b2f
13 changed files with 161 additions and 53 deletions

View File

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

View File

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

View File

@ -33,31 +33,60 @@ export async function sendTransactionsToDltConnector(): Promise<void> {
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<void> {
}
async function findNextPendingTransaction(): Promise<Transaction | User | null> {
const lastTransactionPromise: Promise<Transaction | undefined> = Transaction.createQueryBuilder()
.select()
.leftJoin(DltTransaction, 'dltTransaction', 'transaction.id = dltTransaction.transactionId')
.where('dltTransaction.transactionId IS NULL')
const lastTransactionPromise: Promise<Transaction | null> = 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 | undefined> = User.createQueryBuilder()
.leftJoin(DltUser, 'dltUser', 'user.id = dltUser.userId')
.where('dltUser.userId IS NULL')
const lastUserPromise: Promise<User | null> = 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]) {

View File

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

View File

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

View File

@ -1 +1 @@
export { DltTransaction } from './0070-add_dlt_transactions_table/DltTransaction'
export { DltTransaction } from './0087-add_dlt_users_table/DltTransaction'

View File

@ -3,17 +3,28 @@
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
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<Array<any>>) {
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`;')
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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