From f45705e714625eba9741ad75f69c08fa61b51f7e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 25 Feb 2026 16:04:25 +0100 Subject: [PATCH 1/2] give communitId with txs for blockchain --- .../apis/dltConnector/model/AccountIdentifier.ts | 4 +++- .../apis/dltConnector/model/TransactionDraft.ts | 15 +++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/backend/src/apis/dltConnector/model/AccountIdentifier.ts b/backend/src/apis/dltConnector/model/AccountIdentifier.ts index 3882e8584..1d324a70f 100644 --- a/backend/src/apis/dltConnector/model/AccountIdentifier.ts +++ b/backend/src/apis/dltConnector/model/AccountIdentifier.ts @@ -1,15 +1,17 @@ import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' export class AccountIdentifier { communityTopicId: string + communityId: string account?: CommunityAccountIdentifier seed?: string // used for deferred transfers - constructor(communityTopicId: string, input: CommunityAccountIdentifier | string) { + constructor(communityTopicId: string, communityUuid: string, input: CommunityAccountIdentifier | string) { if (input instanceof CommunityAccountIdentifier) { this.account = input } else { this.seed = input } this.communityTopicId = communityTopicId + this.communityId = communityUuid } } diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 1727c7fd8..5352bf841 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -36,6 +36,7 @@ export class TransactionDraft { const draft = new TransactionDraft() draft.user = new AccountIdentifier( community.hieroTopicId, + community.communityUuid!, new CommunityAccountIdentifier(user.gradidoID), ) draft.type = TransactionType.REGISTER_ADDRESS @@ -58,10 +59,12 @@ export class TransactionDraft { const draft = new TransactionDraft() draft.user = new AccountIdentifier( community.hieroTopicId, + community.communityUuid!, new CommunityAccountIdentifier(contribution.user.gradidoID), ) draft.linkedUser = new AccountIdentifier( community.hieroTopicId, + community.communityUuid!, new CommunityAccountIdentifier(signingUser.gradidoID), ) draft.type = TransactionType.GRADIDO_CREATION @@ -96,10 +99,12 @@ export class TransactionDraft { const draft = new TransactionDraft() draft.user = new AccountIdentifier( senderUserTopic, + sendingUser.community.communityUuid!, new CommunityAccountIdentifier(sendingUser.gradidoID), ) draft.linkedUser = new AccountIdentifier( receiverUserTopic, + receivingUser.community.communityUuid!, new CommunityAccountIdentifier(receivingUser.gradidoID), ) draft.type = TransactionType.GRADIDO_TRANSFER @@ -125,9 +130,10 @@ export class TransactionDraft { const draft = new TransactionDraft() draft.user = new AccountIdentifier( senderUserTopic, + sendingUser.community.communityUuid!, new CommunityAccountIdentifier(sendingUser.gradidoID), ) - draft.linkedUser = new AccountIdentifier(senderUserTopic, 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() @@ -159,9 +165,14 @@ export class TransactionDraft { const createdAtOnlySeconds = createdAt createdAtOnlySeconds.setMilliseconds(0) const draft = new TransactionDraft() - draft.user = new AccountIdentifier(senderUserTopic, transactionLink.code) + draft.user = new AccountIdentifier( + senderUserTopic, + transactionLink.user.community.communityUuid!, + transactionLink.code, + ) draft.linkedUser = new AccountIdentifier( recipientUserTopic, + recipientUser.community.communityUuid!, new CommunityAccountIdentifier(recipientUser.gradidoID), ) draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER From 10334f5a46c38c8dd601e63b95948c7dfc54351d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 25 Feb 2026 16:05:14 +0100 Subject: [PATCH 2/2] add option, fix type errors because of changes regarding need of communityId on some places --- dlt-connector/src/bootstrap/init.ts | 3 +- .../src/bootstrap/initGradidoNode.ts | 3 +- .../client/GradidoNode/GradidoNodeClient.ts | 32 +++++++++---------- .../client/GradidoNode/GradidoNodeProcess.ts | 16 ++++++++++ .../client/GradidoNode/input.schema.test.ts | 22 +++++++------ dlt-connector/src/client/hiero/HieroClient.ts | 5 +-- dlt-connector/src/config/schema.ts | 7 ++++ .../src/data/KeyPairIdentifier.logic.ts | 7 ++-- .../AbstractRemoteKeyPair.role.ts | 8 ++--- .../ForeignCommunityKeyPair.role.ts | 2 +- .../RemoteAccountKeyPair.role.ts | 4 +-- .../resolveKeyPair/ResolveKeyPair.context.ts | 2 +- .../CommunityRootTransaction.role.ts | 5 ++- .../sendToHiero/CreationTransaction.role.ts | 7 +++- .../DeferredTransferTransaction.role.ts | 2 ++ .../RedeemDeferredTransferTransaction.role.ts | 1 + .../RegisterAddressTransaction.role.ts | 5 ++- .../sendToHiero/SendToHiero.context.ts | 15 +++++++-- .../sendToHiero/TransferTransaction.role.ts | 6 +++- .../data/keyPair.ts | 4 ++- dlt-connector/src/schemas/account.schema.ts | 1 + .../src/schemas/transaction.schema.test.ts | 19 +++++++++++ .../src/schemas/transaction.schema.ts | 2 ++ .../src/schemas/typeConverter.schema.ts | 21 ++++++++---- dlt-connector/src/server/index.ts | 12 ++++--- dlt-connector/src/server/input.schema.ts | 2 ++ dlt-connector/src/utils/filesystem.ts | 2 +- dlt-connector/src/utils/typeConverter.ts | 5 +-- 28 files changed, 156 insertions(+), 64 deletions(-) diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index a1c599cea..97a3a03ef 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -1,5 +1,5 @@ import { readFileSync } from 'node:fs' -import { loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' +import { InMemoryBlockchainProvider, loadCryptoKeys, MemoryBlock } from 'gradido-blockchain-js' import { configure, getLogger, Logger } from 'log4js' import * as v from 'valibot' import { CONFIG } from '../config' @@ -80,6 +80,7 @@ export async function checkGradidoNode( // ask gradido node if community blockchain was created try { + InMemoryBlockchainProvider.getInstance().getBlockchain(homeCommunity.uuid) if ( !(await clients.gradidoNode.getTransaction({ transactionId: 1, diff --git a/dlt-connector/src/bootstrap/initGradidoNode.ts b/dlt-connector/src/bootstrap/initGradidoNode.ts index 7c652a667..dfc8d0c10 100644 --- a/dlt-connector/src/bootstrap/initGradidoNode.ts +++ b/dlt-connector/src/bootstrap/initGradidoNode.ts @@ -9,7 +9,6 @@ import { HieroClient } from '../client/hiero/HieroClient' import { CONFIG } from '../config' import { GRADIDO_NODE_HOME_FOLDER_NAME, - GRADIDO_NODE_RUNTIME_PATH, LOG4JS_BASE_CATEGORY, } from '../config/const' import { checkFileExist, checkPathExist } from '../utils/filesystem' @@ -37,7 +36,7 @@ export async function initGradidoNode(clients: AppContextClients): Promise // write Hedera Address Book exportHederaAddressbooks(gradidoNodeHomeFolder, clients.hiero), // check GradidoNode Runtime, download when missing - ensureGradidoNodeRuntimeAvailable(GRADIDO_NODE_RUNTIME_PATH), + ensureGradidoNodeRuntimeAvailable(GradidoNodeProcess.getRuntimePathFileName()), // export communities to GradidoNode Folder exportCommunities(gradidoNodeHomeFolder, clients.backend), ]) diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeClient.ts index d66a58887..0a3d0c7ae 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, HieroId, hex32Schema } from '../../schemas/typeGuard.schema' +import { Hex32, Hex32Input, Uuidv4, hex32Schema } from '../../schemas/typeGuard.schema' import { isPortOpenRetry } from '../../utils/network' import { GradidoNodeErrorCodes } from './GradidoNodeErrorCodes' import { @@ -75,7 +75,7 @@ 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, response.result.transaction) + return v.parse(confirmedTransactionSchema, { base64: response.result.transaction, communityId: parameter.communityId }) } if (response.isError()) { if (response.error.code === GradidoNodeErrorCodes.TRANSACTION_NOT_FOUND) { @@ -88,19 +88,19 @@ export class GradidoNodeClient { /** * getLastTransaction * get the last confirmed transaction from a specific community - * @param hieroTopic the community hiero topic id + * @param communityId the community id * @returns the last confirmed transaction or undefined if blockchain for community is empty or not found * @throws GradidoNodeRequestError */ - public async getLastTransaction(hieroTopic: HieroId): Promise { + public async getLastTransaction(communityId: Uuidv4): Promise { const parameter = { format: 'base64', - topic: hieroTopic, + communityId, } const response = await this.rpcCall<{ transaction: string }>('getLastTransaction', parameter) if (response.isSuccess()) { - return v.parse(confirmedTransactionSchema, response.result.transaction) + return v.parse(confirmedTransactionSchema, { base64: response.result.transaction, communityId: parameter.communityId }) } if (response.isError()) { if (response.error.code === GradidoNodeErrorCodes.GRADIDO_NODE_ERROR) { @@ -115,7 +115,7 @@ export class GradidoNodeClient { * get list of confirmed transactions from a specific community * @param input fromTransactionId is the id of the first transaction to return * @param input maxResultCount is the max number of transactions to return - * @param input topic is the community hiero topic id + * @param input communityId is the community id * @returns list of confirmed transactions * @throws GradidoNodeRequestError * @example @@ -123,7 +123,7 @@ export class GradidoNodeClient { * const transactions = await getTransactions({ * fromTransactionId: 1, * maxResultCount: 100, - * topic: communityUuid, + * communityId: communityUuid, * }) * ``` */ @@ -137,7 +137,7 @@ export class GradidoNodeClient { parameter, ) return result.transactions.map((transactionBase64) => - v.parse(confirmedTransactionSchema, transactionBase64), + v.parse(confirmedTransactionSchema, { base64: transactionBase64, communityId: parameter.communityId }), ) } @@ -163,7 +163,7 @@ export class GradidoNodeClient { parameter, ) return response.transactions.map((transactionBase64) => - v.parse(confirmedTransactionSchema, transactionBase64), + v.parse(confirmedTransactionSchema, { base64: transactionBase64, communityId: parameter.communityId }), ) } @@ -173,15 +173,15 @@ export class GradidoNodeClient { * can be used to check if user/account exists on blockchain * look also for gmw, auf and deferred transfer accounts * @param pubkey the public key of the user or account - * @param hieroTopic the community hiero topic id + * @param communityId the community id * @returns the address type of the user/account, AddressType.NONE if not found * @throws GradidoNodeRequestError */ - public async getAddressType(pubkey: Hex32Input, hieroTopic: HieroId): Promise { + public async getAddressType(pubkey: Hex32Input, communityId: Uuidv4): Promise { const parameter = { pubkey: v.parse(hex32Schema, pubkey), - topic: hieroTopic, + communityId, } const response = await this.rpcCallResolved<{ addressType: string }>( 'getAddressType', @@ -194,17 +194,17 @@ export class GradidoNodeClient { * findUserByNameHash * find a user by name hash * @param nameHash the name hash of the user - * @param hieroTopic the community hiero topic id + * @param communityId the community id * @returns the public key of the user as hex32 string or undefined if user is not found * @throws GradidoNodeRequestError */ public async findUserByNameHash( nameHash: Uuidv4Hash, - hieroTopic: HieroId, + communityId: Uuidv4, ): Promise { const parameter = { nameHash: nameHash.getAsHexString(), - topic: hieroTopic, + communityId, } const response = await this.rpcCall<{ pubkey: string; timeUsed: string }>( 'findUserByNameHash', diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index 0eae2f37e..526fd99be 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -10,6 +10,7 @@ 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. @@ -43,6 +44,20 @@ export class GradidoNodeProcess { return GradidoNodeProcess.instance } + public static getRuntimePathFileName(): string { + const isWindows = process.platform === 'win32' + const binaryName = isWindows ? 'GradidoNode.exe' : 'GradidoNode' + + return path.join( + __dirname, + '..', + '..', + 'gradido_node', + 'bin', + binaryName, + ) + } + public start() { if (this.proc) { this.logger.warn('GradidoNodeProcess already running.') @@ -57,6 +72,7 @@ export class GradidoNodeProcess { SERVER_JSON_RPC_PORT: CONFIG.DLT_NODE_SERVER_PORT.toString(), USERPROFILE: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + UNSECURE_ALLOW_CORS_ALL: CONFIG.DLT_GRADIDO_NODE_SERVER_ALLOW_CORS ? '1' : '0', }, onExit(_proc, exitCode, signalCode, error) { logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`) diff --git a/dlt-connector/src/client/GradidoNode/input.schema.test.ts b/dlt-connector/src/client/GradidoNode/input.schema.test.ts index fbe63dabb..550437100 100644 --- a/dlt-connector/src/client/GradidoNode/input.schema.test.ts +++ b/dlt-connector/src/client/GradidoNode/input.schema.test.ts @@ -1,18 +1,20 @@ import { beforeAll, describe, expect, it } from 'bun:test' import * as v from 'valibot' import { - HieroId, HieroTransactionIdString, + Uuidv4, hieroIdSchema, hieroTransactionIdStringSchema, + uuidv4Schema, } from '../../schemas/typeGuard.schema' import { transactionIdentifierSchema } from './input.schema' +import { v4 as uuidv4 } from 'uuid' -let topic: HieroId -const topicString = '0.0.261' +let communityId: Uuidv4 +const uuidv4String = uuidv4() let hieroTransactionId: HieroTransactionIdString beforeAll(() => { - topic = v.parse(hieroIdSchema, topicString) + communityId = v.parse(uuidv4Schema, uuidv4String) hieroTransactionId = v.parse(hieroTransactionIdStringSchema, '0.0.261-1755348116-1281621') }) @@ -21,26 +23,26 @@ describe('transactionIdentifierSchema ', () => { expect( v.parse(transactionIdentifierSchema, { transactionId: 1, - topic: topicString, + communityId, }), ).toEqual({ transactionId: 1, hieroTransactionId: undefined, - topic, + communityId, }) }) it('valid, transaction identified by hieroTransactionId and topic', () => { expect( v.parse(transactionIdentifierSchema, { hieroTransactionId: '0.0.261-1755348116-1281621', - topic: topicString, + communityId, }), ).toEqual({ hieroTransactionId, - topic, + communityId, }) }) - it('invalid, missing topic', () => { + it('invalid, missing communityId', () => { expect(() => v.parse(transactionIdentifierSchema, { transactionId: 1, @@ -53,7 +55,7 @@ describe('transactionIdentifierSchema ', () => { v.parse(transactionIdentifierSchema, { transactionId: 1, hieroTransactionId: '0.0.261-1755348116-1281621', - topic, + communityId, }), ).toThrowError(new Error('expect transactionNr or hieroTransactionId not both')) }) diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index c32c4cbd7..f82139854 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -20,7 +20,7 @@ import { getLogger, Logger } from 'log4js' import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' +import { HieroId, hieroIdSchema, Uuidv4 } from '../../schemas/typeGuard.schema' import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' @@ -72,6 +72,7 @@ export class HieroClient { public async sendMessage( topicId: HieroId, + communityId: Uuidv4, transaction: GradidoTransaction, ): Promise { const timeUsed = new Profiler() @@ -102,7 +103,7 @@ export class HieroClient { // after 10 seconds, else restart GradidoNode setTimeout(async () => { const transaction = await GradidoNodeClient.getInstance().getTransaction({ - topic: topicId, + communityId, hieroTransactionId: sendResponse.transactionId.toString(), }) if (!transaction) { diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index ef4558545..753da05c5 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -90,6 +90,13 @@ export const configSchema = v.object({ v.string('The home folder for the gradido dlt node server'), path.join(__dirname, '..', '..', 'gradido_node'), ), + DLT_GRADIDO_NODE_SERVER_ALLOW_CORS: v.optional( + v.pipe( + v.string('Whether to allow CORS for the gradido dlt node server'), + v.transform((input: string) => input === 'true'), + ), + 'false', + ), BACKEND_PORT: v.optional( v.pipe( v.string('A valid port on which the backend server is running'), diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 3b6b71c6e..0ee541572 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -54,6 +54,9 @@ export class KeyPairIdentifierLogic { return this.identifier.seed } + getCommunityId(): Uuidv4 { + return this.identifier.communityId + } getCommunityTopicId(): HieroId { return this.identifier.communityTopicId } @@ -76,7 +79,7 @@ export class KeyPairIdentifierLogic { return this.getSeed() } getCommunityKey(): string { - return this.getCommunityTopicId() + return this.getCommunityId() } getCommunityUserKey(): string { return this.deriveCommunityUserHash(0) @@ -107,7 +110,7 @@ export class KeyPairIdentifierLogic { ) } const resultString = - this.identifier.communityTopicId + + this.identifier.communityId + this.identifier.account.userUuid.replace(/-/g, '') + accountNr.toString() return new MemoryBlock(resultString).calculateHash().convertToHex() diff --git a/dlt-connector/src/interactions/resolveKeyPair/AbstractRemoteKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/AbstractRemoteKeyPair.role.ts index 30b824d86..5b99a6c19 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/AbstractRemoteKeyPair.role.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/AbstractRemoteKeyPair.role.ts @@ -1,10 +1,10 @@ import { KeyPairEd25519 } from 'gradido-blockchain-js' -import { HieroId } from '../../schemas/typeGuard.schema' +import { Uuidv4 } from '../../schemas/typeGuard.schema' export abstract class AbstractRemoteKeyPairRole { - protected topic: HieroId - public constructor(communityTopicId: HieroId) { - this.topic = communityTopicId + protected communityId: Uuidv4 + public constructor(communityId: Uuidv4) { + this.communityId = communityId } public abstract retrieveKeyPair(): Promise } diff --git a/dlt-connector/src/interactions/resolveKeyPair/ForeignCommunityKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/ForeignCommunityKeyPair.role.ts index 8911b8851..88db253a7 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ForeignCommunityKeyPair.role.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ForeignCommunityKeyPair.role.ts @@ -10,7 +10,7 @@ export class ForeignCommunityKeyPairRole extends AbstractRemoteKeyPairRole { public async retrieveKeyPair(): Promise { const transactionIdentifier = { transactionId: 1, - topic: this.topic, + communityId: this.communityId, } const firstTransaction = await GradidoNodeClient.getInstance().getTransaction(transactionIdentifier) diff --git a/dlt-connector/src/interactions/resolveKeyPair/RemoteAccountKeyPair.role.ts b/dlt-connector/src/interactions/resolveKeyPair/RemoteAccountKeyPair.role.ts index 524c3dc1a..43e1fa5f6 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/RemoteAccountKeyPair.role.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/RemoteAccountKeyPair.role.ts @@ -7,7 +7,7 @@ import { AbstractRemoteKeyPairRole } from './AbstractRemoteKeyPair.role' export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { public constructor(private identifier: IdentifierAccount) { - super(identifier.communityTopicId) + super(identifier.communityId) } public async retrieveKeyPair(): Promise { @@ -17,7 +17,7 @@ export class RemoteAccountKeyPairRole extends AbstractRemoteKeyPairRole { const accountPublicKey = await GradidoNodeClient.getInstance().findUserByNameHash( new Uuidv4Hash(this.identifier.account.userUuid), - this.topic, + this.communityId, ) if (accountPublicKey) { return new KeyPairEd25519(MemoryBlock.createPtr(MemoryBlock.fromHex(accountPublicKey))) diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts index 406463c4c..551997e9d 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -45,7 +45,7 @@ export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise { const builder = new GradidoTransactionBuilder() const communityKeyPair = await ResolveKeyPair( - new KeyPairIdentifierLogic({ communityTopicId: this.community.hieroTopicId }), + new KeyPairIdentifierLogic({ + communityTopicId: this.community.hieroTopicId, + communityId: this.community.uuid, + }), ) const gmwKeyPair = communityKeyPair.deriveChild( hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX), diff --git a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts index 4f4d653a6..9bd7a7e8c 100644 --- a/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/CreationTransaction.role.ts @@ -52,6 +52,7 @@ export class CreationTransactionRole extends AbstractTransactionRole { const homeCommunityKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic({ communityTopicId: this.homeCommunityTopicId, + communityId: this.creationTransaction.user.communityId, }), ) // Memo: encrypted, home community and recipient can decrypt it @@ -65,7 +66,11 @@ export class CreationTransactionRole extends AbstractTransactionRole { ), ) .setTransactionCreation( - new TransferAmount(recipientKeyPair.getPublicKey(), this.creationTransaction.amount), + new TransferAmount( + recipientKeyPair.getPublicKey(), + this.creationTransaction.amount, + this.creationTransaction.user.communityId, + ), this.creationTransaction.targetDate, ) .sign(signerKeyPair) diff --git a/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts index 95459a8b6..3ac72c0ad 100644 --- a/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/DeferredTransferTransaction.role.ts @@ -41,6 +41,7 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { const recipientKeyPair = await ResolveKeyPair( new KeyPairIdentifierLogic({ communityTopicId: this.deferredTransferTransaction.linkedUser.communityTopicId, + communityId: this.deferredTransferTransaction.linkedUser.communityId, seed: this.seed, }), ) @@ -61,6 +62,7 @@ export class DeferredTransferTransactionRole extends AbstractTransactionRole { this.deferredTransferTransaction.amount.calculateCompoundInterest( this.deferredTransferTransaction.timeoutDuration.getSeconds(), ), + this.deferredTransferTransaction.user.communityId, ), recipientKeyPair.getPublicKey(), ), diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 4615a4707..0c0a3c64e 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -65,6 +65,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo new TransferAmount( senderKeyPair.getPublicKey(), this.redeemDeferredTransferTransaction.amount, + this.redeemDeferredTransferTransaction.user.communityId, ), recipientKeyPair.getPublicKey(), ), diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts index acb40975c..98ddc01f3 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.ts @@ -35,7 +35,10 @@ 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 })) + 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 f96bfe402..9bb6f5c74 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -23,6 +23,8 @@ import { HieroTransactionIdString, hieroTransactionIdStringSchema, identifierSeedSchema, + Uuidv4, + uuidv4Schema, } from '../../schemas/typeGuard.schema' import { isTopicStillOpen } from '../../utils/hiero' import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' @@ -59,6 +61,7 @@ export async function SendToHieroContext( const outboundHieroTransactionIdString = await sendViaHiero( outboundTransaction, role.getSenderCommunityTopicId(), + v.parse(uuidv4Schema, outboundTransaction.getCommunityId()), ) // attach Hiero transaction ID to the builder for the inbound transaction @@ -69,7 +72,11 @@ export async function SendToHieroContext( validate(inboundTransaction) // send inbound transaction to hiero - await sendViaHiero(inboundTransaction, role.getRecipientCommunityTopicId()) + await sendViaHiero( + inboundTransaction, + role.getRecipientCommunityTopicId(), + v.parse(uuidv4Schema, inboundTransaction.getCommunityId()), + ) return outboundHieroTransactionIdString } else { // build and validate local transaction @@ -80,6 +87,7 @@ export async function SendToHieroContext( const hieroTransactionIdString = await sendViaHiero( transaction, role.getSenderCommunityTopicId(), + v.parse(uuidv4Schema, transaction.getCommunityId()), ) return hieroTransactionIdString } @@ -95,9 +103,10 @@ function validate(transaction: GradidoTransaction): void { async function sendViaHiero( gradidoTransaction: GradidoTransaction, topic: HieroId, + communityId: Uuidv4 ): Promise { const client = HieroClient.getInstance() - const transactionId = await client.sendMessage(topic, gradidoTransaction) + const transactionId = await client.sendMessage(topic, communityId, gradidoTransaction) if (!transactionId) { throw new Error('missing transaction id from hiero') } @@ -153,7 +162,7 @@ async function chooseCorrectRole( throw new Error("redeem deferred transfer: couldn't generate seed public key") } const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount( - { maxResultCount: 2, topic: transaction.user.communityTopicId }, + { maxResultCount: 2, communityId: transaction.user.communityId }, seedPublicKey.convertToHex(), ) if (!transactions || transactions.length !== 1) { diff --git a/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts index f0a1314cb..fe9258d74 100644 --- a/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/TransferTransaction.role.ts @@ -51,7 +51,11 @@ export class TransferTransactionRole extends AbstractTransactionRole { ), ) .setTransactionTransfer( - new TransferAmount(senderKeyPair.getPublicKey(), this.transferTransaction.amount), + new TransferAmount( + senderKeyPair.getPublicKey(), + this.transferTransaction.amount, + this.transferTransaction.user.communityId, + ), recipientKeyPair.getPublicKey(), ) const senderCommunity = this.transferTransaction.user.communityTopicId diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/data/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/data/keyPair.ts index cbd365f75..64ba7345d 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/data/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.7/data/keyPair.ts @@ -30,7 +30,7 @@ export function generateKeyPairCommunity( if (!keyPair) { throw new Error(`Couldn't create key pair for community ${community.communityUuid}`) } - const communityKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: topicId }).getKey() + const communityKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: topicId, communityId: community.communityUuid }).getKey() cache.addKeyPair(communityKeyPairKey, keyPair) logger.info(`Community Key Pair added with key: ${communityKeyPairKey}`) } @@ -44,6 +44,7 @@ export async function generateKeyPairUserAccount( const userKeyPairRole = new UserKeyPairRole(user.gradidoId, communityKeyPair) const userKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: communityTopicId, + communityId: user.communityUuid, account: { userUuid: user.gradidoId, accountNr: 0, @@ -56,6 +57,7 @@ export async function generateKeyPairUserAccount( const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) const accountKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: communityTopicId, + communityId: user.communityUuid, account: { userUuid: user.gradidoId, accountNr: 1, diff --git a/dlt-connector/src/schemas/account.schema.ts b/dlt-connector/src/schemas/account.schema.ts index e328a2f90..c36655bcb 100644 --- a/dlt-connector/src/schemas/account.schema.ts +++ b/dlt-connector/src/schemas/account.schema.ts @@ -11,6 +11,7 @@ export type IdentifierCommunityAccount = v.InferOutput { } let topic: HieroId const topicString = '0.0.261' +let communityUuid: Uuidv4 +const communityUuidString = '123e4567-e89b-12d3-a456-426614174000' + beforeAll(() => { topic = v.parse(hieroIdSchema, topicString) + communityUuid = v.parse(uuidv4Schema, communityUuidString) }) describe('transaction schemas', () => { @@ -55,6 +59,7 @@ describe('transaction schemas', () => { registerAddress = { user: { communityTopicId: topicString, + communityId: communityUuidString, account: { userUuid: userUuidString }, }, type: InputTransactionType.REGISTER_ADDRESS, @@ -66,6 +71,7 @@ describe('transaction schemas', () => { expect(v.parse(transactionSchema, registerAddress)).toEqual({ user: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0, @@ -80,6 +86,7 @@ describe('transaction schemas', () => { expect(v.parse(registerAddressTransactionSchema, registerAddress)).toEqual({ user: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0, @@ -101,10 +108,12 @@ describe('transaction schemas', () => { const gradidoTransfer: TransactionInput = { user: { communityTopicId: topicString, + communityId: communityUuidString, account: { userUuid: userUuidString }, }, linkedUser: { communityTopicId: topicString, + communityId: communityUuidString, account: { userUuid: userUuidString }, }, amount: '100', @@ -115,6 +124,7 @@ describe('transaction schemas', () => { expect(v.parse(transactionSchema, gradidoTransfer)).toEqual({ user: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0, @@ -122,6 +132,7 @@ describe('transaction schemas', () => { }, linkedUser: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0, @@ -138,10 +149,12 @@ describe('transaction schemas', () => { const gradidoCreation: TransactionInput = { user: { communityTopicId: topicString, + communityId: communityUuidString, account: { userUuid: userUuidString }, }, linkedUser: { communityTopicId: topicString, + communityId: communityUuidString, account: { userUuid: userUuidString }, }, amount: '1000', @@ -153,10 +166,12 @@ describe('transaction schemas', () => { expect(v.parse(transactionSchema, gradidoCreation)).toEqual({ user: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0 }, }, linkedUser: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0 }, }, amount: v.parse(gradidoAmountSchema, gradidoCreation.amount!), @@ -172,12 +187,14 @@ describe('transaction schemas', () => { const gradidoTransactionLink: TransactionInput = { user: { communityTopicId: topicString, + communityId: communityUuidString, account: { userUuid: userUuidString, }, }, linkedUser: { communityTopicId: topicString, + communityId: communityUuidString, seed, }, amount: '100', @@ -189,6 +206,7 @@ describe('transaction schemas', () => { expect(v.parse(transactionSchema, gradidoTransactionLink)).toEqual({ user: { communityTopicId: topic, + communityId: communityUuid, account: { userUuid, accountNr: 0, @@ -196,6 +214,7 @@ describe('transaction schemas', () => { }, linkedUser: { communityTopicId: topic, + communityId: communityUuid, seed: seedParsed, }, amount: v.parse(gradidoAmountSchema, gradidoTransactionLink.amount!), diff --git a/dlt-connector/src/schemas/transaction.schema.ts b/dlt-connector/src/schemas/transaction.schema.ts index b018a8e86..c1e16c050 100644 --- a/dlt-connector/src/schemas/transaction.schema.ts +++ b/dlt-connector/src/schemas/transaction.schema.ts @@ -43,12 +43,14 @@ export type Transaction = v.InferOutput // if the account is identified by seed export const seedAccountSchema = v.object({ communityTopicId: hieroIdSchema, + communityId: uuidv4Schema, seed: identifierSeedSchema, }) // if the account is identified by userUuid and accountNr export const userAccountSchema = v.object({ communityTopicId: hieroIdSchema, + communityId: uuidv4Schema, account: identifierCommunityAccountSchema, }) diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 8774bd6c2..572593f0c 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -8,6 +8,7 @@ import { toAccountType, toAddressType, } from '../utils/typeConverter' +import { Uuidv4, uuidv4Schema } from './typeGuard.schema' /** * dateSchema for creating a date from string or Date object @@ -72,17 +73,23 @@ export const accountTypeSchema = v.pipe( export const confirmedTransactionSchema = v.pipe( v.union([ v.instance(ConfirmedTransaction, 'expect ConfirmedTransaction'), - v.pipe( - v.string('expect confirmed Transaction base64 as string type'), - v.base64('expect to be valid base64'), - ), + v.object({ + base64: v.pipe( + v.string('expect confirmed Transaction base64 as string type'), + v.base64('expect to be valid base64'), + ), + communityId: uuidv4Schema, + }), ]), - v.transform( - (data: string | ConfirmedTransaction) => { + v.transform( + (data: string | ConfirmedTransaction | { base64: string; communityId: Uuidv4 }) => { if (data instanceof ConfirmedTransaction) { return data } - return confirmedTransactionFromBase64(data) + 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') }, ), ) diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 1692bacfb..8afae814d 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -69,9 +69,10 @@ export const appRoutes = new Elysia() // check if account exists by user, call example: // GET /isAccountExist/by-user/0.0.21732/408780b2-59b3-402a-94be-56a4f4f4e8ec/0 .get( - '/isAccountExist/by-user/:communityTopicId/:userUuid/:accountNr', - async ({ params: { communityTopicId, userUuid, accountNr } }) => ({ + '/isAccountExist/by-user/:communityId/:communityTopicId/:userUuid/:accountNr', + async ({ params: { communityId, communityTopicId, userUuid, accountNr } }) => ({ exists: await isAccountExist({ + communityId, communityTopicId, account: { userUuid, accountNr }, }), @@ -84,9 +85,10 @@ export const appRoutes = new Elysia() // check if account exists by seed, call example: // GET /isAccountExist/by-seed/0.0.21732/0c4676adfd96519a0551596c .get( - '/isAccountExist/by-seed/:communityTopicId/:seed', - async ({ params: { communityTopicId, seed } }) => ({ + '/isAccountExist/by-seed/:communityId/:communityTopicId/:seed', + async ({ params: { communityId, communityTopicId, seed } }) => ({ exists: await isAccountExist({ + communityId, communityTopicId, seed, }), @@ -145,7 +147,7 @@ async function isAccountExist(identifierAccount: IdentifierAccountInput): Promis // ask gradido node server for account type, if type !== NONE account exist const addressType = await GradidoNodeClient.getInstance().getAddressType( publicKey.convertToHex(), - identifierAccountParsed.communityTopicId, + identifierAccountParsed.communityId, ) const exists = addressType !== AddressType_NONE const endTime = Date.now() diff --git a/dlt-connector/src/server/input.schema.ts b/dlt-connector/src/server/input.schema.ts index df93f1d9b..501fdc829 100644 --- a/dlt-connector/src/server/input.schema.ts +++ b/dlt-connector/src/server/input.schema.ts @@ -3,6 +3,7 @@ import { t } from 'elysia' import { hieroIdSchema, uuidv4Schema } from '../schemas/typeGuard.schema' export const accountIdentifierUserTypeBoxSchema = t.Object({ + communityId: TypeBoxFromValibot(uuidv4Schema), communityTopicId: TypeBoxFromValibot(hieroIdSchema), userUuid: TypeBoxFromValibot(uuidv4Schema), accountNr: t.Number({ min: 0 }), @@ -10,6 +11,7 @@ export const accountIdentifierUserTypeBoxSchema = t.Object({ // identifier for a gradido account created by transaction link / deferred transfer export const accountIdentifierSeedTypeBoxSchema = t.Object({ + communityId: TypeBoxFromValibot(uuidv4Schema), communityTopicId: TypeBoxFromValibot(hieroIdSchema), seed: TypeBoxFromValibot(uuidv4Schema), }) diff --git a/dlt-connector/src/utils/filesystem.ts b/dlt-connector/src/utils/filesystem.ts index f01008a93..096437fb5 100644 --- a/dlt-connector/src/utils/filesystem.ts +++ b/dlt-connector/src/utils/filesystem.ts @@ -9,7 +9,7 @@ export function checkFileExist(filePath: string): boolean { fs.accessSync(filePath, fs.constants.R_OK | fs.constants.W_OK) return true } catch (_err) { - // logger.debug(`file ${filePath} does not exist: ${_err}`) + logger.debug(`file ${filePath} does not exist: ${_err}`) return false } } diff --git a/dlt-connector/src/utils/typeConverter.ts b/dlt-connector/src/utils/typeConverter.ts index 148efebd6..4124df7e6 100644 --- a/dlt-connector/src/utils/typeConverter.ts +++ b/dlt-connector/src/utils/typeConverter.ts @@ -6,14 +6,15 @@ import { } from 'gradido-blockchain-js' import { AccountType } from '../data/AccountType.enum' import { AddressType } from '../data/AddressType.enum' +import { Uuidv4 } from '../schemas/typeGuard.schema' -export const confirmedTransactionFromBase64 = (base64: string): ConfirmedTransaction => { +export const confirmedTransactionFromBase64 = (base64: string, communityId: Uuidv4): ConfirmedTransaction => { const confirmedTransactionBinaryPtr = MemoryBlock.createPtr(MemoryBlock.fromBase64(base64)) const deserializer = new InteractionDeserialize( confirmedTransactionBinaryPtr, DeserializeType_CONFIRMED_TRANSACTION, ) - deserializer.run() + deserializer.run(communityId) const confirmedTransaction = deserializer.getConfirmedTransaction() if (!confirmedTransaction) { throw new Error("invalid data, couldn't deserialize")