From 31766b83efd489f3c837af6d444d62d4d2c8d93d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 26 Feb 2026 09:08:29 +0100 Subject: [PATCH] fix linting --- .../dltConnector/model/AccountIdentifier.ts | 6 +- .../dltConnector/model/TransactionDraft.ts | 6 +- .../src/graphql/resolver/CommunityResolver.ts | 11 +- ...097-fix_production_data_for_blockchain2.ts | 2 - database/src/queries/communities.ts | 11 +- .../src/bootstrap/initGradidoNode.ts | 5 +- .../src/cache/KeyPairCacheManager.ts | 5 +- .../client/GradidoNode/GradidoNodeClient.ts | 22 +- .../client/GradidoNode/GradidoNodeProcess.ts | 11 +- .../src/client/GradidoNode/communities.ts | 3 +- .../client/GradidoNode/input.schema.test.ts | 4 +- .../src/client/GradidoNode/input.schema.ts | 2 +- dlt-connector/src/client/backend/graphql.ts | 2 - dlt-connector/src/data/deriveKeyPair.ts | 11 +- .../RegisterAddressTransaction.role.ts | 10 +- .../sendToHiero/SendToHiero.context.ts | 6 +- .../db-v2.7.0_to_blockchain-v3.7/Context.ts | 25 +- .../binaryExport.ts | 15 +- .../blockchain.ts | 15 +- .../db-v2.7.0_to_blockchain-v3.7/bootstrap.ts | 39 ++- .../data/Balance.ts | 174 +++++++------ .../data/keyPair.ts | 5 +- .../db-v2.7.0_to_blockchain-v3.7/database.ts | 25 +- .../drizzle.schema.ts | 54 ++-- .../db-v2.7.0_to_blockchain-v3.7/errors.ts | 18 +- .../db-v2.7.0_to_blockchain-v3.7/index.ts | 23 +- .../syncDbWithBlockchain/AbstractSync.role.ts | 56 ++-- .../ContributionLinkTransactionSync.role.ts | 44 ++-- .../CreationsSync.role.ts | 120 +++++---- .../DeletedTransactionLinksSync.role.ts | 219 +++++++++------- .../LocalTransactionsSync.role.ts | 126 +++++---- .../RedeemTransactionLinksSync.role.ts | 169 +++++++----- .../RemoteTransactionsSync.role.ts | 241 +++++++++++------- .../TransactionLinkFundingsSync.role.ts | 173 ++++++++----- .../syncDbWithBlockchain/UsersSync.role.ts | 71 +++--- .../syncDbWithBlockchain.context.ts | 50 ++-- .../db-v2.7.0_to_blockchain-v3.7/utils.ts | 8 +- .../valibot.schema.ts | 110 ++++---- .../src/schemas/typeConverter.schema.ts | 2 +- dlt-connector/src/utils/filesystem.ts | 2 +- dlt-connector/src/utils/typeConverter.ts | 5 +- shared/src/logic/decay.ts | 4 +- 42 files changed, 1112 insertions(+), 798 deletions(-) diff --git a/backend/src/apis/dltConnector/model/AccountIdentifier.ts b/backend/src/apis/dltConnector/model/AccountIdentifier.ts index 1d324a70f..28fc844cd 100644 --- a/backend/src/apis/dltConnector/model/AccountIdentifier.ts +++ b/backend/src/apis/dltConnector/model/AccountIdentifier.ts @@ -5,7 +5,11 @@ export class AccountIdentifier { account?: CommunityAccountIdentifier seed?: string // used for deferred transfers - constructor(communityTopicId: string, communityUuid: string, input: CommunityAccountIdentifier | string) { + constructor( + communityTopicId: string, + communityUuid: string, + input: CommunityAccountIdentifier | string, + ) { if (input instanceof CommunityAccountIdentifier) { this.account = input } else { diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 5352bf841..162b4e2c5 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -133,7 +133,11 @@ export class TransactionDraft { sendingUser.community.communityUuid!, new CommunityAccountIdentifier(sendingUser.gradidoID), ) - draft.linkedUser = new AccountIdentifier(senderUserTopic, sendingUser.community.communityUuid!, transactionLink.code) + draft.linkedUser = new AccountIdentifier( + senderUserTopic, + sendingUser.community.communityUuid!, + transactionLink.code, + ) draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER draft.createdAt = createdAtOnlySeconds.toISOString() draft.amount = transactionLink.amount.toString() diff --git a/backend/src/graphql/resolver/CommunityResolver.ts b/backend/src/graphql/resolver/CommunityResolver.ts index d037fffb4..4932c0f93 100644 --- a/backend/src/graphql/resolver/CommunityResolver.ts +++ b/backend/src/graphql/resolver/CommunityResolver.ts @@ -2,7 +2,12 @@ import { Paginated } from '@arg/Paginated' import { EditCommunityInput } from '@input/EditCommunityInput' import { AdminCommunityView } from '@model/AdminCommunityView' import { Community } from '@model/Community' -import { Community as DbCommunity, getAuthorizedCommunities, getHomeCommunity, getReachableCommunities } from 'database' +import { + Community as DbCommunity, + getAuthorizedCommunities, + getHomeCommunity, + getReachableCommunities, +} from 'database' import { updateAllDefinedAndChanged } from 'shared' import { Arg, Args, Authorized, Mutation, Query, Resolver } from 'type-graphql' import { RIGHTS } from '@/auth/RIGHTS' @@ -38,9 +43,9 @@ export class CommunityResolver { @Query(() => [Community]) async authorizedCommunities(): Promise { const dbCommunities: DbCommunity[] = await getAuthorizedCommunities({ - // order by + // order by foreign: 'ASC', // home community first - name: 'ASC', + name: 'ASC', }) return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom)) } diff --git a/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts b/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts index 9f67e267a..6cd5f7c39 100644 --- a/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts +++ b/database/migration/migrations/0097-fix_production_data_for_blockchain2.ts @@ -45,7 +45,6 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis * Fix 0: Update transaction links to match holdAvailableAmount with validUntil, because the old formula lead to incorrect values */ - let sumCount = 0 let count = 0 let lastProcessedId = 0 const LIMIT = 200 @@ -106,7 +105,6 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis `, [updates.map((u) => u.id)], ) - sumCount += updates.length } count = rows.length lastProcessedId = rows[rows.length - 1].id diff --git a/database/src/queries/communities.ts b/database/src/queries/communities.ts index 37fba27ff..6d1064f9b 100644 --- a/database/src/queries/communities.ts +++ b/database/src/queries/communities.ts @@ -103,13 +103,12 @@ export async function getNotReachableCommunities( // return the home community and all communities which had at least once make it through the first handshake export async function getAuthorizedCommunities( order?: FindOptionsOrder, -): Promise -{ +): Promise { return await DbCommunity.find({ where: [ { authenticatedAt: Not(IsNull()) }, // or - { foreign: false } - ], - order + { foreign: false }, + ], + order, }) -} \ No newline at end of file +} diff --git a/dlt-connector/src/bootstrap/initGradidoNode.ts b/dlt-connector/src/bootstrap/initGradidoNode.ts index dfc8d0c10..e0d1a047d 100644 --- a/dlt-connector/src/bootstrap/initGradidoNode.ts +++ b/dlt-connector/src/bootstrap/initGradidoNode.ts @@ -7,10 +7,7 @@ import { exportCommunities } from '../client/GradidoNode/communities' import { GradidoNodeProcess } from '../client/GradidoNode/GradidoNodeProcess' import { HieroClient } from '../client/hiero/HieroClient' import { CONFIG } from '../config' -import { - GRADIDO_NODE_HOME_FOLDER_NAME, - LOG4JS_BASE_CATEGORY, -} from '../config/const' +import { GRADIDO_NODE_HOME_FOLDER_NAME, LOG4JS_BASE_CATEGORY } from '../config/const' import { checkFileExist, checkPathExist } from '../utils/filesystem' import { isPortOpen } from '../utils/network' import { AppContextClients } from './appContext' diff --git a/dlt-connector/src/cache/KeyPairCacheManager.ts b/dlt-connector/src/cache/KeyPairCacheManager.ts index f38342904..21b24cae1 100644 --- a/dlt-connector/src/cache/KeyPairCacheManager.ts +++ b/dlt-connector/src/cache/KeyPairCacheManager.ts @@ -77,10 +77,7 @@ export class KeyPairCacheManager { return keyPair } - public getKeyPairSync( - input: string, - createKeyPair: () => KeyPairEd25519, - ): KeyPairEd25519 { + public getKeyPairSync(input: string, createKeyPair: () => KeyPairEd25519): KeyPairEd25519 { const keyPair = this.cache.get(input) if (!keyPair) { const keyPair = createKeyPair() diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index 0a3d0c7ae..9d1515bfc 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts @@ -8,7 +8,7 @@ import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { AddressType } from '../../data/AddressType.enum' import { Uuidv4Hash } from '../../data/Uuidv4Hash' import { addressTypeSchema, confirmedTransactionSchema } from '../../schemas/typeConverter.schema' -import { Hex32, Hex32Input, Uuidv4, hex32Schema } from '../../schemas/typeGuard.schema' +import { Hex32, Hex32Input, hex32Schema, Uuidv4 } from '../../schemas/typeGuard.schema' import { isPortOpenRetry } from '../../utils/network' import { GradidoNodeErrorCodes } from './GradidoNodeErrorCodes' import { @@ -75,7 +75,10 @@ export class GradidoNodeClient { const response = await this.rpcCall<{ transaction: string }>('getTransaction', parameter) if (response.isSuccess()) { // this.logger.debug('result: ', response.result.transaction) - return v.parse(confirmedTransactionSchema, { base64: response.result.transaction, communityId: parameter.communityId }) + return v.parse(confirmedTransactionSchema, { + base64: response.result.transaction, + communityId: parameter.communityId, + }) } if (response.isError()) { if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) { @@ -100,7 +103,10 @@ export class GradidoNodeClient { } const response = await this.rpcCall<{ transaction: string }>('getLastTransaction', parameter) if (response.isSuccess()) { - return v.parse(confirmedTransactionSchema, { base64: response.result.transaction, communityId: parameter.communityId }) + return v.parse(confirmedTransactionSchema, { + base64: response.result.transaction, + communityId: parameter.communityId, + }) } if (response.isError()) { if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) { @@ -137,7 +143,10 @@ export class GradidoNodeClient { parameter, ) return result.transactions.map((transactionBase64) => - v.parse(confirmedTransactionSchema, { base64: transactionBase64, communityId: parameter.communityId }), + v.parse(confirmedTransactionSchema, { + base64: transactionBase64, + communityId: parameter.communityId, + }), ) } @@ -163,7 +172,10 @@ export class GradidoNodeClient { parameter, ) return response.transactions.map((transactionBase64) => - v.parse(confirmedTransactionSchema, { base64: transactionBase64, communityId: parameter.communityId }), + v.parse(confirmedTransactionSchema, { + base64: transactionBase64, + communityId: parameter.communityId, + }), ) } diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index 526fd99be..0347d136e 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -1,3 +1,4 @@ +import path from 'node:path' import { Mutex } from 'async-mutex' import { Subprocess, spawn } from 'bun' import { getLogger, Logger } from 'log4js' @@ -10,7 +11,6 @@ import { LOG4JS_BASE_CATEGORY, } from '../../config/const' import { delay } from '../../utils/time' -import path from 'node:path' /** * A Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. @@ -48,14 +48,7 @@ export class GradidoNodeProcess { const isWindows = process.platform === 'win32' const binaryName = isWindows ? 'GradidoNode.exe' : 'GradidoNode' - return path.join( - __dirname, - '..', - '..', - 'gradido_node', - 'bin', - binaryName, - ) + return path.join(__dirname, '..', '..', 'gradido_node', 'bin', binaryName) } public start() { diff --git a/dlt-connector/src/client/GradidoNode/communities.ts b/dlt-connector/src/client/GradidoNode/communities.ts index b285eed92..8af18e3ef 100644 --- a/dlt-connector/src/client/GradidoNode/communities.ts +++ b/dlt-connector/src/client/GradidoNode/communities.ts @@ -39,7 +39,6 @@ export async function ensureCommunitiesAvailable(communityTopicIds: HieroId[]): export async function exportCommunities(homeFolder: string, client: BackendClient): Promise { const communities = await client.getAuthorizedCommunities() - console.log(`communities: ${JSON.stringify(communities, null, 2)}`) const communitiesPath = path.join(homeFolder, 'communities.json') checkPathExist(path.dirname(communitiesPath), true) const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] @@ -52,7 +51,7 @@ export async function exportCommunities(homeFolder: string, client: BackendClien hieroTopicId: com.hieroTopicId, alias: com.name, // use only alpha-numeric chars for folder name - folder: toFolderName(com.uuid), + folder: toFolderName(com.uuid), }) } fs.writeFileSync(communitiesPath, JSON.stringify(communitiesForDltNodeServer, null, 2)) diff --git a/dlt-connector/src/client/GradidoNode/input.schema.test.ts b/dlt-connector/src/client/GradidoNode/input.schema.test.ts index 550437100..4db653f26 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.test.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.test.ts @@ -1,14 +1,14 @@ import { beforeAll, describe, expect, it } from 'bun:test' +import { v4 as uuidv4 } from 'uuid' import * as v from 'valibot' import { HieroTransactionIdString, - Uuidv4, hieroIdSchema, hieroTransactionIdStringSchema, + Uuidv4, uuidv4Schema, } from '../../schemas/typeGuard.schema' import { transactionIdentifierSchema } from './input.schema' -import { v4 as uuidv4 } from 'uuid' let communityId: Uuidv4 const uuidv4String = uuidv4() diff --git a/dlt-connector/src/client/GradidoNode/input.schema.ts b/dlt-connector/src/client/GradidoNode/input.schema.ts index f8a21f562..61c9887d5 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.ts @@ -1,5 +1,5 @@ import * as v from 'valibot' -import { uuidv4Schema, hieroTransactionIdStringSchema } from '../../schemas/typeGuard.schema' +import { hieroTransactionIdStringSchema, uuidv4Schema } from '../../schemas/typeGuard.schema' export const transactionsRangeSchema = v.object({ // default value is 1, from first transactions diff --git a/dlt-connector/src/client/backend/graphql.ts b/dlt-connector/src/client/backend/graphql.ts index 2f1fbec74..466a16c16 100644 --- a/dlt-connector/src/client/backend/graphql.ts +++ b/dlt-connector/src/client/backend/graphql.ts @@ -53,5 +53,3 @@ export const getAuthorizedCommunities = gql` } ${communityFragment} ` - - diff --git a/dlt-connector/src/data/deriveKeyPair.ts b/dlt-connector/src/data/deriveKeyPair.ts index f0880b207..f4a805eb3 100644 --- a/dlt-connector/src/data/deriveKeyPair.ts +++ b/dlt-connector/src/data/deriveKeyPair.ts @@ -17,9 +17,7 @@ export function deriveFromCode(code: string): KeyPairEd25519 { const hash = new MemoryBlock(code).calculateHash() const keyPair = KeyPairEd25519.create(hash) if (!keyPair) { - throw new ParameterError( - `error creating Ed25519 KeyPair from seed: ${code.substring(0, 5)}...`, - ) + throw new ParameterError(`error creating Ed25519 KeyPair from seed: ${code.substring(0, 5)}...`) } return keyPair } @@ -31,7 +29,10 @@ export function deriveFromKeyPairAndUuid(keyPair: KeyPairEd25519, uuid: Uuidv4): parts[i] = hardenDerivationIndex(wholeHex.subarray(i * 4, (i + 1) * 4).readUInt32BE()) } // parts: [2206563009, 2629978174, 2324817329, 2405141782] - return parts.reduce((keyPair: KeyPairEd25519, node: number) => deriveFromKeyPairAndIndex(keyPair, node), keyPair) + return parts.reduce( + (keyPair: KeyPairEd25519, node: number) => deriveFromKeyPairAndIndex(keyPair, node), + keyPair, + ) } export function deriveFromKeyPairAndIndex(keyPair: KeyPairEd25519, index: number): KeyPairEd25519 { @@ -42,4 +43,4 @@ export function deriveFromKeyPairAndIndex(keyPair: KeyPairEd25519, index: number ) } return localKeyPair -} \ No newline at end of file +} diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts index 98ddc01f3..7344c9a59 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts @@ -35,10 +35,12 @@ export class RegisterAddressTransactionRole extends AbstractTransactionRole { public async getGradidoTransactionBuilder(): Promise { const builder = new GradidoTransactionBuilder() const communityTopicId = this.registerAddressTransaction.user.communityTopicId - const communityKeyPair = await ResolveKeyPair(new KeyPairIdentifierLogic({ - communityTopicId, - communityId: this.registerAddressTransaction.user.communityId, - })) + const communityKeyPair = await ResolveKeyPair( + new KeyPairIdentifierLogic({ + communityTopicId, + communityId: this.registerAddressTransaction.user.communityId, + }), + ) const keyPairIdentifier = this.registerAddressTransaction.user // when accountNr is 0 it is the user account keyPairIdentifier.account.accountNr = 0 diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 9bb6f5c74..bacc01401 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -65,7 +65,9 @@ export async function SendToHieroContext( ) // attach Hiero transaction ID to the builder for the inbound transaction - builder.setParentLedgerAnchor(new LedgerAnchor(new HieroTransactionId(outboundHieroTransactionIdString))) + builder.setParentLedgerAnchor( + new LedgerAnchor(new HieroTransactionId(outboundHieroTransactionIdString)), + ) // build and validate inbound transaction const inboundTransaction = builder.buildInbound() @@ -103,7 +105,7 @@ function validate(transaction: GradidoTransaction): void { async function sendViaHiero( gradidoTransaction: GradidoTransaction, topic: HieroId, - communityId: Uuidv4 + communityId: Uuidv4, ): Promise { const client = HieroClient.getInstance() const transactionId = await client.sendMessage(topic, communityId, gradidoTransaction) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/Context.ts index ea854ce7a..2a24867ef 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/Context.ts @@ -23,7 +23,12 @@ export class Context { public balanceFixGradidoUser: UserDb | null private timeUsed: Profiler - constructor(logger: Logger, db: MySql2Database, cache: KeyPairCacheManager, balanceFixGradidoUser: UserDb | null) { + constructor( + logger: Logger, + db: MySql2Database, + cache: KeyPairCacheManager, + balanceFixGradidoUser: UserDb | null, + ) { this.logger = logger this.db = db this.cache = cache @@ -42,23 +47,23 @@ export class Context { database: CONFIG.MYSQL_DATABASE, port: CONFIG.MYSQL_PORT, }) - const db = drizzle({ client: connection }) + const db = drizzle({ client: connection }) const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`) let balanceFixGradidoUser: UserDb | null = null if (process.env.MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID) { - balanceFixGradidoUser = await loadUserByGradidoId(db, process.env.MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID) + balanceFixGradidoUser = await loadUserByGradidoId( + db, + process.env.MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID, + ) if (!balanceFixGradidoUser) { - logger.error(`MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID was set to ${process.env.MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID} but user not found`) + logger.error( + `MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID was set to ${process.env.MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID} but user not found`, + ) } } else { logger.debug(`MIGRATION_ACCOUNT_BALANCE_FIX_GRADIDO_ID was not set`) } - return new Context( - logger, - db, - KeyPairCacheManager.getInstance(), - balanceFixGradidoUser, - ) + return new Context(logger, db, KeyPairCacheManager.getInstance(), balanceFixGradidoUser) } getCommunityContextByUuid(communityUuid: Uuidv4): CommunityContext { diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/binaryExport.ts index 8ec631201..6870740eb 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/binaryExport.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/binaryExport.ts @@ -43,7 +43,9 @@ export function exportCommunity( const isDebug = context.logger.isDebugEnabled() const printConsole = () => { if (triggeredTransactionsCount > 0) { - process.stdout.write(`exported ${count} transactions + ${triggeredTransactionsCount} triggered from timeouted transaction links\r`) + process.stdout.write( + `exported ${count} transactions + ${triggeredTransactionsCount} triggered from timeouted transaction links\r`, + ) } else { process.stdout.write(`exported ${count} transactions\r`) } @@ -59,7 +61,12 @@ export function exportCommunity( throw new Error(`invalid TransactionEntry at index: ${transactionNr} `) } hash = exportTransaction(confirmedTransaction, hash, binFilePath) - if (confirmedTransaction?.getGradidoTransaction()?.getTransactionBody()?.isTimeoutDeferredTransfer()) { + if ( + confirmedTransaction + ?.getGradidoTransaction() + ?.getTransactionBody() + ?.isTimeoutDeferredTransfer() + ) { triggeredTransactionsCount++ } else { count++ @@ -77,7 +84,7 @@ export function exportCommunity( } } } - f.pagination.page++ + f.pagination.page++ } while (lastTransactionCount === batchSize) printConsole() process.stdout.write(`\n`) @@ -86,7 +93,7 @@ export function exportCommunity( context.logger.info( `binary file for community ${communityContext.communityId} written to ${binFilePath}`, ) - const sumTransactionsCount = ((f.pagination.page - 2) * batchSize) + lastTransactionCount + const sumTransactionsCount = (f.pagination.page - 2) * batchSize + lastTransactionCount const fileSize = fs.statSync(binFilePath).size context.logger.info( `exported ${sumTransactionsCount} transactions (${bytesString(fileSize)}) in ${timeUsed.string()}`, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/blockchain.ts index 770122f92..edf752788 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/blockchain.ts @@ -11,7 +11,7 @@ import { NotEnoughGradidoBalanceError } from './errors' export const defaultHieroAccount = new HieroAccountId(0, 0, 2) export let callTime: number = 0 -const timeUsed = new Profiler +const timeUsed = new Profiler() export function addToBlockchain( transaction: GradidoTransaction, @@ -19,7 +19,7 @@ export function addToBlockchain( ledgerAnchor: LedgerAnchor, accountBalances: AccountBalances, ): boolean { - try { + try { timeUsed.reset() const result = blockchain.createAndAddConfirmedTransactionExternFast( transaction, @@ -30,7 +30,9 @@ export function addToBlockchain( return result } catch (error) { if (error instanceof Error) { - const matches = error.message.match(/not enough Gradido Balance for (send coins|operation), needed: -?(\d+\.\d+), exist: (\d+\.\d+)/) + const matches = error.message.match( + /not enough Gradido Balance for (send coins|operation), needed: -?(\d+\.\d+), exist: (\d+\.\d+)/, + ) if (matches) { const needed = parseFloat(matches[2]) const exist = parseFloat(matches[3]) @@ -40,8 +42,9 @@ export function addToBlockchain( // const wekingheim = InMemoryBlockchainProvider.getInstance().getBlockchain('wekingheim') // const lastTransactionw = wekingheim?.findOne(Filter.LAST_TRANSACTION) - const lastTransaction = blockchain.findOne(Filter.LAST_TRANSACTION) - throw new Error(`Transaction ${transaction.toJson(true)} not added: ${error}, last transaction was: ${lastTransaction?.getConfirmedTransaction()?.toJson(true)}`) + const lastTransaction = blockchain.findOne(Filter.LAST_TRANSACTION) + throw new Error( + `Transaction ${transaction.toJson(true)} not added: ${error}, last transaction was: ${lastTransaction?.getConfirmedTransaction()?.toJson(true)}`, + ) } } - diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/bootstrap.ts index 3ccb24f1d..a95cc136a 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/bootstrap.ts @@ -1,23 +1,36 @@ import { randomBytes } from 'node:crypto' -import { AccountBalances, GradidoTransactionBuilder, InMemoryBlockchainProvider, LedgerAnchor } from 'gradido-blockchain-js' +import { + AccountBalances, + GradidoTransactionBuilder, + InMemoryBlockchainProvider, + LedgerAnchor, +} from 'gradido-blockchain-js' import * as v from 'valibot' import { CONFIG } from '../../config' import { deriveFromSeed } from '../../data/deriveKeyPair' import { Hex32, hex32Schema } from '../../schemas/typeGuard.schema' -import { AUF_ACCOUNT_DERIVATION_INDEX, GMW_ACCOUNT_DERIVATION_INDEX, hardenDerivationIndex } from '../../utils/derivationHelper' +import { + AUF_ACCOUNT_DERIVATION_INDEX, + GMW_ACCOUNT_DERIVATION_INDEX, + hardenDerivationIndex, +} from '../../utils/derivationHelper' +import { toFolderName } from '../../utils/filesystem' import { addToBlockchain } from './blockchain' import { Context } from './Context' import { Balance } from './data/Balance' -import { loadAdminUsersCache, loadCommunities, loadContributionLinkModeratorCache } from './database' +import { + loadAdminUsersCache, + loadCommunities, + loadContributionLinkModeratorCache, +} from './database' import { CommunityContext } from './valibot.schema' -import { toFolderName } from '../../utils/filesystem' export async function bootstrap(): Promise { const context = await Context.create() context.communities = await bootstrapCommunities(context) await Promise.all([ loadContributionLinkModeratorCache(context.db), - loadAdminUsersCache(context.db) + loadAdminUsersCache(context.db), ]) return context } @@ -39,17 +52,23 @@ async function bootstrapCommunities(context: Context): Promise() export const adminUsers = new Map() @@ -29,7 +19,10 @@ export async function loadContributionLinkModeratorCache(db: MySql2Database): Pr .orderBy(asc(eventsTable.id)) result.map((row: any) => { - contributionLinkModerators.set(row.event.involvedContributionLinkId, v.parse(userDbSchema, row.user)) + contributionLinkModerators.set( + row.event.involvedContributionLinkId, + v.parse(userDbSchema, row.user), + ) }) } @@ -69,7 +62,10 @@ export async function loadCommunities(db: MySql2Database): Promise { +export async function loadUserByGradidoId( + db: MySql2Database, + gradidoId: string, +): Promise { const result = await db .select() .from(usersTable) @@ -78,4 +74,3 @@ export async function loadUserByGradidoId(db: MySql2Database, gradidoId: string) return result.length ? v.parse(userDbSchema, result[0]) : null } - diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/drizzle.schema.ts index 9f17d4144..71c5bd08a 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/drizzle.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/drizzle.schema.ts @@ -25,23 +25,23 @@ export const communitiesTable = mysqlTable( ) export const contributionsTable = mysqlTable('contributions', { - id: int().autoincrement().notNull(), + id: int().autoincrement().notNull(), userId: int('user_id').default(sql`NULL`), - contributionDate: datetime("contribution_date", { mode: 'string'}).default(sql`NULL`), - memo: varchar({ length: 512 }).notNull(), - amount: decimal({ precision: 40, scale: 20 }).notNull(), - contributionLinkId: int('contribution_link_id').default(sql`NULL`), - confirmedBy: int('confirmed_by').default(sql`NULL`), - confirmedAt: datetime('confirmed_at', { mode: 'string'}).default(sql`NULL`), - contributionStatus: varchar('contribution_status', { length: 12 }).default('\'PENDING\'').notNull(), - transactionId: int('transaction_id').default(sql`NULL`), + contributionDate: datetime('contribution_date', { mode: 'string' }).default(sql`NULL`), + memo: varchar({ length: 512 }).notNull(), + amount: decimal({ precision: 40, scale: 20 }).notNull(), + contributionLinkId: int('contribution_link_id').default(sql`NULL`), + confirmedBy: int('confirmed_by').default(sql`NULL`), + confirmedAt: datetime('confirmed_at', { mode: 'string' }).default(sql`NULL`), + contributionStatus: varchar('contribution_status', { length: 12 }).default("'PENDING'").notNull(), + transactionId: int('transaction_id').default(sql`NULL`), }) export const eventsTable = mysqlTable('events', { - id: int().autoincrement().notNull(), - type: varchar({ length: 100 }).notNull(), - actingUserId: int('acting_user_id').notNull(), - involvedContributionLinkId: int('involved_contribution_link_id').default(sql`NULL`), + id: int().autoincrement().notNull(), + type: varchar({ length: 100 }).notNull(), + actingUserId: int('acting_user_id').notNull(), + involvedContributionLinkId: int('involved_contribution_link_id').default(sql`NULL`), }) export const usersTable = mysqlTable( @@ -55,19 +55,19 @@ export const usersTable = mysqlTable( createdAt: datetime('created_at', { mode: 'string', fsp: 3 }) .default(sql`current_timestamp(3)`) .notNull(), - }, (table) => [unique('uuid_key').on(table.gradidoId, table.communityUuid)], ) -export const userRolesTable = mysqlTable('user_roles', { - id: int().autoincrement().notNull(), - userId: int('user_id').notNull(), - role: varchar({ length: 40 }).notNull(), -}, -(table) => [ - index('user_id').on(table.userId), -]) +export const userRolesTable = mysqlTable( + 'user_roles', + { + id: int().autoincrement().notNull(), + userId: int('user_id').notNull(), + role: varchar({ length: 40 }).notNull(), + }, + (table) => [index('user_id').on(table.userId)], +) export const transactionsTable = mysqlTable( 'transactions', @@ -84,8 +84,8 @@ export const transactionsTable = mysqlTable( creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), userId: int('user_id').notNull(), linkedUserId: int('linked_user_id').default(sql`NULL`), - linkedUserCommunityUuid: char("linked_user_community_uuid", { length: 36 }).default(sql`NULL`), - linkedUserGradidoId: char("linked_user_gradido_id", { length: 36 }).default(sql`NULL`), + linkedUserCommunityUuid: char('linked_user_community_uuid', { length: 36 }).default(sql`NULL`), + linkedUserGradidoId: char('linked_user_gradido_id', { length: 36 }).default(sql`NULL`), linkedTransactionId: int('linked_transaction_id').default(sql`NULL`), }, (table) => [index('user_id').on(table.userId)], @@ -95,12 +95,12 @@ export const transactionLinksTable = mysqlTable('transaction_links', { id: int().autoincrement().notNull(), userId: int().notNull(), amount: decimal({ precision: 40, scale: 20 }).notNull(), - holdAvailableAmount: decimal("hold_available_amount", { precision: 40, scale: 20 }).notNull(), + holdAvailableAmount: decimal('hold_available_amount', { precision: 40, scale: 20 }).notNull(), memo: varchar({ length: 255 }).notNull(), code: varchar({ length: 24 }).notNull(), createdAt: datetime({ mode: 'string' }).notNull(), deletedAt: datetime({ mode: 'string' }).default(sql`NULL`), validUntil: datetime({ mode: 'string' }).notNull(), - redeemedAt: datetime({ mode: 'string'}).default(sql`NULL`), - redeemedBy: int().default(sql`NULL`), + redeemedAt: datetime({ mode: 'string' }).default(sql`NULL`), + redeemedBy: int().default(sql`NULL`), }) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/errors.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/errors.ts index 0c18102f6..8e09c6995 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/errors.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/errors.ts @@ -1,8 +1,13 @@ import * as v from 'valibot' export class NotEnoughGradidoBalanceError extends Error { - constructor(public needed: number, public exist: number) { - super(`Not enough Gradido Balance for send coins, needed: ${needed} Gradido, exist: ${exist} Gradido`) + constructor( + public needed: number, + public exist: number, + ) { + super( + `Not enough Gradido Balance for send coins, needed: ${needed} Gradido, exist: ${exist} Gradido`, + ) this.name = 'NotEnoughGradidoBalanceError' } } @@ -46,7 +51,12 @@ export class BlockchainError extends Error { } export class NegativeBalanceError extends Error { - constructor(message: string, previousBalanceString: string, amount: string, previousDecayedBalance: string) { + constructor( + message: string, + previousBalanceString: string, + amount: string, + previousDecayedBalance: string, + ) { const parts: string[] = [`NegativeBalanceError in ${message}`] parts.push(`Previous balance: ${previousBalanceString}`) parts.push(`Amount: ${amount}`) @@ -54,4 +64,4 @@ export class NegativeBalanceError extends Error { super(parts.join('\n')) this.name = 'NegativeBalanceError' } -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/index.ts index aa418625d..1576f9770 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/index.ts @@ -1,15 +1,16 @@ +import { Filter, Profiler, ThreadingPolicy_Half, verifySignatures } from 'gradido-blockchain-js' import { onShutdown } from '../../../../shared/src/helper/onShutdown' import { exportAllCommunities } from './binaryExport' import { bootstrap } from './bootstrap' import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' -import { Filter, Profiler, ThreadingPolicy_Half, verifySignatures } from 'gradido-blockchain-js' - // import { hello } from '../../../zig/hello.zig' + +// import { hello } from '../../../zig/hello.zig' const BATCH_SIZE = 1000 async function main() { // hello() - // return + // return // prepare in memory blockchains const context = await bootstrap() onShutdown(async (reason, error) => { @@ -22,8 +23,8 @@ async function main() { // synchronize to in memory blockchain try { await syncDbWithBlockchainContext(context, BATCH_SIZE) - } catch(e) { - console.error(e) + } catch (e) { + context.logger.error(e) //context.logBlogchain(v.parse(uuidv4Schema, 'e70da33e-5976-4767-bade-aa4e4fa1c01a')) } @@ -31,9 +32,15 @@ async function main() { // bulk verify transaction signatures for (const communityContext of context.communities.values()) { // verifySignatures(Filter.ALL_TRANSACTIONS, ThreadingPolicy_Half) - const result = verifySignatures(Filter.ALL_TRANSACTIONS, communityContext.communityId, ThreadingPolicy_Half) - if(!result.isEmpty()){ - throw new Error(`Verification of signatures failed for community ${communityContext.communityId}`) + const result = verifySignatures( + Filter.ALL_TRANSACTIONS, + communityContext.communityId, + ThreadingPolicy_Half, + ) + if (!result.isEmpty()) { + throw new Error( + `Verification of signatures failed for community ${communityContext.communityId}`, + ) } } context.logger.info(`verified in ${timeUsed.string()}`) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/AbstractSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/AbstractSync.role.ts index d6a6fc23a..572252fd9 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/AbstractSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/AbstractSync.role.ts @@ -1,12 +1,12 @@ -import { - AccountBalances, - Filter, - InMemoryBlockchain, - KeyPairEd25519, - MemoryBlockPtr, - Profiler, - SearchDirection_DESC, - GradidoTransactionBuilder +import { + AccountBalances, + Filter, + GradidoTransactionBuilder, + InMemoryBlockchain, + KeyPairEd25519, + MemoryBlockPtr, + Profiler, + SearchDirection_DESC, } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../../../config/const' @@ -21,7 +21,7 @@ export type IndexType = { id: number } export let nanosBalanceForUser = 0 -const lastBalanceOfUserTimeUsed = new Profiler +const lastBalanceOfUserTimeUsed = new Profiler() export abstract class AbstractSyncRole { private items: ItemType[] = [] @@ -40,16 +40,22 @@ export abstract class AbstractSyncRole { getAccountKeyPair(communityContext: CommunityContext, gradidoId: Uuidv4): KeyPairEd25519 { return this.context.cache.getKeyPairSync(gradidoId, () => { - return deriveFromKeyPairAndIndex(deriveFromKeyPairAndUuid(communityContext.keyPair, gradidoId), 1) + return deriveFromKeyPairAndIndex( + deriveFromKeyPairAndUuid(communityContext.keyPair, gradidoId), + 1, + ) }) } - getLastBalanceForUser(publicKey: MemoryBlockPtr, blockchain: InMemoryBlockchain, communityId: string + getLastBalanceForUser( + publicKey: MemoryBlockPtr, + blockchain: InMemoryBlockchain, + communityId: string, ): Balance { lastBalanceOfUserTimeUsed.reset() if (publicKey.isEmpty()) { throw new Error('publicKey is empty') - } + } const f = Filter.lastBalanceFor(publicKey) f.setCommunityId(communityId) const lastSenderTransaction = blockchain.findOne(f) @@ -58,19 +64,31 @@ export abstract class AbstractSyncRole { } const lastConfirmedTransaction = lastSenderTransaction.getConfirmedTransaction() if (!lastConfirmedTransaction) { - throw new Error(`invalid transaction, getConfirmedTransaction call failed for transaction nr: ${lastSenderTransaction.getTransactionNr()}`) - + throw new Error( + `invalid transaction, getConfirmedTransaction call failed for transaction nr: ${lastSenderTransaction.getTransactionNr()}`, + ) } - const senderLastAccountBalance = lastConfirmedTransaction.getAccountBalance(publicKey, communityId) + const senderLastAccountBalance = lastConfirmedTransaction.getAccountBalance( + publicKey, + communityId, + ) if (!senderLastAccountBalance) { return new Balance(publicKey, communityId) } - const result = Balance.fromAccountBalance(senderLastAccountBalance, lastConfirmedTransaction.getConfirmedAt().getDate(), communityId) + const result = Balance.fromAccountBalance( + senderLastAccountBalance, + lastConfirmedTransaction.getConfirmedAt().getDate(), + communityId, + ) nanosBalanceForUser += lastBalanceOfUserTimeUsed.nanos() return result } - logLastBalanceChangingTransactions(publicKey: MemoryBlockPtr, blockchain: InMemoryBlockchain, transactionCount: number = 5) { + logLastBalanceChangingTransactions( + publicKey: MemoryBlockPtr, + blockchain: InMemoryBlockchain, + transactionCount: number = 5, + ) { if (!this.context.logger.isDebugEnabled()) { return } @@ -111,7 +129,7 @@ export abstract class AbstractSyncRole { return this.items.length } return 0 - } + } toBlockchain(): void { if (this.isEmpty()) { diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/ContributionLinkTransactionSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/ContributionLinkTransactionSync.role.ts index 299f4cec4..4e149f583 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/ContributionLinkTransactionSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/ContributionLinkTransactionSync.role.ts @@ -1,14 +1,14 @@ import { and, asc, eq, gt, isNotNull, or } from 'drizzle-orm' import * as v from 'valibot' import { Context } from '../../Context' -import { contributionLinkModerators } from '../../database' -import { CreationTransactionDb, creationTransactionDbSchema } from '../../valibot.schema' -import { CreationsSyncRole } from './CreationsSync.role' -import { contributionsTable, usersTable } from '../../drizzle.schema' import { ContributionStatus } from '../../data/ContributionStatus' +import { contributionLinkModerators } from '../../database' +import { contributionsTable, usersTable } from '../../drizzle.schema' import { DatabaseError } from '../../errors' -import { IndexType } from './AbstractSync.role' import { toMysqlDateTime } from '../../utils' +import { CreationTransactionDb, creationTransactionDbSchema } from '../../valibot.schema' +import { IndexType } from './AbstractSync.role' +import { CreationsSyncRole } from './CreationsSync.role' export class ContributionLinkTransactionSyncRole extends CreationsSyncRole { constructor(readonly context: Context) { @@ -25,30 +25,34 @@ export class ContributionLinkTransactionSyncRole extends CreationsSyncRole { user: usersTable, }) .from(contributionsTable) - .where(and( - isNotNull(contributionsTable.contributionLinkId), - eq(contributionsTable.contributionStatus, ContributionStatus.CONFIRMED), - or( - gt(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), - and( - eq(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), - gt(contributionsTable.transactionId, lastIndex.id) - ) - ) - )) + .where( + and( + isNotNull(contributionsTable.contributionLinkId), + eq(contributionsTable.contributionStatus, ContributionStatus.CONFIRMED), + or( + gt(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), + and( + eq(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), + gt(contributionsTable.transactionId, lastIndex.id), + ), + ), + ), + ) .innerJoin(usersTable, eq(contributionsTable.userId, usersTable.id)) .orderBy(asc(contributionsTable.confirmedAt), asc(contributionsTable.transactionId)) .limit(count) - + const verifiedCreationTransactions: CreationTransactionDb[] = [] - for(const row of result) { + for (const row of result) { if (!row.contribution.contributionLinkId) { - throw new Error(`expect contributionLinkId to be set: ${JSON.stringify(row.contribution, null, 2)}`) + throw new Error( + `expect contributionLinkId to be set: ${JSON.stringify(row.contribution, null, 2)}`, + ) } const item = { ...row.contribution, user: row.user, - confirmedByUser: contributionLinkModerators.get(row.contribution.contributionLinkId) + confirmedByUser: contributionLinkModerators.get(row.contribution.contributionLinkId), } if (!item.confirmedByUser || item.userId === item.confirmedByUser.id) { this.context.logger.warn(`skipped Contribution Link Transaction ${row.contribution.id}`) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/CreationsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/CreationsSync.role.ts index cb4e9ca14..b5555c3a2 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/CreationsSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/CreationsSync.role.ts @@ -1,33 +1,33 @@ -import { and, asc, eq, isNull, gt, or } from 'drizzle-orm' +import { and, asc, eq, gt, isNull, or } from 'drizzle-orm' import { alias } from 'drizzle-orm/mysql-core' -import { - AccountBalances, - AuthenticatedEncryption, - EncryptedMemo, - Filter, - GradidoTransactionBuilder, - KeyPairEd25519, - LedgerAnchor, - MemoryBlockPtr, - SearchDirection_DESC, - TransactionType_CREATION, - TransferAmount +import { + AccountBalances, + AuthenticatedEncryption, + EncryptedMemo, + Filter, + GradidoTransactionBuilder, + KeyPairEd25519, + LedgerAnchor, + MemoryBlockPtr, + SearchDirection_DESC, + TransactionType_CREATION, + TransferAmount, } from 'gradido-blockchain-js' import * as v from 'valibot' import { addToBlockchain } from '../../blockchain' -import { ContributionStatus } from '../../data/ContributionStatus' import { Context } from '../../Context' -import { - contributionsTable, - usersTable -} from '../../drizzle.schema' +import { ContributionStatus } from '../../data/ContributionStatus' +import { contributionsTable, usersTable } from '../../drizzle.schema' import { BlockchainError, DatabaseError } from '../../errors' -import { CommunityContext, CreationTransactionDb, creationTransactionDbSchema } from '../../valibot.schema' -import { AbstractSyncRole, IndexType } from './AbstractSync.role' import { toMysqlDateTime } from '../../utils' +import { + CommunityContext, + CreationTransactionDb, + creationTransactionDbSchema, +} from '../../valibot.schema' +import { AbstractSyncRole, IndexType } from './AbstractSync.role' -export class CreationsSyncRole extends AbstractSyncRole { - +export class CreationsSyncRole extends AbstractSyncRole { constructor(context: Context) { super(context) this.accountBalances.reserve(3) @@ -38,16 +38,16 @@ export class CreationsSyncRole extends AbstractSyncRole { } getLastIndex(): IndexType { - const lastItem = this.peekLast() - return { date: lastItem.confirmedAt, id: lastItem.transactionId } - } + const lastItem = this.peekLast() + return { date: lastItem.confirmedAt, id: lastItem.transactionId } + } itemTypeName(): string { return 'creationTransactions' } async loadFromDb(lastIndex: IndexType, count: number): Promise { - const confirmedByUsers = alias(usersTable, 'confirmedByUser') + const confirmedByUsers = alias(usersTable, 'confirmedByUser') const result = await this.context.db .select({ contribution: contributionsTable, @@ -55,22 +55,24 @@ export class CreationsSyncRole extends AbstractSyncRole { confirmedByUser: confirmedByUsers, }) .from(contributionsTable) - .where(and( - isNull(contributionsTable.contributionLinkId), - eq(contributionsTable.contributionStatus, ContributionStatus.CONFIRMED), - or( - gt(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), - and( - eq(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), - gt(contributionsTable.transactionId, lastIndex.id) - ) - ) - )) + .where( + and( + isNull(contributionsTable.contributionLinkId), + eq(contributionsTable.contributionStatus, ContributionStatus.CONFIRMED), + or( + gt(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), + and( + eq(contributionsTable.confirmedAt, toMysqlDateTime(lastIndex.date)), + gt(contributionsTable.transactionId, lastIndex.id), + ), + ), + ), + ) .innerJoin(usersTable, eq(contributionsTable.userId, usersTable.id)) .innerJoin(confirmedByUsers, eq(contributionsTable.confirmedBy, confirmedByUsers.id)) .orderBy(asc(contributionsTable.confirmedAt), asc(contributionsTable.transactionId)) .limit(count) - + return result.map((row) => { const item = { ...row.contribution, @@ -86,12 +88,12 @@ export class CreationsSyncRole extends AbstractSyncRole { } buildTransaction( - item: CreationTransactionDb, - communityContext: CommunityContext, - recipientKeyPair: KeyPairEd25519, - signerKeyPair: KeyPairEd25519 + item: CreationTransactionDb, + communityContext: CommunityContext, + recipientKeyPair: KeyPairEd25519, + signerKeyPair: KeyPairEd25519, ): GradidoTransactionBuilder { - return this.transactionBuilder + return this.transactionBuilder .setCreatedAt(item.confirmedAt) .setRecipientCommunity(communityContext.communityId) .addMemo( @@ -102,19 +104,27 @@ export class CreationsSyncRole extends AbstractSyncRole { ), ) .setTransactionCreation( - new TransferAmount(recipientKeyPair.getPublicKey(), item.amount, communityContext.communityId), + new TransferAmount( + recipientKeyPair.getPublicKey(), + item.amount, + communityContext.communityId, + ), item.contributionDate, ) .sign(signerKeyPair) } calculateAccountBalances( - item: CreationTransactionDb, - communityContext: CommunityContext, - recipientPublicKey: MemoryBlockPtr + item: CreationTransactionDb, + communityContext: CommunityContext, + recipientPublicKey: MemoryBlockPtr, ): AccountBalances { this.accountBalances.clear() - const balance = this.getLastBalanceForUser(recipientPublicKey, communityContext.blockchain, communityContext.communityId) + const balance = this.getLastBalanceForUser( + recipientPublicKey, + communityContext.blockchain, + communityContext.communityId, + ) // calculate decay since last balance with legacy calculation method balance.updateLegacyDecay(item.amount, item.confirmedAt) @@ -131,9 +141,11 @@ export class CreationsSyncRole extends AbstractSyncRole { const communityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) const blockchain = communityContext.blockchain if (item.confirmedByUser.communityUuid !== item.user.communityUuid) { - throw new Error(`contribution was confirmed from other community: ${JSON.stringify(item, null, 2)}`) + throw new Error( + `contribution was confirmed from other community: ${JSON.stringify(item, null, 2)}`, + ) } - + const recipientKeyPair = this.getAccountKeyPair(communityContext, item.user.gradidoId) const recipientPublicKey = recipientKeyPair.getPublicKey() const signerKeyPair = this.getAccountKeyPair(communityContext, item.confirmedByUser.gradidoId) @@ -148,14 +160,16 @@ export class CreationsSyncRole extends AbstractSyncRole { new LedgerAnchor(item.id, LedgerAnchor.Type_LEGACY_GRADIDO_DB_CONTRIBUTION_ID), this.calculateAccountBalances(item, communityContext, recipientPublicKey), ) - } catch(e) { - const f= new Filter() + } catch (e) { + const f = new Filter() f.transactionType = TransactionType_CREATION f.searchDirection = SearchDirection_DESC f.pagination.size = 1 const lastContribution = blockchain.findOne(f) if (lastContribution) { - this.context.logger.warn(`last contribution: ${lastContribution.getConfirmedTransaction()?.toJson(true)}`) + this.context.logger.warn( + `last contribution: ${lastContribution.getConfirmedTransaction()?.toJson(true)}`, + ) } throw new BlockchainError(`Error adding ${this.itemTypeName()}`, item, e as Error) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts index 7e609ff2c..4aa5159af 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -1,34 +1,38 @@ -import { CommunityContext, DeletedTransactionLinkDb, deletedTransactionLinKDbSchema } from '../../valibot.schema' -import { AbstractSyncRole, IndexType } from './AbstractSync.role' -import { transactionLinksTable, usersTable } from '../../drizzle.schema' -import { and, lt, asc, isNotNull, eq, or, gt } from 'drizzle-orm' -import * as v from 'valibot' -import { - AccountBalance, - AccountBalances, - Filter, - GradidoDeferredTransfer, +import { and, asc, eq, gt, isNotNull, lt, or } from 'drizzle-orm' +import { + AccountBalance, + AccountBalances, + Filter, + GradidoDeferredTransfer, GradidoTransactionBuilder, - GradidoTransfer, - GradidoUnit, - KeyPairEd25519, - LedgerAnchor, + GradidoTransfer, + GradidoUnit, + KeyPairEd25519, + LedgerAnchor, MemoryBlockPtr, - TransferAmount + TransferAmount, } from 'gradido-blockchain-js' +import * as v from 'valibot' import { deriveFromCode } from '../../../../data/deriveKeyPair' import { addToBlockchain } from '../../blockchain' -import { BlockchainError, DatabaseError } from '../../errors' -import { Balance } from '../../data/Balance' -import { toMysqlDateTime } from '../../utils' import { Context } from '../../Context' +import { Balance } from '../../data/Balance' +import { transactionLinksTable, usersTable } from '../../drizzle.schema' +import { BlockchainError, DatabaseError } from '../../errors' +import { toMysqlDateTime } from '../../utils' +import { + CommunityContext, + DeletedTransactionLinkDb, + deletedTransactionLinKDbSchema, +} from '../../valibot.schema' +import { AbstractSyncRole, IndexType } from './AbstractSync.role' export class DeletedTransactionLinksSyncRole extends AbstractSyncRole { constructor(context: Context) { super(context) this.accountBalances.reserve(2) } - + getDate(): Date { return this.peek().deletedAt } @@ -57,15 +61,15 @@ export class DeletedTransactionLinksSyncRole extends AbstractSyncRole { const item = { ...row.transactionLink, @@ -80,95 +84,118 @@ export class DeletedTransactionLinksSyncRole extends AbstractSyncRole { constructor(context: Context) { super(context) this.accountBalances.reserve(2) } - + getDate(): Date { return this.peek().balanceDate } @@ -58,74 +63,83 @@ export class LocalTransactionsSyncRole extends AbstractSyncRole { or( gt(transactionsTable.balanceDate, toMysqlDateTime(lastIndex.date)), and( - eq(transactionsTable.balanceDate, toMysqlDateTime(lastIndex.date)), - gt(transactionsTable.id, lastIndex.id) - ) - ) - ) + eq(transactionsTable.balanceDate, toMysqlDateTime(lastIndex.date)), + gt(transactionsTable.id, lastIndex.id), + ), + ), + ), ) .innerJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) .innerJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) .orderBy(asc(transactionsTable.balanceDate), asc(transactionsTable.id)) .limit(count) - + return result.map((row) => { const item = { - ...row.transaction, - user: row.user, - linkedUser: row.linkedUser, - } + ...row.transaction, + user: row.user, + linkedUser: row.linkedUser, + } try { return v.parse(transactionDbSchema, item) } catch (e) { throw new DatabaseError('loadLocalTransferTransactions', item, e as Error) } - }) + }) } buildTransaction( - communityContext: CommunityContext, - item: TransactionDb, - senderKeyPair: KeyPairEd25519, - recipientKeyPair: KeyPairEd25519, - ): GradidoTransactionBuilder { - return this.transactionBuilder - .setCreatedAt(item.balanceDate) - .addMemo(new EncryptedMemo( - item.memo, - new AuthenticatedEncryption(senderKeyPair), - new AuthenticatedEncryption(recipientKeyPair), - ), - ) - .setSenderCommunity(communityContext.communityId) - .setTransactionTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), item.amount, communityContext.communityId), - recipientKeyPair.getPublicKey(), - ) - .sign(senderKeyPair) + communityContext: CommunityContext, + item: TransactionDb, + senderKeyPair: KeyPairEd25519, + recipientKeyPair: KeyPairEd25519, + ): GradidoTransactionBuilder { + return this.transactionBuilder + .setCreatedAt(item.balanceDate) + .addMemo( + new EncryptedMemo( + item.memo, + new AuthenticatedEncryption(senderKeyPair), + new AuthenticatedEncryption(recipientKeyPair), + ), + ) + .setSenderCommunity(communityContext.communityId) + .setTransactionTransfer( + new TransferAmount(senderKeyPair.getPublicKey(), item.amount, communityContext.communityId), + recipientKeyPair.getPublicKey(), + ) + .sign(senderKeyPair) } calculateBalances( - item: TransactionDb, + item: TransactionDb, communityContext: CommunityContext, senderPublicKey: MemoryBlockPtr, recipientPublicKey: MemoryBlockPtr, ): AccountBalances { this.accountBalances.clear() - - const senderLastBalance = this.getLastBalanceForUser(senderPublicKey, communityContext.blockchain, communityContext.communityId) - const recipientLastBalance = this.getLastBalanceForUser(recipientPublicKey, communityContext.blockchain, communityContext.communityId) + + const senderLastBalance = this.getLastBalanceForUser( + senderPublicKey, + communityContext.blockchain, + communityContext.communityId, + ) + const recipientLastBalance = this.getLastBalanceForUser( + recipientPublicKey, + communityContext.blockchain, + communityContext.communityId, + ) try { senderLastBalance.updateLegacyDecay(item.amount.negated(), item.balanceDate) - } catch(e) { + } catch (e) { if (e instanceof NegativeBalanceError) { this.logLastBalanceChangingTransactions(senderPublicKey, communityContext.blockchain) throw e } } recipientLastBalance.updateLegacyDecay(item.amount, item.balanceDate) - + this.accountBalances.add(senderLastBalance.getAccountBalance()) this.accountBalances.add(recipientLastBalance.getAccountBalance()) return this.accountBalances @@ -135,15 +149,17 @@ export class LocalTransactionsSyncRole extends AbstractSyncRole { const communityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) const blockchain = communityContext.blockchain if (item.linkedUser.communityUuid !== item.user.communityUuid) { - throw new Error(`transfer between user from different communities: ${JSON.stringify(item, null, 2)}`) + throw new Error( + `transfer between user from different communities: ${JSON.stringify(item, null, 2)}`, + ) } - + // I use the received transaction so user and linked user are swapped and user is recipient and linkedUser ist sender const senderKeyPair = this.getAccountKeyPair(communityContext, item.linkedUser.gradidoId) const senderPublicKey = senderKeyPair.getPublicKey() const recipientKeyPair = this.getAccountKeyPair(communityContext, item.user.gradidoId) const recipientPublicKey = recipientKeyPair.getPublicKey() - + if (!senderKeyPair || !senderPublicKey || !recipientKeyPair || !recipientPublicKey) { throw new Error(`missing key for ${this.itemTypeName()}: ${JSON.stringify(item, null, 2)}`) } @@ -155,9 +171,9 @@ export class LocalTransactionsSyncRole extends AbstractSyncRole { new LedgerAnchor(item.id, LedgerAnchor.Type_LEGACY_GRADIDO_DB_TRANSACTION_ID), this.calculateBalances(item, communityContext, senderPublicKey, recipientPublicKey), ) - } catch(e) { + } catch (e) { if (e instanceof NotEnoughGradidoBalanceError) { - this.logLastBalanceChangingTransactions(senderPublicKey, blockchain) + this.logLastBalanceChangingTransactions(senderPublicKey, blockchain) } throw new BlockchainError(`Error adding ${this.itemTypeName()}`, item, e as Error) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/RedeemTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/RedeemTransactionLinksSync.role.ts index e6d9d0c75..6e0c9f6ba 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/RedeemTransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/RedeemTransactionLinksSync.role.ts @@ -1,36 +1,40 @@ -import { and, asc, eq, isNotNull, isNull, or, gt } from 'drizzle-orm' -import { +import { and, asc, eq, gt, isNotNull, isNull, or } from 'drizzle-orm' +import { alias } from 'drizzle-orm/mysql-core' +import { AccountBalance, - AccountBalances, - AuthenticatedEncryption, - EncryptedMemo, + AccountBalances, + AuthenticatedEncryption, + EncryptedMemo, Filter, GradidoDeferredTransfer, - GradidoTransactionBuilder, - GradidoTransfer, - GradidoUnit, - KeyPairEd25519, - LedgerAnchor, - MemoryBlockPtr, - TransferAmount + GradidoTransactionBuilder, + GradidoTransfer, + GradidoUnit, + KeyPairEd25519, + LedgerAnchor, + MemoryBlockPtr, + TransferAmount, } from 'gradido-blockchain-js' import * as v from 'valibot' +import { deriveFromCode } from '../../../../data/deriveKeyPair' import { addToBlockchain } from '../../blockchain' +import { Context } from '../../Context' import { transactionLinksTable, usersTable } from '../../drizzle.schema' import { BlockchainError, DatabaseError } from '../../errors' -import { CommunityContext, RedeemedTransactionLinkDb, redeemedTransactionLinkDbSchema } from '../../valibot.schema' -import { AbstractSyncRole, IndexType } from './AbstractSync.role' -import { deriveFromCode } from '../../../../data/deriveKeyPair' -import { alias } from 'drizzle-orm/mysql-core' import { toMysqlDateTime } from '../../utils' -import { Context } from '../../Context' +import { + CommunityContext, + RedeemedTransactionLinkDb, + redeemedTransactionLinkDbSchema, +} from '../../valibot.schema' +import { AbstractSyncRole, IndexType } from './AbstractSync.role' -export class RedeemTransactionLinksSyncRole extends AbstractSyncRole { +export class RedeemTransactionLinksSyncRole extends AbstractSyncRole { constructor(context: Context) { super(context) this.accountBalances.reserve(3) } - + getDate(): Date { return this.peek().redeemedAt } @@ -62,17 +66,17 @@ export class RedeemTransactionLinksSyncRole extends AbstractSyncRole { const item = { ...row.transactionLink, @@ -88,66 +92,74 @@ export class RedeemTransactionLinksSyncRole extends AbstractSyncRole { constructor(context: Context) { super(context) this.accountBalances.reserve(1) } - + getDate(): Date { return this.peek().balanceDate } @@ -50,23 +64,23 @@ export class RemoteTransactionsSyncRole extends AbstractSyncRole or( gt(transactionsTable.balanceDate, toMysqlDateTime(lastIndex.date)), and( - eq(transactionsTable.balanceDate, toMysqlDateTime(lastIndex.date)), - gt(transactionsTable.id, lastIndex.id) - ) - ) - ) + eq(transactionsTable.balanceDate, toMysqlDateTime(lastIndex.date)), + gt(transactionsTable.id, lastIndex.id), + ), + ), + ), ) .innerJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) .innerJoin(linkedUsers, eq(transactionsTable.linkedUserGradidoId, linkedUsers.gradidoId)) .orderBy(asc(transactionsTable.balanceDate), asc(transactionsTable.id)) .limit(count) - + return result.map((row) => { const item = { - ...row.transaction, - user: row.user, - linkedUser: row.linkedUser, - } + ...row.transaction, + user: row.user, + linkedUser: row.linkedUser, + } if (item.typeId === TransactionTypeId.SEND && item.amount) { item.amount = new Decimal(item.amount).neg().toString() } @@ -75,101 +89,120 @@ export class RemoteTransactionsSyncRole extends AbstractSyncRole } catch (e) { throw new DatabaseError('loadRemoteTransferTransactions', item, e as Error) } - }) + }) } buildTransaction( - item: TransactionDb, - senderKeyPair: KeyPairEd25519, - recipientKeyPair: KeyPairEd25519, - senderCommunityId: string, - recipientCommunityId: string, - ): GradidoTransactionBuilder { - return this.transactionBuilder - .setCreatedAt(item.balanceDate) - .addMemo(new EncryptedMemo( - item.memo, - new AuthenticatedEncryption(senderKeyPair), - new AuthenticatedEncryption(recipientKeyPair), - ), - ) - .setSenderCommunity(senderCommunityId) - .setRecipientCommunity(recipientCommunityId) - .setTransactionTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), item.amount, senderCommunityId), - recipientKeyPair.getPublicKey(), - ) - .sign(senderKeyPair) + item: TransactionDb, + senderKeyPair: KeyPairEd25519, + recipientKeyPair: KeyPairEd25519, + senderCommunityId: string, + recipientCommunityId: string, + ): GradidoTransactionBuilder { + return this.transactionBuilder + .setCreatedAt(item.balanceDate) + .addMemo( + new EncryptedMemo( + item.memo, + new AuthenticatedEncryption(senderKeyPair), + new AuthenticatedEncryption(recipientKeyPair), + ), + ) + .setSenderCommunity(senderCommunityId) + .setRecipientCommunity(recipientCommunityId) + .setTransactionTransfer( + new TransferAmount(senderKeyPair.getPublicKey(), item.amount, senderCommunityId), + recipientKeyPair.getPublicKey(), + ) + .sign(senderKeyPair) } calculateBalances( - item: TransactionDb, - communityContext: CommunityContext, - coinCommunityId: string, - amount: GradidoUnit, - publicKey: MemoryBlockPtr, - ): AccountBalances { - this.accountBalances.clear() - if (communityContext.foreign) { - this.accountBalances.add(new AccountBalance(publicKey, GradidoUnit.zero(), coinCommunityId)) - return this.accountBalances - } else { - // try to use same coins from this community - let lastBalance = this.getLastBalanceForUser(publicKey, communityContext.blockchain, coinCommunityId) - if (lastBalance.getBalance().equal(GradidoUnit.zero()) || lastBalance.getBalance().calculateDecay(lastBalance.getDate(), item.balanceDate).lt(amount)) { - // don't work, so we use or own coins - lastBalance = this.getLastBalanceForUser(publicKey, communityContext.blockchain, communityContext.communityId) - } - - try { - lastBalance.updateLegacyDecay(amount, item.balanceDate) - } catch(e) { - if (e instanceof NegativeBalanceError) { - console.log(`coin community id: ${coinCommunityId}, context community id: ${communityContext.communityId}`) - this.logLastBalanceChangingTransactions(publicKey, communityContext.blockchain, 1) - throw e - } - } - this.accountBalances.add(lastBalance.getAccountBalance()) - return this.accountBalances + item: TransactionDb, + communityContext: CommunityContext, + coinCommunityId: string, + amount: GradidoUnit, + publicKey: MemoryBlockPtr, + ): AccountBalances { + this.accountBalances.clear() + if (communityContext.foreign) { + this.accountBalances.add(new AccountBalance(publicKey, GradidoUnit.zero(), coinCommunityId)) + return this.accountBalances + } else { + // try to use same coins from this community + let lastBalance = this.getLastBalanceForUser( + publicKey, + communityContext.blockchain, + coinCommunityId, + ) + if ( + lastBalance.getBalance().equal(GradidoUnit.zero()) || + lastBalance.getBalance().calculateDecay(lastBalance.getDate(), item.balanceDate).lt(amount) + ) { + // don't work, so we use or own coins + lastBalance = this.getLastBalanceForUser( + publicKey, + communityContext.blockchain, + communityContext.communityId, + ) } + + try { + lastBalance.updateLegacyDecay(amount, item.balanceDate) + } catch (e) { + if (e instanceof NegativeBalanceError) { + this.logLastBalanceChangingTransactions(publicKey, communityContext.blockchain, 1) + throw e + } + } + this.accountBalances.add(lastBalance.getAccountBalance()) + return this.accountBalances + } } - getUser(item: TransactionDb): { senderUser: UserDb, recipientUser: UserDb } { - return ( - item.typeId === TransactionTypeId.RECEIVE - ? { senderUser: item.linkedUser, recipientUser: item.user } - : { senderUser: item.user, recipientUser: item.linkedUser } - ) + getUser(item: TransactionDb): { senderUser: UserDb; recipientUser: UserDb } { + return item.typeId === TransactionTypeId.RECEIVE + ? { senderUser: item.linkedUser, recipientUser: item.user } + : { senderUser: item.user, recipientUser: item.linkedUser } } pushToBlockchain(item: TransactionDb): void { const { senderUser, recipientUser } = this.getUser(item) - const ledgerAnchor = new LedgerAnchor(item.id, LedgerAnchor.Type_LEGACY_GRADIDO_DB_TRANSACTION_ID) + const ledgerAnchor = new LedgerAnchor( + item.id, + LedgerAnchor.Type_LEGACY_GRADIDO_DB_TRANSACTION_ID, + ) if (senderUser.communityUuid === recipientUser.communityUuid) { - throw new Error(`transfer between user from same community: ${JSON.stringify(item, null, 2)}, check db query`) + throw new Error( + `transfer between user from same community: ${JSON.stringify(item, null, 2)}, check db query`, + ) } const senderCommunityContext = this.context.getCommunityContextByUuid(senderUser.communityUuid) - const recipientCommunityContext = this.context.getCommunityContextByUuid(recipientUser.communityUuid) + const recipientCommunityContext = this.context.getCommunityContextByUuid( + recipientUser.communityUuid, + ) const senderBlockchain = senderCommunityContext.blockchain const recipientBlockchain = recipientCommunityContext.blockchain - + // I use the received transaction so user and linked user are swapped and user is recipient and linkedUser ist sender const senderKeyPair = this.getAccountKeyPair(senderCommunityContext, senderUser.gradidoId) const senderPublicKey = senderKeyPair.getPublicKey() - const recipientKeyPair = this.getAccountKeyPair(recipientCommunityContext, recipientUser.gradidoId) + const recipientKeyPair = this.getAccountKeyPair( + recipientCommunityContext, + recipientUser.gradidoId, + ) const recipientPublicKey = recipientKeyPair.getPublicKey() - + if (!senderKeyPair || !senderPublicKey || !recipientKeyPair || !recipientPublicKey) { throw new Error(`missing key for ${this.itemTypeName()}: ${JSON.stringify(item, null, 2)}`) } const transactionBuilder = this.buildTransaction( - item, - senderKeyPair, - recipientKeyPair, - senderCommunityContext.communityId, - recipientCommunityContext.communityId + item, + senderKeyPair, + recipientKeyPair, + senderCommunityContext.communityId, + recipientCommunityContext.communityId, ) const outboundTransaction = transactionBuilder.buildOutbound() @@ -178,11 +211,17 @@ export class RemoteTransactionsSyncRole extends AbstractSyncRole outboundTransaction, senderBlockchain, ledgerAnchor, - this.calculateBalances(item, senderCommunityContext, senderCommunityContext.communityId, item.amount.negated(), senderPublicKey), + this.calculateBalances( + item, + senderCommunityContext, + senderCommunityContext.communityId, + item.amount.negated(), + senderPublicKey, + ), ) - } catch(e) { + } catch (e) { if (e instanceof NotEnoughGradidoBalanceError) { - this.logLastBalanceChangingTransactions(senderPublicKey, senderBlockchain) + this.logLastBalanceChangingTransactions(senderPublicKey, senderBlockchain) } throw new BlockchainError(`Error adding ${this.itemTypeName()}`, item, e as Error) } @@ -193,11 +232,17 @@ export class RemoteTransactionsSyncRole extends AbstractSyncRole inboundTransaction, recipientBlockchain, ledgerAnchor, - this.calculateBalances(item, recipientCommunityContext, senderCommunityContext.communityId, item.amount, recipientPublicKey), + this.calculateBalances( + item, + recipientCommunityContext, + senderCommunityContext.communityId, + item.amount, + recipientPublicKey, + ), ) - } catch(e) { + } catch (e) { if (e instanceof NotEnoughGradidoBalanceError) { - this.logLastBalanceChangingTransactions(recipientPublicKey, recipientBlockchain) + this.logLastBalanceChangingTransactions(recipientPublicKey, recipientBlockchain) } throw new BlockchainError(`Error adding ${this.itemTypeName()}`, item, e as Error) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts index ddbddd9d4..918d33c3b 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/TransactionLinkFundingsSync.role.ts @@ -1,28 +1,28 @@ -import { asc, eq, or, gt, and } from 'drizzle-orm' -import { +import Decimal from 'decimal.js-light' +import { and, asc, eq, gt, or } from 'drizzle-orm' +import { AccountBalance, - AccountBalances, - AuthenticatedEncryption, - DurationSeconds, - EncryptedMemo, - GradidoTransactionBuilder, - GradidoTransfer, - GradidoUnit, - KeyPairEd25519, - LedgerAnchor, - MemoryBlockPtr, - TransferAmount + AccountBalances, + AuthenticatedEncryption, + DurationSeconds, + EncryptedMemo, + GradidoTransactionBuilder, + GradidoTransfer, + GradidoUnit, + KeyPairEd25519, + LedgerAnchor, + MemoryBlockPtr, + TransferAmount, } from 'gradido-blockchain-js' import * as v from 'valibot' +import { deriveFromCode } from '../../../../data/deriveKeyPair' import { addToBlockchain } from '../../blockchain' +import { Context } from '../../Context' import { transactionLinksTable, usersTable } from '../../drizzle.schema' import { BlockchainError, DatabaseError, NegativeBalanceError } from '../../errors' +import { reverseLegacyDecay, toMysqlDateTime } from '../../utils' import { CommunityContext, TransactionLinkDb, transactionLinkDbSchema } from '../../valibot.schema' import { AbstractSyncRole, IndexType } from './AbstractSync.role' -import { deriveFromCode } from '../../../../data/deriveKeyPair' -import { reverseLegacyDecay, toMysqlDateTime } from '../../utils' -import Decimal from 'decimal.js-light' -import { Context } from '../../Context' export class TransactionLinkFundingsSyncRole extends AbstractSyncRole { constructor(context: Context) { @@ -47,16 +47,18 @@ export class TransactionLinkFundingsSyncRole extends AbstractSyncRole { const item = { ...row.transaction_links, @@ -72,11 +74,11 @@ export class TransactionLinkFundingsSyncRole extends AbstractSyncRole { constructor(context: Context) { @@ -40,20 +40,22 @@ export class UsersSyncRole extends AbstractSyncRole { async loadFromDb(lastIndex: IndexType, count: number): Promise { const result = await this.context.db - .select() - .from(usersTable) - .where(and( + .select() + .from(usersTable) + .where( + and( or( gt(usersTable.createdAt, toMysqlDateTime(lastIndex.date)), and( eq(usersTable.createdAt, toMysqlDateTime(lastIndex.date)), - gt(usersTable.id, lastIndex.id) - ) - ) - )) - .orderBy(asc(usersTable.createdAt), asc(usersTable.id)) - .limit(count) - + gt(usersTable.id, lastIndex.id), + ), + ), + ), + ) + .orderBy(asc(usersTable.createdAt), asc(usersTable.id)) + .limit(count) + return result.map((row) => { try { return v.parse(userDbSchema, row) @@ -65,10 +67,10 @@ export class UsersSyncRole extends AbstractSyncRole { buildTransaction( communityContext: CommunityContext, - item: UserDb, - communityKeyPair: KeyPairEd25519, - accountKeyPair: KeyPairEd25519, - userKeyPair: KeyPairEd25519 + item: UserDb, + communityKeyPair: KeyPairEd25519, + accountKeyPair: KeyPairEd25519, + userKeyPair: KeyPairEd25519, ): GradidoTransactionBuilder { return this.transactionBuilder .setCreatedAt(item.createdAt) @@ -84,9 +86,14 @@ export class UsersSyncRole extends AbstractSyncRole { .sign(userKeyPair) } - calculateAccountBalances(accountPublicKey: MemoryBlockPtr, communityContext: CommunityContext,): AccountBalances { + calculateAccountBalances( + accountPublicKey: MemoryBlockPtr, + communityContext: CommunityContext, + ): AccountBalances { this.accountBalances.clear() - this.accountBalances.add(new AccountBalance(accountPublicKey, GradidoUnit.zero(), communityContext.communityId)) + this.accountBalances.add( + new AccountBalance(accountPublicKey, GradidoUnit.zero(), communityContext.communityId), + ) return this.accountBalances } @@ -101,7 +108,13 @@ export class UsersSyncRole extends AbstractSyncRole { try { addToBlockchain( - this.buildTransaction(communityContext, item, communityContext.keyPair, accountKeyPair, userKeyPair).build(), + this.buildTransaction( + communityContext, + item, + communityContext.keyPair, + accountKeyPair, + userKeyPair, + ).build(), communityContext.blockchain, new LedgerAnchor(item.id, LedgerAnchor.Type_LEGACY_GRADIDO_DB_USER_ID), this.calculateAccountBalances(accountPublicKey, communityContext), diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts index 833b7d6f8..201b7427f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts @@ -1,15 +1,15 @@ import { Profiler } from 'gradido-blockchain-js' -import { Context } from '../../Context' -import { CreationsSyncRole } from './CreationsSync.role' -import { LocalTransactionsSyncRole } from './LocalTransactionsSync.role' -import { UsersSyncRole } from './UsersSync.role' -import { TransactionLinkFundingsSyncRole } from './TransactionLinkFundingsSync.role' -import { RedeemTransactionLinksSyncRole } from './RedeemTransactionLinksSync.role' -import { ContributionLinkTransactionSyncRole } from './ContributionLinkTransactionSync.role' -import { DeletedTransactionLinksSyncRole } from './DeletedTransactionLinksSync.role' -import { RemoteTransactionsSyncRole } from './RemoteTransactionsSync.role' import { callTime } from '../../blockchain' +import { Context } from '../../Context' import { nanosBalanceForUser } from './AbstractSync.role' +import { ContributionLinkTransactionSyncRole } from './ContributionLinkTransactionSync.role' +import { CreationsSyncRole } from './CreationsSync.role' +import { DeletedTransactionLinksSyncRole } from './DeletedTransactionLinksSync.role' +import { LocalTransactionsSyncRole } from './LocalTransactionsSync.role' +import { RedeemTransactionLinksSyncRole } from './RedeemTransactionLinksSync.role' +import { RemoteTransactionsSyncRole } from './RemoteTransactionsSync.role' +import { TransactionLinkFundingsSyncRole } from './TransactionLinkFundingsSync.role' +import { UsersSyncRole } from './UsersSync.role' export async function syncDbWithBlockchainContext(context: Context, batchSize: number) { const timeUsedDB = new Profiler() @@ -38,7 +38,7 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) // log only, if at least one new item was loaded if (loadedItemsCount && isDebug) { - context.logger.debug(`${loadedItemsCount} new items loaded from db in ${timeUsedDB.string()}`) + context.logger.debug(`${loadedItemsCount} new items loaded from db in ${timeUsedDB.string()}`) } // remove empty containers @@ -53,17 +53,21 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) // context.logger.debug(`sorted ${available.length} containers in ${sortTime.string()}`) } - available[0].toBlockchain() + available[0].toBlockchain() transactionsCount++ - if (isDebug) { - if (timeBetweenPrints.millis() > 100) { + if (isDebug) { + if (timeBetweenPrints.millis() > 100) { process.stdout.write(`successfully added to blockchain: ${transactionsCount}\r`) timeBetweenPrints.reset() } - transactionsCountSinceLastLog++ + transactionsCountSinceLastLog++ if (transactionsCountSinceLastLog >= batchSize) { - context.logger.debug(`${transactionsCountSinceLastLog} transactions added to blockchain in ${timeUsedBlockchain.string()}`) - context.logger.info(`Time for createAndConfirm: ${((callTime - lastPrintedCallTime) / 1000 / 1000).toFixed(2)} milliseconds`) + context.logger.debug( + `${transactionsCountSinceLastLog} transactions added to blockchain in ${timeUsedBlockchain.string()}`, + ) + context.logger.info( + `Time for createAndConfirm: ${((callTime - lastPrintedCallTime) / 1000 / 1000).toFixed(2)} milliseconds`, + ) lastPrintedCallTime = callTime timeUsedBlockchain.reset() transactionsCountSinceLastLog = 0 @@ -76,8 +80,14 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n } } } - process.stdout.write(`successfully added to blockchain: ${transactionsCount}\n`) - context.logger.info(`Synced ${transactionsCount} transactions to blockchain in ${timeUsedAll.string()}`) - context.logger.info(`Time for createAndConfirm: ${(callTime / 1000 / 1000 / 1000).toFixed(2)} seconds`) - context.logger.info(`Time for call lastBalance of user: ${(nanosBalanceForUser / 1000 / 1000 / 1000).toFixed(2)} seconds`) + process.stdout.write(`successfully added to blockchain: ${transactionsCount}\n`) + context.logger.info( + `Synced ${transactionsCount} transactions to blockchain in ${timeUsedAll.string()}`, + ) + context.logger.info( + `Time for createAndConfirm: ${(callTime / 1000 / 1000 / 1000).toFixed(2)} seconds`, + ) + context.logger.info( + `Time for call lastBalance of user: ${(nanosBalanceForUser / 1000 / 1000 / 1000).toFixed(2)} seconds`, + ) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/utils.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/utils.ts index 58d7c1133..86604b2c6 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/utils.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/utils.ts @@ -10,7 +10,7 @@ export function bytesToKbyte(bytes: number): string { } export function bytesString(bytes: number): string { - if (bytes > (1024 * 1024)) { + if (bytes > 1024 * 1024) { return `${bytesToMbyte(bytes)} MB` } else if (bytes > 1024) { return `${bytesToKbyte(bytes)} KB` @@ -50,7 +50,9 @@ export function legacyCalculateDecay(amount: Decimal, from: Date, to: Date): Dec const startBlockMs = DECAY_START_TIME.getTime() if (toMs < fromMs) { - throw new Error(`calculateDecay: to (${to.toISOString()}) < from (${from.toISOString()}), reverse decay calculation is invalid`) + throw new Error( + `calculateDecay: to (${to.toISOString()}) < from (${from.toISOString()}), reverse decay calculation is invalid`, + ) } // decay started after end date; no decay @@ -59,7 +61,7 @@ export function legacyCalculateDecay(amount: Decimal, from: Date, to: Date): Dec } // decay started before start date; decay for full duration let duration = (toMs - fromMs) / 1000 - + // decay started between start and end date; decay from decay start till end date if (startBlockMs >= fromMs) { duration = (toMs - startBlockMs) / 1000 diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/valibot.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/valibot.schema.ts index 904be605d..28cab0be7 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/valibot.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/valibot.schema.ts @@ -1,3 +1,4 @@ +import Decimal from 'decimal.js-light' import { GradidoUnit, InMemoryBlockchain, KeyPairEd25519 } from 'gradido-blockchain-js' import * as v from 'valibot' import { booleanSchema, dateSchema } from '../../schemas/typeConverter.schema' @@ -9,7 +10,6 @@ import { } from '../../schemas/typeGuard.schema' import { Balance } from './data/Balance' import { TransactionTypeId } from './data/TransactionTypeId' -import Decimal from 'decimal.js-light' const positiveNumberSchema = v.pipe(v.number(), v.minValue(1)) @@ -51,53 +51,71 @@ export const transactionBaseSchema = v.object({ user: userDbSchema, }) +export const transactionDbSchema = v.pipe( + v.object({ + ...transactionBaseSchema.entries, + typeId: v.enum(TransactionTypeId), + balanceDate: dateSchema, + linkedUser: userDbSchema, + }), + v.custom((value: any) => { + if ( + value.user && + value.linkedUser && + !value.transactionLinkCode && + value.user.gradidoId === value.linkedUser.gradidoId + ) { + throw new Error( + `expect user to be different from linkedUser: ${JSON.stringify(value, null, 2)}`, + ) + } + // check that user and linked user exist before transaction balance date + const balanceDate = new Date(value.balanceDate) + if ( + value.user.createdAt.getTime() >= balanceDate.getTime() || + value.linkedUser?.createdAt.getTime() >= balanceDate.getTime() + ) { + throw new Error( + `at least one user was created after transaction balance date, logic error! ${JSON.stringify(value, null, 2)}`, + ) + } -export const transactionDbSchema = v.pipe(v.object({ - ...transactionBaseSchema.entries, - typeId: v.enum(TransactionTypeId), - balanceDate: dateSchema, - linkedUser: userDbSchema, -}), v.custom((value: any) => { - if (value.user && value.linkedUser && !value.transactionLinkCode && value.user.gradidoId === value.linkedUser.gradidoId) { - throw new Error(`expect user to be different from linkedUser: ${JSON.stringify(value, null, 2)}`) - } - // check that user and linked user exist before transaction balance date - const balanceDate = new Date(value.balanceDate) - if ( - value.user.createdAt.getTime() >= balanceDate.getTime() || - value.linkedUser?.createdAt.getTime() >= balanceDate.getTime() - ) { - throw new Error( - `at least one user was created after transaction balance date, logic error! ${JSON.stringify(value, null, 2)}`, - ) - } - - return value -})) + return value + }), +) -export const creationTransactionDbSchema = v.pipe(v.object({ - ...transactionBaseSchema.entries, - contributionDate: dateSchema, - confirmedAt: dateSchema, - confirmedByUser: userDbSchema, - transactionId: positiveNumberSchema, -}), v.custom((value: any) => { - if (value.user && value.confirmedByUser && value.user.gradidoId === value.confirmedByUser.gradidoId) { - throw new Error(`expect user to be different from confirmedByUser: ${JSON.stringify(value, null, 2)}`) - } - // check that user and confirmedByUser exist before transaction balance date - const confirmedAt = new Date(value.confirmedAt) - if ( - value.user.createdAt.getTime() >= confirmedAt.getTime() || - value.confirmedByUser?.createdAt.getTime() >= confirmedAt.getTime() - ) { - throw new Error( - `at least one user was created after transaction confirmedAt date, logic error! ${JSON.stringify(value, null, 2)}`, - ) - } - - return value -})) +export const creationTransactionDbSchema = v.pipe( + v.object({ + ...transactionBaseSchema.entries, + contributionDate: dateSchema, + confirmedAt: dateSchema, + confirmedByUser: userDbSchema, + transactionId: positiveNumberSchema, + }), + v.custom((value: any) => { + if ( + value.user && + value.confirmedByUser && + value.user.gradidoId === value.confirmedByUser.gradidoId + ) { + throw new Error( + `expect user to be different from confirmedByUser: ${JSON.stringify(value, null, 2)}`, + ) + } + // check that user and confirmedByUser exist before transaction balance date + const confirmedAt = new Date(value.confirmedAt) + if ( + value.user.createdAt.getTime() >= confirmedAt.getTime() || + value.confirmedByUser?.createdAt.getTime() >= confirmedAt.getTime() + ) { + throw new Error( + `at least one user was created after transaction confirmedAt date, logic error! ${JSON.stringify(value, null, 2)}`, + ) + } + + return value + }), +) export const transactionLinkDbSchema = v.object({ ...transactionBaseSchema.entries, diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 572593f0c..167712660 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -89,7 +89,7 @@ export const confirmedTransactionSchema = v.pipe( if (typeof data === 'object' && 'base64' in data && 'communityId' in data) { return confirmedTransactionFromBase64(data.base64, data.communityId) } - throw new Error('invalid data, community id missing, couldn\'t deserialize') + throw new Error("invalid data, community id missing, couldn't deserialize") }, ), ) diff --git a/dlt-connector/src/utils/filesystem.ts b/dlt-connector/src/utils/filesystem.ts index 096437fb5..338d536d8 100644 --- a/dlt-connector/src/utils/filesystem.ts +++ b/dlt-connector/src/utils/filesystem.ts @@ -31,4 +31,4 @@ export function checkPathExist(path: string, createIfMissing: boolean = false): export function toFolderName(name: string): string { return name.toLowerCase().replace(/[^a-z0-9]/g, '_') -} \ No newline at end of file +} diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 4124df7e6..1e0ac464a 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -8,7 +8,10 @@ import { AccountType } from '../data/AccountType.enum' import { AddressType } from '../data/AddressType.enum' import { Uuidv4 } from '../schemas/typeGuard.schema' -export const confirmedTransactionFromBase64 = (base64: string, communityId: Uuidv4): ConfirmedTransaction => { +export const confirmedTransactionFromBase64 = ( + base64: string, + communityId: Uuidv4, +): ConfirmedTransaction => { const confirmedTransactionBinaryPtr = MemoryBlock.createPtr(MemoryBlock.fromBase64(base64)) const deserializer = new InteractionDeserialize( confirmedTransactionBinaryPtr, diff --git a/shared/src/logic/decay.ts b/shared/src/logic/decay.ts index 23c37abf2..2346c2635 100644 --- a/shared/src/logic/decay.ts +++ b/shared/src/logic/decay.ts @@ -22,9 +22,7 @@ export function decayFormula(value: Decimal, seconds: number): Decimal { // chatgpt: We convert to string here to avoid precision loss: // .pow(seconds) can internally round the result, especially for large values of `seconds`. // Using .toString() ensures full precision is preserved in the multiplication. - return value.mul( - DECAY_FACTOR.pow(seconds).toString(), - ) + return value.mul(DECAY_FACTOR.pow(seconds).toString()) } // legacy reverse decay formula