adapt to GradidoNode Changes

This commit is contained in:
einhornimmond 2026-02-25 12:12:58 +01:00
parent 14f7e91fdc
commit 3ef4c25ae8
9 changed files with 52 additions and 42 deletions

View File

@ -83,7 +83,7 @@ export async function checkGradidoNode(
if ( if (
!(await clients.gradidoNode.getTransaction({ !(await clients.gradidoNode.getTransaction({
transactionId: 1, transactionId: 1,
topic: homeCommunity.hieroTopicId, communityId: homeCommunity.uuid,
})) }))
) { ) {
// if not exist, create community root transaction // if not exist, create community root transaction

View File

@ -5,7 +5,7 @@ import { getLogger } from 'log4js'
import { CONFIG } from '../../config' 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 { HieroId } from '../../schemas/typeGuard.schema' import { HieroId } from '../../schemas/typeGuard.schema'
import { checkFileExist, checkPathExist } from '../../utils/filesystem' import { checkFileExist, checkPathExist, toFolderName } from '../../utils/filesystem'
import { BackendClient } from '../backend/BackendClient' import { BackendClient } from '../backend/BackendClient'
import { GradidoNodeProcess } from './GradidoNodeProcess' import { GradidoNodeProcess } from './GradidoNodeProcess'
@ -15,7 +15,7 @@ const ensureCommunitiesAvailableMutex: Mutex = new Mutex()
// prototype, later add api call to gradido dlt node server for adding/updating communities // prototype, later add api call to gradido dlt node server for adding/updating communities
type CommunityForDltNodeServer = { type CommunityForDltNodeServer = {
communityId: string communityId: string
hieroTopicId: string hieroTopicId?: string | null
alias: string alias: string
folder: string folder: string
} }
@ -38,28 +38,21 @@ export async function ensureCommunitiesAvailable(communityTopicIds: HieroId[]):
} }
export async function exportCommunities(homeFolder: string, client: BackendClient): Promise<void> { export async function exportCommunities(homeFolder: string, client: BackendClient): Promise<void> {
const communities = await client.getReachableCommunities() const communities = await client.getAuthorizedCommunities()
console.log(`communities: ${JSON.stringify(communities, null, 2)}`)
const communitiesPath = path.join(homeFolder, 'communities.json') const communitiesPath = path.join(homeFolder, 'communities.json')
checkPathExist(path.dirname(communitiesPath), true) checkPathExist(path.dirname(communitiesPath), true)
// make sure communityName is unique
const communityName = new Set<string>()
const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] const communitiesForDltNodeServer: CommunityForDltNodeServer[] = []
for (const com of communities) { for (const com of communities) {
if (!com.uuid || !com.hieroTopicId) { if (!com.uuid) {
continue continue
} }
// use name as alias if not empty and unique, otherwise use uuid
let alias = com.name
if (!alias || communityName.has(alias)) {
alias = com.uuid
}
communityName.add(alias)
communitiesForDltNodeServer.push({ communitiesForDltNodeServer.push({
communityId: com.uuid, communityId: com.uuid,
hieroTopicId: com.hieroTopicId, hieroTopicId: com.hieroTopicId,
alias, alias: com.name,
// use only alpha-numeric chars for folder name // use only alpha-numeric chars for folder name
folder: alias.replace(/[^a-zA-Z0-9]/g, '_'), folder: toFolderName(com.uuid),
}) })
} }
fs.writeFileSync(communitiesPath, JSON.stringify(communitiesForDltNodeServer, null, 2)) fs.writeFileSync(communitiesPath, JSON.stringify(communitiesForDltNodeServer, null, 2))

View File

@ -1,12 +1,12 @@
import * as v from 'valibot' import * as v from 'valibot'
import { hieroIdSchema, hieroTransactionIdStringSchema } from '../../schemas/typeGuard.schema' import { uuidv4Schema, hieroTransactionIdStringSchema } from '../../schemas/typeGuard.schema'
export const transactionsRangeSchema = v.object({ export const transactionsRangeSchema = v.object({
// default value is 1, from first transactions // default value is 1, from first transactions
fromTransactionId: v.nullish(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 1), fromTransactionId: v.nullish(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 1),
// default value is 100, max 100 transactions // default value is 100, max 100 transactions
maxResultCount: v.nullish(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 100), maxResultCount: v.nullish(v.pipe(v.number(), v.minValue(1, 'expect number >= 1')), 100),
topic: hieroIdSchema, communityId: uuidv4Schema,
}) })
export type TransactionsRangeInput = v.InferInput<typeof transactionsRangeSchema> export type TransactionsRangeInput = v.InferInput<typeof transactionsRangeSchema>
@ -19,7 +19,7 @@ export const transactionIdentifierSchema = v.pipe(
undefined, undefined,
), ),
hieroTransactionId: v.nullish(hieroTransactionIdStringSchema, undefined), hieroTransactionId: v.nullish(hieroTransactionIdStringSchema, undefined),
topic: hieroIdSchema, communityId: uuidv4Schema,
}), }),
v.custom((value: any) => { v.custom((value: any) => {
const setFieldsCount = const setFieldsCount =

View File

@ -6,6 +6,7 @@ import { CONFIG } from '../../config'
import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { LOG4JS_BASE_CATEGORY } from '../../config/const'
import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema'
import { import {
getAuthorizedCommunities,
getReachableCommunities, getReachableCommunities,
homeCommunityGraphqlQuery, homeCommunityGraphqlQuery,
setHomeCommunityTopicId, setHomeCommunityTopicId,
@ -101,6 +102,19 @@ export class BackendClient {
return v.parse(v.array(communitySchema), data.reachableCommunities) return v.parse(v.array(communitySchema), data.reachableCommunities)
} }
public async getAuthorizedCommunities(): Promise<Community[]> {
this.logger.info('get authorized communities on backend')
const { data, errors } = await this.client.rawRequest<{ authorizedCommunities: Community[] }>(
getAuthorizedCommunities,
{},
await this.getRequestHeader(),
)
if (errors) {
throw errors[0]
}
return v.parse(v.array(communitySchema), data.authorizedCommunities)
}
private async getRequestHeader(): Promise<{ private async getRequestHeader(): Promise<{
authorization: string authorization: string
}> { }> {

View File

@ -44,3 +44,14 @@ export const getReachableCommunities = gql`
} }
${communityFragment} ${communityFragment}
` `
export const getAuthorizedCommunities = gql`
query {
authorizedCommunities {
...Community_common
}
}
${communityFragment}
`

View File

@ -17,6 +17,6 @@ export const GRADIDO_NODE_RUNTIME_PATH = path.join(
// if last start was less than this time, do not restart // if last start was less than this time, do not restart
export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30 export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS = 1000 * 30
export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS = 1000 * 2 export const GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS = 1000 * 2
export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 10000 export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 60 * 1000
// currently hard coded in gradido node, update in future // currently hard coded in gradido node, update in future
export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido' export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido'

View File

@ -10,6 +10,7 @@ import { Context } from './Context'
import { Balance } from './data/Balance' import { Balance } from './data/Balance'
import { loadAdminUsersCache, loadCommunities, loadContributionLinkModeratorCache } from './database' import { loadAdminUsersCache, loadCommunities, loadContributionLinkModeratorCache } from './database'
import { CommunityContext } from './valibot.schema' import { CommunityContext } from './valibot.schema'
import { toFolderName } from '../../utils/filesystem'
export async function bootstrap(): Promise<Context> { export async function bootstrap(): Promise<Context> {
const context = await Context.create() const context = await Context.create()
@ -24,20 +25,14 @@ export async function bootstrap(): Promise<Context> {
async function bootstrapCommunities(context: Context): Promise<Map<string, CommunityContext>> { async function bootstrapCommunities(context: Context): Promise<Map<string, CommunityContext>> {
const communities = new Map<string, CommunityContext>() const communities = new Map<string, CommunityContext>()
const communitiesDb = await loadCommunities(context.db) const communitiesDb = await loadCommunities(context.db)
const communityNames = new Set<string>()
for (const communityDb of communitiesDb) { for (const communityDb of communitiesDb) {
let alias = communityDb.name.toLowerCase() const communityId = communityDb.communityUuid
if (communityNames.has(alias)) { const blockchain = InMemoryBlockchainProvider.getInstance().getBlockchain(communityId)
alias = communityDb.communityUuid
} else {
communityNames.add(alias)
}
const blockchain = InMemoryBlockchainProvider.getInstance().getBlockchain(alias)
if (!blockchain) { if (!blockchain) {
throw new Error(`Couldn't create Blockchain for community ${alias}`) throw new Error(`Couldn't create Blockchain for community ${communityId}`)
} }
context.logger.info(`Blockchain for community '${alias}' created`) context.logger.info(`Blockchain for community '${communityId}' created`)
let seed: Hex32 let seed: Hex32
if (!communityDb.foreign) { if (!communityDb.foreign) {
seed = v.parse(hex32Schema, CONFIG.HOME_COMMUNITY_SEED.convertToHex()) seed = v.parse(hex32Schema, CONFIG.HOME_COMMUNITY_SEED.convertToHex())
@ -59,7 +54,7 @@ async function bootstrapCommunities(context: Context): Promise<Map<string, Commu
const builder = new GradidoTransactionBuilder() const builder = new GradidoTransactionBuilder()
builder builder
.setCreatedAt(creationDate) .setCreatedAt(creationDate)
.setSenderCommunity(alias) .setSenderCommunity(communityId)
.setCommunityRoot( .setCommunityRoot(
communityKeyPair.getPublicKey(), communityKeyPair.getPublicKey(),
gmwKeyPair.getPublicKey(), gmwKeyPair.getPublicKey(),
@ -68,15 +63,15 @@ async function bootstrapCommunities(context: Context): Promise<Map<string, Commu
.sign(communityKeyPair) .sign(communityKeyPair)
const communityContext: CommunityContext = { const communityContext: CommunityContext = {
communityId: alias, communityId,
foreign: communityDb.foreign, foreign: communityDb.foreign,
blockchain, blockchain,
keyPair: communityKeyPair, keyPair: communityKeyPair,
folder: alias.replace(/[^a-z0-9]/g, '_'), folder: toFolderName(communityId),
gmwBalance: new Balance(gmwKeyPair.getPublicKey()!, alias), gmwBalance: new Balance(gmwKeyPair.getPublicKey()!, communityId),
aufBalance: new Balance(aufKeyPair.getPublicKey()!, alias), aufBalance: new Balance(aufKeyPair.getPublicKey()!, communityId),
} }
communities.set(communityDb.communityUuid, communityContext) communities.set(communityId, communityContext)
const accountBalances = new AccountBalances() const accountBalances = new AccountBalances()
accountBalances.add(communityContext.aufBalance.getAccountBalance()) accountBalances.add(communityContext.aufBalance.getAccountBalance())
accountBalances.add(communityContext.gmwBalance.getAccountBalance()) accountBalances.add(communityContext.gmwBalance.getAccountBalance())

View File

@ -1,8 +1,6 @@
import { asc, eq, isNotNull, sql } from 'drizzle-orm' import { asc, eq, isNotNull, sql } from 'drizzle-orm'
import { MySql2Database } from 'drizzle-orm/mysql2' import { MySql2Database } from 'drizzle-orm/mysql2'
import { getLogger } from 'log4js'
import * as v from 'valibot' import * as v from 'valibot'
import { LOG4JS_BASE_CATEGORY } from '../../config/const'
import { import {
communitiesTable, communitiesTable,
eventsTable, eventsTable,
@ -16,13 +14,8 @@ import {
userDbSchema, userDbSchema,
} from './valibot.schema' } from './valibot.schema'
const logger = getLogger(
`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`,
)
export const contributionLinkModerators = new Map<number, UserDb>() export const contributionLinkModerators = new Map<number, UserDb>()
export const adminUsers = new Map<string, UserDb>() export const adminUsers = new Map<string, UserDb>()
const transactionIdSet = new Set<number>()
export async function loadContributionLinkModeratorCache(db: MySql2Database): Promise<void> { export async function loadContributionLinkModeratorCache(db: MySql2Database): Promise<void> {
const result = await db const result = await db

View File

@ -28,3 +28,7 @@ export function checkPathExist(path: string, createIfMissing: boolean = false):
} }
return false return false
} }
export function toFolderName(name: string): string {
return name.toLowerCase().replace(/[^a-z0-9]/g, '_')
}