mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
handle deletiono of transaction link with dlt
This commit is contained in:
parent
a24ed8ef98
commit
ec2d5cb98d
8
backend/src/apis/dltConnector/enum/DltTransactionType.ts
Normal file
8
backend/src/apis/dltConnector/enum/DltTransactionType.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export enum DltTransactionType {
|
||||
REGISTER_ADDRESS = 1,
|
||||
CREATION = 2,
|
||||
TRANSFER = 3,
|
||||
DEFERRED_TRANSFER = 4,
|
||||
REDEEM_DEFERRED_TRANSFER = 5,
|
||||
DELETE_DEFERRED_TRANSFER = 6,
|
||||
}
|
||||
@ -22,7 +22,7 @@ export abstract class AbstractTransactionToDltRole<T extends ObjectLiteral> {
|
||||
const dltTransaction = DltTransaction.create()
|
||||
dltTransaction.messageId = messageId
|
||||
dltTransaction.error = error
|
||||
this.setJoinId(dltTransaction)
|
||||
this.setJoinIdAndType(dltTransaction)
|
||||
await DltTransaction.save(dltTransaction)
|
||||
if (dltTransaction.error) {
|
||||
logger.error(
|
||||
@ -36,7 +36,7 @@ export abstract class AbstractTransactionToDltRole<T extends ObjectLiteral> {
|
||||
}
|
||||
|
||||
// intern
|
||||
protected abstract setJoinId(dltTransaction: DltTransaction): void
|
||||
protected abstract setJoinIdAndType(dltTransaction: DltTransaction): void
|
||||
|
||||
// helper
|
||||
protected createQueryForPendingItems(
|
||||
@ -50,7 +50,6 @@ export abstract class AbstractTransactionToDltRole<T extends ObjectLiteral> {
|
||||
.andWhere('dltTransaction.transaction_id IS NULL')
|
||||
.andWhere('dltTransaction.transaction_link_Id IS NULL')
|
||||
.orderBy(orderBy)
|
||||
.limit(1)
|
||||
}
|
||||
|
||||
protected createDltTransactionEntry(messageId: string, error: string | null): DltTransaction {
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed'
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { UserIdentifier } from '@dltConnector/model/UserIdentifier'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
|
||||
/**
|
||||
* redeem deferred transfer transaction by creator, so "deleting" it
|
||||
*/
|
||||
export class TransactionLinkDeleteToDltRole extends AbstractTransactionToDltRole<TransactionLink> {
|
||||
async initWithLast(): Promise<this> {
|
||||
const queryBuilder = this.createQueryForPendingItems(
|
||||
TransactionLink.createQueryBuilder().leftJoinAndSelect('TransactionLink.user', 'user'),
|
||||
'TransactionLink.id = dltTransaction.transactionLinkId and dltTransaction.type_id <> 4',
|
||||
// eslint-disable-next-line camelcase
|
||||
{ TransactionLink_deletedAt: 'ASC', User_id: 'ASC' },
|
||||
)
|
||||
.andWhere('TransactionLink.deletedAt IS NOT NULL')
|
||||
.withDeleted()
|
||||
const queryBuilder2 = TransactionLink.createQueryBuilder()
|
||||
.leftJoinAndSelect('TransactionLink.user', 'user')
|
||||
.where('TransactionLink.deletedAt IS NOT NULL')
|
||||
.andWhere(() => {
|
||||
const subQuery = DltTransaction.createQueryBuilder()
|
||||
.select('1')
|
||||
.where('DltTransaction.transaction_link_id = TransactionLink.id')
|
||||
.andWhere('DltTransaction.type_id = :typeId', {
|
||||
typeId: DltTransactionType.DELETE_DEFERRED_TRANSFER,
|
||||
})
|
||||
.getQuery()
|
||||
return `NOT EXIST (${subQuery})`
|
||||
})
|
||||
.withDeleted()
|
||||
// eslint-disable-next-line camelcase
|
||||
.orderBy({ TransactionLink_deletedAt: 'ASC', User_id: 'ASC' })
|
||||
// console.log('query: ', queryBuilder.getSql())
|
||||
this.self = await queryBuilder.getOne()
|
||||
return this
|
||||
}
|
||||
|
||||
public getTimestamp(): number {
|
||||
if (!this.self) {
|
||||
return Infinity
|
||||
}
|
||||
if (!this.self.deletedAt) {
|
||||
throw new LogError('not deleted transaction link selected')
|
||||
}
|
||||
return this.self.deletedAt.getTime()
|
||||
}
|
||||
|
||||
public convertToGraphqlInput(): TransactionDraft {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction link')
|
||||
}
|
||||
if (!this.self.deletedAt) {
|
||||
throw new LogError('not deleted transaction link selected')
|
||||
}
|
||||
const draft = new TransactionDraft()
|
||||
draft.amount = this.self.amount.abs().toString()
|
||||
const user = this.self.user
|
||||
draft.user = new UserIdentifier(user.communityUuid, new IdentifierSeed(this.self.code))
|
||||
draft.linkedUser = new UserIdentifier(user.communityUuid, new CommunityUser(user.gradidoID))
|
||||
draft.createdAt = this.self.deletedAt.toISOString()
|
||||
draft.type = TransactionType.GRADIDO_TRANSFER
|
||||
return draft
|
||||
}
|
||||
|
||||
protected setJoinIdAndType(dltTransaction: DltTransaction): void {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction link')
|
||||
}
|
||||
dltTransaction.transactionLinkId = this.self.id
|
||||
dltTransaction.typeId = DltTransactionType.DELETE_DEFERRED_TRANSFER
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed'
|
||||
@ -47,10 +48,11 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole<Trans
|
||||
return draft
|
||||
}
|
||||
|
||||
protected setJoinId(dltTransaction: DltTransaction): void {
|
||||
protected setJoinIdAndType(dltTransaction: DltTransaction): void {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction link')
|
||||
}
|
||||
dltTransaction.transactionLinkId = this.self.id
|
||||
dltTransaction.typeId = DltTransactionType.DEFERRED_TRANSFER
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { IdentifierSeed } from '@dltConnector/model/IdentifierSeed'
|
||||
@ -16,6 +17,7 @@ import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
* send transfer and creations transactions to dlt connector as GradidoTransfer and GradidoCreation
|
||||
*/
|
||||
export class TransactionToDltRole extends AbstractTransactionToDltRole<Transaction> {
|
||||
private type: DltTransactionType
|
||||
async initWithLast(): Promise<this> {
|
||||
this.self = await this.createQueryForPendingItems(
|
||||
Transaction.createQueryBuilder().leftJoinAndSelect(
|
||||
@ -27,7 +29,7 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole<Transacti
|
||||
{ balance_date: 'ASC', Transaction_id: 'ASC' },
|
||||
)
|
||||
// we don't need the receive transactions, there contain basically the same data as the send transactions
|
||||
.andWhere('transaction.typeId NOT :typeId', { typeId: TransactionTypeId.RECEIVE })
|
||||
.andWhere('Transaction.type_id <> :typeId', { typeId: TransactionTypeId.RECEIVE })
|
||||
.getOne()
|
||||
return this
|
||||
}
|
||||
@ -55,6 +57,19 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole<Transacti
|
||||
`missing necessary field in transaction: ${this.self.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`,
|
||||
)
|
||||
}
|
||||
switch (this.self.typeId as TransactionTypeId) {
|
||||
case TransactionTypeId.CREATION:
|
||||
draft.type = TransactionType.GRADIDO_CREATION
|
||||
this.type = DltTransactionType.CREATION
|
||||
break
|
||||
case TransactionTypeId.SEND:
|
||||
case TransactionTypeId.RECEIVE:
|
||||
draft.type = TransactionType.GRADIDO_TRANSFER
|
||||
this.type = DltTransactionType.TRANSFER
|
||||
break
|
||||
default:
|
||||
throw new LogError('wrong role for type', this.self.typeId as TransactionTypeId)
|
||||
}
|
||||
// it is a redeem of a transaction link?
|
||||
const transactionLink = this.self.transactionLink
|
||||
if (transactionLink) {
|
||||
@ -62,6 +77,7 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole<Transacti
|
||||
this.self.userCommunityUuid,
|
||||
new IdentifierSeed(transactionLink.code),
|
||||
)
|
||||
this.type = DltTransactionType.REDEEM_DEFERRED_TRANSFER
|
||||
} else {
|
||||
draft.user = new UserIdentifier(
|
||||
this.self.userCommunityUuid,
|
||||
@ -74,24 +90,14 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole<Transacti
|
||||
)
|
||||
draft.createdAt = this.self.balanceDate.toISOString()
|
||||
draft.targetDate = this.self.creationDate?.toISOString()
|
||||
switch (this.self.typeId as TransactionTypeId) {
|
||||
case TransactionTypeId.CREATION:
|
||||
draft.type = TransactionType.GRADIDO_CREATION
|
||||
break
|
||||
case TransactionTypeId.SEND:
|
||||
case TransactionTypeId.RECEIVE:
|
||||
draft.type = TransactionType.GRADIDO_TRANSFER
|
||||
break
|
||||
default:
|
||||
throw new LogError('wrong role for type', this.self.typeId as TransactionTypeId)
|
||||
}
|
||||
return draft
|
||||
}
|
||||
|
||||
protected setJoinId(dltTransaction: DltTransaction): void {
|
||||
protected setJoinIdAndType(dltTransaction: DltTransaction): void {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction')
|
||||
}
|
||||
dltTransaction.transactionId = this.self.id
|
||||
dltTransaction.typeId = this.type
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { AccountType } from '@dltConnector/enum/AccountType'
|
||||
import { DltTransactionType } from '@dltConnector/enum/DltTransactionType'
|
||||
import { TransactionType } from '@dltConnector/enum/TransactionType'
|
||||
import { CommunityUser } from '@dltConnector/model/CommunityUser'
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
@ -44,10 +45,11 @@ export class UserToDltRole extends AbstractTransactionToDltRole<User> {
|
||||
return draft
|
||||
}
|
||||
|
||||
protected setJoinId(dltTransaction: DltTransaction): void {
|
||||
protected setJoinIdAndType(dltTransaction: DltTransaction): void {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty user')
|
||||
}
|
||||
dltTransaction.userId = this.self.id
|
||||
dltTransaction.typeId = DltTransactionType.REGISTER_ADDRESS
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import { DltConnectorClient } from '@/apis/dltConnector/DltConnectorClient'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
import { AbstractTransactionToDltRole } from './AbstractTransactionToDlt.role'
|
||||
import { TransactionLinkDeleteToDltRole } from './TransactionLinkDeleteToDlt.role'
|
||||
import { TransactionLinkToDltRole } from './TransactionLinkToDlt.role'
|
||||
import { TransactionToDltRole } from './TransactionToDlt.role'
|
||||
import { UserToDltRole } from './UserToDlt.role'
|
||||
@ -23,6 +24,7 @@ export async function transactionToDlt(dltConnector: DltConnectorClient): Promis
|
||||
new TransactionToDltRole().initWithLast(),
|
||||
new UserToDltRole().initWithLast(),
|
||||
new TransactionLinkToDltRole().initWithLast(),
|
||||
new TransactionLinkDeleteToDltRole().initWithLast(),
|
||||
])
|
||||
|
||||
// sort array to get oldest at first place
|
||||
|
||||
@ -33,6 +33,10 @@ import { Context, getUser, getClientTimezoneOffset } from '@/server/context'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
import {
|
||||
InterruptiveSleepManager,
|
||||
TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY,
|
||||
} from '@/util/InterruptiveSleepManager'
|
||||
import { TRANSACTION_LINK_LOCK } from '@/util/TRANSACTION_LINK_LOCK'
|
||||
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
|
||||
import { fullName } from '@/util/utilities'
|
||||
@ -300,6 +304,8 @@ export class TransactionLinkResolver {
|
||||
contributionLink,
|
||||
contributionLink.amount,
|
||||
)
|
||||
// notify dlt-connector loop for new work
|
||||
InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY)
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new LogError('Creation from contribution link was not successful', e)
|
||||
@ -354,6 +360,8 @@ export class TransactionLinkResolver {
|
||||
transactionLink,
|
||||
transactionLink.amount,
|
||||
)
|
||||
// notify dlt-connector loop for new work
|
||||
InterruptiveSleepManager.getInstance().interrupt(TRANSMIT_TO_IOTA_INTERRUPTIVE_SLEEP_KEY)
|
||||
} finally {
|
||||
releaseLinkLock()
|
||||
}
|
||||
|
||||
@ -17,6 +17,9 @@ export class DltTransaction extends BaseEntity {
|
||||
@Column({ name: 'transaction_link_id', type: 'int', unsigned: true, nullable: true })
|
||||
transactionLinkId?: number | null
|
||||
|
||||
@Column({ name: 'type_id', unsigned: true, nullable: false })
|
||||
typeId: number
|
||||
|
||||
@Column({
|
||||
name: 'message_id',
|
||||
length: 64,
|
||||
|
||||
@ -171,6 +171,6 @@ export class Transaction extends BaseEntity {
|
||||
previousTransaction?: Transaction | null
|
||||
|
||||
@ManyToOne(() => TransactionLink, (transactionLink) => transactionLink.transactions)
|
||||
@JoinColumn({ name: 'transactionLinkId' })
|
||||
@JoinColumn({ name: 'transaction_link_id' })
|
||||
transactionLink?: TransactionLink | null
|
||||
}
|
||||
|
||||
@ -80,6 +80,6 @@ export class TransactionLink extends BaseEntity {
|
||||
user: User
|
||||
|
||||
@OneToMany(() => Transaction, (transaction) => transaction.transactionLink)
|
||||
@JoinColumn({ referencedColumnName: 'transactionLinkId' })
|
||||
@JoinColumn({ referencedColumnName: 'transaction_link_id' })
|
||||
transactions: Transaction[]
|
||||
}
|
||||
|
||||
@ -7,7 +7,9 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
|
||||
ALTER TABLE \`dlt_transactions\`
|
||||
CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NULL DEFAULT NULL,
|
||||
ADD \`user_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`transaction_id\`,
|
||||
ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`;
|
||||
ADD \`transaction_link_id\` INT UNSIGNED NULL DEFAULT NULL AFTER \`user_id\`
|
||||
ADD \`type_id\` INT UNSIGNED NOT NULL AFTER \`transaction_link_id\`
|
||||
;
|
||||
`)
|
||||
}
|
||||
|
||||
@ -28,6 +30,8 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom
|
||||
ALTER TABLE \`dlt_transactions\`
|
||||
CHANGE \`transaction_id\` \`transaction_id\` INT(10) UNSIGNED NOT NULL,
|
||||
DROP COLUMN \`user_id\`,
|
||||
DROP COLUMN \`transaction_link_id\`;
|
||||
DROP COLUMN \`transaction_link_id\`
|
||||
DROP COLUMN \`type_id\`
|
||||
;
|
||||
`)
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { KeyPairEd25519 } from 'gradido-blockchain-js'
|
||||
|
||||
import { IdentifierSeed } from '@/graphql/input/IdentifierSeed'
|
||||
import { UserIdentifier } from '@/graphql/input/UserIdentifier'
|
||||
import { logger } from '@/logging/logger'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
// Source: https://refactoring.guru/design-patterns/singleton/typescript/example
|
||||
@ -52,7 +52,8 @@ export class KeyPairCacheManager {
|
||||
public addKeyPair(input: UserIdentifier | string, keyPair: KeyPairEd25519): void {
|
||||
const key = this.getKey(input)
|
||||
if (this.cache.has(key)) {
|
||||
throw new LogError('key already exist, cannot add', key)
|
||||
logger.warn('key already exist, cannot add', key)
|
||||
return
|
||||
}
|
||||
this.cache.set(key, keyPair)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user