From f54097e6baffae0ceb4e545742fc7afcf5fbe6aa Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 30 Oct 2025 14:44:47 +0100 Subject: [PATCH 01/33] structure migration --- dlt-connector/.env.dist | 10 +- dlt-connector/.env.template | 10 +- dlt-connector/bun.lock | 248 +++++++++++------- dlt-connector/src/config/schema.ts | 41 +++ .../src/data/KeyPairIdentifier.logic.ts | 8 +- .../resolveKeyPair/ResolveKeyPair.context.ts | 2 +- .../RegisterAddressTransaction.role.test.ts | 4 +- .../db-v2.7.0_to_blockchain-v3.6/Context.ts | 53 ++++ .../OrderedContainer.ts | 58 ++++ .../blockchain.ts | 98 +++++++ .../db-v2.7.0_to_blockchain-v3.6/bootstrap.ts | 49 ++++ .../db-v2.7.0_to_blockchain-v3.6/convert.ts | 86 ++++++ .../db-v2.7.0_to_blockchain-v3.6/database.ts | 176 +++++++++++++ .../db-v2.7.0_to_blockchain-v3.6/index.ts | 171 ++++++++++++ .../db-v2.7.0_to_blockchain-v3.6/keyPair.ts | 56 ++++ .../src/schemas/typeConverter.schema.ts | 12 + 16 files changed, 973 insertions(+), 109 deletions(-) create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts diff --git a/dlt-connector/.env.dist b/dlt-connector/.env.dist index 165ca7bd0..fe90a30ef 100644 --- a/dlt-connector/.env.dist +++ b/dlt-connector/.env.dist @@ -22,4 +22,12 @@ GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=a51ef8ac7ef1abf162fb7a65261acd7a # Route to Backend PORT=4000 -JWT_SECRET=secret123 \ No newline at end of file +JWT_SECRET=secret123 + + +# Database +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=root +MYSQL_PASSWORD= +MYSQL_DATABASE=gradido_community \ No newline at end of file diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 92819f579..18dad36ee 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -22,4 +22,12 @@ GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY=$GRADIDO_BLOCKCHAIN_SERVER_CRYPTO_KEY # Route to Backend BACKEND_PORT=$BACKEND_PORT -JWT_SECRET=$JWT_SECRET \ No newline at end of file +JWT_SECRET=$JWT_SECRET + + +# Database +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=$DB_USER +MYSQL_PASSWORD=$DB_PASSWORD +MYSQL_DATABASE=gradido_community \ No newline at end of file diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 46e566b54..21caa0f07 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -31,11 +31,11 @@ "packages": { "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], - "@babel/compat-data": ["@babel/compat-data@7.28.4", "", {}, "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw=="], + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], - "@babel/core": ["@babel/core@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.4", "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA=="], + "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], - "@babel/generator": ["@babel/generator@7.28.3", "", { "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw=="], + "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], @@ -49,13 +49,13 @@ "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], - "@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="], + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], "@babel/plugin-syntax-async-generators": ["@babel/plugin-syntax-async-generators@7.8.4", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="], @@ -91,11 +91,11 @@ "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], - "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], - "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="], + "@babel/traverse--for-generate-function-map": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], - "@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="], + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], "@biomejs/biome": ["@biomejs/biome@2.0.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.0.0", "@biomejs/cli-darwin-x64": "2.0.0", "@biomejs/cli-linux-arm64": "2.0.0", "@biomejs/cli-linux-arm64-musl": "2.0.0", "@biomejs/cli-linux-x64": "2.0.0", "@biomejs/cli-linux-x64-musl": "2.0.0", "@biomejs/cli-win32-arm64": "2.0.0", "@biomejs/cli-win32-x64": "2.0.0" }, "bin": { "biome": "bin/biome" } }, "sha512-BlUoXEOI/UQTDEj/pVfnkMo8SrZw3oOWBDrXYFT43V7HTkIUDkBRY53IC5Jx1QkZbaB+0ai1wJIfYwp9+qaJTQ=="], @@ -155,15 +155,15 @@ "@graphql-typed-document-node/core": ["@graphql-typed-document-node/core@3.2.0", "", { "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ=="], - "@grpc/grpc-js": ["@grpc/grpc-js@1.13.4", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-GsFaMXCkMqkKIvwCQjCrwH+GHbPKBjhwo/8ZuUkWHqbI73Kky9I+pQltrlT0+MWpedCoosda53lgjYfyEPgxBg=="], + "@grpc/grpc-js": ["@grpc/grpc-js@1.12.6", "", { "dependencies": { "@grpc/proto-loader": "^0.7.13", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q=="], "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], - "@hashgraph/cryptography": ["@hashgraph/cryptography@1.9.0", "", { "dependencies": { "@noble/curves": "^1.8.1", "asn1js": "^3.0.6", "bignumber.js": "^9.1.1", "bn.js": "^5.2.1", "buffer": "^6.0.3", "crypto-js": "^4.2.0", "forge-light": "1.1.4", "js-base64": "^3.7.7", "react-native-get-random-values": "^1.11.0", "spark-md5": "^3.0.2", "tweetnacl": "^1.0.3", "utf8": "^3.0.0" } }, "sha512-0UItolO1W/f8YIsGBrIxvjY+cSdvs4sEdzXOL49ThYEfPskJUprG3vhMhosRFoA4d0hxdJ7/glB7f7He8RW9xg=="], + "@hashgraph/cryptography": ["@hashgraph/cryptography@1.13.0", "", { "dependencies": { "@noble/curves": "1.8.1", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "asn1js": "3.0.6", "bignumber.js": "9.1.1", "bn.js": "5.2.1", "buffer": "6.0.3", "crypto-js": "4.2.0", "debug": "4.4.1", "forge-light": "1.1.4", "js-base64": "3.7.7", "react-native-get-random-values": "1.11.0", "spark-md5": "3.0.2", "strip-ansi": "7.1.2", "tweetnacl": "1.0.3", "utf8": "3.0.0" } }, "sha512-bttkU9cnbA2NgmE41V4IDYZ5IYMY9HtVTnlvg3fdj8m83+7T4KgTBPPSkqwFCgSeW2x/6MV2GDzvaj4Lx4IYfw=="], - "@hashgraph/proto": ["@hashgraph/proto@2.22.0", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "7.2.5" } }, "sha512-+h2qqk+KwpV+rr1AN4ip1Gel3X4v0DvFO9WH7o0ZR3gQX9pfzurptKGs30DlBnH21xPqDH61v90bZvVknE27NA=="], + "@hashgraph/proto": ["@hashgraph/proto@2.24.0", "", { "dependencies": { "long": "5.3.1" }, "peerDependencies": { "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "debug": "4.4.1", "protobufjs": "7.5.4", "strip-ansi": "7.1.2" } }, "sha512-S1eE0CoQ17s40JuzKaKpMze8h0JoN13za5arCp3xaqbWVT4UEFq/O/zJud9cpZ31uYwpPe8gH65TPZ3pKd9ZWQ=="], - "@hashgraph/sdk": ["@hashgraph/sdk@2.72.0", "", { "dependencies": { "@ethersproject/abi": "^5.8.0", "@ethersproject/bignumber": "^5.8.0", "@ethersproject/bytes": "^5.8.0", "@ethersproject/rlp": "^5.8.0", "@grpc/grpc-js": "^1.12.6", "@hashgraph/cryptography": "1.9.0", "@hashgraph/proto": "2.22.0", "bignumber.js": "^9.1.1", "bn.js": "^5.1.1", "crypto-js": "^4.2.0", "js-base64": "^3.7.4", "long": "^5.3.1", "pino": "^9.6.0", "pino-pretty": "^13.0.0", "protobufjs": "7.2.5", "rfc4648": "^1.5.3", "utf8": "^3.0.0" } }, "sha512-w35M77OAkJutENG4CldUGzfT+qubDjEYCQR5Ran75uHB+SLeCodR87AXWJ3ocr5vPaZ7lsflBXEYZLhgCi1G2g=="], + "@hashgraph/sdk": ["@hashgraph/sdk@2.75.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/rlp": "5.8.0", "@grpc/grpc-js": "1.12.6", "@hashgraph/cryptography": "1.13.0", "@hashgraph/proto": "2.24.0", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "bignumber.js": "9.1.1", "bn.js": "5.1.1", "crypto-js": "4.2.0", "debug": "4.4.1", "js-base64": "3.7.4", "long": "5.3.1", "pino": "9.6.0", "pino-pretty": "13.0.0", "protobufjs": "7.5.4", "rfc4648": "1.5.3", "strip-ansi": "7.1.2", "utf8": "3.0.0" } }, "sha512-Nkv57So2RbNlKxog1nsyqHgorgrStr3yzx0ZWse4R6yg1TztafiqA2+9m3YlmH3eNMr7vmghgtGqPkRflfVhZg=="], "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], @@ -193,13 +193,13 @@ "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], - "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.30", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q=="], + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], "@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="], - "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="], - "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="], "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], @@ -221,23 +221,25 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="], - "@react-native/assets-registry": ["@react-native/assets-registry@0.81.1", "", {}, "sha512-o/AeHeoiPW8x9MzxE1RSnKYc+KZMW9b7uaojobEz0G8fKgGD1R8n5CJSOiQ/0yO2fJdC5wFxMMOgy2IKwRrVgw=="], + "@react-native/assets-registry": ["@react-native/assets-registry@0.82.1", "", {}, "sha512-B1SRwpntaAcckiatxbjzylvNK562Ayza05gdJCjDQHTiDafa1OABmyB5LHt7qWDOpNkaluD+w11vHF7pBmTpzQ=="], - "@react-native/codegen": ["@react-native/codegen@0.81.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.29.1", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-8KoUE1j65fF1PPHlAhSeUHmcyqpE+Z7Qv27A89vSZkz3s8eqWSRu2hZtCl0D3nSgS0WW0fyrIsFaRFj7azIiPw=="], + "@react-native/codegen": ["@react-native/codegen@0.82.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", "hermes-parser": "0.32.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "yargs": "^17.6.2" } }, "sha512-ezXTN70ygVm9l2m0i+pAlct0RntoV4afftWMGUIeAWLgaca9qItQ54uOt32I/9dBJvzBibT33luIR/pBG0dQvg=="], - "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.81.1", "", { "dependencies": { "@react-native/dev-middleware": "0.81.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-FuIpZcjBiiYcVMNx+1JBqTPLs2bUIm6X4F5enYGYcetNE2nfSMUVO8SGUtTkBdbUTfKesXYSYN8wungyro28Ag=="], + "@react-native/community-cli-plugin": ["@react-native/community-cli-plugin@0.82.1", "", { "dependencies": { "@react-native/dev-middleware": "0.82.1", "debug": "^4.4.0", "invariant": "^2.2.4", "metro": "^0.83.1", "metro-config": "^0.83.1", "metro-core": "^0.83.1", "semver": "^7.1.3" }, "peerDependencies": { "@react-native-community/cli": "*", "@react-native/metro-config": "*" }, "optionalPeers": ["@react-native-community/cli", "@react-native/metro-config"] }, "sha512-H/eMdtOy9nEeX7YVeEG1N2vyCoifw3dr9OV8++xfUElNYV7LtSmJ6AqxZUUfxGJRDFPQvaU/8enmJlM/l11VxQ=="], - "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.81.1", "", {}, "sha512-dwKv1EqKD+vONN4xsfyTXxn291CNl1LeBpaHhNGWASK1GO4qlyExMs4TtTjN57BnYHikR9PzqPWcUcfzpVRaLg=="], + "@react-native/debugger-frontend": ["@react-native/debugger-frontend@0.82.1", "", {}, "sha512-a2O6M7/OZ2V9rdavOHyCQ+10z54JX8+B+apYKCQ6a9zoEChGTxUMG2YzzJ8zZJVvYf1ByWSNxv9Se0dca1hO9A=="], - "@react-native/dev-middleware": ["@react-native/dev-middleware@0.81.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.81.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-hy3KlxNOfev3O5/IuyZSstixWo7E9FhljxKGHdvVtZVNjQdM+kPMh66mxeJbB2TjdJGAyBT4DjIwBaZnIFOGHQ=="], + "@react-native/debugger-shell": ["@react-native/debugger-shell@0.82.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "fb-dotslash": "0.5.8" } }, "sha512-fdRHAeqqPT93bSrxfX+JHPpCXHApfDUdrXMXhoxlPgSzgXQXJDykIViKhtpu0M6slX6xU/+duq+AtP/qWJRpBw=="], - "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.81.1", "", {}, "sha512-RpRxs/LbWVM9Zi5jH1qBLgTX746Ei+Ui4vj3FmUCd9EXUSECM5bJpphcsvqjxM5Vfl/o2wDLSqIoFkVP/6Te7g=="], + "@react-native/dev-middleware": ["@react-native/dev-middleware@0.82.1", "", { "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.82.1", "@react-native/debugger-shell": "0.82.1", "chrome-launcher": "^0.15.2", "chromium-edge-launcher": "^0.2.0", "connect": "^3.6.5", "debug": "^4.4.0", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "open": "^7.0.3", "serve-static": "^1.16.2", "ws": "^6.2.3" } }, "sha512-wuOIzms/Qg5raBV6Ctf2LmgzEOCqdP3p1AYN4zdhMT110c39TVMbunpBaJxm0Kbt2HQ762MQViF9naxk7SBo4w=="], - "@react-native/js-polyfills": ["@react-native/js-polyfills@0.81.1", "", {}, "sha512-w093OkHFfCnJKnkiFizwwjgrjh5ra53BU0ebPM3uBLkIQ6ZMNSCTZhG8ZHIlAYeIGtEinvmnSUi3JySoxuDCAQ=="], + "@react-native/gradle-plugin": ["@react-native/gradle-plugin@0.82.1", "", {}, "sha512-KkF/2T1NSn6EJ5ALNT/gx0MHlrntFHv8YdooH9OOGl9HQn5NM0ZmQSr86o5utJsGc7ME3R6p3SaQuzlsFDrn8Q=="], - "@react-native/normalize-colors": ["@react-native/normalize-colors@0.81.1", "", {}, "sha512-TsaeZlE8OYFy3PSWc+1VBmAzI2T3kInzqxmwXoGU4w1d4XFkQFg271Ja9GmDi9cqV3CnBfqoF9VPwRxVlc/l5g=="], + "@react-native/js-polyfills": ["@react-native/js-polyfills@0.82.1", "", {}, "sha512-tf70X7pUodslOBdLN37J57JmDPB/yiZcNDzS2m+4bbQzo8fhx3eG9QEBv5n4fmzqfGAgSB4BWRHgDMXmmlDSVA=="], - "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.81.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-yG+zcMtyApW1yRwkNFvlXzEg3RIFdItuwr/zEvPCSdjaL+paX4rounpL0YX5kS9MsDIE5FXfcqINXg7L0xuwPg=="], + "@react-native/normalize-colors": ["@react-native/normalize-colors@0.82.1", "", {}, "sha512-CCfTR1uX+Z7zJTdt3DNX9LUXr2zWXsNOyLbwupW2wmRzrxlHRYfmLgTABzRL/cKhh0Ubuwn15o72MQChvCRaHw=="], + + "@react-native/virtualized-lists": ["@react-native/virtualized-lists@0.82.1", "", { "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "*", "react-native": "*" }, "optionalPeers": ["@types/react"] }, "sha512-f5zpJg9gzh7JtCbsIwV+4kP3eI0QBuA93JGmwFRd4onQ3DnCjV2J5pYqdWtM95sjSKK1dyik59Gj01lLeKqs1Q=="], "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], @@ -261,7 +263,7 @@ "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], - "@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="], + "@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], "@types/graceful-fs": ["@types/graceful-fs@4.1.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ=="], @@ -271,15 +273,15 @@ "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], - "@types/node": ["@types/node@24.3.1", "", { "dependencies": { "undici-types": "~7.10.0" } }, "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g=="], + "@types/node": ["@types/node@24.9.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg=="], - "@types/react": ["@types/react@19.1.12", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w=="], + "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], "@types/uuid": ["@types/uuid@8.3.4", "", {}, "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="], - "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@types/yargs": ["@types/yargs@17.0.34", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-KExbHVa92aJpw9WDQvzBaGVE2/Pz+pLZQloT2hjL8IqsZnV62rlPOYvNnLmf/L2dyllfVUOVBj64M0z/46eR2A=="], "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], @@ -295,9 +297,9 @@ "anser": ["anser@1.4.10", "", {}, "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], @@ -327,7 +329,7 @@ "babel-plugin-jest-hoist": ["babel-plugin-jest-hoist@29.6.3", "", { "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg=="], - "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.29.1", "", { "dependencies": { "hermes-parser": "0.29.1" } }, "sha512-2WFYnoWGdmih1I1J5eIqxATOeycOqRwYxAQBu3cUu/rhwInwHUg7k60AFNbuGjSDL8tje5GDrAnxzRLcu2pYcA=="], + "babel-plugin-syntax-hermes-parser": ["babel-plugin-syntax-hermes-parser@0.32.0", "", { "dependencies": { "hermes-parser": "0.32.0" } }, "sha512-m5HthL++AbyeEA2FcdwOLfVFvWYECOBObLHNqdR8ceY4TsEdn4LdX2oTvbB2QJSSElE2AWA/b2MXZ/PF/CqLZg=="], "babel-preset-current-node-syntax": ["babel-preset-current-node-syntax@1.2.0", "", { "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-class-static-block": "^7.14.5", "@babel/plugin-syntax-import-attributes": "^7.24.7", "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", "@babel/plugin-syntax-private-property-in-object": "^7.14.5", "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0 || ^8.0.0-0" } }, "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg=="], @@ -337,13 +339,15 @@ "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], - "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.20", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ=="], + + "bignumber.js": ["bignumber.js@9.1.1", "", {}, "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig=="], "bindings": ["bindings@1.5.0", "", { "dependencies": { "file-uri-to-path": "1.0.0" } }, "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ=="], "bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="], - "bn.js": ["bn.js@5.2.2", "", {}, "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw=="], + "bn.js": ["bn.js@5.1.1", "", {}, "sha512-IUTD/REb78Z2eodka1QZyyEk66pciRcP6Sroka0aI3tG/iwIdYLrBD62RsubR7vqdt3WyX8p4jxeatzmRSphtA=="], "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], @@ -351,7 +355,7 @@ "brorand": ["brorand@1.1.0", "", {}, "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w=="], - "browserslist": ["browserslist@4.25.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001737", "electron-to-chromium": "^1.5.211", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg=="], + "browserslist": ["browserslist@4.27.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", "electron-to-chromium": "^1.5.238", "node-releases": "^2.0.26", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-AXVQwdhot1eqLihwasPElhX2tAZiBjWdJ9i/Zcj2S6QYIjkx62OKSfnobkriB81C3l4w0rVy3Nt4jaTBltYEpw=="], "bser": ["bser@2.1.1", "", { "dependencies": { "node-int64": "^0.4.0" } }, "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="], @@ -359,19 +363,13 @@ "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], - "bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="], + "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], - "caller-callsite": ["caller-callsite@2.0.0", "", { "dependencies": { "callsites": "^2.0.0" } }, "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ=="], - - "caller-path": ["caller-path@2.0.0", "", { "dependencies": { "caller-callsite": "^2.0.0" } }, "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A=="], - - "callsites": ["callsites@2.0.0", "", {}, "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ=="], - "camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001741", "", {}, "sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -409,7 +407,7 @@ "cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="], - "cosmiconfig": ["cosmiconfig@5.2.1", "", { "dependencies": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", "js-yaml": "^3.13.1", "parse-json": "^4.0.0" } }, "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "crypto-js": ["crypto-js@4.2.0", "", {}, "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="], @@ -437,7 +435,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.214", "", {}, "sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q=="], + "electron-to-chromium": ["electron-to-chromium@1.5.241", "", {}, "sha512-ILMvKX/ZV5WIJzzdtuHg8xquk2y0BOGlFOxBVwTpbiXqWIH0hamG45ddU4R3PQ0gYu+xgo0vdHXHli9sHIGb4w=="], "elliptic": ["elliptic@6.6.1", "", { "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", "hash.js": "^1.0.0", "hmac-drbg": "^1.0.1", "inherits": "^2.0.4", "minimalistic-assert": "^1.0.1", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g=="], @@ -449,8 +447,6 @@ "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - "error-ex": ["error-ex@1.3.2", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="], - "error-stack-parser": ["error-stack-parser@2.1.4", "", { "dependencies": { "stackframe": "^1.3.4" } }, "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], @@ -477,7 +473,7 @@ "execspawn": ["execspawn@1.0.1", "", { "dependencies": { "util-extend": "^1.0.1" } }, "sha512-s2k06Jy9i8CUkYe0+DxRlvtkZoOkwwfhB+Xxo5HGUtrISVW2m98jO2tr67DGRFxZwkjQqloA3v/tNtjhBRBieg=="], - "exponential-backoff": ["exponential-backoff@3.1.2", "", {}, "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA=="], + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], "fast-base64-decode": ["fast-base64-decode@1.0.0", "", {}, "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="], @@ -491,6 +487,8 @@ "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], + "fb-dotslash": ["fb-dotslash@0.5.8", "", { "bin": { "dotslash": "bin/dotslash" } }, "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA=="], + "fb-watchman": ["fb-watchman@2.0.2", "", { "dependencies": { "bser": "2.1.1" } }, "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA=="], "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], @@ -547,11 +545,11 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#f1c4bbc", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-f1c4bbc"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#8a0c7b0", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-8a0c7b0"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], - "graphql-request": ["graphql-request@7.2.0", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-0GR7eQHBFYz372u9lxS16cOtEekFlZYB2qOyq8wDvzRmdRSJ0mgUVX1tzNcIzk3G+4NY+mGtSz411wZdeDF/+A=="], + "graphql-request": ["graphql-request@7.3.1", "", { "dependencies": { "@graphql-typed-document-node/core": "^3.2.0" }, "peerDependencies": { "graphql": "14 - 16" } }, "sha512-GdinBsBVYrWzwEvOlzadrV5j8mdOc9ZT8In9QyRIZaxbhkTL08j35yNbPp96jAacYzjeD/hKKy2E2RGI7c7Yug=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], @@ -567,9 +565,11 @@ "help-me": ["help-me@5.0.0", "", {}, "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg=="], - "hermes-estree": ["hermes-estree@0.29.1", "", {}, "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ=="], + "hermes-compiler": ["hermes-compiler@0.0.0", "", {}, "sha512-boVFutx6ME/Km2mB6vvsQcdnazEYYI/jV1pomx1wcFUG/EVqTkr5CU0CW9bKipOA/8Hyu3NYwW3THg2Q1kNCfA=="], - "hermes-parser": ["hermes-parser@0.29.1", "", { "dependencies": { "hermes-estree": "0.29.1" } }, "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA=="], + "hermes-estree": ["hermes-estree@0.32.0", "", {}, "sha512-KWn3BqnlDOl97Xe1Yviur6NbgIZ+IP+UVSpshlZWkq+EtoHg6/cwiDj/osP9PCEgFE15KBm1O55JRwbMEm5ejQ=="], + + "hermes-parser": ["hermes-parser@0.32.0", "", { "dependencies": { "hermes-estree": "0.32.0" } }, "sha512-g4nBOWFpuiTqjR3LZdRxKUkij9iyveWeuks7INEsMX741f3r9xxrOe8TeQfUxtda0eXmiIFiMQzoeSQEno33Hw=="], "hmac-drbg": ["hmac-drbg@1.0.1", "", { "dependencies": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", "minimalistic-crypto-utils": "^1.0.1" } }, "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg=="], @@ -581,8 +581,6 @@ "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], - "import-fresh": ["import-fresh@2.0.0", "", { "dependencies": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" } }, "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg=="], - "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], @@ -593,10 +591,6 @@ "invariant": ["invariant@2.2.4", "", { "dependencies": { "loose-envify": "^1.0.0" } }, "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA=="], - "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], - - "is-directory": ["is-directory@0.3.1", "", {}, "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw=="], - "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], @@ -633,7 +627,7 @@ "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], - "js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="], + "js-base64": ["js-base64@3.7.4", "", {}, "sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ=="], "js-sha3": ["js-sha3@0.8.0", "", {}, "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="], @@ -645,8 +639,6 @@ "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], - "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="], - "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], @@ -665,7 +657,7 @@ "log4js": ["log4js@6.9.1", "", { "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", "flatted": "^3.2.7", "rfdc": "^1.3.0", "streamroller": "^3.1.5" } }, "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g=="], - "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + "long": ["long@5.3.1", "", {}, "sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -683,33 +675,33 @@ "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], - "metro": ["metro@0.83.1", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.29.1", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.1", "metro-cache": "0.83.1", "metro-cache-key": "0.83.1", "metro-config": "0.83.1", "metro-core": "0.83.1", "metro-file-map": "0.83.1", "metro-resolver": "0.83.1", "metro-runtime": "0.83.1", "metro-source-map": "0.83.1", "metro-symbolicate": "0.83.1", "metro-transform-plugins": "0.83.1", "metro-transform-worker": "0.83.1", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-UGKepmTxoGD4HkQV8YWvpvwef7fUujNtTgG4Ygf7m/M0qjvb9VuDmAsEU+UdriRX7F61pnVK/opz89hjKlYTXA=="], + "metro": ["metro@0.83.3", "", { "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "@babel/types": "^7.25.2", "accepts": "^1.3.7", "chalk": "^4.0.0", "ci-info": "^2.0.0", "connect": "^3.6.5", "debug": "^4.4.0", "error-stack-parser": "^2.0.6", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "hermes-parser": "0.32.0", "image-size": "^1.0.2", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "jsc-safe-url": "^0.2.2", "lodash.throttle": "^4.1.1", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-config": "0.83.3", "metro-core": "0.83.3", "metro-file-map": "0.83.3", "metro-resolver": "0.83.3", "metro-runtime": "0.83.3", "metro-source-map": "0.83.3", "metro-symbolicate": "0.83.3", "metro-transform-plugins": "0.83.3", "metro-transform-worker": "0.83.3", "mime-types": "^2.1.27", "nullthrows": "^1.1.1", "serialize-error": "^2.1.0", "source-map": "^0.5.6", "throat": "^5.0.0", "ws": "^7.5.10", "yargs": "^17.6.2" }, "bin": { "metro": "src/cli.js" } }, "sha512-+rP+/GieOzkt97hSJ0MrPOuAH/jpaS21ZDvL9DJ35QYRDlQcwzcvUlGUf79AnQxq/2NPiS/AULhhM4TKutIt8Q=="], - "metro-babel-transformer": ["metro-babel-transformer@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.29.1", "nullthrows": "^1.1.1" } }, "sha512-r3xAD3964E8dwDBaZNSO2aIIvWXjIK80uO2xo0/pi3WI8XWT9h5SCjtGWtMtE5PRWw+t20TN0q1WMRsjvhC1rQ=="], + "metro-babel-transformer": ["metro-babel-transformer@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", "hermes-parser": "0.32.0", "nullthrows": "^1.1.1" } }, "sha512-1vxlvj2yY24ES1O5RsSIvg4a4WeL7PFXgKOHvXTXiW0deLvQr28ExXj6LjwCCDZ4YZLhq6HddLpZnX4dEdSq5g=="], - "metro-cache": ["metro-cache@0.83.1", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.1" } }, "sha512-7N/Ad1PHa1YMWDNiyynTPq34Op2qIE68NWryGEQ4TSE3Zy6a8GpsYnEEZE4Qi6aHgsE+yZHKkRczeBgxhnFIxQ=="], + "metro-cache": ["metro-cache@0.83.3", "", { "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", "https-proxy-agent": "^7.0.5", "metro-core": "0.83.3" } }, "sha512-3jo65X515mQJvKqK3vWRblxDEcgY55Sk3w4xa6LlfEXgQ9g1WgMh9m4qVZVwgcHoLy0a2HENTPCCX4Pk6s8c8Q=="], - "metro-cache-key": ["metro-cache-key@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ZUs+GD5CNeDLxx5UUWmfg26IL+Dnbryd+TLqTlZnDEgehkIa11kUSvgF92OFfJhONeXzV4rZDRGNXoo6JT+8Gg=="], + "metro-cache-key": ["metro-cache-key@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-59ZO049jKzSmvBmG/B5bZ6/dztP0ilp0o988nc6dpaDsU05Cl1c/lRf+yx8m9WW/JVgbmfO5MziBU559XjI5Zw=="], - "metro-config": ["metro-config@0.83.1", "", { "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.1", "metro-cache": "0.83.1", "metro-core": "0.83.1", "metro-runtime": "0.83.1" } }, "sha512-HJhpZx3wyOkux/jeF1o7akFJzZFdbn6Zf7UQqWrvp7gqFqNulQ8Mju09raBgPmmSxKDl4LbbNeigkX0/nKY1QA=="], + "metro-config": ["metro-config@0.83.3", "", { "dependencies": { "connect": "^3.6.5", "flow-enums-runtime": "^0.0.6", "jest-validate": "^29.7.0", "metro": "0.83.3", "metro-cache": "0.83.3", "metro-core": "0.83.3", "metro-runtime": "0.83.3", "yaml": "^2.6.1" } }, "sha512-mTel7ipT0yNjKILIan04bkJkuCzUUkm2SeEaTads8VfEecCh+ltXchdq6DovXJqzQAXuR2P9cxZB47Lg4klriA=="], - "metro-core": ["metro-core@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.83.1" } }, "sha512-uVL1eAJcMFd2o2Q7dsbpg8COaxjZBBGaXqO2OHnivpCdfanraVL8dPmY6It9ZeqWLOihUKZ2yHW4b6soVCzH/Q=="], + "metro-core": ["metro-core@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", "metro-resolver": "0.83.3" } }, "sha512-M+X59lm7oBmJZamc96usuF1kusd5YimqG/q97g4Ac7slnJ3YiGglW5CsOlicTR5EWf8MQFxxjDoB6ytTqRe8Hw=="], - "metro-file-map": ["metro-file-map@0.83.1", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-Yu429lnexKl44PttKw3nhqgmpBR+6UQ/tRaYcxPeEShtcza9DWakCn7cjqDTQZtWR2A8xSNv139izJMyQ4CG+w=="], + "metro-file-map": ["metro-file-map@0.83.3", "", { "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", "flow-enums-runtime": "^0.0.6", "graceful-fs": "^4.2.4", "invariant": "^2.2.4", "jest-worker": "^29.7.0", "micromatch": "^4.0.4", "nullthrows": "^1.1.1", "walker": "^1.0.7" } }, "sha512-jg5AcyE0Q9Xbbu/4NAwwZkmQn7doJCKGW0SLeSJmzNB9Z24jBe0AL2PHNMy4eu0JiKtNWHz9IiONGZWq7hjVTA=="], - "metro-minify-terser": ["metro-minify-terser@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-kmooOxXLvKVxkh80IVSYO4weBdJDhCpg5NSPkjzzAnPJP43u6+usGXobkTWxxrAlq900bhzqKek4pBsUchlX6A=="], + "metro-minify-terser": ["metro-minify-terser@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" } }, "sha512-O2BmfWj6FSfzBLrNCXt/rr2VYZdX5i6444QJU0fFoc7Ljg+Q+iqebwE3K0eTvkI6TRjELsXk1cjU+fXwAR4OjQ=="], - "metro-resolver": ["metro-resolver@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-t8j46kiILAqqFS5RNa+xpQyVjULxRxlvMidqUswPEk5nQVNdlJslqizDm/Et3v/JKwOtQGkYAQCHxP1zGStR/g=="], + "metro-resolver": ["metro-resolver@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-0js+zwI5flFxb1ktmR///bxHYg7OLpRpWZlBBruYG8OKYxeMP7SV0xQ/o/hUelrEMdK4LJzqVtHAhBm25LVfAQ=="], - "metro-runtime": ["metro-runtime@0.83.1", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-3Ag8ZS4IwafL/JUKlaeM6/CbkooY+WcVeqdNlBG0m4S0Qz0om3rdFdy1y6fYBpl6AwXJwWeMuXrvZdMuByTcRA=="], + "metro-runtime": ["metro-runtime@0.83.3", "", { "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" } }, "sha512-JHCJb9ebr9rfJ+LcssFYA2x1qPYuSD/bbePupIGhpMrsla7RCwC/VL3yJ9cSU+nUhU4c9Ixxy8tBta+JbDeZWw=="], - "metro-source-map": ["metro-source-map@0.83.1", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.1", "nullthrows": "^1.1.1", "ob1": "0.83.1", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-De7Vbeo96fFZ2cqmI0fWwVJbtHIwPZv++LYlWSwzTiCzxBDJORncN0LcT48Vi2UlQLzXJg+/CuTAcy7NBVh69A=="], + "metro-source-map": ["metro-source-map@0.83.3", "", { "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-symbolicate": "0.83.3", "nullthrows": "^1.1.1", "ob1": "0.83.3", "source-map": "^0.5.6", "vlq": "^1.0.0" } }, "sha512-xkC3qwUBh2psVZgVavo8+r2C9Igkk3DibiOXSAht1aYRRcztEZNFtAMtfSB7sdO2iFMx2Mlyu++cBxz/fhdzQg=="], - "metro-symbolicate": ["metro-symbolicate@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.1", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-wPxYkONlq/Sv8Ji7vHEx5OzFouXAMQJjpcPW41ySKMLP/Ir18SsiJK2h4YkdKpYrTS1+0xf8oqF6nxCsT3uWtg=="], + "metro-symbolicate": ["metro-symbolicate@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", "metro-source-map": "0.83.3", "nullthrows": "^1.1.1", "source-map": "^0.5.6", "vlq": "^1.0.0" }, "bin": { "metro-symbolicate": "src/index.js" } }, "sha512-F/YChgKd6KbFK3eUR5HdUsfBqVsanf5lNTwFd4Ca7uuxnHgBC3kR/Hba/RGkenR3pZaGNp5Bu9ZqqP52Wyhomw=="], - "metro-transform-plugins": ["metro-transform-plugins@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-1Y+I8oozXwhuS0qwC+ezaHXBf0jXW4oeYn4X39XWbZt9X2HfjodqY9bH9r6RUTsoiK7S4j8Ni2C91bUC+sktJQ=="], + "metro-transform-plugins": ["metro-transform-plugins@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/template": "^7.25.0", "@babel/traverse": "^7.25.3", "flow-enums-runtime": "^0.0.6", "nullthrows": "^1.1.1" } }, "sha512-eRGoKJU6jmqOakBMH5kUB7VitEWiNrDzBHpYbkBXW7C5fUGeOd2CyqrosEzbMK5VMiZYyOcNFEphvxk3OXey2A=="], - "metro-transform-worker": ["metro-transform-worker@0.83.1", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "metro": "0.83.1", "metro-babel-transformer": "0.83.1", "metro-cache": "0.83.1", "metro-cache-key": "0.83.1", "metro-minify-terser": "0.83.1", "metro-source-map": "0.83.1", "metro-transform-plugins": "0.83.1", "nullthrows": "^1.1.1" } }, "sha512-owCrhPyUxdLgXEEEAL2b14GWTPZ2zYuab1VQXcfEy0sJE71iciD7fuMcrngoufh7e7UHDZ56q4ktXg8wgiYA1Q=="], + "metro-transform-worker": ["metro-transform-worker@0.83.3", "", { "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", "@babel/parser": "^7.25.3", "@babel/types": "^7.25.2", "flow-enums-runtime": "^0.0.6", "metro": "0.83.3", "metro-babel-transformer": "0.83.3", "metro-cache": "0.83.3", "metro-cache-key": "0.83.3", "metro-minify-terser": "0.83.3", "metro-source-map": "0.83.3", "metro-transform-plugins": "0.83.3", "nullthrows": "^1.1.1" } }, "sha512-Ztekew9t/gOIMZX1tvJOgX7KlSLL5kWykl0Iwu2cL2vKMKVALRl1hysyhUw0vjpAvLFx+Kfq9VLjnHIkW32fPA=="], "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], @@ -741,17 +733,17 @@ "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], - "node-abi": ["node-abi@3.77.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ=="], + "node-abi": ["node-abi@3.78.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-E2wEyrgX/CqvicaQYU3Ze1PFGjc4QYPGsjUrlYkqAE0WjHEZwgOsGMPMzkMse4LjJbDmaEuDX3CM036j5K2DSQ=="], "node-addon-api": ["node-addon-api@7.1.1", "", {}, "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="], - "node-api-headers": ["node-api-headers@1.5.0", "", {}, "sha512-Yi/FgnN8IU/Cd6KeLxyHkylBUvDTsSScT0Tna2zTrz8klmc8qF2ppj6Q1LHsmOueJWhigQwR4cO2p0XBGW5IaQ=="], + "node-api-headers": ["node-api-headers@1.6.0", "", {}, "sha512-81T99+mWLZnxX0LlZPYuafyFlxVVaWKQ0BDAbSrOqLO+v+gzCzu0GTAVNeVK8lucqjqo9L/1UcK9cpkem8Py4Q=="], "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], - "node-releases": ["node-releases@2.0.20", "", {}, "sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA=="], + "node-releases": ["node-releases@2.0.26", "", {}, "sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -765,7 +757,7 @@ "nullthrows": ["nullthrows@1.1.1", "", {}, "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw=="], - "ob1": ["ob1@0.83.1", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-ngwqewtdUzFyycomdbdIhFLjePPSOt1awKMUXQ0L7iLHgWEPF3DsCerblzjzfAUHaXuvE9ccJymWQ/4PNNqvnQ=="], + "ob1": ["ob1@0.83.3", "", { "dependencies": { "flow-enums-runtime": "^0.0.6" } }, "sha512-egUxXCDwoWG06NGCS5s5AdcpnumHKJlfd3HH06P3m9TEMwwScfcY35wpQxbm9oHof+dM/lVH9Rfyu1elTVelSA=="], "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], @@ -783,8 +775,6 @@ "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], - "parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="], - "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], @@ -797,11 +787,11 @@ "picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "pino": ["pino@9.9.4", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-d1XorUQ7sSKqVcYdXuEYs2h1LKxejSorMEJ76XoZ0pPDf8VzJMe7GlPXpMBZeQ9gE4ZPIp5uGD+5Nw7scxiigg=="], + "pino": ["pino@9.6.0", "", { "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^4.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-i85pKRCt4qMjZ1+L7sy2Ag4t1atFcdbEt76+7iRJn1g2BvsnRMGu9p8pivl9fs63M2kF/A0OacFZhTub+m/qMg=="], "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], - "pino-pretty": ["pino-pretty@13.1.1", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^4.0.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^5.0.2" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA=="], + "pino-pretty": ["pino-pretty@13.0.0", "", { "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", "fast-copy": "^3.0.2", "fast-safe-stringify": "^2.1.1", "help-me": "^5.0.0", "joycon": "^3.1.1", "minimist": "^1.2.6", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pump": "^3.0.0", "secure-json-parse": "^2.4.0", "sonic-boom": "^4.0.1", "strip-json-comments": "^3.1.1" }, "bin": { "pino-pretty": "bin.js" } }, "sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA=="], "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], @@ -811,11 +801,11 @@ "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], - "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], + "process-warning": ["process-warning@4.0.1", "", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="], "promise": ["promise@8.3.0", "", { "dependencies": { "asap": "~2.0.6" } }, "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg=="], - "protobufjs": ["protobufjs@7.2.5", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A=="], + "protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="], "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], @@ -823,7 +813,7 @@ "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], - "pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="], + "pvutils": ["pvutils@1.1.5", "", {}, "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA=="], "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], @@ -833,13 +823,13 @@ "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], - "react": ["react@19.1.1", "", {}, "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ=="], + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], "react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="], "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "react-native": ["react-native@0.81.1", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.81.1", "@react-native/codegen": "0.81.1", "@react-native/community-cli-plugin": "0.81.1", "@react-native/gradle-plugin": "0.81.1", "@react-native/js-polyfills": "0.81.1", "@react-native/normalize-colors": "0.81.1", "@react-native/virtualized-lists": "0.81.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.29.1", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.0", "react": "^19.1.0" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-k2QJzWc/CUOwaakmD1SXa4uJaLcwB2g2V9BauNIjgtXYYAeyFjx9jlNz/+wAEcHLg9bH5mgMdeAwzvXqjjh9Hg=="], + "react-native": ["react-native@0.82.1", "", { "dependencies": { "@jest/create-cache-key-function": "^29.7.0", "@react-native/assets-registry": "0.82.1", "@react-native/codegen": "0.82.1", "@react-native/community-cli-plugin": "0.82.1", "@react-native/gradle-plugin": "0.82.1", "@react-native/js-polyfills": "0.82.1", "@react-native/normalize-colors": "0.82.1", "@react-native/virtualized-lists": "0.82.1", "abort-controller": "^3.0.0", "anser": "^1.4.9", "ansi-regex": "^5.0.0", "babel-jest": "^29.7.0", "babel-plugin-syntax-hermes-parser": "0.32.0", "base64-js": "^1.5.1", "commander": "^12.0.0", "flow-enums-runtime": "^0.0.6", "glob": "^7.1.1", "hermes-compiler": "0.0.0", "invariant": "^2.2.4", "jest-environment-node": "^29.7.0", "memoize-one": "^5.0.0", "metro-runtime": "^0.83.1", "metro-source-map": "^0.83.1", "nullthrows": "^1.1.1", "pretty-format": "^29.7.0", "promise": "^8.3.0", "react-devtools-core": "^6.1.5", "react-refresh": "^0.14.0", "regenerator-runtime": "^0.13.2", "scheduler": "0.26.0", "semver": "^7.1.3", "stacktrace-parser": "^0.1.10", "whatwg-fetch": "^3.0.0", "ws": "^6.2.3", "yargs": "^17.6.2" }, "peerDependencies": { "@types/react": "^19.1.1", "react": "^19.1.1" }, "optionalPeers": ["@types/react"], "bin": { "react-native": "cli.js" } }, "sha512-tFAqcU7Z4g49xf/KnyCEzI4nRTu1Opcx05Ov2helr8ZTg1z7AJR/3sr2rZ+AAVlAs2IXk+B0WOxXGmdD3+4czA=="], "react-native-get-random-values": ["react-native-get-random-values@1.11.0", "", { "dependencies": { "fast-base64-decode": "^1.0.0" }, "peerDependencies": { "react-native": ">=0.56" } }, "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ=="], @@ -855,7 +845,7 @@ "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], - "rfc4648": ["rfc4648@1.5.4", "", {}, "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg=="], + "rfc4648": ["rfc4648@1.5.3", "", {}, "sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ=="], "rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="], @@ -867,9 +857,9 @@ "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], - "secure-json-parse": ["secure-json-parse@4.0.0", "", {}, "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA=="], + "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], - "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], @@ -881,6 +871,10 @@ "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], @@ -913,9 +907,9 @@ "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], - "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - "strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="], + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], "strtok3": ["strtok3@10.3.4", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], @@ -923,7 +917,7 @@ "tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="], - "tar-fs": ["tar-fs@2.1.3", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg=="], + "tar-fs": ["tar-fs@2.1.4", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ=="], "tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="], @@ -951,17 +945,17 @@ "type-fest": ["type-fest@0.7.1", "", {}, "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg=="], - "typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], - "undici-types": ["undici-types@7.10.0", "", {}, "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], - "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="], + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], "url-join": ["url-join@4.0.1", "", {}, "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="], @@ -999,27 +993,53 @@ "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + "yaml": ["yaml@2.8.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw=="], + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "@babel/core/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/traverse/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@babel/traverse--for-generate-function-map/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@ethersproject/bignumber/bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "@ethersproject/signing-key/bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "@hashgraph/cryptography/bn.js": ["bn.js@5.2.1", "", {}, "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ=="], + + "@hashgraph/cryptography/js-base64": ["js-base64@3.7.7", "", {}, "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="], + "@istanbuljs/load-nyc-config/camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="], "@jest/schemas/@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + "@react-native/community-cli-plugin/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@react-native/dev-middleware/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "@tokenizer/inflate/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "bl/buffer": ["buffer@5.7.1", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" } }, "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ=="], "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - "cmake-js/axios": ["axios@1.11.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA=="], + "cliui/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], - "cmake-js/fs-extra": ["fs-extra@11.3.1", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g=="], + "cmake-js/axios": ["axios@1.13.0", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-zt40Pz4zcRXra9CVV31KeyofwiNvAbJ5B6YPz9pMJ+yOSLikvPT4Yi5LjfgjRa9CawVYBaD1JQzIVcIvBejKeA=="], + + "cmake-js/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "cmake-js/fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="], "connect/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -1031,9 +1051,11 @@ "fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "gauge/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], - "import-fresh/resolve-from": ["resolve-from@3.0.0", "", {}, "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="], + "https-proxy-agent/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "istanbul-lib-instrument/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], @@ -1041,22 +1063,34 @@ "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + "jsonrpc-ts-client/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "lighthouse-logger/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + "log4js/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "metro/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "metro-file-map/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + "minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], "npm-path/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], "npm-which/which": ["which@1.3.1", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "which": "./bin/which" } }, "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="], + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], "react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], + "react-native/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "react-native/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "send/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], @@ -1071,10 +1105,18 @@ "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], + "streamroller/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="], "wrap-ansi/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "cmake-js/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], "cmake-js/fs-extra/universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], @@ -1083,8 +1125,14 @@ "finalhandler/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + "gauge/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "lighthouse-logger/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], "send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], } } diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 9490e8a00..9131a3132 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -99,4 +99,45 @@ export const configSchema = v.object({ ), '4000', ), + MYSQL_HOST: v.optional( + v.string('The host of the database'), + 'localhost', + ), + MYSQL_PORT: v.optional( + v.pipe( + v.string('The port of the database'), + v.transform((input: string) => Number.parseInt(input)), + v.minValue(1), + v.maxValue(65535), + ), + '3306', + ), + MYSQL_USER: v.optional( + v.pipe( + v.string('The user name of the database'), + v.custom((input: unknown): boolean => { + if (process.env.NODE_ENV === 'production' && input === 'root') { + return false + } + return true + }, "Shouldn't use default root user in production"), + ), + 'root', + ), + MYSQL_PASSWORD: v.optional( + v.pipe( + v.string('The password of the database'), + v.custom((input: unknown): boolean => { + if (process.env.NODE_ENV === 'production' && input === '') { + return false + } + return true + }, "Shouldn't use empty password in production"), + ), + '', + ), + MYSQL_DATABASE: v.optional( + v.string('The name of the database'), + 'gradido_community', + ), }) diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 7ae40ea99..61f4d3cfb 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -79,10 +79,10 @@ export class KeyPairIdentifierLogic { return this.getCommunityTopicId() } getCommunityUserKey(): string { - return this.deriveCommunityUserHash() + return this.deriveCommunityUserHash(0) } getCommunityUserAccountKey(): string { - return this.deriveCommunityUserHash() + this.getAccountNr().toString() + return this.deriveCommunityUserHash(this.getAccountNr()) } getKey(): string { @@ -100,14 +100,14 @@ export class KeyPairIdentifierLogic { } } - private deriveCommunityUserHash(): string { + private deriveCommunityUserHash(accountNr: number): string { if (!this.identifier.account) { throw new InvalidCallError( 'Invalid call: getCommunityUserKey or getCommunityUserAccountKey() on non-user/non-account identifier', ) } const resultString = - this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') + this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') + accountNr.toString() return new MemoryBlock(resultString).calculateHash().convertToHex() } } diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts index 406463c4c..21187602b 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -32,7 +32,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' */ export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise { const cache = KeyPairCacheManager.getInstance() - + return await cache.getKeyPair( input.getKey(), // function is called from cache manager, if key isn't currently cached diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts index ef896e1e8..7bb6e1140 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'bun:test' -import { InteractionToJson, InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' +import { InteractionValidate, ValidateType_SINGLE } from 'gradido-blockchain-js' import * as v from 'valibot' import { transactionSchema } from '../../schemas/transaction.schema' import { hieroIdSchema } from '../../schemas/typeGuard.schema' @@ -31,7 +31,7 @@ describe('RegisterAddressTransaction.role', () => { const builder = await registerAddressTransactionRole.getGradidoTransactionBuilder() const gradidoTransaction = builder.build() expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() - const json = JSON.parse(new InteractionToJson(gradidoTransaction).run()) + const json = JSON.parse(gradidoTransaction.toJson(true)) expect(json.bodyBytes.json.registerAddress.nameHash).toBe( 'bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08', ) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts new file mode 100644 index 000000000..b60a08b08 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts @@ -0,0 +1,53 @@ +import { SQL } from 'bun' +import { InMemoryBlockchain } from 'gradido-blockchain-js' +import { Logger } from 'log4js' + +import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' + +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import { loadConfig } from '../../bootstrap/init' +import { CONFIG } from '../../config' + + +export type CommunityContext = { + communityId: string + blockchain: InMemoryBlockchain + topicId: HieroId +} + +export class Context { + public logger: Logger + public db: SQL + public communities: Map + public cache: KeyPairCacheManager + + constructor(logger: Logger, db: SQL, cache: KeyPairCacheManager) { + this.logger = logger + this.db = db + this.cache = cache + this.communities = new Map() + } + + static create(): Context { + return new Context( + loadConfig(), + new SQL({ + adapter: 'mysql', + hostname: CONFIG.MYSQL_HOST, + username: CONFIG.MYSQL_USER, + password: CONFIG.MYSQL_PASSWORD, + database: CONFIG.MYSQL_DATABASE, + port: CONFIG.MYSQL_PORT + }), + KeyPairCacheManager.getInstance() + ) + } + + getCommunityContextByUuid(communityUuid: Uuidv4): CommunityContext { + const community = this.communities.get(communityUuid) + if (!community) { + throw new Error(`Community not found for communityUuid ${communityUuid}`) + } + return community + } +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts new file mode 100644 index 000000000..90dcc0e74 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts @@ -0,0 +1,58 @@ + +export type Loader = (context: ContextType, offset: number, count: number) => Promise + +export interface Orderable { + getDate(): Date + // return count of new loaded items + ensureFilled(context: ContextType, batchSize: number): Promise + pushToBlockchain(context: ContextType): Promise + isEmpty(): boolean +} + +export class OrderedContainer implements Orderable { + private items: T[] = [] + private offset = 0 + + constructor( + private readonly loader: Loader, + private readonly getDateHandler: (item: T) => Date, + private readonly pushToBlockchainHandler: (context: ContextType, item: T) => Promise + ) {} + + + async ensureFilled(context: ContextType, batchSize: number): Promise { + if (this.items.length === 0) { + this.items = await this.loader(context, this.offset, batchSize) + this.offset += this.items.length + return this.items.length + } + return 0 + } + + async pushToBlockchain(context: ContextType): Promise { + return this.pushToBlockchainHandler(context, this.shift()) + } + + peek(): T { + if (this.isEmpty()) { + throw new Error(`[peek] No items, please call this only if isEmpty returns false`) + } + return this.items[0] + } + + shift(): T { + const item = this.items.shift() + if (!item) { + throw new Error(`[shift] No items, shift return undefined`) + } + return item + } + + getDate(): Date { + return this.getDateHandler(this.peek()) + } + + isEmpty(): boolean { + return this.items.length === 0 + } +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts new file mode 100644 index 000000000..22fa9b400 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts @@ -0,0 +1,98 @@ +import { sql, SQL } from 'bun' +import { + InMemoryBlockchain, + InMemoryBlockchainProvider, + GradidoTransactionBuilder, + KeyPairEd25519, + MemoryBlock, + Timestamp, + HieroTransactionId, + HieroAccountId, + InteractionSerialize, + loadCryptoKeys, + Filter, + SearchDirection_ASC +} from 'gradido-blockchain-js' +import { Logger, getLogger } from 'log4js' +import { CONFIG } from '../../config' +import { amountSchema, HieroId, hieroIdSchema, memoSchema, uuidv4Schema, Uuidv4, gradidoAmountSchema } from '../../schemas/typeGuard.schema' +import { dateSchema } from '../../schemas/typeConverter.schema' +import * as v from 'valibot' +import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import { InputTransactionType } from '../../data/InputTransactionType.enum' +import { AccountType } from '../../data/AccountType.enum' +import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' +import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' +import { loadConfig } from '../../bootstrap/init' +import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' +import { CommunityDb, loadCommunities, TransactionDb, TransactionTypeId, UserDb } from './database' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { Community, Transaction } from '../../schemas/transaction.schema' +import { communityDbToCommunity, userDbToTransaction } from './convert' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) +export const defaultHieroAccount = new HieroAccountId(0, 0, 2) + +function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemoryBlockchain, createdAtTimestamp: Timestamp): boolean { + const transaction = builder.build() + const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) + const interactionSerialize = new InteractionSerialize(transactionId) + return blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) +} + +export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain, community: Community): Promise { + const communityRootTransactionRole = new CommunityRootTransactionRole(community) + if(addToBlockchain(await communityRootTransactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(community.creationDate))) { + logger.info(`Community Root Transaction added`) + } else { + throw new Error(`Community Root Transaction not added`) + } +} + +export async function addRegisterAddressTransaction(blockchain: InMemoryBlockchain, transaction: Transaction): Promise { + const registerAddressRole = new RegisterAddressTransactionRole(transaction) + if(addToBlockchain(await registerAddressRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transaction.createdAt))) { + logger.info(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) + } +} +/* + + +export async function addTransaction(blockchain: InMemoryBlockchain, transactionDb: TransactionDb): Promise { + + let transactionRole: AbstractTransactionRole + switch (transactionDb.typeId) { + case TransactionTypeId.CREATION: + transactionRole = new CreationTransactionRole({ + user: { + communityTopicId: transactionDb.user.communityTopicId, + account: { + userUuid: transactionDb.user.gradidoId, + accountNr: 0, + }, + }, + linkedUser: { + communityTopicId: transactionDb.linkedUser.communityTopicId, + account: { + userUuid: transactionDb.linkedUser.gradidoId, + accountNr: 0, + }, + }, + amount: v.parse(gradidoAmountSchema, transactionDb.amount), + memo: v.parse(memoSchema, transactionDb.memo), + createdAt: transactionDb.creationDate, + targetDate: transactionDb.balanceDate, + type: getInputTransactionTypeFromTypeId(transactionDb.typeId), + }) + if(addToBlockchain(await transactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transactionDb.creationDate))) { + logger.info(`Transaction added for user ${transactionDb.user.gradidoId}`) + } else { + throw new Error(`Transaction not added for user ${transactionDb.user.gradidoId}`) + } +} +*/ \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts new file mode 100644 index 000000000..325347369 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts @@ -0,0 +1,49 @@ +import { Context } from './Context' +import { CommunityContext } from './Context' +import { loadCommunities } from './database' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' +import * as v from 'valibot' +import { InMemoryBlockchainProvider } from 'gradido-blockchain-js' +import { generateKeyPairCommunity } from './keyPair' +import { communityDbToCommunity } from './convert' +import { addCommunityRootTransaction } from './blockchain' + +export async function bootstrap(): Promise { + const context = Context.create() + context.communities = await bootstrapCommunities(context) + return context +} + +async function bootstrapCommunities(context: Context): Promise> { + const communities = new Map() + const communitiesDb = await loadCommunities(context.db) + const topicIds = new Set() + + for (const communityDb of communitiesDb) { + const blockchain = InMemoryBlockchainProvider.getInstance().findBlockchain(communityDb.uniqueAlias) + if (!blockchain) { + throw new Error(`Couldn't create Blockchain for community ${communityDb.communityUuid}`) + } + context.logger.info(`Blockchain for community '${communityDb.uniqueAlias}' created`) + // make sure topic id is unique + let topicId: HieroId + do { + topicId = v.parse(hieroIdSchema, '0.0.' + Math.floor(Math.random() * 10000)) + } while(topicIds.has(topicId)) + topicIds.add(topicId) + + communities.set(communityDb.communityUuid, { + communityId: communityDb.uniqueAlias, + blockchain, + topicId + }) + + generateKeyPairCommunity(communityDb, context.cache, topicId) + // create community root transaction 1 minute before first user + const creationDate = new Date(new Date(communityDb.userMinCreatedAt).getTime() - 1000 * 60) + // community from db to community format the dlt connector normally uses + const community = communityDbToCommunity(topicId, communityDb, creationDate) + await addCommunityRootTransaction(blockchain, community) + } + return communities +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts new file mode 100644 index 000000000..f182664bc --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts @@ -0,0 +1,86 @@ +import { InputTransactionType } from '../../data/InputTransactionType.enum' +import { CommunityDb, TransactionDb, TransactionTypeId, CreatedUserDb } from './database' +import { Community, communitySchema, transactionSchema, Transaction, TransactionInput } from '../../schemas/transaction.schema' +import { AccountType } from '../../data/AccountType.enum' +import { gradidoAmountSchema, HieroId, memoSchema } from '../../schemas/typeGuard.schema' +import * as v from 'valibot' + +export function getInputTransactionTypeFromTypeId(typeId: TransactionTypeId): InputTransactionType { + switch (typeId) { + case TransactionTypeId.CREATION: + return InputTransactionType.GRADIDO_CREATION + case TransactionTypeId.SEND: + return InputTransactionType.GRADIDO_TRANSFER + case TransactionTypeId.RECEIVE: + throw new Error('not used') + default: + throw new Error('not implemented') + } +} + +export function communityDbToCommunity(topicId: HieroId, communityDb: CommunityDb, creationDate: Date): Community { + return v.parse(communitySchema, { + hieroTopicId: topicId, + uuid: communityDb.communityUuid, + foreign: communityDb.foreign, + creationDate, + }) +} + +export function userDbToTransaction(userDb: CreatedUserDb, communityTopicId: HieroId): Transaction { + return v.parse(transactionSchema, { + user: { + communityTopicId: communityTopicId, + account: { userUuid: userDb.gradidoId }, + }, + type: InputTransactionType.REGISTER_ADDRESS, + accountType: AccountType.COMMUNITY_HUMAN, + createdAt: userDb.createdAt, + }) +} + +export function transactionDbToTransaction(transactionDb: TransactionDb, communityTopicId: HieroId, recipientCommunityTopicId: HieroId): Transaction { + if ( + transactionDb.typeId !== TransactionTypeId.CREATION + && transactionDb.typeId !== TransactionTypeId.SEND + && transactionDb.typeId !== TransactionTypeId.RECEIVE) { + throw new Error('not implemented') + } + const user = { + communityTopicId: communityTopicId, + account: { userUuid: transactionDb.user.gradidoId }, + } + const linkedUser = { + communityTopicId: recipientCommunityTopicId, + account: { userUuid: transactionDb.linkedUser.gradidoId }, + } + const transaction: TransactionInput = { + user, + linkedUser, + amount: v.parse(gradidoAmountSchema, transactionDb.amount), + memo: v.parse(memoSchema, transactionDb.memo), + type: InputTransactionType.GRADIDO_TRANSFER, + createdAt: transactionDb.balanceDate, + } + if (transactionDb.typeId === TransactionTypeId.CREATION) { + if (!transactionDb.creationDate) { + throw new Error('contribution transaction without creation date') + } + transaction.targetDate = transactionDb.creationDate + transaction.type = InputTransactionType.GRADIDO_CREATION + } else if (transactionDb.typeId === TransactionTypeId.RECEIVE) { + transaction.user = linkedUser + transaction.linkedUser = user + } + if (transactionDb.transactionLinkCode) { + if (transactionDb.typeId !== TransactionTypeId.RECEIVE) { + throw new Error('linked transaction which isn\'t receive, send will taken care of on link creation') + } + transaction.user = { + communityTopicId: recipientCommunityTopicId, + seed: transactionDb.transactionLinkCode, + } + transaction.type = InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER + } + return v.parse(transactionSchema, transaction) +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts new file mode 100644 index 000000000..71561e33d --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts @@ -0,0 +1,176 @@ +import { SQL } from 'bun' +import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema } from '../../schemas/typeGuard.schema' +import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' +import * as v from 'valibot' +import { GradidoUnit } from 'gradido-blockchain-js' + +export const createdUserDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, + createdAt: dateSchema, +}) + +export const userDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, +}) + +export enum TransactionTypeId { + CREATION = 1, + SEND = 2, + RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, +} + +export const transactionDbSchema = v.object({ + typeId: v.enum(TransactionTypeId), + amount: amountSchema, + balanceDate: dateSchema, + memo: memoSchema, + creationDate: v.nullish(dateSchema), + user: userDbSchema, + linkedUser: userDbSchema, + transactionLinkCode: v.nullish(identifierSeedSchema), +}) + +export const transactionLinkDbSchema = v.object({ + userUuid: uuidv4Schema, + code: identifierSeedSchema, + amount: amountSchema, + memo: memoSchema, + createdAt: dateSchema, + validUntil: dateSchema, +}) + +export const communityDbSchema = v.object({ + foreign: booleanSchema, + communityUuid: uuidv4Schema, + name: v.string(), + creationDate: dateSchema, + userMinCreatedAt: dateSchema, + uniqueAlias: v.string(), +}) + +export type TransactionDb = v.InferOutput +export type UserDb = v.InferOutput +export type CreatedUserDb = v.InferOutput +export type TransactionLinkDb = v.InferOutput +export type CommunityDb = v.InferOutput + +// queries +export async function loadCommunities(db: SQL): Promise { + const result = await db` + SELECT c.foreign, c.community_uuid as communityUuid, c.name as name, c.creation_date as creationDate, MIN(u.created_at) as userMinCreatedAt + FROM communities c + LEFT JOIN users u ON c.community_uuid = u.community_uuid + WHERE c.community_uuid IS NOT NULL + GROUP BY c.community_uuid + ` + const communityNames = new Set() + return result.map((row: any) => { + let alias = row.name + if (communityNames.has(row.name)) { + alias = row.community_uuid + } else { + communityNames.add(row.name) + } + return v.parse(communityDbSchema, { + ...row, + uniqueAlias: alias, + }) + }) +} + +export async function loadUsers(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT id, gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users + ORDER by created_at ASC + LIMIT ${offset}, ${count} + ` + const totalCount = await db` + SELECT COUNT(*) as count FROM users + ` + console.log(`Loaded ${result.length} users, total ${totalCount[0].count} with offset ${offset} and count ${count}`) + return result.map((row: any) => { + return v.parse(createdUserDbSchema, row) + }) +} + +export async function loadTransactions(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT type_id, amount, balance_date, memo, creation_date, + u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, + lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, + tl.code as transaction_link_code + FROM transactions + LEFT JOIN users u ON transactions.user_id = u.id + LEFT JOIN users lu ON transactions.linked_user_id = lu.id + LEFT JOIN transaction_links tl ON transactions.transaction_link_id = tl.id + ORDER by balance_date ASC + LIMIT ${offset}, ${count} + ` + return result.map((row: any) => { + let amount = GradidoUnit.fromString(row.amount) + if (row.type_id === TransactionTypeId.SEND) { + amount = amount.mul(new GradidoUnit(-1)) + } + return v.parse(transactionDbSchema, { + typeId: row.type_id, + amount, + balanceDate: new Date(row.balance_date), + memo: row.memo, + creationDate: new Date(row.creation_date), + transactionLinkCode: row.transaction_link_code, + user: { + gradidoId: row.user_gradido_id, + communityUuid: row.user_community_uuid + }, + linkedUser: { + gradidoId: row.linked_user_gradido_id, + communityUuid: row.linked_user_community_uuid + } + }) + }) +} + +export async function loadTransactionLinks(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT u.gradido_id as userUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil + FROM transaction_links tl + LEFT JOIN users u ON tl.userId = u.id + ORDER by createdAt ASC + LIMIT ${offset}, ${count} + ` + return result.map((row: any) => { + return v.parse(transactionLinkDbSchema, row) + }) +} + +export async function loadDeletedTransactionLinks(db: SQL, offset: number, count: number): Promise { + const result = await db` + SELECT u.gradido_id as user_gradido_id, u.community_uuid as user_community_uuid, + tl.code, tl.amount, tl.memo, tl.deletedAt + FROM transaction_links tl + LEFT JOIN users u ON tl.userId = u.id + WHERE deletedAt IS NOT NULL + ORDER by deletedAt ASC + LIMIT ${offset}, ${count} + ` + return result.map((row: any) => { + const user = { + gradidoId: row.user_gradido_id, + communityUuid: row.user_community_uuid + } + return v.parse(transactionDbSchema, { + typeId: TransactionTypeId.RECEIVE, + amount: row.amount, + balanceDate: new Date(row.deletedAt), + memo: row.memo, + transactionLinkCode: row.code, + user, + linkedUser: user + }) + }) +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts new file mode 100644 index 000000000..201526fbb --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts @@ -0,0 +1,171 @@ +import { + InMemoryBlockchain, + Filter, + SearchDirection_ASC, + HieroTransactionId, + Timestamp, + InteractionSerialize +} from 'gradido-blockchain-js' +import { Logger } from 'log4js' + +import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' +import { addRegisterAddressTransaction, defaultHieroAccount } from './blockchain' +import { generateKeyPairUserAccount } from './keyPair' +import { transactionDbToTransaction, userDbToTransaction } from './convert' +import { Orderable, OrderedContainer } from './OrderedContainer' +import { Context } from './Context' +import { bootstrap } from './bootstrap' +import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' + +async function main() { + // prepare in memory blockchains + const context = await bootstrap() + + // synchronize to blockchain + const BATCH_SIZE = 10 + + const users = new OrderedContainer( + getNextUsers, + (user: CreatedUserDb) => user.createdAt, + (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) + ) + + await synchronizeToBlockchain(context, [users], BATCH_SIZE) + + // log blockchains + for(const community of context.communities.values()) { + context.logger.info(`Community '${community.communityId}', blockchain`) + logBlogchain(context.logger, community.blockchain) + } + context.db.close() + return Promise.resolve() +} + +async function synchronizeToBlockchain( + context: Context, + containers: Orderable[], + batchSize: number +): Promise { + let rounds = 20 + while (rounds-- > 0) { + await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) + // console.log(`filled containers, rounds left: ${rounds}`) + // remove empty containers + const available = containers.filter(c => !c.isEmpty()) + if (available.length === 0) break + // console.log(`available containers: ${available.length}`) + + // find container with smallest date + available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + // console.log(`smallest date: ${available[0].getDate()}`) + + if(rounds >= 0) { + await available[0].pushToBlockchain(context) + } else { + const user = (available[0] as any as OrderedContainer).shift() + console.log(JSON.stringify(user, null, 2)) + console.log(`context: ${JSON.stringify(context, null, 2)}`) + const communityContext = context.getCommunityContextByUuid(user.communityUuid) + const transactionBase = userDbToTransaction(user, communityContext.topicId) + console.log(JSON.stringify(transactionBase, null, 2)) + const registerAddressRole = new RegisterAddressTransactionRole(transactionBase) + const builder = await registerAddressRole.getGradidoTransactionBuilder() + const transaction = builder.build() + console.log(transaction.toJson(true)) + const createdAtTimestamp = new Timestamp(user.createdAt) + console.log(`createdAtTimestamp: ${createdAtTimestamp.toJson()}`) + const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) + const interactionSerialize = new InteractionSerialize(transactionId) + const serializedTransactionId = interactionSerialize.run() + if (serializedTransactionId) { + console.log(`serialized transaction id: ${serializedTransactionId.convertToHex()}`) + } + console.log(communityContext.blockchain) + try { + communityContext.blockchain.createAndAddConfirmedTransaction(transaction, serializedTransactionId, createdAtTimestamp) + } catch(e) { + console.log(e) + } + } + // console.log(`pushed to blockchain, rounds left: ${rounds}`) + } +} + +async function fillBlockchains(context: Context): Promise { + const BATCH_SIZE = 10 + + const users = new OrderedContainer( + getNextUsers, + (user: CreatedUserDb) => user.createdAt, + (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) + ) + /*const transactions = new OrderedContainer(getNextTransactions, (transaction) => transaction.balanceDate) + const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) + const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) +*/ + await synchronizeToBlockchain(context, [users], BATCH_SIZE) +} + +// ---------------- load from db graiddo backend transactions format ----------------------------------------------- +/// load next max ${count} users and calculate key pair for calculating signatures later +async function getNextUsers(context: Context, offset: number, count: number): Promise { + const users = await loadUsers(context.db, offset, count) + for (const user of users) { + const communityContext = context.getCommunityContextByUuid(user.communityUuid) + generateKeyPairUserAccount(user, context.cache, communityContext.topicId) + } + return users +} + +// load next max ${count} transactions (contain also redeem transaction link transactions) +async function getNextTransactions(context: Context, offset: number, count: number): Promise { + return loadTransactions(context.db, offset, count) +} + +// load next max ${count} transaction links (freshly created links, in blockchain format this is a separate transaction) +async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { + return loadTransactionLinks(context.db, offset, count) +} + +// load next max ${count} deleted transaction links (in blockchain format this is a separate transaction) +async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { + return loadDeletedTransactionLinks(context.db, offset, count) +} + +// ---------------- put into in memory blockchain ----------------------------------------------- + +async function pushRegisterAddressTransaction(context: Context, user: CreatedUserDb): Promise { + const communityContext = context.getCommunityContextByUuid(user.communityUuid) + const transaction = userDbToTransaction(user, communityContext.topicId) + return await addRegisterAddressTransaction(communityContext.blockchain, transaction) +} + +/* +async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { + const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) + const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) + // CreationTransactionRole will check that community topic id belongs to home community + context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) + const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) + await addTransaction(senderCommunityContext.blockchain, transaction) +} +*/ +function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { + const f = new Filter() + f.pagination.size = 0 + f.searchDirection = SearchDirection_ASC + + const transactions = blockchain.findAll(f) + for(let i = 0; i < transactions.size(); i++) { + const transaction = transactions.get(i) + const confirmedTransaction = transaction?.getConfirmedTransaction() + logger.info(confirmedTransaction?.toJson(true)) + } +} + + +main().catch((e) => { + // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here + console.error(e) + process.exit(1) +}) \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts new file mode 100644 index 000000000..67337a656 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts @@ -0,0 +1,56 @@ +import { CommunityDb, UserDb } from './database' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' +import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { getLogger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { CONFIG } from '../../config' +import { HieroId } from '../../schemas/typeGuard.schema' +import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' + +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.keyPair`) + +export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairCacheManager, topicId: HieroId): void { + let seed: MemoryBlock | null = null + if (community.foreign) { + const randomBuffer = Buffer.alloc(32) + for (let i = 0; i < 32; i++) { + randomBuffer[i] = Math.floor(Math.random() * 256) + } + seed = new MemoryBlock(randomBuffer) + } else { + seed = new MemoryBlock(CONFIG.HOME_COMMUNITY_SEED) + } + const keyPair = KeyPairEd25519.create(seed) + if (!keyPair) { + throw new Error(`Couldn't create key pair for community ${community.communityUuid}`) + } + const communityKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: topicId }).getKey() + cache.addKeyPair(communityKeyPairKey, keyPair) + logger.info(`Community Key Pair added with key: ${communityKeyPairKey}`) +} + +export function generateKeyPairUserAccount(user: UserDb, cache: KeyPairCacheManager, communityTopicId: HieroId): void { + const communityKeyPair = cache.findKeyPair(communityTopicId)! + const userKeyPair = new UserKeyPairRole(user.gradidoId, communityKeyPair).generateKeyPair() + const userKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, + account: { + userUuid: user.gradidoId, + accountNr: 0 + } + }).getKey() + cache.addKeyPair(userKeyPairKey, userKeyPair) + + const accountKeyPair = new AccountKeyPairRole(1, userKeyPair).generateKeyPair() + const accountKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, + account: { + userUuid: user.gradidoId, + accountNr: 1 + } + }).getKey() + cache.addKeyPair(accountKeyPairKey, accountKeyPair) + logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) +} \ No newline at end of file diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index 3d68cfe24..d5ca78ea3 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -28,6 +28,18 @@ export const dateSchema = v.pipe( }), ) +export const booleanSchema = v.pipe( + v.union([v.boolean('expect boolean type'), v.number('expect boolean number type'), v.string('expect boolean string type')]), + v.transform((input) => { + if (typeof input === 'number') { + return input != 0 + } else if (typeof input === 'string') { + return input === 'true' + } + return input + }), +) + /** * AddressType is defined in gradido-blockchain C++ Code * AccountType is the enum defined in TypeScript but with the same options From 74bc448b96edb51478354e9f2e68b35bec6d302d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 31 Oct 2025 10:59:09 +0100 Subject: [PATCH 02/33] refine migration code structure --- .../blockchain.ts | 55 +++++++---------- .../db-v2.7.0_to_blockchain-v3.6/convert.ts | 10 +++- .../db-v2.7.0_to_blockchain-v3.6/database.ts | 57 ++++++++++-------- .../db-v2.7.0_to_blockchain-v3.6/index.ts | 60 ++++++++++++------- .../db-v2.7.0_to_blockchain-v3.6/keyPair.ts | 22 ++++--- docker-compose.yml | 2 + nginx/gradido.conf | 26 ++++++++ 7 files changed, 142 insertions(+), 90 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts index 22fa9b400..4154b0ba9 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts @@ -32,6 +32,7 @@ import { CommunityDb, loadCommunities, TransactionDb, TransactionTypeId, UserDb import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Community, Transaction } from '../../schemas/transaction.schema' import { communityDbToCommunity, userDbToTransaction } from './convert' +import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) @@ -60,39 +61,27 @@ export async function addRegisterAddressTransaction(blockchain: InMemoryBlockcha throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) } } -/* - -export async function addTransaction(blockchain: InMemoryBlockchain, transactionDb: TransactionDb): Promise { - - let transactionRole: AbstractTransactionRole - switch (transactionDb.typeId) { - case TransactionTypeId.CREATION: - transactionRole = new CreationTransactionRole({ - user: { - communityTopicId: transactionDb.user.communityTopicId, - account: { - userUuid: transactionDb.user.gradidoId, - accountNr: 0, - }, - }, - linkedUser: { - communityTopicId: transactionDb.linkedUser.communityTopicId, - account: { - userUuid: transactionDb.linkedUser.gradidoId, - accountNr: 0, - }, - }, - amount: v.parse(gradidoAmountSchema, transactionDb.amount), - memo: v.parse(memoSchema, transactionDb.memo), - createdAt: transactionDb.creationDate, - targetDate: transactionDb.balanceDate, - type: getInputTransactionTypeFromTypeId(transactionDb.typeId), - }) - if(addToBlockchain(await transactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transactionDb.creationDate))) { - logger.info(`Transaction added for user ${transactionDb.user.gradidoId}`) - } else { - throw new Error(`Transaction not added for user ${transactionDb.user.gradidoId}`) +export async function addTransaction( + senderBlockchain: InMemoryBlockchain, + _recipientBlockchain: InMemoryBlockchain, + transaction: Transaction +): Promise { + const createdAtTimestamp = new Timestamp(transaction.createdAt) + if (transaction.type === InputTransactionType.GRADIDO_CREATION) { + const creationTransactionRole = new CreationTransactionRole(transaction) + if(addToBlockchain(await creationTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.info(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) + } + } else if (transaction.type === InputTransactionType.GRADIDO_TRANSFER) { + const transferTransactionRole = new TransferTransactionRole(transaction) + // will crash with cross group transaction + if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.info(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + } } } -*/ \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts index f182664bc..e8052df88 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts @@ -39,7 +39,11 @@ export function userDbToTransaction(userDb: CreatedUserDb, communityTopicId: Hie }) } -export function transactionDbToTransaction(transactionDb: TransactionDb, communityTopicId: HieroId, recipientCommunityTopicId: HieroId): Transaction { +export function transactionDbToTransaction( + transactionDb: TransactionDb, + communityTopicId: HieroId, + recipientCommunityTopicId: HieroId +): Transaction { if ( transactionDb.typeId !== TransactionTypeId.CREATION && transactionDb.typeId !== TransactionTypeId.SEND @@ -48,11 +52,11 @@ export function transactionDbToTransaction(transactionDb: TransactionDb, communi } const user = { communityTopicId: communityTopicId, - account: { userUuid: transactionDb.user.gradidoId }, + account: { userUuid: transactionDb.user.gradidoId, accountNr: 0 }, } const linkedUser = { communityTopicId: recipientCommunityTopicId, - account: { userUuid: transactionDb.linkedUser.gradidoId }, + account: { userUuid: transactionDb.linkedUser.gradidoId, accountNr: 0 }, } const transaction: TransactionInput = { user, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts index 71561e33d..ce990a76f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts @@ -1,5 +1,5 @@ import { SQL } from 'bun' -import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema } from '../../schemas/typeGuard.schema' +import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' import { GradidoUnit } from 'gradido-blockchain-js' @@ -26,7 +26,7 @@ export enum TransactionTypeId { export const transactionDbSchema = v.object({ typeId: v.enum(TransactionTypeId), - amount: amountSchema, + amount: gradidoAmountSchema, balanceDate: dateSchema, memo: memoSchema, creationDate: v.nullish(dateSchema), @@ -38,7 +38,7 @@ export const transactionDbSchema = v.object({ export const transactionLinkDbSchema = v.object({ userUuid: uuidv4Schema, code: identifierSeedSchema, - amount: amountSchema, + amount: gradidoAmountSchema, memo: memoSchema, createdAt: dateSchema, validUntil: dateSchema, @@ -85,7 +85,7 @@ export async function loadCommunities(db: SQL): Promise { export async function loadUsers(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT id, gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users + SELECT gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users ORDER by created_at ASC LIMIT ${offset}, ${count} ` @@ -100,38 +100,47 @@ export async function loadUsers(db: SQL, offset: number, count: number): Promise export async function loadTransactions(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT type_id, amount, balance_date, memo, creation_date, + SELECT t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, tl.code as transaction_link_code - FROM transactions - LEFT JOIN users u ON transactions.user_id = u.id - LEFT JOIN users lu ON transactions.linked_user_id = lu.id - LEFT JOIN transaction_links tl ON transactions.transaction_link_id = tl.id + FROM transactions as t + LEFT JOIN users u ON t.user_id = u.id + LEFT JOIN users lu ON t.linked_user_id = lu.id + LEFT JOIN transaction_links tl ON t.transaction_link_id = tl.id ORDER by balance_date ASC LIMIT ${offset}, ${count} ` return result.map((row: any) => { + // console.log(row) let amount = GradidoUnit.fromString(row.amount) if (row.type_id === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) } - return v.parse(transactionDbSchema, { - typeId: row.type_id, - amount, - balanceDate: new Date(row.balance_date), - memo: row.memo, - creationDate: new Date(row.creation_date), - transactionLinkCode: row.transaction_link_code, - user: { - gradidoId: row.user_gradido_id, - communityUuid: row.user_community_uuid - }, - linkedUser: { - gradidoId: row.linked_user_gradido_id, - communityUuid: row.linked_user_community_uuid + try { + return v.parse(transactionDbSchema, { + typeId: row.type_id, + amount, + balanceDate: new Date(row.balance_date), + memo: row.memo, + creationDate: new Date(row.creation_date), + transactionLinkCode: row.transaction_link_code, + user: { + gradidoId: row.user_gradido_id, + communityUuid: row.user_community_uuid + }, + linkedUser: { + gradidoId: row.linked_user_gradido_id, + communityUuid: row.linked_user_community_uuid + } + }) + } catch (e) { + if (e instanceof v.ValiError) { + console.error(v.flatten(e.issues)) + } else { + throw e } - }) + } }) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts index 201526fbb..2aaa02366 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts @@ -9,7 +9,7 @@ import { import { Logger } from 'log4js' import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' -import { addRegisterAddressTransaction, defaultHieroAccount } from './blockchain' +import { addRegisterAddressTransaction, addTransaction, defaultHieroAccount } from './blockchain' import { generateKeyPairUserAccount } from './keyPair' import { transactionDbToTransaction, userDbToTransaction } from './convert' import { Orderable, OrderedContainer } from './OrderedContainer' @@ -17,20 +17,35 @@ import { Context } from './Context' import { bootstrap } from './bootstrap' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +const publicKeyUserIdMap = new Map() + async function main() { // prepare in memory blockchains const context = await bootstrap() + const startTime = Date.now() + await getNextUsers(context, 0, 110) + const endTime = Date.now() + console.log(`getNextUsers took ${endTime - startTime} ms`) + // synchronize to blockchain const BATCH_SIZE = 10 const users = new OrderedContainer( - getNextUsers, + (context: Context, offset: number, count: number) => loadUsers(context.db, offset, count), (user: CreatedUserDb) => user.createdAt, (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) ) + const transactions = new OrderedContainer( + getNextTransactions, + (transaction: TransactionDb) => transaction.balanceDate, + (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) + ) - await synchronizeToBlockchain(context, [users], BATCH_SIZE) + // const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) + // const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) + + await synchronizeToBlockchain(context, [users, transactions], BATCH_SIZE) // log blockchains for(const community of context.communities.values()) { @@ -60,7 +75,16 @@ async function synchronizeToBlockchain( // console.log(`smallest date: ${available[0].getDate()}`) if(rounds >= 0) { - await available[0].pushToBlockchain(context) + try { + await available[0].pushToBlockchain(context) + } catch (e) { + console.error(e) + logBlogchain(context.logger, context.communities.values().next().value!.blockchain) + // for(const [key, value] of publicKeyUserIdMap.entries()) { + // console.log(`${key}: ${value}`) + // } + throw e + } } else { const user = (available[0] as any as OrderedContainer).shift() console.log(JSON.stringify(user, null, 2)) @@ -91,28 +115,16 @@ async function synchronizeToBlockchain( } } -async function fillBlockchains(context: Context): Promise { - const BATCH_SIZE = 10 - - const users = new OrderedContainer( - getNextUsers, - (user: CreatedUserDb) => user.createdAt, - (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) - ) - /*const transactions = new OrderedContainer(getNextTransactions, (transaction) => transaction.balanceDate) - const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) - const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) -*/ - await synchronizeToBlockchain(context, [users], BATCH_SIZE) -} - // ---------------- load from db graiddo backend transactions format ----------------------------------------------- + /// load next max ${count} users and calculate key pair for calculating signatures later async function getNextUsers(context: Context, offset: number, count: number): Promise { const users = await loadUsers(context.db, offset, count) for (const user of users) { const communityContext = context.getCommunityContextByUuid(user.communityUuid) - generateKeyPairUserAccount(user, context.cache, communityContext.topicId) + const { userKeyPair, accountKeyPair } = await generateKeyPairUserAccount(user, context.cache, communityContext.topicId) + publicKeyUserIdMap.set(userKeyPair.convertToHex(), user.gradidoId) + publicKeyUserIdMap.set(accountKeyPair.convertToHex(), user.gradidoId) } return users } @@ -140,16 +152,18 @@ async function pushRegisterAddressTransaction(context: Context, user: CreatedUse return await addRegisterAddressTransaction(communityContext.blockchain, transaction) } -/* + async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) // CreationTransactionRole will check that community topic id belongs to home community context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) - await addTransaction(senderCommunityContext.blockchain, transaction) + await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) } -*/ + +// ---------------- utils ---------------------------------------------------------------------- + function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { const f = new Filter() f.pagination.size = 0 diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts index 67337a656..d5d471210 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts @@ -1,7 +1,7 @@ import { CommunityDb, UserDb } from './database' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { KeyPairEd25519, MemoryBlock } from 'gradido-blockchain-js' +import { KeyPairEd25519, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { CONFIG } from '../../config' @@ -31,19 +31,23 @@ export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairC logger.info(`Community Key Pair added with key: ${communityKeyPairKey}`) } -export function generateKeyPairUserAccount(user: UserDb, cache: KeyPairCacheManager, communityTopicId: HieroId): void { +export async function generateKeyPairUserAccount( + user: UserDb, + cache: KeyPairCacheManager, + communityTopicId: HieroId +): Promise<{userKeyPair: MemoryBlockPtr, accountKeyPair: MemoryBlockPtr}> { const communityKeyPair = cache.findKeyPair(communityTopicId)! - const userKeyPair = new UserKeyPairRole(user.gradidoId, communityKeyPair).generateKeyPair() + const userKeyPairRole = new UserKeyPairRole(user.gradidoId, communityKeyPair) const userKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: communityTopicId, account: { userUuid: user.gradidoId, accountNr: 0 } - }).getKey() - cache.addKeyPair(userKeyPairKey, userKeyPair) + }).getKey() + const userKeyPair = await cache.getKeyPair(userKeyPairKey, () => Promise.resolve(userKeyPairRole.generateKeyPair())) - const accountKeyPair = new AccountKeyPairRole(1, userKeyPair).generateKeyPair() + const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) const accountKeyPairKey = new KeyPairIdentifierLogic({ communityTopicId: communityTopicId, account: { @@ -51,6 +55,10 @@ export function generateKeyPairUserAccount(user: UserDb, cache: KeyPairCacheMana accountNr: 1 } }).getKey() - cache.addKeyPair(accountKeyPairKey, accountKeyPair) + const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => Promise.resolve(accountKeyPairRole.generateKeyPair())) logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) + return { + userKeyPair: userKeyPair.getPublicKey()!, + accountKeyPair: accountKeyPair.getPublicKey()! + } } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d2d88cc9c..c8e23557b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -71,6 +71,8 @@ services: context: ./inspector dockerfile: Dockerfile target: production + profiles: + - dlt networks: - internal-net ports: diff --git a/nginx/gradido.conf b/nginx/gradido.conf index bbfd8db51..edaf12d22 100644 --- a/nginx/gradido.conf +++ b/nginx/gradido.conf @@ -82,4 +82,30 @@ server { proxy_redirect off; } + # Inspector + location /inspector { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://inspector:3100; + proxy_redirect off; + } + + # Gradido Node + location /dlt { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + + proxy_pass http://dlt-connector:8340/api; + proxy_redirect off; + } + } From bf39551416c4f4c0b7f9f90f4f8f5a321b195e39 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Sat, 1 Nov 2025 08:21:31 +0100 Subject: [PATCH 03/33] correct path, add migration into dlt-connector/package.json --- dlt-connector/log4js-config.json | 6 +- dlt-connector/package.json | 1 + dlt-connector/src/bootstrap/init.ts | 2 +- .../Context.ts | 7 +- .../OrderedContainer.ts | 0 .../blockchain.ts | 6 +- .../bootstrap.ts | 0 .../convert.ts | 1 + .../database.ts | 25 +++++-- .../index.ts | 67 ++++++++++++++----- .../keyPair.ts | 2 +- 11 files changed, 81 insertions(+), 36 deletions(-) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/Context.ts (87%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/OrderedContainer.ts (100%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/blockchain.ts (93%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/bootstrap.ts (100%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/convert.ts (99%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/database.ts (86%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/index.ts (76%) rename dlt-connector/src/migrations/{db-v2.7.0_to_blockchain-v3.6 => db-v2.7.0_to_blockchain-v3.5}/keyPair.ts (96%) diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index 66127eb80..8d865fa26 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -8,7 +8,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c - %m" }, "compress": true, "keepFileExt" : true, @@ -21,7 +21,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] - %m" }, "compress": true, "keepFileExt" : true, @@ -53,7 +53,7 @@ "type": "stdout", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c - %m" } } }, diff --git a/dlt-connector/package.json b/dlt-connector/package.json index e1bef07c9..78c3c1b96 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -10,6 +10,7 @@ "start": "bun run src/index.ts", "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --minify", "dev": "bun run --watch src/index.ts", + "migrate": "cross-env MIMALLOC_SHOW_STATS=1 bun src/migrations/db-v2.7.0_to_blockchain-v3.5", "test": "bun test", "test:debug": "bun test --inspect-brk", "typecheck": "tsc --noEmit", diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index 13b77783c..e0289db57 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -39,7 +39,7 @@ export async function checkHomeCommunity( // wait for backend server await isPortOpenRetry(backend.url) // ask backend for home community - let homeCommunity = await backend.getHomeCommunityDraft() + let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one if (!homeCommunity.hieroTopicId) { const topicId = await hiero.createTopic(homeCommunity.name) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts similarity index 87% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index b60a08b08..dde47b7c4 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,13 +1,13 @@ import { SQL } from 'bun' import { InMemoryBlockchain } from 'gradido-blockchain-js' -import { Logger } from 'log4js' +import { getLogger, Logger } from 'log4js' import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { loadConfig } from '../../bootstrap/init' import { CONFIG } from '../../config' - +import { LOG4JS_BASE_CATEGORY } from '../../config/const' export type CommunityContext = { communityId: string @@ -29,8 +29,9 @@ export class Context { } static create(): Context { + loadConfig() return new Context( - loadConfig(), + getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`), new SQL({ adapter: 'mysql', hostname: CONFIG.MYSQL_HOST, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts similarity index 100% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/OrderedContainer.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts similarity index 93% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 4154b0ba9..9d1e43409 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -56,7 +56,7 @@ export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain export async function addRegisterAddressTransaction(blockchain: InMemoryBlockchain, transaction: Transaction): Promise { const registerAddressRole = new RegisterAddressTransactionRole(transaction) if(addToBlockchain(await registerAddressRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transaction.createdAt))) { - logger.info(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) } @@ -71,7 +71,7 @@ export async function addTransaction( if (transaction.type === InputTransactionType.GRADIDO_CREATION) { const creationTransactionRole = new CreationTransactionRole(transaction) if(addToBlockchain(await creationTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.info(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) } @@ -79,7 +79,7 @@ export async function addTransaction( const transferTransactionRole = new TransferTransactionRole(transaction) // will crash with cross group transaction if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.info(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts similarity index 100% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/bootstrap.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts similarity index 99% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts index e8052df88..a455aa1e1 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/convert.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts @@ -50,6 +50,7 @@ export function transactionDbToTransaction( && transactionDb.typeId !== TransactionTypeId.RECEIVE) { throw new Error('not implemented') } + const user = { communityTopicId: communityTopicId, account: { userUuid: transactionDb.user.gradidoId, accountNr: 0 }, diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts similarity index 86% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index ce990a76f..bdd377821 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -3,6 +3,8 @@ import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAm import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' import { GradidoUnit } from 'gradido-blockchain-js' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { getLogger } from 'log4js' export const createdUserDbSchema = v.object({ gradidoId: uuidv4Schema, @@ -59,6 +61,8 @@ export type CreatedUserDb = v.InferOutput export type TransactionLinkDb = v.InferOutput export type CommunityDb = v.InferOutput +const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) + // queries export async function loadCommunities(db: SQL): Promise { const result = await db` @@ -89,10 +93,6 @@ export async function loadUsers(db: SQL, offset: number, count: number): Promise ORDER by created_at ASC LIMIT ${offset}, ${count} ` - const totalCount = await db` - SELECT COUNT(*) as count FROM users - ` - console.log(`Loaded ${result.length} users, total ${totalCount[0].count} with offset ${offset} and count ${count}`) return result.map((row: any) => { return v.parse(createdUserDbSchema, row) }) @@ -100,9 +100,9 @@ export async function loadUsers(db: SQL, offset: number, count: number): Promise export async function loadTransactions(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, - u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, - lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, + SELECT t.id, t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, + u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, u.created_at as user_created_at, + lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, lu.created_at as linked_user_created_at, tl.code as transaction_link_code FROM transactions as t LEFT JOIN users u ON t.user_id = u.id @@ -113,6 +113,17 @@ export async function loadTransactions(db: SQL, offset: number, count: number): ` return result.map((row: any) => { // console.log(row) + // check for consistent data beforehand + const userCreatedAt = new Date(row.user_created_at) + const linkedUserCreatedAd = new Date(row.linked_user_created_at) + const balanceDate = new Date(row.balance_date) + if (userCreatedAt.getTime() > balanceDate.getTime() || + linkedUserCreatedAd.getTime() > balanceDate.getTime() + ){ + logger.error(`table row: `, row) + throw new Error('at least one user was created after transaction balance date, logic error!') + } + let amount = GradidoUnit.fromString(row.amount) if (row.type_id === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts similarity index 76% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 2aaa02366..113f37aa1 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -4,7 +4,8 @@ import { SearchDirection_ASC, HieroTransactionId, Timestamp, - InteractionSerialize + InteractionSerialize, + Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' @@ -16,23 +17,20 @@ import { Orderable, OrderedContainer } from './OrderedContainer' import { Context } from './Context' import { bootstrap } from './bootstrap' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +import { heapStats } from 'bun:jsc' const publicKeyUserIdMap = new Map() async function main() { + const timeUsed = new Profiler() // prepare in memory blockchains const context = await bootstrap() - const startTime = Date.now() - await getNextUsers(context, 0, 110) - const endTime = Date.now() - console.log(`getNextUsers took ${endTime - startTime} ms`) - // synchronize to blockchain - const BATCH_SIZE = 10 + const BATCH_SIZE = 100 const users = new OrderedContainer( - (context: Context, offset: number, count: number) => loadUsers(context.db, offset, count), + (context: Context, offset: number, count: number) => getNextUsers(context, offset, count), (user: CreatedUserDb) => user.createdAt, (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) ) @@ -46,22 +44,40 @@ async function main() { // const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) await synchronizeToBlockchain(context, [users, transactions], BATCH_SIZE) - - // log blockchains - for(const community of context.communities.values()) { - context.logger.info(`Community '${community.communityId}', blockchain`) - logBlogchain(context.logger, community.blockchain) - } + context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) + timeUsed.reset() + context.communities.forEach((communityContext) => { + const f = new Filter() + // hotfix for bug in gradido_blockchain for Filter::ALL_TRANSACTIONS + f.pagination.size = 0 + const transactions = communityContext.blockchain.findAll(f) + context.logger.info(`Community '${communityContext.communityId}', transactions: ${transactions.size()}`) + // logBlogchain(context.logger, communityContext.blockchain) + }) + context.logger.info(`${timeUsed.string()} for logging blockchains`) context.db.close() + const runtimeStats = heapStats() + /* + heapSize: 24254530, + heapCapacity: 32191922, + extraMemorySize: 7003858 + */ + context.logger.info( + `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` + ) return Promise.resolve() } +function bytesToMbyte(bytes: number): string { + return (bytes / 1024 / 1024).toFixed(4) +} + async function synchronizeToBlockchain( context: Context, containers: Orderable[], batchSize: number ): Promise { - let rounds = 20 + let rounds = 200 while (rounds-- > 0) { await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) // console.log(`filled containers, rounds left: ${rounds}`) @@ -119,6 +135,7 @@ async function synchronizeToBlockchain( /// load next max ${count} users and calculate key pair for calculating signatures later async function getNextUsers(context: Context, offset: number, count: number): Promise { + const timeUsed = new Profiler() const users = await loadUsers(context.db, offset, count) for (const user of users) { const communityContext = context.getCommunityContextByUuid(user.communityUuid) @@ -126,22 +143,36 @@ async function getNextUsers(context: Context, offset: number, count: number): Pr publicKeyUserIdMap.set(userKeyPair.convertToHex(), user.gradidoId) publicKeyUserIdMap.set(accountKeyPair.convertToHex(), user.gradidoId) } + if(users.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${users.length} users from db and calculate ed25519 KeyPairs for them`) + } return users } // load next max ${count} transactions (contain also redeem transaction link transactions) async function getNextTransactions(context: Context, offset: number, count: number): Promise { - return loadTransactions(context.db, offset, count) + const timeUsed = new Profiler() + const transactions = await loadTransactions(context.db, offset, count) + if(transactions.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) + } + return transactions } // load next max ${count} transaction links (freshly created links, in blockchain format this is a separate transaction) async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { - return loadTransactionLinks(context.db, offset, count) + const timeUsed = new Profiler() + const transactionLinks = await loadTransactionLinks(context.db, offset, count) + context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + return transactionLinks } // load next max ${count} deleted transaction links (in blockchain format this is a separate transaction) async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { - return loadDeletedTransactionLinks(context.db, offset, count) + const timeUsed = new Profiler() + const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) + context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + return deletedTransactionLinks } // ---------------- put into in memory blockchain ----------------------------------------------- diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts similarity index 96% rename from dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts rename to dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts index d5d471210..6d30760c5 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.6/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts @@ -56,7 +56,7 @@ export async function generateKeyPairUserAccount( } }).getKey() const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => Promise.resolve(accountKeyPairRole.generateKeyPair())) - logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) + //logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) return { userKeyPair: userKeyPair.getPublicKey()!, accountKeyPair: accountKeyPair.getPublicKey()! From eb8c806b5dd44e6207a38177954f7a49c288fa67 Mon Sep 17 00:00:00 2001 From: Einhornimmond Date: Mon, 3 Nov 2025 14:25:03 +0100 Subject: [PATCH 04/33] restructure, optimize logging --- dlt-connector/bun.lock | 3 + dlt-connector/package.json | 3 +- .../OrderedContainer.ts | 5 + .../blockchain.ts | 39 +++---- .../db-v2.7.0_to_blockchain-v3.5/convert.ts | 27 ++++- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 14 ++- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 109 ++++++++---------- 7 files changed, 108 insertions(+), 92 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 21caa0f07..1f27138de 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -25,6 +25,7 @@ "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", + "yoctocolors-cjs": "^2.1.3", }, }, }, @@ -999,6 +1000,8 @@ "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + "yoctocolors-cjs": ["yoctocolors-cjs@2.1.3", "", {}, "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw=="], + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@babel/core/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 78c3c1b96..fd33612a5 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -38,7 +38,8 @@ "log4js": "^6.9.1", "typescript": "^5.8.3", "uuid": "^8.3.2", - "valibot": "1.1.0" + "valibot": "1.1.0", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts index 90dcc0e74..47595b3d0 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts @@ -7,6 +7,7 @@ export interface Orderable { ensureFilled(context: ContextType, batchSize: number): Promise pushToBlockchain(context: ContextType): Promise isEmpty(): boolean + get length(): number } export class OrderedContainer implements Orderable { @@ -48,6 +49,10 @@ export class OrderedContainer implements Orderable return item } + get length(): number { + return this.items.length + } + getDate(): Date { return this.getDateHandler(this.peek()) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 9d1e43409..12ba38017 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -1,38 +1,21 @@ -import { sql, SQL } from 'bun' import { InMemoryBlockchain, - InMemoryBlockchainProvider, GradidoTransactionBuilder, - KeyPairEd25519, - MemoryBlock, Timestamp, HieroTransactionId, HieroAccountId, InteractionSerialize, - loadCryptoKeys, - Filter, - SearchDirection_ASC } from 'gradido-blockchain-js' -import { Logger, getLogger } from 'log4js' -import { CONFIG } from '../../config' -import { amountSchema, HieroId, hieroIdSchema, memoSchema, uuidv4Schema, Uuidv4, gradidoAmountSchema } from '../../schemas/typeGuard.schema' -import { dateSchema } from '../../schemas/typeConverter.schema' -import * as v from 'valibot' +import { getLogger } from 'log4js' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' -import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' -import { InputTransactionType } from '../../data/InputTransactionType.enum' -import { AccountType } from '../../data/AccountType.enum' import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' -import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' -import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' -import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' -import { loadConfig } from '../../bootstrap/init' import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' -import { CommunityDb, loadCommunities, TransactionDb, TransactionTypeId, UserDb } from './database' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { Community, Transaction } from '../../schemas/transaction.schema' -import { communityDbToCommunity, userDbToTransaction } from './convert' import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' +import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' +import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' +import { InputTransactionType } from '../../data/InputTransactionType.enum' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) @@ -83,5 +66,19 @@ export async function addTransaction( } else { throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) } + } else if (transaction.type === InputTransactionType.GRADIDO_DEFERRED_TRANSFER) { + const transferTransactionRole = new DeferredTransferTransactionRole(transaction) + if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.debug(`Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + } + } else if (transaction.type === InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER) { + const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction) + if(addToBlockchain(await redeemTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + logger.debug(`Redeem Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + } else { + throw new Error(`Redeem Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + } } } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts index a455aa1e1..747e6c2ef 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/convert.ts @@ -1,8 +1,8 @@ import { InputTransactionType } from '../../data/InputTransactionType.enum' -import { CommunityDb, TransactionDb, TransactionTypeId, CreatedUserDb } from './database' +import { CommunityDb, TransactionDb, TransactionTypeId, CreatedUserDb, TransactionLinkDb } from './database' import { Community, communitySchema, transactionSchema, Transaction, TransactionInput } from '../../schemas/transaction.schema' import { AccountType } from '../../data/AccountType.enum' -import { gradidoAmountSchema, HieroId, memoSchema } from '../../schemas/typeGuard.schema' +import { gradidoAmountSchema, HieroId, memoSchema, timeoutDurationSchema } from '../../schemas/typeGuard.schema' import * as v from 'valibot' export function getInputTransactionTypeFromTypeId(typeId: TransactionTypeId): InputTransactionType { @@ -53,11 +53,11 @@ export function transactionDbToTransaction( const user = { communityTopicId: communityTopicId, - account: { userUuid: transactionDb.user.gradidoId, accountNr: 0 }, + account: { userUuid: transactionDb.user.gradidoId }, } const linkedUser = { communityTopicId: recipientCommunityTopicId, - account: { userUuid: transactionDb.linkedUser.gradidoId, accountNr: 0 }, + account: { userUuid: transactionDb.linkedUser.gradidoId }, } const transaction: TransactionInput = { user, @@ -89,3 +89,22 @@ export function transactionDbToTransaction( } return v.parse(transactionSchema, transaction) } + +export function transactionLinkDbToTransaction(transactionLinkDb: TransactionLinkDb, communityTopicId: HieroId): Transaction { + return v.parse(transactionSchema, { + user: { + communityTopicId: communityTopicId, + account: { userUuid: transactionLinkDb.user.gradidoId }, + }, + linkedUser: { + communityTopicId: communityTopicId, + seed: transactionLinkDb.code, + }, + type: InputTransactionType.GRADIDO_DEFERRED_TRANSFER, + amount: v.parse(gradidoAmountSchema, transactionLinkDb.amount), + memo: v.parse(memoSchema, transactionLinkDb.memo), + createdAt: transactionLinkDb.createdAt, + timeoutDuration: v.parse(timeoutDurationSchema, Math.round((transactionLinkDb.validUntil.getTime() - transactionLinkDb.createdAt.getTime()) / 1000)), + }) +} + diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index bdd377821..f63a7a002 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -1,5 +1,5 @@ import { SQL } from 'bun' -import { amountSchema, memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' +import { memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' import { GradidoUnit } from 'gradido-blockchain-js' @@ -38,7 +38,7 @@ export const transactionDbSchema = v.object({ }) export const transactionLinkDbSchema = v.object({ - userUuid: uuidv4Schema, + user: userDbSchema, code: identifierSeedSchema, amount: gradidoAmountSchema, memo: memoSchema, @@ -157,14 +157,20 @@ export async function loadTransactions(db: SQL, offset: number, count: number): export async function loadTransactionLinks(db: SQL, offset: number, count: number): Promise { const result = await db` - SELECT u.gradido_id as userUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil + SELECT u.gradido_id as userGradidoId, u.community_uuid as userCommunityUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil FROM transaction_links tl LEFT JOIN users u ON tl.userId = u.id ORDER by createdAt ASC LIMIT ${offset}, ${count} ` return result.map((row: any) => { - return v.parse(transactionLinkDbSchema, row) + return v.parse(transactionLinkDbSchema, { + ...row, + user: { + gradidoId: row.userGradidoId, + communityUuid: row.userCommunityUuid + } + }) }) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 113f37aa1..b7edfb6ec 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -2,22 +2,19 @@ import { InMemoryBlockchain, Filter, SearchDirection_ASC, - HieroTransactionId, - Timestamp, - InteractionSerialize, Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' -import { addRegisterAddressTransaction, addTransaction, defaultHieroAccount } from './blockchain' +import { addRegisterAddressTransaction, addTransaction } from './blockchain' import { generateKeyPairUserAccount } from './keyPair' -import { transactionDbToTransaction, userDbToTransaction } from './convert' +import { transactionDbToTransaction, transactionLinkDbToTransaction, userDbToTransaction } from './convert' import { Orderable, OrderedContainer } from './OrderedContainer' import { Context } from './Context' import { bootstrap } from './bootstrap' -import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' import { heapStats } from 'bun:jsc' +import { onShutdown } from '../../../../shared/src/helper/onShutdown' const publicKeyUserIdMap = new Map() @@ -25,7 +22,13 @@ async function main() { const timeUsed = new Profiler() // prepare in memory blockchains const context = await bootstrap() - + onShutdown(async (reason, error) => { + context.logger.info(`shutdown reason: ${reason}`) + if(error) { + context.logger.error(error) + } + context.db.close() + }) // synchronize to blockchain const BATCH_SIZE = 100 @@ -40,10 +43,19 @@ async function main() { (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) ) - // const transactionLinks = new OrderedContainer(getNextTransactionLinks, (transactionLink) => transactionLink.createdAt) - // const deletedTransactionLinks = new OrderedContainer(getNextDeletedTransactionLinks, (transactionLink) => transactionLink.balanceDate) + const transactionLinks = new OrderedContainer( + getNextTransactionLinks, + (transactionLink: TransactionLinkDb) => transactionLink.createdAt, + (context: Context, transactionLink: TransactionLinkDb) => pushTransactionLink(context, transactionLink) + ) - await synchronizeToBlockchain(context, [users, transactions], BATCH_SIZE) + const deletedTransactionLinks = new OrderedContainer( + getNextDeletedTransactionLinks, + (transaction: TransactionDb) => transaction.balanceDate, + (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) + ) + + await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) timeUsed.reset() context.communities.forEach((communityContext) => { @@ -55,17 +67,12 @@ async function main() { // logBlogchain(context.logger, communityContext.blockchain) }) context.logger.info(`${timeUsed.string()} for logging blockchains`) - context.db.close() const runtimeStats = heapStats() - /* - heapSize: 24254530, - heapCapacity: 32191922, - extraMemorySize: 7003858 - */ context.logger.info( `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` ) - return Promise.resolve() + // needed because of shutdown handler (TODO: fix shutdown handler) + process.exit(0) } function bytesToMbyte(bytes: number): string { @@ -77,57 +84,26 @@ async function synchronizeToBlockchain( containers: Orderable[], batchSize: number ): Promise { - let rounds = 200 - while (rounds-- > 0) { + while (true) { + const timeUsed = new Profiler() await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) - // console.log(`filled containers, rounds left: ${rounds}`) + const itemCount = containers.reduce((acc, c) => acc + c.length, 0) + context.logger.info(`${timeUsed.string()} for ensuring filled containers, ${itemCount} items`) + // remove empty containers const available = containers.filter(c => !c.isEmpty()) if (available.length === 0) break - // console.log(`available containers: ${available.length}`) // find container with smallest date available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) - // console.log(`smallest date: ${available[0].getDate()}`) - if(rounds >= 0) { - try { - await available[0].pushToBlockchain(context) - } catch (e) { - console.error(e) - logBlogchain(context.logger, context.communities.values().next().value!.blockchain) - // for(const [key, value] of publicKeyUserIdMap.entries()) { - // console.log(`${key}: ${value}`) - // } - throw e - } - } else { - const user = (available[0] as any as OrderedContainer).shift() - console.log(JSON.stringify(user, null, 2)) - console.log(`context: ${JSON.stringify(context, null, 2)}`) - const communityContext = context.getCommunityContextByUuid(user.communityUuid) - const transactionBase = userDbToTransaction(user, communityContext.topicId) - console.log(JSON.stringify(transactionBase, null, 2)) - const registerAddressRole = new RegisterAddressTransactionRole(transactionBase) - const builder = await registerAddressRole.getGradidoTransactionBuilder() - const transaction = builder.build() - console.log(transaction.toJson(true)) - const createdAtTimestamp = new Timestamp(user.createdAt) - console.log(`createdAtTimestamp: ${createdAtTimestamp.toJson()}`) - const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) - const interactionSerialize = new InteractionSerialize(transactionId) - const serializedTransactionId = interactionSerialize.run() - if (serializedTransactionId) { - console.log(`serialized transaction id: ${serializedTransactionId.convertToHex()}`) - } - console.log(communityContext.blockchain) - try { - communityContext.blockchain.createAndAddConfirmedTransaction(transaction, serializedTransactionId, createdAtTimestamp) - } catch(e) { - console.log(e) - } + try { + await available[0].pushToBlockchain(context) + } catch (e) { + console.error(e) + logBlogchain(context.logger, context.communities.values().next().value!.blockchain) + throw e } - // console.log(`pushed to blockchain, rounds left: ${rounds}`) } } @@ -163,7 +139,9 @@ async function getNextTransactions(context: Context, offset: number, count: numb async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { const timeUsed = new Profiler() const transactionLinks = await loadTransactionLinks(context.db, offset, count) - context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + if(transactionLinks.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + } return transactionLinks } @@ -171,7 +149,9 @@ async function getNextTransactionLinks(context: Context, offset: number, count: async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { const timeUsed = new Profiler() const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) - context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + if(deletedTransactionLinks.length !== 0) { + context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + } return deletedTransactionLinks } @@ -183,7 +163,6 @@ async function pushRegisterAddressTransaction(context: Context, user: CreatedUse return await addRegisterAddressTransaction(communityContext.blockchain, transaction) } - async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) @@ -193,6 +172,12 @@ async function pushTransaction(context: Context, transactionDb: TransactionDb): await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) } +async function pushTransactionLink(context: Context, transactionLinkDb: TransactionLinkDb): Promise { + const communityContext = context.getCommunityContextByUuid(transactionLinkDb.user.communityUuid) + const transaction = transactionLinkDbToTransaction(transactionLinkDb, communityContext.topicId) + await addTransaction(communityContext.blockchain, communityContext.blockchain, transaction) +} + // ---------------- utils ---------------------------------------------------------------------- function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { From f027bf5b7a965983ddd331457ac36f4de1d122a5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 5 Nov 2025 11:43:51 +0100 Subject: [PATCH 05/33] fix some issues --- dlt-connector/bun.lock | 4 +- dlt-connector/package.json | 2 +- .../RedeemDeferredTransferTransaction.role.ts | 20 +++---- .../sendToHiero/SendToHiero.context.ts | 18 ++++++- .../blockchain.ts | 35 +++++++++--- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 54 +++++++++++++------ 6 files changed, 92 insertions(+), 41 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 1f27138de..7ad790bf3 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -160,11 +160,11 @@ "@grpc/proto-loader": ["@grpc/proto-loader@0.7.15", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.2.5", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ=="], - "@hashgraph/cryptography": ["@hashgraph/cryptography@1.13.0", "", { "dependencies": { "@noble/curves": "1.8.1", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "asn1js": "3.0.6", "bignumber.js": "9.1.1", "bn.js": "5.2.1", "buffer": "6.0.3", "crypto-js": "4.2.0", "debug": "4.4.1", "forge-light": "1.1.4", "js-base64": "3.7.7", "react-native-get-random-values": "1.11.0", "spark-md5": "3.0.2", "strip-ansi": "7.1.2", "tweetnacl": "1.0.3", "utf8": "3.0.0" } }, "sha512-bttkU9cnbA2NgmE41V4IDYZ5IYMY9HtVTnlvg3fdj8m83+7T4KgTBPPSkqwFCgSeW2x/6MV2GDzvaj4Lx4IYfw=="], + "@hashgraph/cryptography": ["@hashgraph/cryptography@1.14.0", "", { "dependencies": { "@noble/curves": "1.8.1", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "asn1js": "3.0.6", "bignumber.js": "9.1.1", "bn.js": "5.2.1", "buffer": "6.0.3", "crypto-js": "4.2.0", "debug": "4.4.1", "forge-light": "1.1.4", "js-base64": "3.7.7", "react-native-get-random-values": "1.11.0", "spark-md5": "3.0.2", "strip-ansi": "7.1.2", "tweetnacl": "1.0.3", "utf8": "3.0.0" } }, "sha512-vYeRpkdYHgO0y09BJJms4DQvjkSQuoOWnf1tCaOHfs4w2u1RttQUMgQbaZCM07+6YL3Pq8SPHbcEch5tbSdBNg=="], "@hashgraph/proto": ["@hashgraph/proto@2.24.0", "", { "dependencies": { "long": "5.3.1" }, "peerDependencies": { "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "debug": "4.4.1", "protobufjs": "7.5.4", "strip-ansi": "7.1.2" } }, "sha512-S1eE0CoQ17s40JuzKaKpMze8h0JoN13za5arCp3xaqbWVT4UEFq/O/zJud9cpZ31uYwpPe8gH65TPZ3pKd9ZWQ=="], - "@hashgraph/sdk": ["@hashgraph/sdk@2.75.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/rlp": "5.8.0", "@grpc/grpc-js": "1.12.6", "@hashgraph/cryptography": "1.13.0", "@hashgraph/proto": "2.24.0", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "bignumber.js": "9.1.1", "bn.js": "5.1.1", "crypto-js": "4.2.0", "debug": "4.4.1", "js-base64": "3.7.4", "long": "5.3.1", "pino": "9.6.0", "pino-pretty": "13.0.0", "protobufjs": "7.5.4", "rfc4648": "1.5.3", "strip-ansi": "7.1.2", "utf8": "3.0.0" } }, "sha512-Nkv57So2RbNlKxog1nsyqHgorgrStr3yzx0ZWse4R6yg1TztafiqA2+9m3YlmH3eNMr7vmghgtGqPkRflfVhZg=="], + "@hashgraph/sdk": ["@hashgraph/sdk@2.76.0", "", { "dependencies": { "@ethersproject/abi": "5.8.0", "@ethersproject/bignumber": "5.8.0", "@ethersproject/bytes": "5.8.0", "@ethersproject/rlp": "5.8.0", "@grpc/grpc-js": "1.12.6", "@hashgraph/cryptography": "1.14.0", "@hashgraph/proto": "2.24.0", "ansi-regex": "6.2.2", "ansi-styles": "6.2.3", "bignumber.js": "9.1.1", "bn.js": "5.1.1", "crypto-js": "4.2.0", "debug": "4.4.1", "js-base64": "3.7.4", "long": "5.3.1", "pino": "9.6.0", "pino-pretty": "13.0.0", "protobufjs": "7.5.4", "rfc4648": "1.5.3", "strip-ansi": "7.1.2", "utf8": "3.0.0" } }, "sha512-FrLDeiHCJak+ZBcRv5cFoX23LPHvn1xWvVIST+oheI0NGfMxOXrGLWICaP5FMWdOnLfkM1OklCQ93J+QBFP7+Q=="], "@isaacs/ttlcache": ["@isaacs/ttlcache@1.4.1", "", {}, "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index fd33612a5..b314584c6 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -10,7 +10,7 @@ "start": "bun run src/index.ts", "build": "bun build src/index.ts --outdir=build --target=bun --external=gradido-blockchain-js --minify", "dev": "bun run --watch src/index.ts", - "migrate": "cross-env MIMALLOC_SHOW_STATS=1 bun src/migrations/db-v2.7.0_to_blockchain-v3.5", + "migrate": "bun src/migrations/db-v2.7.0_to_blockchain-v3.5", "test": "bun test", "test:debug": "bun test --inspect-brk", "typecheck": "tsc --noEmit", diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 626712404..2f51f8f21 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -1,6 +1,5 @@ -import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { ConfirmedTransaction, GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' import * as v from 'valibot' -import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { RedeemDeferredTransferTransaction, @@ -15,12 +14,14 @@ import { AbstractTransactionRole } from './AbstractTransaction.role' export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRole { private linkedUser: UserAccount private readonly redeemDeferredTransferTransaction: RedeemDeferredTransferTransaction - constructor(transaction: Transaction) { + private readonly parentDeferredTransaction: ConfirmedTransaction + constructor(transaction: Transaction, parentDeferredTransaction: ConfirmedTransaction) { super() this.redeemDeferredTransferTransaction = v.parse( redeemDeferredTransferTransactionSchema, transaction, ) + this.parentDeferredTransaction = parentDeferredTransaction this.linkedUser = this.redeemDeferredTransferTransaction.linkedUser } @@ -41,16 +42,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo if (!senderPublicKey) { throw new Error("redeem deferred transfer: couldn't calculate sender public key") } - // load deferred transfer transaction from gradido node - const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount( - { maxResultCount: 2, topic: this.getSenderCommunityTopicId() }, - senderPublicKey.convertToHex(), - ) - if (!transactions || transactions.length !== 1) { - throw new Error("redeem deferred transfer: couldn't find deferred transfer on Gradido Node") - } - const deferredTransfer = transactions[0] - const deferredTransferBody = deferredTransfer.getGradidoTransaction()?.getTransactionBody() + const deferredTransferBody = this.parentDeferredTransaction.getGradidoTransaction()?.getTransactionBody() if (!deferredTransferBody) { throw new Error( "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", @@ -61,7 +53,7 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo builder .setCreatedAt(this.redeemDeferredTransferTransaction.createdAt) .setRedeemDeferredTransfer( - deferredTransfer.getId(), + this.parentDeferredTransaction.getId(), new GradidoTransfer( new TransferAmount( senderKeyPair.getPublicKey(), diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 5b5f1f629..5ef946ec9 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -6,6 +6,7 @@ import { ValidateType_SINGLE, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import * as v from 'valibot' import { ensureCommunitiesAvailable } from '../../client/GradidoNode/communities' import { HieroClient } from '../../client/hiero/HieroClient' @@ -21,6 +22,7 @@ import { HieroId, HieroTransactionIdString, hieroTransactionIdStringSchema, + identifierSeedSchema, } from '../../schemas/typeGuard.schema' import { isTopicStillOpen } from '../../utils/hiero' import { AbstractTransactionRole } from './AbstractTransaction.role' @@ -30,6 +32,7 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' +import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) @@ -144,7 +147,20 @@ async function chooseCorrectRole( case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: return new DeferredTransferTransactionRole(transaction) case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: - return new RedeemDeferredTransferTransactionRole(transaction) + // load deferred transfer transaction from gradido node + const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const seedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() + if (!seedPublicKey) { + throw new Error("redeem deferred transfer: couldn't generate seed public key") + } + const transactions = await GradidoNodeClient.getInstance().getTransactionsForAccount( + { maxResultCount: 2, topic: transaction.user.communityTopicId }, + seedPublicKey.convertToHex(), + ) + if (!transactions || transactions.length !== 1) { + throw new Error("redeem deferred transfer: couldn't find exactly one deferred transfer on Gradido Node") + } + return new RedeemDeferredTransferTransactionRole(transaction, transactions[0]) default: throw new Error('not supported transaction type: ' + transaction.type) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 12ba38017..2d135b184 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -4,7 +4,8 @@ import { Timestamp, HieroTransactionId, HieroAccountId, - InteractionSerialize, + InteractionSerialize, + Filter, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' @@ -16,6 +17,9 @@ import { TransferTransactionRole } from '../../interactions/sendToHiero/Transfer import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' import { InputTransactionType } from '../../data/InputTransactionType.enum' +import { LinkedTransactionKeyPairRole } from '../../interactions/resolveKeyPair/LinkedTransactionKeyPair.role' +import { identifierSeedSchema } from '../../schemas/typeGuard.schema' +import * as v from 'valibot' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) @@ -24,7 +28,13 @@ function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemor const transaction = builder.build() const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) - return blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) + try { + const result = blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) + return result + } catch (error) { + logger.error(`Transaction ${transaction.toJson(true)} not added: ${error}`) + return false + } } export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain, community: Community): Promise { @@ -57,7 +67,7 @@ export async function addTransaction( logger.debug(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) } else { throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) - } + } } else if (transaction.type === InputTransactionType.GRADIDO_TRANSFER) { const transferTransactionRole = new TransferTransactionRole(transaction) // will crash with cross group transaction @@ -71,14 +81,27 @@ export async function addTransaction( if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { logger.debug(`Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) } else { + throw new Error(`Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) } } else if (transaction.type === InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER) { - const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction) + const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const f = new Filter() + f.involvedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() + const deferredTransaction = senderBlockchain.findOne(f) + if (!deferredTransaction) { + throw new Error("redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node") + } + const confirmedDeferredTransaction = deferredTransaction.getConfirmedTransaction() + if (!confirmedDeferredTransaction) { + throw new Error("redeem deferred transfer: invalid TransactionEntry") + } + const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction, confirmedDeferredTransaction) + const involvedUser = transaction.user.account ? transaction.user.account.userUuid : transaction.linkedUser?.account?.userUuid if(addToBlockchain(await redeemTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.debug(`Redeem Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + logger.debug(`Redeem Deferred Transfer Transaction added for user ${involvedUser}`) } else { - throw new Error(`Redeem Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error(`Redeem Deferred Transfer Transaction not added for user ${involvedUser}`) } } } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index b7edfb6ec..8d66db750 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -15,6 +15,7 @@ import { Context } from './Context' import { bootstrap } from './bootstrap' import { heapStats } from 'bun:jsc' import { onShutdown } from '../../../../shared/src/helper/onShutdown' +import { sleep } from 'bun' const publicKeyUserIdMap = new Map() @@ -29,6 +30,7 @@ async function main() { } context.db.close() }) + // synchronize to blockchain const BATCH_SIZE = 100 @@ -54,11 +56,15 @@ async function main() { (transaction: TransactionDb) => transaction.balanceDate, (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) ) - - await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) + try { + await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) + } catch (e) { + console.error(e) + throw e + } context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) - timeUsed.reset() - context.communities.forEach((communityContext) => { + // timeUsed.reset() + /*context.communities.forEach((communityContext) => { const f = new Filter() // hotfix for bug in gradido_blockchain for Filter::ALL_TRANSACTIONS f.pagination.size = 0 @@ -67,6 +73,7 @@ async function main() { // logBlogchain(context.logger, communityContext.blockchain) }) context.logger.info(`${timeUsed.string()} for logging blockchains`) + */ const runtimeStats = heapStats() context.logger.info( `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` @@ -84,24 +91,33 @@ async function synchronizeToBlockchain( containers: Orderable[], batchSize: number ): Promise { - while (true) { - const timeUsed = new Profiler() - await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) - const itemCount = containers.reduce((acc, c) => acc + c.length, 0) - context.logger.info(`${timeUsed.string()} for ensuring filled containers, ${itemCount} items`) + const timeUsed = new Profiler() + while (true) { + timeUsed.reset() + const results = await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) + const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) + // log only, if at least one new item was loaded + if (loadedItemsCount && context.logger.isInfoEnabled()) { + context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) + } // remove empty containers const available = containers.filter(c => !c.isEmpty()) - if (available.length === 0) break + if (available.length === 0) { + break + } // find container with smallest date - available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + if (available.length > 0) { + available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + } try { await available[0].pushToBlockchain(context) + // await sleep(1) } catch (e) { - console.error(e) - logBlogchain(context.logger, context.communities.values().next().value!.blockchain) + context.logger.error(e) + // logBlogchain(context.logger, context.communities.values().next().value!.blockchain) throw e } } @@ -130,8 +146,8 @@ async function getNextTransactions(context: Context, offset: number, count: numb const timeUsed = new Profiler() const transactions = await loadTransactions(context.db, offset, count) if(transactions.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) - } + context.logger.debug(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) + } return transactions } @@ -140,7 +156,7 @@ async function getNextTransactionLinks(context: Context, offset: number, count: const timeUsed = new Profiler() const transactionLinks = await loadTransactionLinks(context.db, offset, count) if(transactionLinks.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) + context.logger.debug(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) } return transactionLinks } @@ -150,7 +166,7 @@ async function getNextDeletedTransactionLinks(context: Context, offset: number, const timeUsed = new Profiler() const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) if(deletedTransactionLinks.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) + context.logger.debug(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) } return deletedTransactionLinks } @@ -165,11 +181,15 @@ async function pushRegisterAddressTransaction(context: Context, user: CreatedUse async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) + // context.logger.info(`before adding non register address and non link transaction:`) + // logBlogchain(context.logger, senderCommunityContext.blockchain) const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) // CreationTransactionRole will check that community topic id belongs to home community context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) + // const firstTransaction = senderCommunityContext.blockchain.findOne(Filter.FIRST_TRANSACTION) + // console.log(`first transaction: ${firstTransaction?.getConfirmedTransaction()?.toJson(true)}`) } async function pushTransactionLink(context: Context, transactionLinkDb: TransactionLinkDb): Promise { From cbd98708254c75cad66ed20b72e3c3aa0f674dd5 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 5 Nov 2025 13:29:15 +0100 Subject: [PATCH 06/33] replace bun native mysql code with drizzle orm and mysql2 as driver --- dlt-connector/bun.lock | 34 +++- dlt-connector/package.json | 2 + .../db-v2.7.0_to_blockchain-v3.5/Context.ts | 26 +-- .../db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 158 ++++++++---------- .../drizzle.schema.ts | 53 ++++++ .../db-v2.7.0_to_blockchain-v3.5/index.ts | 14 +- 7 files changed, 186 insertions(+), 103 deletions(-) create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 7ad790bf3..f4dcee45b 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -17,11 +17,13 @@ "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", "dotenv": "^10.0.0", + "drizzle-orm": "^0.44.7", "elysia": "1.3.8", "graphql-request": "^7.2.0", "jose": "^5.2.2", "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", + "mysql2": "^3.15.3", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", @@ -322,6 +324,8 @@ "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], + "aws-ssl-profiles": ["aws-ssl-profiles@1.1.2", "", {}, "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="], + "axios": ["axios@0.24.0", "", { "dependencies": { "follow-redirects": "^1.14.4" } }, "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA=="], "babel-jest": ["babel-jest@29.7.0", "", { "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", "babel-preset-jest": "^29.6.3", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" } }, "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg=="], @@ -426,12 +430,16 @@ "delegates": ["delegates@1.0.0", "", {}, "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="], + "denque": ["denque@2.1.0", "", {}, "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="], + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], "destroy": ["destroy@1.2.0", "", {}, "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="], "dotenv": ["dotenv@10.0.0", "", {}, "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="], + "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], @@ -530,6 +538,8 @@ "gauge": ["gauge@4.0.4", "", { "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", "console-control-strings": "^1.1.0", "has-unicode": "^2.0.1", "signal-exit": "^3.0.7", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", "wide-align": "^1.1.5" } }, "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg=="], + "generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], @@ -578,6 +588,8 @@ "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + "iconv-lite": ["iconv-lite@0.7.0", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], @@ -598,6 +610,8 @@ "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + "is-property": ["is-property@1.0.2", "", {}, "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="], + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "^2.0.0" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], @@ -662,7 +676,9 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + + "lru.min": ["lru.min@1.1.2", "", {}, "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg=="], "makeerror": ["makeerror@1.0.12", "", { "dependencies": { "tmpl": "1.0.5" } }, "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="], @@ -730,6 +746,10 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + "mysql2": ["mysql2@3.15.3", "", { "dependencies": { "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.7.0", "long": "^5.2.1", "lru.min": "^1.0.0", "named-placeholders": "^1.1.3", "seq-queue": "^0.0.5", "sqlstring": "^2.3.2" } }, "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg=="], + + "named-placeholders": ["named-placeholders@1.1.3", "", { "dependencies": { "lru-cache": "^7.14.1" } }, "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w=="], + "nan": ["nan@2.23.0", "", {}, "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ=="], "negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="], @@ -856,6 +876,8 @@ "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + "scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="], "secure-json-parse": ["secure-json-parse@2.7.0", "", {}, "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="], @@ -864,6 +886,8 @@ "send": ["send@0.19.0", "", { "dependencies": { "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "~1.2.1", "statuses": "2.0.1" } }, "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw=="], + "seq-queue": ["seq-queue@0.0.5", "", {}, "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="], + "serialize-error": ["serialize-error@2.1.0", "", {}, "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="], "serve-static": ["serve-static@1.16.2", "", { "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.19.0" } }, "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw=="], @@ -894,6 +918,8 @@ "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], + "sqlstring": ["sqlstring@2.3.3", "", {}, "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg=="], + "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], "stackframe": ["stackframe@1.3.4", "", {}, "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw=="], @@ -1008,6 +1034,8 @@ "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], "@babel/traverse/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], @@ -1072,8 +1100,6 @@ "log4js/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], - "lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], - "metro/debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "metro/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="], @@ -1118,6 +1144,8 @@ "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "cliui/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], "cmake-js/fs-extra/jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index b314584c6..749258400 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -31,11 +31,13 @@ "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", "dotenv": "^10.0.0", + "drizzle-orm": "^0.44.7", "elysia": "1.3.8", "graphql-request": "^7.2.0", "jose": "^5.2.2", "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", + "mysql2": "^3.15.3", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index dde47b7c4..5708cccd3 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,4 +1,5 @@ -import { SQL } from 'bun' +import { drizzle, MySql2Database } from 'drizzle-orm/mysql2' +import mysql from 'mysql2/promise' import { InMemoryBlockchain } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' @@ -17,29 +18,30 @@ export type CommunityContext = { export class Context { public logger: Logger - public db: SQL + public db: MySql2Database public communities: Map public cache: KeyPairCacheManager - constructor(logger: Logger, db: SQL, cache: KeyPairCacheManager) { + constructor(logger: Logger, db: MySql2Database, cache: KeyPairCacheManager) { this.logger = logger this.db = db this.cache = cache this.communities = new Map() } - static create(): Context { + static async create(): Promise { loadConfig() + + const connection = await mysql.createConnection({ + host: CONFIG.MYSQL_HOST, + user: CONFIG.MYSQL_USER, + password: CONFIG.MYSQL_PASSWORD, + database: CONFIG.MYSQL_DATABASE, + port: CONFIG.MYSQL_PORT + }) return new Context( getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`), - new SQL({ - adapter: 'mysql', - hostname: CONFIG.MYSQL_HOST, - username: CONFIG.MYSQL_USER, - password: CONFIG.MYSQL_PASSWORD, - database: CONFIG.MYSQL_DATABASE, - port: CONFIG.MYSQL_PORT - }), + drizzle({ client: connection }), KeyPairCacheManager.getInstance() ) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index 325347369..f987d579e 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -9,7 +9,7 @@ import { communityDbToCommunity } from './convert' import { addCommunityRootTransaction } from './blockchain' export async function bootstrap(): Promise { - const context = Context.create() + const context = await Context.create() context.communities = await bootstrapCommunities(context) return context } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index f63a7a002..125c9fb71 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -1,10 +1,13 @@ -import { SQL } from 'bun' import { memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema } from '../../schemas/typeGuard.schema' import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' import * as v from 'valibot' -import { GradidoUnit } from 'gradido-blockchain-js' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { getLogger } from 'log4js' +import { MySql2Database } from 'drizzle-orm/mysql2' +import { communitiesTable, transactionLinksTable, transactionsTable, usersTable } from './drizzle.schema' +import { asc, sql, eq, isNotNull } from 'drizzle-orm' +import { alias } from 'drizzle-orm/mysql-core' +import { GradidoUnit } from 'gradido-blockchain-js' export const createdUserDbSchema = v.object({ gradidoId: uuidv4Schema, @@ -64,14 +67,19 @@ export type CommunityDb = v.InferOutput const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) // queries -export async function loadCommunities(db: SQL): Promise { - const result = await db` - SELECT c.foreign, c.community_uuid as communityUuid, c.name as name, c.creation_date as creationDate, MIN(u.created_at) as userMinCreatedAt - FROM communities c - LEFT JOIN users u ON c.community_uuid = u.community_uuid - WHERE c.community_uuid IS NOT NULL - GROUP BY c.community_uuid - ` +export async function loadCommunities(db: MySql2Database): Promise { + const result = await db.select({ + foreign: communitiesTable.foreign, + communityUuid: communitiesTable.communityUuid, + name: communitiesTable.name, + creationDate: communitiesTable.creationDate, + userMinCreatedAt: sql`MIN(${usersTable.createdAt})`, + }) + .from(communitiesTable) + .leftJoin(usersTable, eq(communitiesTable.communityUuid, usersTable.communityUuid)) + .where(isNotNull(communitiesTable.communityUuid)) + .groupBy(communitiesTable.communityUuid) + const communityNames = new Set() return result.map((row: any) => { let alias = row.name @@ -87,36 +95,39 @@ export async function loadCommunities(db: SQL): Promise { }) } -export async function loadUsers(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT gradido_id as gradidoId, community_uuid as communityUuid, created_at as createdAt FROM users - ORDER by created_at ASC - LIMIT ${offset}, ${count} - ` +export async function loadUsers(db: MySql2Database, offset: number, count: number): Promise { + const result = await db.select() + .from(usersTable) + .orderBy(asc(usersTable.createdAt)) + .limit(count).offset(offset) + return result.map((row: any) => { return v.parse(createdUserDbSchema, row) }) } -export async function loadTransactions(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT t.id, t.type_id, t.amount, t.balance_date, t.memo, t.creation_date, - u.gradido_id AS user_gradido_id, u.community_uuid AS user_community_uuid, u.created_at as user_created_at, - lu.gradido_id AS linked_user_gradido_id, lu.community_uuid AS linked_user_community_uuid, lu.created_at as linked_user_created_at, - tl.code as transaction_link_code - FROM transactions as t - LEFT JOIN users u ON t.user_id = u.id - LEFT JOIN users lu ON t.linked_user_id = lu.id - LEFT JOIN transaction_links tl ON t.transaction_link_id = tl.id - ORDER by balance_date ASC - LIMIT ${offset}, ${count} - ` +export async function loadTransactions(db: MySql2Database, offset: number, count: number): Promise { + const linkedUsers = alias(usersTable, 'linkedUser') + + const result = await db.select({ + transaction: transactionsTable, + user: usersTable, + linkedUser: linkedUsers, + transactionLink: transactionLinksTable, + }) + .from(transactionsTable) + .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) + .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) + .leftJoin(transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id)) + .orderBy(asc(transactionsTable.balanceDate)) + .limit(count).offset(offset) + return result.map((row: any) => { // console.log(row) // check for consistent data beforehand - const userCreatedAt = new Date(row.user_created_at) - const linkedUserCreatedAd = new Date(row.linked_user_created_at) - const balanceDate = new Date(row.balance_date) + const userCreatedAt = new Date(row.user.createdAt) + const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) + const balanceDate = new Date(row.transaction.balanceDate) if (userCreatedAt.getTime() > balanceDate.getTime() || linkedUserCreatedAd.getTime() > balanceDate.getTime() ){ @@ -124,79 +135,58 @@ export async function loadTransactions(db: SQL, offset: number, count: number): throw new Error('at least one user was created after transaction balance date, logic error!') } - let amount = GradidoUnit.fromString(row.amount) - if (row.type_id === TransactionTypeId.SEND) { + let amount = GradidoUnit.fromString(row.transaction.amount) + if (row.transaction.typeId === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) } try { return v.parse(transactionDbSchema, { - typeId: row.type_id, - amount, - balanceDate: new Date(row.balance_date), - memo: row.memo, - creationDate: new Date(row.creation_date), - transactionLinkCode: row.transaction_link_code, - user: { - gradidoId: row.user_gradido_id, - communityUuid: row.user_community_uuid - }, - linkedUser: { - gradidoId: row.linked_user_gradido_id, - communityUuid: row.linked_user_community_uuid - } + ...row.transaction, + transactionLinkCode: row.transactionLink ? row.transactionLink.code : null, + user: row.user, + linkedUser: row.linkedUser, }) } catch (e) { if (e instanceof v.ValiError) { - console.error(v.flatten(e.issues)) - } else { - throw e + logger.error(v.flatten(e.issues)) } + throw e } }) } -export async function loadTransactionLinks(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT u.gradido_id as userGradidoId, u.community_uuid as userCommunityUuid, tl.code, tl.amount, tl.memo, tl.createdAt, tl.validUntil - FROM transaction_links tl - LEFT JOIN users u ON tl.userId = u.id - ORDER by createdAt ASC - LIMIT ${offset}, ${count} - ` +export async function loadTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { + const result = await db.select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .orderBy(asc(transactionLinksTable.createdAt)) + .limit(count).offset(offset) + return result.map((row: any) => { return v.parse(transactionLinkDbSchema, { - ...row, - user: { - gradidoId: row.userGradidoId, - communityUuid: row.userCommunityUuid - } + ...row.transaction_links, + user: row.users, }) }) } -export async function loadDeletedTransactionLinks(db: SQL, offset: number, count: number): Promise { - const result = await db` - SELECT u.gradido_id as user_gradido_id, u.community_uuid as user_community_uuid, - tl.code, tl.amount, tl.memo, tl.deletedAt - FROM transaction_links tl - LEFT JOIN users u ON tl.userId = u.id - WHERE deletedAt IS NOT NULL - ORDER by deletedAt ASC - LIMIT ${offset}, ${count} - ` +export async function loadDeletedTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { + const result = await db.select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .where(isNotNull(transactionLinksTable.deletedAt)) + .orderBy(asc(transactionLinksTable.deletedAt)) + .limit(count).offset(offset) + return result.map((row: any) => { - const user = { - gradidoId: row.user_gradido_id, - communityUuid: row.user_community_uuid - } return v.parse(transactionDbSchema, { typeId: TransactionTypeId.RECEIVE, - amount: row.amount, - balanceDate: new Date(row.deletedAt), - memo: row.memo, - transactionLinkCode: row.code, - user, - linkedUser: user + amount: row.transaction_links.amount, + balanceDate: new Date(row.transaction_links.deletedAt), + memo: row.transaction_links.memo, + transactionLinkCode: row.transaction_links.code, + user: row.users, + linkedUser: row.users }) }) } \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts new file mode 100644 index 000000000..12c92eaa9 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -0,0 +1,53 @@ + +import { mysqlTable, unique, int, varchar, char, datetime, tinyint, decimal, index } from 'drizzle-orm/mysql-core' +import { sql } from 'drizzle-orm' + + +// use only fields needed in the migration, after update the rest of the project, import database instead +export const communitiesTable = mysqlTable('communities', { + foreign: tinyint().default(1).notNull(), + communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), + name: varchar({ length: 40 }).default(sql`NULL`), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), +}, +(table) => [ + unique('uuid_key').on(table.communityUuid), +]) + + +export const usersTable = mysqlTable('users', { + id: int().autoincrement().notNull(), + gradidoId: char('gradido_id', { length: 36 }).notNull(), + communityUuid: varchar('community_uuid', { length: 36 }).default(sql`NULL`), + 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 transactionsTable = mysqlTable('transactions', { + id: int().autoincrement().notNull(), + typeId: int("type_id").default(sql`NULL`), + transactionLinkId: int("transaction_link_id").default(sql`NULL`), + amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), + balanceDate: datetime("balance_date", { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), + memo: varchar({ length: 255 }).notNull(), + creationDate: datetime("creation_date", { mode: 'string', fsp: 3 }).default(sql`NULL`), + userId: int("user_id").notNull(), + linkedUserId: int("linked_user_id").default(sql`NULL`), +}, +(table) => [ + index("user_id").on(table.userId), +]) + + +export const transactionLinksTable = mysqlTable('transaction_links', { + id: int().autoincrement().notNull(), + userId: int().notNull(), + amount: decimal({ 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(), +}) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 8d66db750..1c309d021 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -5,8 +5,15 @@ import { Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' - -import { CreatedUserDb, loadDeletedTransactionLinks, loadTransactionLinks, loadTransactions, loadUsers, TransactionDb, TransactionLinkDb } from './database' +import { + CreatedUserDb, + loadDeletedTransactionLinks, + loadTransactionLinks, + loadTransactions, + loadUsers, + TransactionDb, + TransactionLinkDb +} from './database' import { addRegisterAddressTransaction, addTransaction } from './blockchain' import { generateKeyPairUserAccount } from './keyPair' import { transactionDbToTransaction, transactionLinkDbToTransaction, userDbToTransaction } from './convert' @@ -28,7 +35,6 @@ async function main() { if(error) { context.logger.error(error) } - context.db.close() }) // synchronize to blockchain @@ -39,6 +45,7 @@ async function main() { (user: CreatedUserDb) => user.createdAt, (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) ) + const transactions = new OrderedContainer( getNextTransactions, (transaction: TransactionDb) => transaction.balanceDate, @@ -56,6 +63,7 @@ async function main() { (transaction: TransactionDb) => transaction.balanceDate, (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) ) + try { await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) } catch (e) { From f09c8e917d83345bba7055df1fec681d33298f17 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 5 Nov 2025 14:17:23 +0100 Subject: [PATCH 07/33] move some code into interaction --- .../OrderedContainer.ts | 63 ------- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 168 +----------------- .../syncDbWithBlockchain/AbstractSync.role.ts | 67 +++++++ .../DeletedTransactionLinksSync.role.ts | 13 ++ .../TransactionLinksSync.role.ts | 25 +++ .../TransactionsSync.role.ts | 27 +++ .../syncDbWithBlockchain/UsersSync.role.ts | 32 ++++ .../syncDbWithBlockchain.context.ts | 39 ++++ 8 files changed, 205 insertions(+), 229 deletions(-) delete mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts deleted file mode 100644 index 47595b3d0..000000000 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/OrderedContainer.ts +++ /dev/null @@ -1,63 +0,0 @@ - -export type Loader = (context: ContextType, offset: number, count: number) => Promise - -export interface Orderable { - getDate(): Date - // return count of new loaded items - ensureFilled(context: ContextType, batchSize: number): Promise - pushToBlockchain(context: ContextType): Promise - isEmpty(): boolean - get length(): number -} - -export class OrderedContainer implements Orderable { - private items: T[] = [] - private offset = 0 - - constructor( - private readonly loader: Loader, - private readonly getDateHandler: (item: T) => Date, - private readonly pushToBlockchainHandler: (context: ContextType, item: T) => Promise - ) {} - - - async ensureFilled(context: ContextType, batchSize: number): Promise { - if (this.items.length === 0) { - this.items = await this.loader(context, this.offset, batchSize) - this.offset += this.items.length - return this.items.length - } - return 0 - } - - async pushToBlockchain(context: ContextType): Promise { - return this.pushToBlockchainHandler(context, this.shift()) - } - - peek(): T { - if (this.isEmpty()) { - throw new Error(`[peek] No items, please call this only if isEmpty returns false`) - } - return this.items[0] - } - - shift(): T { - const item = this.items.shift() - if (!item) { - throw new Error(`[shift] No items, shift return undefined`) - } - return item - } - - get length(): number { - return this.items.length - } - - getDate(): Date { - return this.getDateHandler(this.peek()) - } - - isEmpty(): boolean { - return this.items.length === 0 - } -} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 1c309d021..14a85e9bf 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -5,26 +5,11 @@ import { Profiler } from 'gradido-blockchain-js' import { Logger } from 'log4js' -import { - CreatedUserDb, - loadDeletedTransactionLinks, - loadTransactionLinks, - loadTransactions, - loadUsers, - TransactionDb, - TransactionLinkDb -} from './database' -import { addRegisterAddressTransaction, addTransaction } from './blockchain' -import { generateKeyPairUserAccount } from './keyPair' -import { transactionDbToTransaction, transactionLinkDbToTransaction, userDbToTransaction } from './convert' -import { Orderable, OrderedContainer } from './OrderedContainer' -import { Context } from './Context' import { bootstrap } from './bootstrap' import { heapStats } from 'bun:jsc' import { onShutdown } from '../../../../shared/src/helper/onShutdown' -import { sleep } from 'bun' +import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' -const publicKeyUserIdMap = new Map() async function main() { const timeUsed = new Profiler() @@ -40,48 +25,13 @@ async function main() { // synchronize to blockchain const BATCH_SIZE = 100 - const users = new OrderedContainer( - (context: Context, offset: number, count: number) => getNextUsers(context, offset, count), - (user: CreatedUserDb) => user.createdAt, - (context: Context, user: CreatedUserDb) => pushRegisterAddressTransaction(context, user) - ) - - const transactions = new OrderedContainer( - getNextTransactions, - (transaction: TransactionDb) => transaction.balanceDate, - (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) - ) - - const transactionLinks = new OrderedContainer( - getNextTransactionLinks, - (transactionLink: TransactionLinkDb) => transactionLink.createdAt, - (context: Context, transactionLink: TransactionLinkDb) => pushTransactionLink(context, transactionLink) - ) - - const deletedTransactionLinks = new OrderedContainer( - getNextDeletedTransactionLinks, - (transaction: TransactionDb) => transaction.balanceDate, - (context: Context, transaction: TransactionDb) => pushTransaction(context, transaction) - ) - try { - await synchronizeToBlockchain(context, [users, transactions, transactionLinks, deletedTransactionLinks], BATCH_SIZE) + await syncDbWithBlockchainContext(context, BATCH_SIZE) } catch (e) { console.error(e) throw e } context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) - // timeUsed.reset() - /*context.communities.forEach((communityContext) => { - const f = new Filter() - // hotfix for bug in gradido_blockchain for Filter::ALL_TRANSACTIONS - f.pagination.size = 0 - const transactions = communityContext.blockchain.findAll(f) - context.logger.info(`Community '${communityContext.communityId}', transactions: ${transactions.size()}`) - // logBlogchain(context.logger, communityContext.blockchain) - }) - context.logger.info(`${timeUsed.string()} for logging blockchains`) - */ const runtimeStats = heapStats() context.logger.info( `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` @@ -94,120 +44,6 @@ function bytesToMbyte(bytes: number): string { return (bytes / 1024 / 1024).toFixed(4) } -async function synchronizeToBlockchain( - context: Context, - containers: Orderable[], - batchSize: number -): Promise { - const timeUsed = new Profiler() - while (true) { - timeUsed.reset() - const results = await Promise.all(containers.map(c => c.ensureFilled(context, batchSize))) - const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) - // log only, if at least one new item was loaded - if (loadedItemsCount && context.logger.isInfoEnabled()) { - context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) - } - - // remove empty containers - const available = containers.filter(c => !c.isEmpty()) - if (available.length === 0) { - break - } - - // find container with smallest date - if (available.length > 0) { - available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) - } - - try { - await available[0].pushToBlockchain(context) - // await sleep(1) - } catch (e) { - context.logger.error(e) - // logBlogchain(context.logger, context.communities.values().next().value!.blockchain) - throw e - } - } -} - -// ---------------- load from db graiddo backend transactions format ----------------------------------------------- - -/// load next max ${count} users and calculate key pair for calculating signatures later -async function getNextUsers(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const users = await loadUsers(context.db, offset, count) - for (const user of users) { - const communityContext = context.getCommunityContextByUuid(user.communityUuid) - const { userKeyPair, accountKeyPair } = await generateKeyPairUserAccount(user, context.cache, communityContext.topicId) - publicKeyUserIdMap.set(userKeyPair.convertToHex(), user.gradidoId) - publicKeyUserIdMap.set(accountKeyPair.convertToHex(), user.gradidoId) - } - if(users.length !== 0) { - context.logger.info(`${timeUsed.string()} for loading ${users.length} users from db and calculate ed25519 KeyPairs for them`) - } - return users -} - -// load next max ${count} transactions (contain also redeem transaction link transactions) -async function getNextTransactions(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const transactions = await loadTransactions(context.db, offset, count) - if(transactions.length !== 0) { - context.logger.debug(`${timeUsed.string()} for loading ${transactions.length} transactions from db`) - } - return transactions -} - -// load next max ${count} transaction links (freshly created links, in blockchain format this is a separate transaction) -async function getNextTransactionLinks(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const transactionLinks = await loadTransactionLinks(context.db, offset, count) - if(transactionLinks.length !== 0) { - context.logger.debug(`${timeUsed.string()} for loading ${transactionLinks.length} transaction links from db`) - } - return transactionLinks -} - -// load next max ${count} deleted transaction links (in blockchain format this is a separate transaction) -async function getNextDeletedTransactionLinks(context: Context, offset: number, count: number): Promise { - const timeUsed = new Profiler() - const deletedTransactionLinks = await loadDeletedTransactionLinks(context.db, offset, count) - if(deletedTransactionLinks.length !== 0) { - context.logger.debug(`${timeUsed.string()} for loading ${deletedTransactionLinks.length} deleted transaction links from db`) - } - return deletedTransactionLinks -} - -// ---------------- put into in memory blockchain ----------------------------------------------- - -async function pushRegisterAddressTransaction(context: Context, user: CreatedUserDb): Promise { - const communityContext = context.getCommunityContextByUuid(user.communityUuid) - const transaction = userDbToTransaction(user, communityContext.topicId) - return await addRegisterAddressTransaction(communityContext.blockchain, transaction) -} - -async function pushTransaction(context: Context, transactionDb: TransactionDb): Promise { - const senderCommunityContext = context.getCommunityContextByUuid(transactionDb.user.communityUuid) - // context.logger.info(`before adding non register address and non link transaction:`) - // logBlogchain(context.logger, senderCommunityContext.blockchain) - const recipientCommunityContext = context.getCommunityContextByUuid(transactionDb.linkedUser.communityUuid) - // CreationTransactionRole will check that community topic id belongs to home community - context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) - const transaction = transactionDbToTransaction(transactionDb, senderCommunityContext.topicId, recipientCommunityContext.topicId) - await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) - // const firstTransaction = senderCommunityContext.blockchain.findOne(Filter.FIRST_TRANSACTION) - // console.log(`first transaction: ${firstTransaction?.getConfirmedTransaction()?.toJson(true)}`) -} - -async function pushTransactionLink(context: Context, transactionLinkDb: TransactionLinkDb): Promise { - const communityContext = context.getCommunityContextByUuid(transactionLinkDb.user.communityUuid) - const transaction = transactionLinkDbToTransaction(transactionLinkDb, communityContext.topicId) - await addTransaction(communityContext.blockchain, communityContext.blockchain, transaction) -} - -// ---------------- utils ---------------------------------------------------------------------- - function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { const f = new Filter() f.pagination.size = 0 diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts new file mode 100644 index 000000000..44fd0b471 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts @@ -0,0 +1,67 @@ +import { Context } from '../../Context' +import { getLogger, Logger } from 'log4js' +import { LOG4JS_BASE_CATEGORY } from '../../../../config/const' +import { Profiler } from 'gradido-blockchain-js' + +export abstract class AbstractSyncRole { + private items: T[] = [] + private offset = 0 + protected logger: Logger + + constructor(protected readonly context: Context) { + this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`) + } + + abstract getDate(): Date + abstract loadFromDb(offset: number, count: number): Promise + abstract pushToBlockchain(item: T): Promise + abstract itemTypeName(): string + + // return count of new loaded items + async ensureFilled(batchSize: number): Promise + { + if (this.items.length === 0) { + let timeUsed: Profiler | undefined + if (this.logger.isDebugEnabled()) { + timeUsed = new Profiler() + } + this.items = await this.loadFromDb(this.offset, batchSize) + this.offset += this.items.length + if (timeUsed && this.items.length) { + this.logger.debug(`${timeUsed.string()} for loading ${this.items.length} ${this.itemTypeName()} from db`) + } + return this.items.length + } + return 0 + } + + async toBlockchain(): Promise { + if (this.isEmpty()) { + throw new Error(`[toBlockchain] No items, please call this only if isEmpty returns false`) + } + await this.pushToBlockchain(this.shift()) + } + + peek(): T { + if (this.isEmpty()) { + throw new Error(`[peek] No items, please call this only if isEmpty returns false`) + } + return this.items[0] + } + + shift(): T { + const item = this.items.shift() + if (!item) { + throw new Error(`[shift] No items, shift return undefined`) + } + return item + } + + get length(): number { + return this.items.length + } + + isEmpty(): boolean { + return this.items.length === 0 + } +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts new file mode 100644 index 000000000..d4e8eaa6e --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -0,0 +1,13 @@ +import { loadDeletedTransactionLinks } from '../../database' +import { TransactionsSyncRole } from './TransactionsSync.role' +import { TransactionDb } from '../../database' + +export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { + itemTypeName(): string { + return 'deletedTransactionLinks' + } + + async loadFromDb(offset: number, count: number): Promise { + return await loadDeletedTransactionLinks(this.context.db, offset, count) + } +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts new file mode 100644 index 000000000..c4d5e94d7 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts @@ -0,0 +1,25 @@ +import { TransactionLinkDb, loadTransactionLinks } from '../../database' +import { transactionLinkDbToTransaction } from '../../convert' +import { addTransaction } from '../../blockchain' +import { AbstractSyncRole } from './AbstractSync.role' + +export class TransactionLinksSyncRole extends AbstractSyncRole { + getDate(): Date { + return this.peek().createdAt + } + + itemTypeName(): string { + return 'transactionLinks' + } + + async loadFromDb(offset: number, count: number): Promise { + return await loadTransactionLinks(this.context.db, offset, count) + } + + async pushToBlockchain(item: TransactionLinkDb): Promise { + const communityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) + const transaction = transactionLinkDbToTransaction(item, communityContext.topicId) + await addTransaction(communityContext.blockchain, communityContext.blockchain, transaction) + } +} + \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts new file mode 100644 index 000000000..2f05e4378 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts @@ -0,0 +1,27 @@ +import { TransactionDb, loadTransactions } from '../../database' +import { transactionDbToTransaction } from '../../convert' +import { addTransaction } from '../../blockchain' +import { AbstractSyncRole } from './AbstractSync.role' + +export class TransactionsSyncRole extends AbstractSyncRole { + getDate(): Date { + return this.peek().balanceDate + } + + itemTypeName(): string { + return 'transactions' + } + + async loadFromDb(offset: number, count: number): Promise { + return await loadTransactions(this.context.db, offset, count) + } + + async pushToBlockchain(item: TransactionDb): Promise { + const senderCommunityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) + const recipientCommunityContext = this.context.getCommunityContextByUuid(item.linkedUser.communityUuid) + this.context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) + const transaction = transactionDbToTransaction(item, senderCommunityContext.topicId, recipientCommunityContext.topicId) + await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) + } +} + \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts new file mode 100644 index 000000000..ca4799b68 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts @@ -0,0 +1,32 @@ +import { CreatedUserDb } from '../../database' +import { AbstractSyncRole } from './AbstractSync.role' +import { loadUsers } from '../../database' +import { generateKeyPairUserAccount } from '../../keyPair' +import { userDbToTransaction } from '../../convert' +import { addRegisterAddressTransaction } from '../../blockchain' + + +export class UsersSyncRole extends AbstractSyncRole { + getDate(): Date { + return this.peek().createdAt + } + + itemTypeName(): string { + return 'users' + } + + async loadFromDb(offset: number, count: number): Promise { + const users = await loadUsers(this.context.db, offset, count) + for (const user of users) { + const communityContext = this.context.getCommunityContextByUuid(user.communityUuid) + await generateKeyPairUserAccount(user, this.context.cache, communityContext.topicId) + } + return users + } + + async pushToBlockchain(item: CreatedUserDb): Promise { + const communityContext = this.context.getCommunityContextByUuid(item.communityUuid) + const transaction = userDbToTransaction(item, communityContext.topicId) + return await addRegisterAddressTransaction(communityContext.blockchain, transaction) + } +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts new file mode 100644 index 000000000..edef30caa --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts @@ -0,0 +1,39 @@ +import { Context } from '../../Context' +import { Profiler } from 'gradido-blockchain-js' +import { TransactionsSyncRole } from './TransactionsSync.role' +import { DeletedTransactionLinksSyncRole } from './DeletedTransactionLinksSync.role' +import { TransactionLinksSyncRole } from './TransactionLinksSync.role' +import { UsersSyncRole } from './UsersSync.role' + +export async function syncDbWithBlockchainContext(context: Context, batchSize: number) { + const timeUsed = new Profiler() + const containers = [ + new UsersSyncRole(context), + new TransactionsSyncRole(context), + new DeletedTransactionLinksSyncRole(context), + new TransactionLinksSyncRole(context) + ] + + while (true) { + timeUsed.reset() + const results = await Promise.all(containers.map(c => c.ensureFilled(batchSize))) + const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) + // log only, if at least one new item was loaded + if (loadedItemsCount && context.logger.isInfoEnabled()) { + context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) + } + + // remove empty containers + const available = containers.filter(c => !c.isEmpty()) + if (available.length === 0) { + break + } + + // sort by date, to ensure container on index 0 is the one with the smallest date + if (available.length > 0) { + available.sort((a, b) => a.getDate().getTime() - b.getDate().getTime()) + } + await available[0].toBlockchain() + } +} + From 290a6a4f27630d50d631100698f7abd29c8c50ae Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Sat, 8 Nov 2025 12:47:49 +0100 Subject: [PATCH 08/33] refactor, finalize export to blockchain file --- dlt-connector/bun.lock | 19 +++++ dlt-connector/package.json | 1 + .../db-v2.7.0_to_blockchain-v3.5/Context.ts | 40 ++++++++-- .../TransactionTypeId.ts | 8 ++ .../binaryExport.ts | 76 +++++++++++++++++++ .../blockchain.ts | 1 + .../db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 5 +- .../db-v2.7.0_to_blockchain-v3.5/convert.ts | 3 +- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 68 +++-------------- .../drizzle.schema.ts | 17 ++--- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 51 +++---------- .../DeletedTransactionLinksSync.role.ts | 2 +- .../TransactionLinksSync.role.ts | 3 +- .../TransactionsSync.role.ts | 3 +- .../syncDbWithBlockchain/UsersSync.role.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/keyPair.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/utils.ts | 15 ++++ .../valibot.schema.ts | 66 ++++++++++++++++ 18 files changed, 259 insertions(+), 123 deletions(-) create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts create mode 100644 dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index f4dcee45b..6f6fd84d4 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -24,6 +24,7 @@ "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", "mysql2": "^3.15.3", + "sodium-native": "5.0.9", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", @@ -342,6 +343,18 @@ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "bare-addon-resolve": ["bare-addon-resolve@1.9.5", "", { "dependencies": { "bare-module-resolve": "^1.10.0", "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-XdqrG73zLK9LDfblOJwoAxmJ+7YdfRW4ex46+f4L+wPhk7H7LDrRMAbBw8s8jkxeEFpUenyB7QHnv0ErAWd3Yg=="], + + "bare-module-resolve": ["bare-module-resolve@1.11.2", "", { "dependencies": { "bare-semver": "^1.0.0" }, "peerDependencies": { "bare-url": "*" }, "optionalPeers": ["bare-url"] }, "sha512-HIBu9WacMejg3Dz4X1v6lJjp7ECnwpujvuLub+8I7JJLRwJaGxWMzGYvieOoS9R1n5iRByvTmLtIdPbwjfRgiQ=="], + + "bare-os": ["bare-os@3.6.2", "", {}, "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A=="], + + "bare-path": ["bare-path@3.0.0", "", { "dependencies": { "bare-os": "^3.0.1" } }, "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw=="], + + "bare-semver": ["bare-semver@1.0.2", "", {}, "sha512-ESVaN2nzWhcI5tf3Zzcq9aqCZ676VWzqw07eEZ0qxAcEOAFYBa0pWq8sK34OQeHLY3JsfKXZS9mDyzyxGjeLzA=="], + + "bare-url": ["bare-url@2.3.2", "", { "dependencies": { "bare-path": "^3.0.0" } }, "sha512-ZMq4gd9ngV5aTMa5p9+UfY0b3skwhHELaDkhEHetMdX0LRkW9kzaym4oo/Eh+Ghm0CCDuMTsRIGM/ytUc1ZYmw=="], + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], "baseline-browser-mapping": ["baseline-browser-mapping@2.8.20", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JMWsdF+O8Orq3EMukbUN1QfbLK9mX2CkUmQBcW2T0s8OmdAUL5LLM/6wFwSrqXzlXB13yhyK9gTKS1rIizOduQ=="], @@ -862,6 +875,8 @@ "regenerator-runtime": ["regenerator-runtime@0.13.11", "", {}, "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="], + "require-addon": ["require-addon@1.1.0", "", { "dependencies": { "bare-addon-resolve": "^1.3.0", "bare-url": "^2.1.0" } }, "sha512-KbXAD5q2+v1GJnkzd8zzbOxchTkStSyJZ9QwoCq3QwEXAaIlG3wDYRZGzVD357jmwaGY7hr5VaoEAL0BkF0Kvg=="], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], @@ -906,6 +921,8 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + "sodium-native": ["sodium-native@5.0.9", "", { "dependencies": { "require-addon": "^1.1.0", "which-runtime": "^1.2.1" } }, "sha512-6fpu3d6zdrRpLhuV3CDIBO5g90KkgaeR+c3xvDDz0ZnDkAlqbbPhFW7zhMJfsskfZ9SuC3SvBbqvxcECkXRyKw=="], + "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], "source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], @@ -1006,6 +1023,8 @@ "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + "which-runtime": ["which-runtime@1.3.2", "", {}, "sha512-5kwCfWml7+b2NO7KrLMhYihjRx0teKkd3yGp1Xk5Vaf2JGdSh+rgVhEALAD9c/59dP+YwJHXoEO7e8QPy7gOkw=="], + "wide-align": ["wide-align@1.1.5", "", { "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg=="], "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 749258400..c4c6f1099 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -38,6 +38,7 @@ "jsonrpc-ts-client": "^0.2.3", "log4js": "^6.9.1", "mysql2": "^3.15.3", + "sodium-native": "5.0.9", "typescript": "^5.8.3", "uuid": "^8.3.2", "valibot": "1.1.0", diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index 5708cccd3..9eb549a30 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,32 +1,31 @@ import { drizzle, MySql2Database } from 'drizzle-orm/mysql2' import mysql from 'mysql2/promise' -import { InMemoryBlockchain } from 'gradido-blockchain-js' +import { Filter, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' -import { HieroId, Uuidv4 } from '../../schemas/typeGuard.schema' +import { Uuidv4 } from '../../schemas/typeGuard.schema' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { loadConfig } from '../../bootstrap/init' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' - -export type CommunityContext = { - communityId: string - blockchain: InMemoryBlockchain - topicId: HieroId -} +import { heapStats } from 'bun:jsc' +import { CommunityContext } from './valibot.schema' +import { bytesToMbyte } from './utils' export class Context { public logger: Logger public db: MySql2Database public communities: Map public cache: KeyPairCacheManager + private timeUsed: Profiler constructor(logger: Logger, db: MySql2Database, cache: KeyPairCacheManager) { this.logger = logger this.db = db this.cache = cache this.communities = new Map() + this.timeUsed = new Profiler() } static async create(): Promise { @@ -53,4 +52,29 @@ export class Context { } return community } + + logRuntimeStatistics() { + this.logger.info(`${this.timeUsed.string()} for synchronizing to blockchain`) + const runtimeStats = heapStats() + this.logger.info( + `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` + ) + } + + logBlogchain(communityUuid: Uuidv4) { + const communityContext = this.getCommunityContextByUuid(communityUuid) + const f = new Filter() + f.pagination.size = 0 + f.searchDirection = SearchDirection_ASC + + const transactions = communityContext.blockchain.findAll(f) + for(let i = 0; i < transactions.size(); i++) { + const transaction = transactions.get(i) + const confirmedTransaction = transaction?.getConfirmedTransaction() + this.logger.info(confirmedTransaction?.toJson(true)) + } + } + + // TODO: move into utils + } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts new file mode 100644 index 000000000..dc5fc25e0 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/TransactionTypeId.ts @@ -0,0 +1,8 @@ +export enum TransactionTypeId { + CREATION = 1, + SEND = 2, + RECEIVE = 3, + // This is a virtual property, never occurring on the database + DECAY = 4, + LINK_SUMMARY = 5, +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts new file mode 100644 index 000000000..74181f34f --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts @@ -0,0 +1,76 @@ +import { ConfirmedTransaction, Filter, InteractionSerialize, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' +import path from 'node:path' +import { CONFIG } from '../../config' +import fs from 'node:fs' +import { bytesToKbyte } from './utils' +import { calculateOneHashStep } from './utils' +import { Context } from './Context' +import { CommunityContext } from './valibot.schema' + +export function exportAllCommunities(context: Context, batchSize: number) { + const timeUsed = new Profiler() + for(const communityContext of context.communities.values()) { + exportCommunity(communityContext, context, batchSize) + } + context.logger.info(`time used for exporting communities to binary file: ${timeUsed.string()}`) +} + +export function exportCommunity(communityContext: CommunityContext, context: Context, batchSize: number) { + // write as binary file for GradidoNode + const f = new Filter() + f.pagination.size = batchSize + f.pagination.page = 1 + f.searchDirection = SearchDirection_ASC + const binFilePath = prepareFolder(communityContext) + + let lastTransactionCount = 0 + let hash = Buffer.alloc(32, 0) + do { + const transactions = communityContext.blockchain.findAll(f) + lastTransactionCount = transactions.size() + + for (let i = 0; i < lastTransactionCount; i++) { + const confirmedTransaction = transactions.get(i)?.getConfirmedTransaction() + const transactionNr = f.pagination.page * batchSize + i + if (!confirmedTransaction) { + throw new Error(`invalid TransactionEntry at index: ${transactionNr} `) + } + hash = exportTransaction(confirmedTransaction, hash, binFilePath) + } + f.pagination.page++ + } while (lastTransactionCount === batchSize) + + fs.appendFileSync(binFilePath, hash!) + context.logger.info(`binary file for community ${communityContext.communityId} written to ${binFilePath}`) + context.logger.info( + `transactions count: ${(f.pagination.page - 1) * batchSize + lastTransactionCount}, size: ${bytesToKbyte(fs.statSync(binFilePath).size)} KByte` + ) +} + +function exportTransaction(confirmedTransaction: ConfirmedTransaction, hash: Buffer, binFilePath: string): Buffer { + const sizeBuffer = Buffer.alloc(2) + const interactionSerialize = new InteractionSerialize(confirmedTransaction) + const binBlock = interactionSerialize.run() + if (!binBlock) { + throw new Error(`invalid TransactionEntry at index: ${confirmedTransaction.getId()}, serialize into protobuf format failed`) + } + + hash = calculateOneHashStep(hash, binBlock.data()) + sizeBuffer.writeUInt16LE(binBlock.size(), 0) + fs.appendFileSync(binFilePath, sizeBuffer) + fs.appendFileSync(binFilePath, binBlock.data()) + return hash +} + +function prepareFolder(communityContext: CommunityContext): string { + const binFileFolder = path.join( + CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + '.gradido', + communityContext.folder, + ) + const binFilePath = path.join(binFileFolder, 'blk00000001.dat') + // make sure we work with a clean folder, rm beforehand with all content + fs.rmSync(binFileFolder, { recursive: true }) + fs.mkdirSync(binFileFolder, { recursive: true }) + return binFilePath +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 2d135b184..5a09065a8 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -28,6 +28,7 @@ function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemor const transaction = builder.build() const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) + try { const result = blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) return result diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index f987d579e..ef792e8d6 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -1,5 +1,4 @@ import { Context } from './Context' -import { CommunityContext } from './Context' import { loadCommunities } from './database' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import * as v from 'valibot' @@ -7,6 +6,7 @@ import { InMemoryBlockchainProvider } from 'gradido-blockchain-js' import { generateKeyPairCommunity } from './keyPair' import { communityDbToCommunity } from './convert' import { addCommunityRootTransaction } from './blockchain' +import { CommunityContext } from './valibot.schema' export async function bootstrap(): Promise { const context = await Context.create() @@ -35,7 +35,8 @@ async function bootstrapCommunities(context: Context): Promise -export type UserDb = v.InferOutput -export type CreatedUserDb = v.InferOutput -export type TransactionLinkDb = v.InferOutput -export type CommunityDb = v.InferOutput +import { + CommunityDb, + communityDbSchema, + CreatedUserDb, + createdUserDbSchema, + TransactionDb, + transactionDbSchema, + TransactionLinkDb, + transactionLinkDbSchema +} from './valibot.schema' +import { TransactionTypeId } from './TransactionTypeId' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts index 12c92eaa9..f96b71bfe 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -2,7 +2,6 @@ import { mysqlTable, unique, int, varchar, char, datetime, tinyint, decimal, index } from 'drizzle-orm/mysql-core' import { sql } from 'drizzle-orm' - // use only fields needed in the migration, after update the rest of the project, import database instead export const communitiesTable = mysqlTable('communities', { foreign: tinyint().default(1).notNull(), @@ -14,7 +13,6 @@ export const communitiesTable = mysqlTable('communities', { unique('uuid_key').on(table.communityUuid), ]) - export const usersTable = mysqlTable('users', { id: int().autoincrement().notNull(), gradidoId: char('gradido_id', { length: 36 }).notNull(), @@ -27,20 +25,19 @@ export const usersTable = mysqlTable('users', { export const transactionsTable = mysqlTable('transactions', { id: int().autoincrement().notNull(), - typeId: int("type_id").default(sql`NULL`), - transactionLinkId: int("transaction_link_id").default(sql`NULL`), + typeId: int('type_id').default(sql`NULL`), + transactionLinkId: int('transaction_link_id').default(sql`NULL`), amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), - balanceDate: datetime("balance_date", { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), + balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), memo: varchar({ length: 255 }).notNull(), - creationDate: datetime("creation_date", { mode: 'string', fsp: 3 }).default(sql`NULL`), - userId: int("user_id").notNull(), - linkedUserId: int("linked_user_id").default(sql`NULL`), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), + userId: int('user_id').notNull(), + linkedUserId: int('linked_user_id').default(sql`NULL`), }, (table) => [ - index("user_id").on(table.userId), + index('user_id').on(table.userId), ]) - export const transactionLinksTable = mysqlTable('transaction_links', { id: int().autoincrement().notNull(), userId: int().notNull(), diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 14a85e9bf..5bae06fee 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -1,18 +1,12 @@ -import { - InMemoryBlockchain, - Filter, - SearchDirection_ASC, - Profiler -} from 'gradido-blockchain-js' -import { Logger } from 'log4js' import { bootstrap } from './bootstrap' -import { heapStats } from 'bun:jsc' import { onShutdown } from '../../../../shared/src/helper/onShutdown' import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' +import { exportAllCommunities } from './binaryExport' +import { Filter } from 'gradido-blockchain-js' +const BATCH_SIZE = 100 async function main() { - const timeUsed = new Profiler() // prepare in memory blockchains const context = await bootstrap() onShutdown(async (reason, error) => { @@ -22,42 +16,19 @@ async function main() { } }) - // synchronize to blockchain - const BATCH_SIZE = 100 + // synchronize to in memory blockchain + await syncDbWithBlockchainContext(context, BATCH_SIZE) + + // write as binary file for GradidoNode + exportAllCommunities(context, BATCH_SIZE) + + // log runtime statistics + context.logRuntimeStatistics() - try { - await syncDbWithBlockchainContext(context, BATCH_SIZE) - } catch (e) { - console.error(e) - throw e - } - context.logger.info(`${timeUsed.string()} for synchronizing to blockchain`) - const runtimeStats = heapStats() - context.logger.info( - `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` - ) // needed because of shutdown handler (TODO: fix shutdown handler) process.exit(0) } -function bytesToMbyte(bytes: number): string { - return (bytes / 1024 / 1024).toFixed(4) -} - -function logBlogchain(logger: Logger, blockchain: InMemoryBlockchain) { - const f = new Filter() - f.pagination.size = 0 - f.searchDirection = SearchDirection_ASC - - const transactions = blockchain.findAll(f) - for(let i = 0; i < transactions.size(); i++) { - const transaction = transactions.get(i) - const confirmedTransaction = transaction?.getConfirmedTransaction() - logger.info(confirmedTransaction?.toJson(true)) - } -} - - main().catch((e) => { // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here console.error(e) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts index d4e8eaa6e..2ff3961b1 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -1,6 +1,6 @@ import { loadDeletedTransactionLinks } from '../../database' import { TransactionsSyncRole } from './TransactionsSync.role' -import { TransactionDb } from '../../database' +import { TransactionDb } from '../../valibot.schema' export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { itemTypeName(): string { diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts index c4d5e94d7..30706dba3 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts @@ -1,4 +1,5 @@ -import { TransactionLinkDb, loadTransactionLinks } from '../../database' +import { TransactionLinkDb } from '../../valibot.schema' +import { loadTransactionLinks } from '../../database' import { transactionLinkDbToTransaction } from '../../convert' import { addTransaction } from '../../blockchain' import { AbstractSyncRole } from './AbstractSync.role' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts index 2f05e4378..b2ca9d75f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionsSync.role.ts @@ -1,4 +1,5 @@ -import { TransactionDb, loadTransactions } from '../../database' +import { TransactionDb } from '../../valibot.schema' +import { loadTransactions } from '../../database' import { transactionDbToTransaction } from '../../convert' import { addTransaction } from '../../blockchain' import { AbstractSyncRole } from './AbstractSync.role' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts index ca4799b68..acdf5011d 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts @@ -1,4 +1,4 @@ -import { CreatedUserDb } from '../../database' +import { CreatedUserDb } from '../../valibot.schema' import { AbstractSyncRole } from './AbstractSync.role' import { loadUsers } from '../../database' import { generateKeyPairUserAccount } from '../../keyPair' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts index 6d30760c5..dda017cbd 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts @@ -1,4 +1,4 @@ -import { CommunityDb, UserDb } from './database' +import { CommunityDb, UserDb } from './valibot.schema' import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairEd25519, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts new file mode 100644 index 000000000..57ae73137 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts @@ -0,0 +1,15 @@ +import { crypto_generichash_batch, crypto_generichash_KEYBYTES } from 'sodium-native' + +export function bytesToMbyte(bytes: number): string { + return (bytes / 1024 / 1024).toFixed(4) +} + +export function bytesToKbyte(bytes: number): string { + return (bytes / 1024).toFixed(0) +} + +export function calculateOneHashStep(hash: Buffer, data: Buffer): Buffer { + const outputHash = Buffer.alloc(crypto_generichash_KEYBYTES, 0) + crypto_generichash_batch(outputHash, [hash, data]) + return outputHash +} \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts new file mode 100644 index 000000000..354a62543 --- /dev/null +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts @@ -0,0 +1,66 @@ +import { memoSchema, uuidv4Schema, identifierSeedSchema, gradidoAmountSchema, hieroIdSchema } from '../../schemas/typeGuard.schema' +import { dateSchema, booleanSchema } from '../../schemas/typeConverter.schema' +import { TransactionTypeId } from './TransactionTypeId' +import { InMemoryBlockchain } from 'gradido-blockchain-js' +import * as v from 'valibot' + +export const createdUserDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, + createdAt: dateSchema, +}) + +export const userDbSchema = v.object({ + gradidoId: uuidv4Schema, + communityUuid: uuidv4Schema, +}) + + +export const transactionDbSchema = v.object({ + typeId: v.enum(TransactionTypeId), + amount: gradidoAmountSchema, + balanceDate: dateSchema, + memo: memoSchema, + creationDate: v.nullish(dateSchema), + user: userDbSchema, + linkedUser: userDbSchema, + transactionLinkCode: v.nullish(identifierSeedSchema), +}) + +export const transactionLinkDbSchema = v.object({ + user: userDbSchema, + code: identifierSeedSchema, + amount: gradidoAmountSchema, + memo: memoSchema, + createdAt: dateSchema, + validUntil: dateSchema, +}) + +export const communityDbSchema = v.object({ + foreign: booleanSchema, + communityUuid: uuidv4Schema, + name: v.string(), + creationDate: dateSchema, + userMinCreatedAt: dateSchema, + uniqueAlias: v.string(), +}) + +export const communityContextSchema = v.object({ + communityId: v.string(), + blockchain: v.instance(InMemoryBlockchain, 'expect InMemoryBlockchain type'), + topicId: hieroIdSchema, + folder: v.pipe( + v.string(), + v.minLength(1, 'expect string length >= 1'), + v.maxLength(255, 'expect string length <= 255'), + v.regex(/^[a-zA-Z0-9-_]+$/, + 'expect string to be a valid (alphanumeric, _, -) folder name'), + ), +}) + +export type TransactionDb = v.InferOutput +export type UserDb = v.InferOutput +export type CreatedUserDb = v.InferOutput +export type TransactionLinkDb = v.InferOutput +export type CommunityDb = v.InferOutput +export type CommunityContext = v.InferOutput \ No newline at end of file From a70cfa88ebe7a77dee7af8c49399596d97ef0ca2 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:32:13 +0100 Subject: [PATCH 09/33] remove code which was moved to dlt-connector --- backend/src/federation/validateCommunities.ts | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 3b910b313..09217b494 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -87,8 +87,6 @@ export async function validateCommunities(): Promise { logger.error(`Error:`, err) } } - // export communities for gradido dlt node server - await exportCommunitiesToDltNodeServer() } export async function writeJwtKeyPairInHomeCommunity(): Promise { @@ -156,40 +154,3 @@ type CommunityForDltNodeServer = { alias: string folder: string } -async function exportCommunitiesToDltNodeServer(): Promise { - if (!CONFIG.DLT_CONNECTOR) { - return Promise.resolve() - } - const folder = CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER - try { - fs.accessSync(folder, fs.constants.R_OK | fs.constants.W_OK) - } catch (err) { - logger.error(`Error: home folder for DLT Gradido Node Server ${folder} does not exist`) - return - } - - const dbComs = await getReachableCommunities(CONFIG.FEDERATION_VALIDATE_COMMUNITY_TIMER * 4) - const communitiesForDltNodeServer: CommunityForDltNodeServer[] = [] - // make sure communityName is unique - const communityName = new Set() - dbComs.forEach((com) => { - if (!com.communityUuid || !com.hieroTopicId) { - return - } - let alias = com.name - if (!alias || communityName.has(alias)) { - alias = com.communityUuid - } - communityName.add(alias) - communitiesForDltNodeServer.push({ - communityId: com.communityUuid, - hieroTopicId: com.hieroTopicId, - alias, - // use only alpha-numeric chars for folder name - folder: alias.replace(/[^a-zA-Z0-9]/g, '_') - }) - }) - const dltNodeServerCommunitiesFile = path.join(folder, 'communities.json') - fs.writeFileSync(dltNodeServerCommunitiesFile, JSON.stringify(communitiesForDltNodeServer, null, 2)) - logger.debug(`Written communitiesForDltNodeServer to ${dltNodeServerCommunitiesFile}`) -} From 495622d55d80ece4e44d3282e0bb873dfd1ac0de Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:32:42 +0100 Subject: [PATCH 10/33] update transaction seed account for structure chance in dlt-connector --- backend/src/apis/dltConnector/index.ts | 2 ++ backend/src/apis/dltConnector/model/AccountIdentifier.ts | 8 +++----- backend/src/apis/dltConnector/model/IdentifierSeed.ts | 9 --------- backend/src/apis/dltConnector/model/TransactionDraft.ts | 5 ++--- 4 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 backend/src/apis/dltConnector/model/IdentifierSeed.ts diff --git a/backend/src/apis/dltConnector/index.ts b/backend/src/apis/dltConnector/index.ts index bce319674..f81d928d1 100644 --- a/backend/src/apis/dltConnector/index.ts +++ b/backend/src/apis/dltConnector/index.ts @@ -36,8 +36,10 @@ async function checkDltConnectorResult(dltTransaction: DbDltTransaction, clientR logger.debug(e) if (e instanceof Error) { dltTransaction.error = e.message + logger.error('Error from dlt-connector', e) } else if (typeof e === 'string') { dltTransaction.error = e + logger.error('error from dlt-connector', e) } else { throw e } diff --git a/backend/src/apis/dltConnector/model/AccountIdentifier.ts b/backend/src/apis/dltConnector/model/AccountIdentifier.ts index ed1d61e51..3882e8584 100644 --- a/backend/src/apis/dltConnector/model/AccountIdentifier.ts +++ b/backend/src/apis/dltConnector/model/AccountIdentifier.ts @@ -1,15 +1,13 @@ import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' -import { IdentifierSeed } from './IdentifierSeed' - export class AccountIdentifier { communityTopicId: string account?: CommunityAccountIdentifier - seed?: IdentifierSeed // used for deferred transfers + seed?: string // used for deferred transfers - constructor(communityTopicId: string, input: CommunityAccountIdentifier | IdentifierSeed) { + constructor(communityTopicId: string, input: CommunityAccountIdentifier | string) { if (input instanceof CommunityAccountIdentifier) { this.account = input - } else if (input instanceof IdentifierSeed) { + } else { this.seed = input } this.communityTopicId = communityTopicId diff --git a/backend/src/apis/dltConnector/model/IdentifierSeed.ts b/backend/src/apis/dltConnector/model/IdentifierSeed.ts deleted file mode 100644 index 7f7e2fe34..000000000 --- a/backend/src/apis/dltConnector/model/IdentifierSeed.ts +++ /dev/null @@ -1,9 +0,0 @@ -// https://www.npmjs.com/package/@apollo/protobufjs - -export class IdentifierSeed { - seed: string - - constructor(seed: string) { - this.seed = seed - } -} diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index 5c40da289..fdbce026f 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -12,7 +12,6 @@ import { import { CommunityAccountIdentifier } from './CommunityAccountIdentifier' import { getLogger } from 'log4js' import { LOG4JS_BASE_CATEGORY_NAME } from '@/config/const' -import { IdentifierSeed } from './IdentifierSeed' import { CODE_VALID_DAYS_DURATION } from '@/graphql/resolver/const/const' const logger = getLogger(`${LOG4JS_BASE_CATEGORY_NAME}.dltConnector.model.TransactionDraft`) @@ -94,7 +93,7 @@ export class TransactionDraft { } const draft = new TransactionDraft() draft.user = new AccountIdentifier(senderUserTopic, new CommunityAccountIdentifier(sendingUser.gradidoID)) - draft.linkedUser = new AccountIdentifier(senderUserTopic, new IdentifierSeed(transactionLink.code)) + draft.linkedUser = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER draft.createdAt = transactionLink.createdAt.toISOString() draft.amount = transactionLink.amount.toString() @@ -119,7 +118,7 @@ export class TransactionDraft { throw new Error(`missing topicId for community ${recipientUser.community.id}`) } const draft = new TransactionDraft() - draft.user = new AccountIdentifier(senderUserTopic, new IdentifierSeed(transactionLink.code)) + draft.user = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.linkedUser = new AccountIdentifier(recipientUserTopic, new CommunityAccountIdentifier(recipientUser.gradidoID)) draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER draft.createdAt = createdAt.toISOString() From b63724c4700f692fd5e642afc75df6a266dffda4 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:33:07 +0100 Subject: [PATCH 11/33] remove unneccessary lines --- dlt-connector/log4js-config.json | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/dlt-connector/log4js-config.json b/dlt-connector/log4js-config.json index 8d865fa26..2956a0816 100644 --- a/dlt-connector/log4js-config.json +++ b/dlt-connector/log4js-config.json @@ -15,19 +15,6 @@ "fileNameSep" : "_", "numBackups" : 30 }, - "dlt.client.HieroClient": { - "type": "dateFile", - "filename": "../logs/dlt-connector/apiversion-%v.log", - "pattern": "yyyy-MM-dd", - "layout": - { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [topicId=%X{topicId}] - %m" - }, - "compress": true, - "keepFileExt" : true, - "fileNameSep" : "_", - "numBackups" : 30 - }, "errorFile": { "type": "dateFile", From f716c92fe93edc4dbd70d3cf018f90c8796b7c19 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:35:06 +0100 Subject: [PATCH 12/33] more infos in error logging --- .../db-v2.7.0_to_blockchain-v3.5/blockchain.ts | 2 +- dlt-connector/src/server/index.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 5a09065a8..38db2af38 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -91,7 +91,7 @@ export async function addTransaction( f.involvedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() const deferredTransaction = senderBlockchain.findOne(f) if (!deferredTransaction) { - throw new Error("redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node") + throw new Error(`redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node for ${JSON.stringify(transaction, null, 2)} and public key from seed: ${f.involvedPublicKey?.convertToHex()}`) } const confirmedDeferredTransaction = deferredTransaction.getConfirmedTransaction() if (!confirmedDeferredTransaction) { diff --git a/dlt-connector/src/server/index.ts b/dlt-connector/src/server/index.ts index 191e990d3..1692bacfb 100644 --- a/dlt-connector/src/server/index.ts +++ b/dlt-connector/src/server/index.ts @@ -1,5 +1,5 @@ import { TypeBoxFromValibot } from '@sinclair/typemap' -import { Elysia, status, t } from 'elysia' +import { Elysia, status, t, ValidationError } from 'elysia' import { AddressType_NONE } from 'gradido-blockchain-js' import { getLogger } from 'log4js' import * as v from 'valibot' @@ -58,6 +58,14 @@ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.server`) * 🔗 More info: https://elysiajs.com/at-glance.html */ export const appRoutes = new Elysia() + .onError(({ code, error }) => { + if (code === 'VALIDATION' && error instanceof ValidationError) { + logger.debug(JSON.stringify(error.all[0], null, 2)) + logger.error(error.all[0].summary) + return error.all[0].summary + } + return error + }) // check if account exists by user, call example: // GET /isAccountExist/by-user/0.0.21732/408780b2-59b3-402a-94be-56a4f4f4e8ec/0 .get( From f66f33307d3d0ef319b03a256da4057837fcb619 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 08:36:09 +0100 Subject: [PATCH 13/33] hotfix restart gradido node if it don't get new transaction after 1 second --- .../client/GradidoNode/GradidoNodeProcess.ts | 4 ++ dlt-connector/src/client/hiero/HieroClient.ts | 24 +++++++++++ dlt-connector/src/utils/time.ts | 42 +++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 dlt-connector/src/utils/time.ts diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index eb2bf6b66..bedbedf38 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -97,6 +97,10 @@ export class GradidoNodeProcess { } } + public getLastStarted(): Date | null { + return this.lastStarted + } + public async exit(): Promise { this.exitCalled = true if (this.proc) { diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 33a208b78..0ed375d62 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -22,6 +22,9 @@ import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { type TopicInfoOutput, topicInfoSchema } from './output.schema' +import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' +import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' +import { printTimeDuration } from '../../utils/time' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds @@ -95,6 +98,27 @@ export class HieroClient { logger.info( `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`, ) + // TODO: fix issue in GradidoNode + // hot fix, when gradido node is running some time, the hiero listener stop working, so we check if our new transaction is received + // after 1 second, else restart GradidoNode + setTimeout(async () => { + const transaction = await GradidoNodeClient.getInstance().getTransaction({ + topic: topicId, + hieroTransactionId: sendResponse.transactionId.toString(), + }) + if (!transaction) { + const process = GradidoNodeProcess.getInstance() + const lastStarted = process.getLastStarted() + if (lastStarted) { + const serverRunTime = printTimeDuration(new Date().getTime() - lastStarted.getTime()) + this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`) + await GradidoNodeProcess.getInstance().restart() + } else { + this.logger.error('transaction not found, GradidoNode not running, start it') + GradidoNodeProcess.getInstance().start() + } + } + }, 1000) if (logger.isInfoEnabled()) { // only for logging sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { diff --git a/dlt-connector/src/utils/time.ts b/dlt-connector/src/utils/time.ts new file mode 100644 index 000000000..ccbb91c07 --- /dev/null +++ b/dlt-connector/src/utils/time.ts @@ -0,0 +1,42 @@ +/** + * @param {number} time - in minutes + */ +export const getTimeDurationObject = ( + time: number, +): { + hours?: number + minutes: number +} => { + if (time > 60) { + return { + hours: Math.floor(time / 60), + minutes: time % 60, + } + } + return { minutes: time } +} + +/** + * @param startDate + * @param endDate + * @returns duration in minutes + */ +export const durationInMinutesFromDates = (startDate: Date, endDate: Date): number => { + const diff = endDate.getTime() - startDate.getTime() + return Math.floor(diff / (1000 * 60)) +} + +/** + * @param duration in minutes + */ +export const printTimeDuration = (duration: number): string => { + const time = getTimeDurationObject(duration) + const result = time.minutes > 0 ? `${time.minutes} minutes` : '' + if (time.hours) { + return `${time.hours} hours` + (result !== '' ? ` and ${result}` : '') + } + if (result === '') { + return '0 minutes' + } + return result +} From 94ce58a68f33b54d831ca89a73b19c6df8c875f0 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 13 Nov 2025 09:52:01 +0100 Subject: [PATCH 14/33] make restart and exit GradidoNode Process more robust, fix error in ensureCommunitiesAvailable --- .../client/GradidoNode/GradidoNodeProcess.ts | 16 +++++++++++--- .../src/client/GradidoNode/communities.ts | 10 +++++---- dlt-connector/src/client/hiero/HieroClient.ts | 21 ++++++++----------- dlt-connector/src/config/const.ts | 1 + .../sendToHiero/SendToHiero.context.ts | 2 +- dlt-connector/src/utils/time.ts | 4 ++++ 6 files changed, 34 insertions(+), 20 deletions(-) diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index bedbedf38..3980bb9f2 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -3,11 +3,13 @@ import { getLogger, Logger } from 'log4js' import { CONFIG } from '../../config' import { GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS, + GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS, GRADIDO_NODE_MIN_RUNTIME_BEFORE_RESTART_MILLISECONDS, GRADIDO_NODE_RUNTIME_PATH, LOG4JS_BASE_CATEGORY, } from '../../config/const' - +import { Mutex } from 'async-mutex' +import { delay } from '../../utils/time' /** * A Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. @@ -22,6 +24,7 @@ export class GradidoNodeProcess { private logger: Logger private lastStarted: Date | null = null private exitCalled: boolean = false + private restartMutex: Mutex = new Mutex() private constructor() { // constructor is private to prevent instantiation from outside @@ -55,7 +58,7 @@ export class GradidoNodeProcess { USERPROFILE: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, HOME: CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, }, - onExit(proc, exitCode, signalCode, error) { + onExit(_proc, exitCode, signalCode, error) { logger.warn(`GradidoNodeProcess exited with code ${exitCode} and signalCode ${signalCode}`) if (error) { logger.error(`GradidoNodeProcess exit error: ${error}`) @@ -69,7 +72,6 @@ export class GradidoNodeProcess { }) }*/ } - logger.debug(`ressource usage: ${JSON.stringify(proc?.resourceUsage(), null, 2)}`) const gradidoNodeProcess = GradidoNodeProcess.getInstance() gradidoNodeProcess.proc = null if ( @@ -90,11 +92,16 @@ export class GradidoNodeProcess { } public async restart() { + const release = await this.restartMutex.acquire() + try { if (this.proc) { await this.exit() this.exitCalled = false this.start() } + } finally { + release() + } } public getLastStarted(): Date | null { @@ -104,6 +111,9 @@ export class GradidoNodeProcess { public async exit(): Promise { this.exitCalled = true if (this.proc) { + if (this.lastStarted && Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS) { + await delay(GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - Date.now() - this.lastStarted.getTime()) + } this.proc.kill('SIGTERM') const timeout = setTimeout(() => { this.logger.warn( diff --git a/dlt-connector/src/client/GradidoNode/communities.ts b/dlt-connector/src/client/GradidoNode/communities.ts index d25ed4dd4..76384f847 100644 --- a/dlt-connector/src/client/GradidoNode/communities.ts +++ b/dlt-connector/src/client/GradidoNode/communities.ts @@ -27,7 +27,8 @@ export async function ensureCommunitiesAvailable(communityTopicIds: HieroId[]): CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, GRADIDO_NODE_HOME_FOLDER_NAME, ) - if (!checkCommunityAvailable(communityTopicIds, homeFolder)) { + const communityTopicIdsSet = new Set(communityTopicIds) + if (!checkCommunityAvailable(communityTopicIdsSet, homeFolder)) { await exportCommunities(homeFolder, BackendClient.getInstance()) return GradidoNodeProcess.getInstance().restart() } @@ -65,7 +66,7 @@ export async function exportCommunities(homeFolder: string, client: BackendClien logger.info(`exported ${communitiesForDltNodeServer.length} communities to ${communitiesPath}`) } -export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder: string): boolean { +export function checkCommunityAvailable(communityTopicIds: Set, homeFolder: string): boolean { const communitiesPath = path.join(homeFolder, 'communities.json') if (!checkFileExist(communitiesPath)) { return false @@ -73,12 +74,13 @@ export function checkCommunityAvailable(communityTopicIds: HieroId[], homeFolder const communities = JSON.parse(fs.readFileSync(communitiesPath, 'utf-8')) let foundCount = 0 for (const community of communities) { - if (communityTopicIds.includes(community.hieroTopicId)) { + if (communityTopicIds.has(community.hieroTopicId)) { foundCount++ - if (foundCount >= communityTopicIds.length) { + if (foundCount >= communityTopicIds.size) { return true } } } + logger.debug(`community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`) return false } diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index 0ed375d62..f81da11c5 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -15,7 +15,7 @@ import { TransactionId, Wallet, } from '@hashgraph/sdk' -import { GradidoTransaction } from 'gradido-blockchain-js' +import { GradidoTransaction, Profiler } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' import * as v from 'valibot' import { CONFIG } from '../../config' @@ -24,8 +24,7 @@ import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { type TopicInfoOutput, topicInfoSchema } from './output.schema' import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' -import { printTimeDuration } from '../../utils/time' - +import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds export const MAX_AUTORENEW_PERIOD = 8000001 // seconds @@ -75,7 +74,7 @@ export class HieroClient { topicId: HieroId, transaction: GradidoTransaction, ): Promise { - const startTime = new Date() + const timeUsed = new Profiler() this.transactionInternNr++ const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.client.HieroClient`) logger.addContext('trNr', this.transactionInternNr) @@ -96,11 +95,11 @@ export class HieroClient { .then(async (signedHieroTransaction) => { const sendResponse = await signedHieroTransaction.executeWithSigner(this.wallet) logger.info( - `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}`, + `message sent to topic ${topicId}, transaction id: ${sendResponse.transactionId.toString()}, timeUsed: ${timeUsed.string()}`, ) // TODO: fix issue in GradidoNode // hot fix, when gradido node is running some time, the hiero listener stop working, so we check if our new transaction is received - // after 1 second, else restart GradidoNode + // after 10 seconds, else restart GradidoNode setTimeout(async () => { const transaction = await GradidoNodeClient.getInstance().getTransaction({ topic: topicId, @@ -110,7 +109,7 @@ export class HieroClient { const process = GradidoNodeProcess.getInstance() const lastStarted = process.getLastStarted() if (lastStarted) { - const serverRunTime = printTimeDuration(new Date().getTime() - lastStarted.getTime()) + const serverRunTime = printTimeDuration(durationInMinutesFromDates(lastStarted, new Date())) this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`) await GradidoNodeProcess.getInstance().restart() } else { @@ -118,7 +117,7 @@ export class HieroClient { GradidoNodeProcess.getInstance().start() } } - }, 1000) + }, 10000) if (logger.isInfoEnabled()) { // only for logging sendResponse.getReceiptWithSigner(this.wallet).then((receipt) => { @@ -127,9 +126,8 @@ export class HieroClient { // only for logging sendResponse.getRecordWithSigner(this.wallet).then((record) => { logger.info(`message sent, cost: ${record.transactionFee.toString()}`) - const localEndTime = new Date() logger.info( - `HieroClient.sendMessage used time (full process): ${localEndTime.getTime() - startTime.getTime()}ms`, + `HieroClient.sendMessage used time (full process): ${timeUsed.string()}`, ) }) } @@ -141,8 +139,7 @@ export class HieroClient { this.pendingPromises.splice(pendingPromiseIndex, 1) }), ) - const endTime = new Date() - logger.info(`HieroClient.sendMessage used time: ${endTime.getTime() - startTime.getTime()}ms`) + logger.debug(`create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`) return hieroTransaction.transactionId } diff --git a/dlt-connector/src/config/const.ts b/dlt-connector/src/config/const.ts index dc4b0177c..5657f65ee 100644 --- a/dlt-connector/src/config/const.ts +++ b/dlt-connector/src/config/const.ts @@ -16,6 +16,7 @@ export const GRADIDO_NODE_RUNTIME_PATH = path.join( ) // 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_EXIT_MILLISECONDS = 1000 * 2 export const GRADIDO_NODE_KILL_TIMEOUT_MILLISECONDS = 10000 // currently hard coded in gradido node, update in future export const GRADIDO_NODE_HOME_FOLDER_NAME = '.gradido' diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 5ef946ec9..269bccada 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -104,7 +104,7 @@ async function sendViaHiero( if (!transactionId) { throw new Error('missing transaction id from hiero') } - logger.info('transmitted Gradido Transaction to Hiero', { + logger.debug('give Gradido Transaction to Hiero Client', { transactionId: transactionId.toString(), }) return v.parse(hieroTransactionIdStringSchema, transactionId.toString()) diff --git a/dlt-connector/src/utils/time.ts b/dlt-connector/src/utils/time.ts index ccbb91c07..4f69ebd98 100644 --- a/dlt-connector/src/utils/time.ts +++ b/dlt-connector/src/utils/time.ts @@ -1,3 +1,5 @@ +import { promisify } from 'node:util' + /** * @param {number} time - in minutes */ @@ -40,3 +42,5 @@ export const printTimeDuration = (duration: number): string => { } return result } + +export const delay = promisify(setTimeout) \ No newline at end of file From 7912c2517cc7e932d89972aafa481c482895500c Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:00:57 +0100 Subject: [PATCH 15/33] update versions of gradido node and gradido-blockchain-js --- dlt-connector/bun.lock | 4 ++-- dlt-connector/package.json | 2 +- dlt-connector/src/config/schema.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index 6f6fd84d4..fb882d0b9 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -4,7 +4,7 @@ "": { "name": "dlt-connector", "dependencies": { - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js", + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#f265dbb1780a912cf8b0418dfe3eaf5cdc5b51cf", }, "devDependencies": { "@biomejs/biome": "2.0.0", @@ -569,7 +569,7 @@ "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], - "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#8a0c7b0", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-8a0c7b0"], + "gradido-blockchain-js": ["gradido-blockchain-js@github:gradido/gradido-blockchain-js#f265dbb", { "dependencies": { "bindings": "^1.5.0", "nan": "^2.20.0", "node-addon-api": "^7.1.1", "node-gyp-build": "^4.8.1", "prebuildify": "git+https://github.com/einhornimmond/prebuildify#65d94455fab86b902c0d59bb9c06ac70470e56b2" } }, "gradido-gradido-blockchain-js-f265dbb"], "graphql": ["graphql@16.11.0", "", {}, "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index c4c6f1099..57302b3ab 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -18,7 +18,7 @@ "lint:fix": "biome check --error-on-warnings . --write" }, "dependencies": { - "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js" + "gradido-blockchain-js": "git+https://github.com/gradido/gradido-blockchain-js#f265dbb1780a912cf8b0418dfe3eaf5cdc5b51cf" }, "devDependencies": { "@biomejs/biome": "2.0.0", diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 9131a3132..09eca49b2 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -84,7 +84,7 @@ export const configSchema = v.object({ v.string('The version of the DLT node server, for example: 0.9.0'), v.regex(/^\d+\.\d+\.\d+$/), ), - '0.9.0', + '0.9.1', ), DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( v.string('The home folder for the gradido dlt node server'), From 56e4d6387c096ebe786efef1c3c7f2dbf3a5d912 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:01:54 +0100 Subject: [PATCH 16/33] precision fixes for dlt migration and live transactions --- backend/src/apis/dltConnector/model/TransactionDraft.ts | 8 ++++++-- .../migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts | 1 + .../migrations/db-v2.7.0_to_blockchain-v3.5/database.ts | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/src/apis/dltConnector/model/TransactionDraft.ts b/backend/src/apis/dltConnector/model/TransactionDraft.ts index fdbce026f..0fae08297 100755 --- a/backend/src/apis/dltConnector/model/TransactionDraft.ts +++ b/backend/src/apis/dltConnector/model/TransactionDraft.ts @@ -91,11 +91,13 @@ export class TransactionDraft { if (!senderUserTopic) { throw new Error(`missing topicId for community ${sendingUser.community.id}`) } + const createdAtOnlySeconds = transactionLink.createdAt + createdAtOnlySeconds.setMilliseconds(0) const draft = new TransactionDraft() draft.user = new AccountIdentifier(senderUserTopic, new CommunityAccountIdentifier(sendingUser.gradidoID)) draft.linkedUser = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.type = TransactionType.GRADIDO_DEFERRED_TRANSFER - draft.createdAt = transactionLink.createdAt.toISOString() + draft.createdAt = createdAtOnlySeconds.toISOString() draft.amount = transactionLink.amount.toString() draft.memo = transactionLink.memo draft.timeoutDuration = CODE_VALID_DAYS_DURATION * 24 * 60 * 60 @@ -117,11 +119,13 @@ export class TransactionDraft { if (!recipientUserTopic) { throw new Error(`missing topicId for community ${recipientUser.community.id}`) } + const createdAtOnlySeconds = createdAt + createdAtOnlySeconds.setMilliseconds(0) const draft = new TransactionDraft() draft.user = new AccountIdentifier(senderUserTopic, transactionLink.code) draft.linkedUser = new AccountIdentifier(recipientUserTopic, new CommunityAccountIdentifier(recipientUser.gradidoID)) draft.type = TransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER - draft.createdAt = createdAt.toISOString() + draft.createdAt = createdAtOnlySeconds.toISOString() draft.amount = amount return draft } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 38db2af38..273451e14 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -26,6 +26,7 @@ export const defaultHieroAccount = new HieroAccountId(0, 0, 2) function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemoryBlockchain, createdAtTimestamp: Timestamp): boolean { const transaction = builder.build() + // TOD: use actual transaction id if exist in dlt_transactions table const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index f66536c0a..459996642 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -3,7 +3,7 @@ import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { getLogger } from 'log4js' import { MySql2Database } from 'drizzle-orm/mysql2' import { communitiesTable, transactionLinksTable, transactionsTable, usersTable } from './drizzle.schema' -import { asc, sql, eq, isNotNull } from 'drizzle-orm' +import { asc, sql, eq, isNotNull, inArray } from 'drizzle-orm' import { alias } from 'drizzle-orm/mysql-core' import { GradidoUnit } from 'gradido-blockchain-js' import { @@ -70,6 +70,7 @@ export async function loadTransactions(db: MySql2Database, offset: number, count transactionLink: transactionLinksTable, }) .from(transactionsTable) + .where(inArray(transactionsTable.typeId, [TransactionTypeId.CREATION, TransactionTypeId.RECEIVE])) .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) .leftJoin(transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id)) @@ -102,6 +103,7 @@ export async function loadTransactions(db: MySql2Database, offset: number, count }) } catch (e) { if (e instanceof v.ValiError) { + logger.error(`table row: ${JSON.stringify(row, null, 2)}`) logger.error(v.flatten(e.issues)) } throw e From a7c3bab20e4b05a9539fb0947438626b6e84b596 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:07:24 +0100 Subject: [PATCH 17/33] fix lint --- dlt-connector/src/bootstrap/init.ts | 2 +- .../client/GradidoNode/GradidoNodeProcess.ts | 23 ++- .../src/client/GradidoNode/communities.ts | 9 +- dlt-connector/src/client/hiero/HieroClient.ts | 22 ++- dlt-connector/src/config/schema.ts | 10 +- .../src/data/KeyPairIdentifier.logic.ts | 4 +- .../resolveKeyPair/ResolveKeyPair.context.ts | 2 +- .../RedeemDeferredTransferTransaction.role.ts | 11 +- .../sendToHiero/SendToHiero.context.ts | 15 +- .../db-v2.7.0_to_blockchain-v3.5/Context.ts | 27 ++- .../binaryExport.ts | 53 ++++-- .../blockchain.ts | 152 +++++++++++---- .../db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 24 +-- .../db-v2.7.0_to_blockchain-v3.5/convert.ts | 65 +++++-- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 174 +++++++++++------- .../drizzle.schema.ts | 98 +++++----- .../db-v2.7.0_to_blockchain-v3.5/index.ts | 14 +- .../syncDbWithBlockchain/AbstractSync.role.ts | 17 +- .../DeletedTransactionLinksSync.role.ts | 4 +- .../TransactionLinksSync.role.ts | 7 +- .../TransactionsSync.role.ts | 23 ++- .../syncDbWithBlockchain/UsersSync.role.ts | 9 +- .../syncDbWithBlockchain.context.ts | 19 +- .../db-v2.7.0_to_blockchain-v3.5/keyPair.ts | 64 ++++--- .../db-v2.7.0_to_blockchain-v3.5/utils.ts | 2 +- .../valibot.schema.ts | 22 ++- .../src/schemas/typeConverter.schema.ts | 8 +- dlt-connector/src/utils/time.ts | 2 +- 28 files changed, 549 insertions(+), 333 deletions(-) diff --git a/dlt-connector/src/bootstrap/init.ts b/dlt-connector/src/bootstrap/init.ts index e0289db57..13b77783c 100644 --- a/dlt-connector/src/bootstrap/init.ts +++ b/dlt-connector/src/bootstrap/init.ts @@ -39,7 +39,7 @@ export async function checkHomeCommunity( // wait for backend server await isPortOpenRetry(backend.url) // ask backend for home community - let homeCommunity = await backend.getHomeCommunityDraft() + let homeCommunity = await backend.getHomeCommunityDraft() // on missing topicId, create one if (!homeCommunity.hieroTopicId) { const topicId = await hiero.createTopic(homeCommunity.name) diff --git a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts index 3980bb9f2..0eae2f37e 100644 --- a/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts +++ b/dlt-connector/src/client/GradidoNode/GradidoNodeProcess.ts @@ -1,3 +1,4 @@ +import { Mutex } from 'async-mutex' import { Subprocess, spawn } from 'bun' import { getLogger, Logger } from 'log4js' import { CONFIG } from '../../config' @@ -8,7 +9,6 @@ import { GRADIDO_NODE_RUNTIME_PATH, LOG4JS_BASE_CATEGORY, } from '../../config/const' -import { Mutex } from 'async-mutex' import { delay } from '../../utils/time' /** * A Singleton class defines the `getInstance` method that lets clients access @@ -94,11 +94,11 @@ export class GradidoNodeProcess { public async restart() { const release = await this.restartMutex.acquire() try { - if (this.proc) { - await this.exit() - this.exitCalled = false - this.start() - } + if (this.proc) { + await this.exit() + this.exitCalled = false + this.start() + } } finally { release() } @@ -111,8 +111,15 @@ export class GradidoNodeProcess { public async exit(): Promise { this.exitCalled = true if (this.proc) { - if (this.lastStarted && Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS) { - await delay(GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - Date.now() - this.lastStarted.getTime()) + if ( + this.lastStarted && + Date.now() - this.lastStarted.getTime() < GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS + ) { + await delay( + GRADIDO_NODE_MIN_RUNTIME_BEFORE_EXIT_MILLISECONDS - + Date.now() - + this.lastStarted.getTime(), + ) } this.proc.kill('SIGTERM') const timeout = setTimeout(() => { diff --git a/dlt-connector/src/client/GradidoNode/communities.ts b/dlt-connector/src/client/GradidoNode/communities.ts index 76384f847..a418255f7 100644 --- a/dlt-connector/src/client/GradidoNode/communities.ts +++ b/dlt-connector/src/client/GradidoNode/communities.ts @@ -66,7 +66,10 @@ export async function exportCommunities(homeFolder: string, client: BackendClien logger.info(`exported ${communitiesForDltNodeServer.length} communities to ${communitiesPath}`) } -export function checkCommunityAvailable(communityTopicIds: Set, homeFolder: string): boolean { +export function checkCommunityAvailable( + communityTopicIds: Set, + homeFolder: string, +): boolean { const communitiesPath = path.join(homeFolder, 'communities.json') if (!checkFileExist(communitiesPath)) { return false @@ -81,6 +84,8 @@ export function checkCommunityAvailable(communityTopicIds: Set, homeFol } } } - logger.debug(`community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`) + logger.debug( + `community not found for topic ids: ${communityTopicIds}, communities: ${JSON.stringify(communities, null, 2)}`, + ) return false } diff --git a/dlt-connector/src/client/hiero/HieroClient.ts b/dlt-connector/src/client/hiero/HieroClient.ts index f81da11c5..c32c4cbd7 100644 --- a/dlt-connector/src/client/hiero/HieroClient.ts +++ b/dlt-connector/src/client/hiero/HieroClient.ts @@ -21,10 +21,10 @@ import * as v from 'valibot' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' -import { type TopicInfoOutput, topicInfoSchema } from './output.schema' +import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' import { GradidoNodeClient } from '../GradidoNode/GradidoNodeClient' import { GradidoNodeProcess } from '../GradidoNode/GradidoNodeProcess' -import { durationInMinutesFromDates, printTimeDuration } from '../../utils/time' +import { type TopicInfoOutput, topicInfoSchema } from './output.schema' // https://docs.hedera.com/hedera/sdks-and-apis/hedera-api/consensus/consensusupdatetopic export const MIN_AUTORENEW_PERIOD = 6999999 //seconds export const MAX_AUTORENEW_PERIOD = 8000001 // seconds @@ -109,9 +109,13 @@ export class HieroClient { const process = GradidoNodeProcess.getInstance() const lastStarted = process.getLastStarted() if (lastStarted) { - const serverRunTime = printTimeDuration(durationInMinutesFromDates(lastStarted, new Date())) - this.logger.error(`transaction not found, restart GradidoNode after ${serverRunTime}`) - await GradidoNodeProcess.getInstance().restart() + const serverRunTime = printTimeDuration( + durationInMinutesFromDates(lastStarted, new Date()), + ) + this.logger.error( + `transaction not found, restart GradidoNode after ${serverRunTime}`, + ) + await GradidoNodeProcess.getInstance().restart() } else { this.logger.error('transaction not found, GradidoNode not running, start it') GradidoNodeProcess.getInstance().start() @@ -126,9 +130,7 @@ export class HieroClient { // only for logging sendResponse.getRecordWithSigner(this.wallet).then((record) => { logger.info(`message sent, cost: ${record.transactionFee.toString()}`) - logger.info( - `HieroClient.sendMessage used time (full process): ${timeUsed.string()}`, - ) + logger.info(`HieroClient.sendMessage used time (full process): ${timeUsed.string()}`) }) } }) @@ -139,7 +141,9 @@ export class HieroClient { this.pendingPromises.splice(pendingPromiseIndex, 1) }), ) - logger.debug(`create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`) + logger.debug( + `create transactionId: ${hieroTransaction.transactionId?.toString()}, used time: ${timeUsed.string()}`, + ) return hieroTransaction.transactionId } diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 09eca49b2..45ef83831 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -99,10 +99,7 @@ export const configSchema = v.object({ ), '4000', ), - MYSQL_HOST: v.optional( - v.string('The host of the database'), - 'localhost', - ), + MYSQL_HOST: v.optional(v.string('The host of the database'), 'localhost'), MYSQL_PORT: v.optional( v.pipe( v.string('The port of the database'), @@ -136,8 +133,5 @@ export const configSchema = v.object({ ), '', ), - MYSQL_DATABASE: v.optional( - v.string('The name of the database'), - 'gradido_community', - ), + MYSQL_DATABASE: v.optional(v.string('The name of the database'), 'gradido_community'), }) diff --git a/dlt-connector/src/data/KeyPairIdentifier.logic.ts b/dlt-connector/src/data/KeyPairIdentifier.logic.ts index 61f4d3cfb..3b6b71c6e 100644 --- a/dlt-connector/src/data/KeyPairIdentifier.logic.ts +++ b/dlt-connector/src/data/KeyPairIdentifier.logic.ts @@ -107,7 +107,9 @@ export class KeyPairIdentifierLogic { ) } const resultString = - this.identifier.communityTopicId + this.identifier.account.userUuid.replace(/-/g, '') + accountNr.toString() + this.identifier.communityTopicId + + this.identifier.account.userUuid.replace(/-/g, '') + + accountNr.toString() return new MemoryBlock(resultString).calculateHash().convertToHex() } } diff --git a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts index 21187602b..406463c4c 100644 --- a/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts +++ b/dlt-connector/src/interactions/resolveKeyPair/ResolveKeyPair.context.ts @@ -32,7 +32,7 @@ import { UserKeyPairRole } from './UserKeyPair.role' */ export async function ResolveKeyPair(input: KeyPairIdentifierLogic): Promise { const cache = KeyPairCacheManager.getInstance() - + return await cache.getKeyPair( input.getKey(), // function is called from cache manager, if key isn't currently cached diff --git a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts index 2f51f8f21..4615a4707 100644 --- a/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts +++ b/dlt-connector/src/interactions/sendToHiero/RedeemDeferredTransferTransaction.role.ts @@ -1,4 +1,9 @@ -import { ConfirmedTransaction, GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js' +import { + ConfirmedTransaction, + GradidoTransactionBuilder, + GradidoTransfer, + TransferAmount, +} from 'gradido-blockchain-js' import * as v from 'valibot' import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { @@ -42,7 +47,9 @@ export class RedeemDeferredTransferTransactionRole extends AbstractTransactionRo if (!senderPublicKey) { throw new Error("redeem deferred transfer: couldn't calculate sender public key") } - const deferredTransferBody = this.parentDeferredTransaction.getGradidoTransaction()?.getTransactionBody() + const deferredTransferBody = this.parentDeferredTransaction + .getGradidoTransaction() + ?.getTransactionBody() if (!deferredTransferBody) { throw new Error( "redeem deferred transfer: couldn't deserialize deferred transfer from Gradido Node", diff --git a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts index 269bccada..622addb28 100644 --- a/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts +++ b/dlt-connector/src/interactions/sendToHiero/SendToHiero.context.ts @@ -6,9 +6,9 @@ import { ValidateType_SINGLE, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import * as v from 'valibot' import { ensureCommunitiesAvailable } from '../../client/GradidoNode/communities' +import { GradidoNodeClient } from '../../client/GradidoNode/GradidoNodeClient' import { HieroClient } from '../../client/hiero/HieroClient' import { LOG4JS_BASE_CATEGORY } from '../../config/const' import { InputTransactionType } from '../../data/InputTransactionType.enum' @@ -25,6 +25,7 @@ import { identifierSeedSchema, } from '../../schemas/typeGuard.schema' import { isTopicStillOpen } from '../../utils/hiero' +import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' import { AbstractTransactionRole } from './AbstractTransaction.role' import { CommunityRootTransactionRole } from './CommunityRootTransaction.role' import { CreationTransactionRole } from './CreationTransaction.role' @@ -32,7 +33,6 @@ import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.r import { RedeemDeferredTransferTransactionRole } from './RedeemDeferredTransferTransaction.role' import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role' import { TransferTransactionRole } from './TransferTransaction.role' -import { LinkedTransactionKeyPairRole } from '../resolveKeyPair/LinkedTransactionKeyPair.role' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.interactions.sendToHiero.SendToHieroContext`) @@ -146,9 +146,11 @@ async function chooseCorrectRole( return new RegisterAddressTransactionRole(transaction) case InputTransactionType.GRADIDO_DEFERRED_TRANSFER: return new DeferredTransferTransactionRole(transaction) - case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: + case InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER: { // load deferred transfer transaction from gradido node - const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const seedKeyPairRole = new LinkedTransactionKeyPairRole( + v.parse(identifierSeedSchema, transaction.user.seed), + ) const seedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() if (!seedPublicKey) { throw new Error("redeem deferred transfer: couldn't generate seed public key") @@ -158,9 +160,12 @@ async function chooseCorrectRole( seedPublicKey.convertToHex(), ) if (!transactions || transactions.length !== 1) { - throw new Error("redeem deferred transfer: couldn't find exactly one deferred transfer on Gradido Node") + throw new Error( + "redeem deferred transfer: couldn't find exactly one deferred transfer on Gradido Node", + ) } return new RedeemDeferredTransferTransactionRole(transaction, transactions[0]) + } default: throw new Error('not supported transaction type: ' + transaction.type) } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts index 9eb549a30..58400a615 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/Context.ts @@ -1,17 +1,15 @@ +import { heapStats } from 'bun:jsc' import { drizzle, MySql2Database } from 'drizzle-orm/mysql2' -import mysql from 'mysql2/promise' import { Filter, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' - -import { Uuidv4 } from '../../schemas/typeGuard.schema' - -import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' +import mysql from 'mysql2/promise' import { loadConfig } from '../../bootstrap/init' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { CONFIG } from '../../config' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { heapStats } from 'bun:jsc' -import { CommunityContext } from './valibot.schema' +import { Uuidv4 } from '../../schemas/typeGuard.schema' import { bytesToMbyte } from './utils' +import { CommunityContext } from './valibot.schema' export class Context { public logger: Logger @@ -36,12 +34,12 @@ export class Context { user: CONFIG.MYSQL_USER, password: CONFIG.MYSQL_PASSWORD, database: CONFIG.MYSQL_DATABASE, - port: CONFIG.MYSQL_PORT + port: CONFIG.MYSQL_PORT, }) return new Context( getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5`), - drizzle({ client: connection }), - KeyPairCacheManager.getInstance() + drizzle({ client: connection }), + KeyPairCacheManager.getInstance(), ) } @@ -57,18 +55,18 @@ export class Context { this.logger.info(`${this.timeUsed.string()} for synchronizing to blockchain`) const runtimeStats = heapStats() this.logger.info( - `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte` + `Memory Statistics: heap size: ${bytesToMbyte(runtimeStats.heapSize)} MByte, heap capacity: ${bytesToMbyte(runtimeStats.heapCapacity)} MByte, extra memory: ${bytesToMbyte(runtimeStats.extraMemorySize)} MByte`, ) } logBlogchain(communityUuid: Uuidv4) { const communityContext = this.getCommunityContextByUuid(communityUuid) - const f = new Filter() + const f = new Filter() f.pagination.size = 0 f.searchDirection = SearchDirection_ASC - + const transactions = communityContext.blockchain.findAll(f) - for(let i = 0; i < transactions.size(); i++) { + for (let i = 0; i < transactions.size(); i++) { const transaction = transactions.get(i) const confirmedTransaction = transaction?.getConfirmedTransaction() this.logger.info(confirmedTransaction?.toJson(true)) @@ -76,5 +74,4 @@ export class Context { } // TODO: move into utils - } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts index 74181f34f..474df61b8 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts @@ -1,21 +1,30 @@ -import { ConfirmedTransaction, Filter, InteractionSerialize, Profiler, SearchDirection_ASC } from 'gradido-blockchain-js' -import path from 'node:path' -import { CONFIG } from '../../config' import fs from 'node:fs' -import { bytesToKbyte } from './utils' -import { calculateOneHashStep } from './utils' +import path from 'node:path' +import { + ConfirmedTransaction, + Filter, + InteractionSerialize, + Profiler, + SearchDirection_ASC, +} from 'gradido-blockchain-js' +import { CONFIG } from '../../config' import { Context } from './Context' +import { bytesToKbyte, calculateOneHashStep } from './utils' import { CommunityContext } from './valibot.schema' export function exportAllCommunities(context: Context, batchSize: number) { const timeUsed = new Profiler() - for(const communityContext of context.communities.values()) { + for (const communityContext of context.communities.values()) { exportCommunity(communityContext, context, batchSize) } context.logger.info(`time used for exporting communities to binary file: ${timeUsed.string()}`) } -export function exportCommunity(communityContext: CommunityContext, context: Context, batchSize: number) { +export function exportCommunity( + communityContext: CommunityContext, + context: Context, + batchSize: number, +) { // write as binary file for GradidoNode const f = new Filter() f.pagination.size = batchSize @@ -28,7 +37,7 @@ export function exportCommunity(communityContext: CommunityContext, context: Con do { const transactions = communityContext.blockchain.findAll(f) lastTransactionCount = transactions.size() - + for (let i = 0; i < lastTransactionCount; i++) { const confirmedTransaction = transactions.get(i)?.getConfirmedTransaction() const transactionNr = f.pagination.page * batchSize + i @@ -39,22 +48,30 @@ export function exportCommunity(communityContext: CommunityContext, context: Con } f.pagination.page++ } while (lastTransactionCount === batchSize) - + fs.appendFileSync(binFilePath, hash!) - context.logger.info(`binary file for community ${communityContext.communityId} written to ${binFilePath}`) context.logger.info( - `transactions count: ${(f.pagination.page - 1) * batchSize + lastTransactionCount}, size: ${bytesToKbyte(fs.statSync(binFilePath).size)} KByte` + `binary file for community ${communityContext.communityId} written to ${binFilePath}`, + ) + context.logger.info( + `transactions count: ${(f.pagination.page - 1) * batchSize + lastTransactionCount}, size: ${bytesToKbyte(fs.statSync(binFilePath).size)} KByte`, ) } -function exportTransaction(confirmedTransaction: ConfirmedTransaction, hash: Buffer, binFilePath: string): Buffer { - const sizeBuffer = Buffer.alloc(2) +function exportTransaction( + confirmedTransaction: ConfirmedTransaction, + hash: Buffer, + binFilePath: string, +): Buffer { + const sizeBuffer = Buffer.alloc(2) const interactionSerialize = new InteractionSerialize(confirmedTransaction) const binBlock = interactionSerialize.run() if (!binBlock) { - throw new Error(`invalid TransactionEntry at index: ${confirmedTransaction.getId()}, serialize into protobuf format failed`) + throw new Error( + `invalid TransactionEntry at index: ${confirmedTransaction.getId()}, serialize into protobuf format failed`, + ) } - + hash = calculateOneHashStep(hash, binBlock.data()) sizeBuffer.writeUInt16LE(binBlock.size(), 0) fs.appendFileSync(binFilePath, sizeBuffer) @@ -64,13 +81,13 @@ function exportTransaction(confirmedTransaction: ConfirmedTransaction, hash: Buf function prepareFolder(communityContext: CommunityContext): string { const binFileFolder = path.join( - CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, + CONFIG.DLT_GRADIDO_NODE_SERVER_HOME_FOLDER, '.gradido', communityContext.folder, ) const binFilePath = path.join(binFileFolder, 'blk00000001.dat') // make sure we work with a clean folder, rm beforehand with all content fs.rmSync(binFileFolder, { recursive: true }) - fs.mkdirSync(binFileFolder, { recursive: true }) + fs.mkdirSync(binFileFolder, { recursive: true }) return binFilePath -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts index 273451e14..fd89d5ea0 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/blockchain.ts @@ -1,37 +1,47 @@ -import { - InMemoryBlockchain, - GradidoTransactionBuilder, - Timestamp, - HieroTransactionId, - HieroAccountId, - InteractionSerialize, +import { Filter, + GradidoTransactionBuilder, + HieroAccountId, + HieroTransactionId, + InMemoryBlockchain, + InteractionSerialize, + Timestamp, } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' -import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' -import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' +import * as v from 'valibot' import { LOG4JS_BASE_CATEGORY } from '../../config/const' -import { Community, Transaction } from '../../schemas/transaction.schema' -import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' -import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' -import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' import { InputTransactionType } from '../../data/InputTransactionType.enum' import { LinkedTransactionKeyPairRole } from '../../interactions/resolveKeyPair/LinkedTransactionKeyPair.role' +import { CommunityRootTransactionRole } from '../../interactions/sendToHiero/CommunityRootTransaction.role' +import { CreationTransactionRole } from '../../interactions/sendToHiero/CreationTransaction.role' +import { DeferredTransferTransactionRole } from '../../interactions/sendToHiero/DeferredTransferTransaction.role' +import { RedeemDeferredTransferTransactionRole } from '../../interactions/sendToHiero/RedeemDeferredTransferTransaction.role' +import { RegisterAddressTransactionRole } from '../../interactions/sendToHiero/RegisterAddressTransaction.role' +import { TransferTransactionRole } from '../../interactions/sendToHiero/TransferTransaction.role' +import { Community, Transaction } from '../../schemas/transaction.schema' import { identifierSeedSchema } from '../../schemas/typeGuard.schema' -import * as v from 'valibot' -const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`) +const logger = getLogger( + `${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.blockchain`, +) export const defaultHieroAccount = new HieroAccountId(0, 0, 2) -function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemoryBlockchain, createdAtTimestamp: Timestamp): boolean { +function addToBlockchain( + builder: GradidoTransactionBuilder, + blockchain: InMemoryBlockchain, + createdAtTimestamp: Timestamp, +): boolean { const transaction = builder.build() // TOD: use actual transaction id if exist in dlt_transactions table const transactionId = new HieroTransactionId(createdAtTimestamp, defaultHieroAccount) const interactionSerialize = new InteractionSerialize(transactionId) try { - const result = blockchain.createAndAddConfirmedTransaction(transaction, interactionSerialize.run(), createdAtTimestamp) + const result = blockchain.createAndAddConfirmedTransaction( + transaction, + interactionSerialize.run(), + createdAtTimestamp, + ) return result } catch (error) { logger.error(`Transaction ${transaction.toJson(true)} not added: ${error}`) @@ -39,68 +49,130 @@ function addToBlockchain(builder: GradidoTransactionBuilder, blockchain: InMemor } } -export async function addCommunityRootTransaction(blockchain: InMemoryBlockchain, community: Community): Promise { +export async function addCommunityRootTransaction( + blockchain: InMemoryBlockchain, + community: Community, +): Promise { const communityRootTransactionRole = new CommunityRootTransactionRole(community) - if(addToBlockchain(await communityRootTransactionRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(community.creationDate))) { + if ( + addToBlockchain( + await communityRootTransactionRole.getGradidoTransactionBuilder(), + blockchain, + new Timestamp(community.creationDate), + ) + ) { logger.info(`Community Root Transaction added`) } else { throw new Error(`Community Root Transaction not added`) } } -export async function addRegisterAddressTransaction(blockchain: InMemoryBlockchain, transaction: Transaction): Promise { +export async function addRegisterAddressTransaction( + blockchain: InMemoryBlockchain, + transaction: Transaction, +): Promise { const registerAddressRole = new RegisterAddressTransactionRole(transaction) - if(addToBlockchain(await registerAddressRole.getGradidoTransactionBuilder(), blockchain, new Timestamp(transaction.createdAt))) { - logger.debug(`Register Address Transaction added for user ${transaction.user.account!.userUuid}`) + if ( + addToBlockchain( + await registerAddressRole.getGradidoTransactionBuilder(), + blockchain, + new Timestamp(transaction.createdAt), + ) + ) { + logger.debug( + `Register Address Transaction added for user ${transaction.user.account!.userUuid}`, + ) } else { - throw new Error(`Register Address Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error( + `Register Address Transaction not added for user ${transaction.user.account!.userUuid}`, + ) } } export async function addTransaction( senderBlockchain: InMemoryBlockchain, _recipientBlockchain: InMemoryBlockchain, - transaction: Transaction + transaction: Transaction, ): Promise { const createdAtTimestamp = new Timestamp(transaction.createdAt) if (transaction.type === InputTransactionType.GRADIDO_CREATION) { const creationTransactionRole = new CreationTransactionRole(transaction) - if(addToBlockchain(await creationTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + if ( + addToBlockchain( + await creationTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { logger.debug(`Creation Transaction added for user ${transaction.user.account!.userUuid}`) } else { - throw new Error(`Creation Transaction not added for user ${transaction.user.account!.userUuid}`) - } + throw new Error( + `Creation Transaction not added for user ${transaction.user.account!.userUuid}`, + ) + } } else if (transaction.type === InputTransactionType.GRADIDO_TRANSFER) { const transferTransactionRole = new TransferTransactionRole(transaction) // will crash with cross group transaction - if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + if ( + addToBlockchain( + await transferTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { logger.debug(`Transfer Transaction added for user ${transaction.user.account!.userUuid}`) } else { - throw new Error(`Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error( + `Transfer Transaction not added for user ${transaction.user.account!.userUuid}`, + ) } } else if (transaction.type === InputTransactionType.GRADIDO_DEFERRED_TRANSFER) { const transferTransactionRole = new DeferredTransferTransactionRole(transaction) - if(addToBlockchain(await transferTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { - logger.debug(`Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`) + if ( + addToBlockchain( + await transferTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { + logger.debug( + `Deferred Transfer Transaction added for user ${transaction.user.account!.userUuid}`, + ) } else { - - throw new Error(`Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`) + throw new Error( + `Deferred Transfer Transaction not added for user ${transaction.user.account!.userUuid}`, + ) } } else if (transaction.type === InputTransactionType.GRADIDO_REDEEM_DEFERRED_TRANSFER) { - const seedKeyPairRole = new LinkedTransactionKeyPairRole(v.parse(identifierSeedSchema, transaction.user.seed)) + const seedKeyPairRole = new LinkedTransactionKeyPairRole( + v.parse(identifierSeedSchema, transaction.user.seed), + ) const f = new Filter() f.involvedPublicKey = seedKeyPairRole.generateKeyPair().getPublicKey() const deferredTransaction = senderBlockchain.findOne(f) if (!deferredTransaction) { - throw new Error(`redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node for ${JSON.stringify(transaction, null, 2)} and public key from seed: ${f.involvedPublicKey?.convertToHex()}`) + throw new Error( + `redeem deferred transfer: couldn't find parent deferred transfer on Gradido Node for ${JSON.stringify(transaction, null, 2)} and public key from seed: ${f.involvedPublicKey?.convertToHex()}`, + ) } const confirmedDeferredTransaction = deferredTransaction.getConfirmedTransaction() if (!confirmedDeferredTransaction) { - throw new Error("redeem deferred transfer: invalid TransactionEntry") + throw new Error('redeem deferred transfer: invalid TransactionEntry') } - const redeemTransactionRole = new RedeemDeferredTransferTransactionRole(transaction, confirmedDeferredTransaction) - const involvedUser = transaction.user.account ? transaction.user.account.userUuid : transaction.linkedUser?.account?.userUuid - if(addToBlockchain(await redeemTransactionRole.getGradidoTransactionBuilder(), senderBlockchain, createdAtTimestamp)) { + const redeemTransactionRole = new RedeemDeferredTransferTransactionRole( + transaction, + confirmedDeferredTransaction, + ) + const involvedUser = transaction.user.account + ? transaction.user.account.userUuid + : transaction.linkedUser?.account?.userUuid + if ( + addToBlockchain( + await redeemTransactionRole.getGradidoTransactionBuilder(), + senderBlockchain, + createdAtTimestamp, + ) + ) { logger.debug(`Redeem Deferred Transfer Transaction added for user ${involvedUser}`) } else { throw new Error(`Redeem Deferred Transfer Transaction not added for user ${involvedUser}`) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index ef792e8d6..c613eb655 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -1,11 +1,11 @@ -import { Context } from './Context' -import { loadCommunities } from './database' -import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' -import * as v from 'valibot' import { InMemoryBlockchainProvider } from 'gradido-blockchain-js' -import { generateKeyPairCommunity } from './keyPair' -import { communityDbToCommunity } from './convert' +import * as v from 'valibot' +import { HieroId, hieroIdSchema } from '../../schemas/typeGuard.schema' import { addCommunityRootTransaction } from './blockchain' +import { Context } from './Context' +import { communityDbToCommunity } from './convert' +import { loadCommunities } from './database' +import { generateKeyPairCommunity } from './keyPair' import { CommunityContext } from './valibot.schema' export async function bootstrap(): Promise { @@ -18,18 +18,20 @@ async function bootstrapCommunities(context: Context): Promise() const communitiesDb = await loadCommunities(context.db) const topicIds = new Set() - + for (const communityDb of communitiesDb) { - const blockchain = InMemoryBlockchainProvider.getInstance().findBlockchain(communityDb.uniqueAlias) + const blockchain = InMemoryBlockchainProvider.getInstance().findBlockchain( + communityDb.uniqueAlias, + ) if (!blockchain) { throw new Error(`Couldn't create Blockchain for community ${communityDb.communityUuid}`) } context.logger.info(`Blockchain for community '${communityDb.uniqueAlias}' created`) // make sure topic id is unique - let topicId: HieroId + let topicId: HieroId do { topicId = v.parse(hieroIdSchema, '0.0.' + Math.floor(Math.random() * 10000)) - } while(topicIds.has(topicId)) + } while (topicIds.has(topicId)) topicIds.add(topicId) communities.set(communityDb.communityUuid, { @@ -38,7 +40,7 @@ async function bootstrapCommunities(context: Context): Promise { - const result = await db.select({ - foreign: communitiesTable.foreign, - communityUuid: communitiesTable.communityUuid, - name: communitiesTable.name, - creationDate: communitiesTable.creationDate, - userMinCreatedAt: sql`MIN(${usersTable.createdAt})`, - }) - .from(communitiesTable) - .leftJoin(usersTable, eq(communitiesTable.communityUuid, usersTable.communityUuid)) - .where(isNotNull(communitiesTable.communityUuid)) - .groupBy(communitiesTable.communityUuid) + const result = await db + .select({ + foreign: communitiesTable.foreign, + communityUuid: communitiesTable.communityUuid, + name: communitiesTable.name, + creationDate: communitiesTable.creationDate, + userMinCreatedAt: sql`MIN(${usersTable.createdAt})`, + }) + .from(communitiesTable) + .leftJoin(usersTable, eq(communitiesTable.communityUuid, usersTable.communityUuid)) + .where(isNotNull(communitiesTable.communityUuid)) + .groupBy(communitiesTable.communityUuid) const communityNames = new Set() return result.map((row: any) => { @@ -49,33 +57,50 @@ export async function loadCommunities(db: MySql2Database): Promise { - const result = await db.select() - .from(usersTable) - .orderBy(asc(usersTable.createdAt)) - .limit(count).offset(offset) +export async function loadUsers( + db: MySql2Database, + offset: number, + count: number, +): Promise { + const result = await db + .select() + .from(usersTable) + .orderBy(asc(usersTable.createdAt)) + .limit(count) + .offset(offset) return result.map((row: any) => { return v.parse(createdUserDbSchema, row) }) } -export async function loadTransactions(db: MySql2Database, offset: number, count: number): Promise { +export async function loadTransactions( + db: MySql2Database, + offset: number, + count: number, +): Promise { const linkedUsers = alias(usersTable, 'linkedUser') - - const result = await db.select({ - transaction: transactionsTable, - user: usersTable, - linkedUser: linkedUsers, - transactionLink: transactionLinksTable, - }) - .from(transactionsTable) - .where(inArray(transactionsTable.typeId, [TransactionTypeId.CREATION, TransactionTypeId.RECEIVE])) - .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) - .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) - .leftJoin(transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id)) - .orderBy(asc(transactionsTable.balanceDate)) - .limit(count).offset(offset) + + const result = await db + .select({ + transaction: transactionsTable, + user: usersTable, + linkedUser: linkedUsers, + transactionLink: transactionLinksTable, + }) + .from(transactionsTable) + .where( + inArray(transactionsTable.typeId, [TransactionTypeId.CREATION, TransactionTypeId.RECEIVE]), + ) + .leftJoin(usersTable, eq(transactionsTable.userId, usersTable.id)) + .leftJoin(linkedUsers, eq(transactionsTable.linkedUserId, linkedUsers.id)) + .leftJoin( + transactionLinksTable, + eq(transactionsTable.transactionLinkId, transactionLinksTable.id), + ) + .orderBy(asc(transactionsTable.balanceDate)) + .limit(count) + .offset(offset) return result.map((row: any) => { // console.log(row) @@ -83,13 +108,14 @@ export async function loadTransactions(db: MySql2Database, offset: number, count const userCreatedAt = new Date(row.user.createdAt) const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) const balanceDate = new Date(row.transaction.balanceDate) - if (userCreatedAt.getTime() > balanceDate.getTime() || - linkedUserCreatedAd.getTime() > balanceDate.getTime() - ){ + if ( + userCreatedAt.getTime() > balanceDate.getTime() || + linkedUserCreatedAd.getTime() > balanceDate.getTime() + ) { logger.error(`table row: `, row) throw new Error('at least one user was created after transaction balance date, logic error!') } - + let amount = GradidoUnit.fromString(row.transaction.amount) if (row.transaction.typeId === TransactionTypeId.SEND) { amount = amount.mul(new GradidoUnit(-1)) @@ -111,12 +137,18 @@ export async function loadTransactions(db: MySql2Database, offset: number, count }) } -export async function loadTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { - const result = await db.select() - .from(transactionLinksTable) - .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) - .orderBy(asc(transactionLinksTable.createdAt)) - .limit(count).offset(offset) +export async function loadTransactionLinks( + db: MySql2Database, + offset: number, + count: number, +): Promise { + const result = await db + .select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .orderBy(asc(transactionLinksTable.createdAt)) + .limit(count) + .offset(offset) return result.map((row: any) => { return v.parse(transactionLinkDbSchema, { @@ -126,23 +158,29 @@ export async function loadTransactionLinks(db: MySql2Database, offset: number, c }) } -export async function loadDeletedTransactionLinks(db: MySql2Database, offset: number, count: number): Promise { - const result = await db.select() - .from(transactionLinksTable) - .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) - .where(isNotNull(transactionLinksTable.deletedAt)) - .orderBy(asc(transactionLinksTable.deletedAt)) - .limit(count).offset(offset) +export async function loadDeletedTransactionLinks( + db: MySql2Database, + offset: number, + count: number, +): Promise { + const result = await db + .select() + .from(transactionLinksTable) + .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) + .where(isNotNull(transactionLinksTable.deletedAt)) + .orderBy(asc(transactionLinksTable.deletedAt)) + .limit(count) + .offset(offset) return result.map((row: any) => { return v.parse(transactionDbSchema, { typeId: TransactionTypeId.RECEIVE, - amount: row.transaction_links.amount, + amount: row.transaction_links.amount, balanceDate: new Date(row.transaction_links.deletedAt), memo: row.transaction_links.memo, transactionLinkCode: row.transaction_links.code, user: row.users, - linkedUser: row.users + linkedUser: row.users, }) }) -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts index f96b71bfe..59cc6573c 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -1,50 +1,66 @@ - -import { mysqlTable, unique, int, varchar, char, datetime, tinyint, decimal, index } from 'drizzle-orm/mysql-core' import { sql } from 'drizzle-orm' +import { + char, + datetime, + decimal, + index, + int, + mysqlTable, + tinyint, + unique, + varchar, +} from 'drizzle-orm/mysql-core' // use only fields needed in the migration, after update the rest of the project, import database instead -export const communitiesTable = mysqlTable('communities', { - foreign: tinyint().default(1).notNull(), - communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), - name: varchar({ length: 40 }).default(sql`NULL`), - creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), -}, -(table) => [ - unique('uuid_key').on(table.communityUuid), -]) +export const communitiesTable = mysqlTable( + 'communities', + { + foreign: tinyint().default(1).notNull(), + communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), + name: varchar({ length: 40 }).default(sql`NULL`), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), + }, + (table) => [unique('uuid_key').on(table.communityUuid)], +) -export const usersTable = mysqlTable('users', { - id: int().autoincrement().notNull(), - gradidoId: char('gradido_id', { length: 36 }).notNull(), - communityUuid: varchar('community_uuid', { length: 36 }).default(sql`NULL`), - 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 usersTable = mysqlTable( + 'users', + { + id: int().autoincrement().notNull(), + gradidoId: char('gradido_id', { length: 36 }).notNull(), + communityUuid: varchar('community_uuid', { length: 36 }).default(sql`NULL`), + 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 transactionsTable = mysqlTable('transactions', { - id: int().autoincrement().notNull(), - typeId: int('type_id').default(sql`NULL`), - transactionLinkId: int('transaction_link_id').default(sql`NULL`), - amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), - balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 }).default(sql`current_timestamp(3)`).notNull(), - memo: varchar({ length: 255 }).notNull(), - creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), - userId: int('user_id').notNull(), - linkedUserId: int('linked_user_id').default(sql`NULL`), -}, -(table) => [ - index('user_id').on(table.userId), -]) +export const transactionsTable = mysqlTable( + 'transactions', + { + id: int().autoincrement().notNull(), + typeId: int('type_id').default(sql`NULL`), + transactionLinkId: int('transaction_link_id').default(sql`NULL`), + amount: decimal({ precision: 40, scale: 20 }).default(sql`NULL`), + balanceDate: datetime('balance_date', { mode: 'string', fsp: 3 }) + .default(sql`current_timestamp(3)`) + .notNull(), + memo: varchar({ length: 255 }).notNull(), + creationDate: datetime('creation_date', { mode: 'string', fsp: 3 }).default(sql`NULL`), + userId: int('user_id').notNull(), + linkedUserId: int('linked_user_id').default(sql`NULL`), + }, + (table) => [index('user_id').on(table.userId)], +) export const transactionLinksTable = mysqlTable('transaction_links', { - id: int().autoincrement().notNull(), + id: int().autoincrement().notNull(), userId: int().notNull(), - amount: decimal({ 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(), + amount: decimal({ 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(), }) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts index 5bae06fee..875c59eba 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/index.ts @@ -1,8 +1,8 @@ -import { bootstrap } from './bootstrap' -import { onShutdown } from '../../../../shared/src/helper/onShutdown' -import { syncDbWithBlockchainContext } from './interaction/syncDbWithBlockchain/syncDbWithBlockchain.context' -import { exportAllCommunities } from './binaryExport' import { Filter } 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' const BATCH_SIZE = 100 @@ -11,11 +11,11 @@ async function main() { const context = await bootstrap() onShutdown(async (reason, error) => { context.logger.info(`shutdown reason: ${reason}`) - if(error) { + if (error) { context.logger.error(error) } }) - + // synchronize to in memory blockchain await syncDbWithBlockchainContext(context, BATCH_SIZE) @@ -33,4 +33,4 @@ main().catch((e) => { // biome-ignore lint/suspicious/noConsole: maybe logger isn't initialized here console.error(e) process.exit(1) -}) \ No newline at end of file +}) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts index 44fd0b471..90523fa1b 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/AbstractSync.role.ts @@ -1,7 +1,7 @@ -import { Context } from '../../Context' +import { Profiler } from 'gradido-blockchain-js' import { getLogger, Logger } from 'log4js' import { LOG4JS_BASE_CATEGORY } from '../../../../config/const' -import { Profiler } from 'gradido-blockchain-js' +import { Context } from '../../Context' export abstract class AbstractSyncRole { private items: T[] = [] @@ -9,17 +9,18 @@ export abstract class AbstractSyncRole { protected logger: Logger constructor(protected readonly context: Context) { - this.logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`) + this.logger = getLogger( + `${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.5.interaction.syncDbWithBlockchain`, + ) } abstract getDate(): Date abstract loadFromDb(offset: number, count: number): Promise abstract pushToBlockchain(item: T): Promise abstract itemTypeName(): string - + // return count of new loaded items - async ensureFilled(batchSize: number): Promise - { + async ensureFilled(batchSize: number): Promise { if (this.items.length === 0) { let timeUsed: Profiler | undefined if (this.logger.isDebugEnabled()) { @@ -28,7 +29,9 @@ export abstract class AbstractSyncRole { this.items = await this.loadFromDb(this.offset, batchSize) this.offset += this.items.length if (timeUsed && this.items.length) { - this.logger.debug(`${timeUsed.string()} for loading ${this.items.length} ${this.itemTypeName()} from db`) + this.logger.debug( + `${timeUsed.string()} for loading ${this.items.length} ${this.itemTypeName()} from db`, + ) } return this.items.length } diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts index 2ff3961b1..fd1ae225f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/DeletedTransactionLinksSync.role.ts @@ -1,6 +1,6 @@ import { loadDeletedTransactionLinks } from '../../database' -import { TransactionsSyncRole } from './TransactionsSync.role' import { TransactionDb } from '../../valibot.schema' +import { TransactionsSyncRole } from './TransactionsSync.role' export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { itemTypeName(): string { @@ -10,4 +10,4 @@ export class DeletedTransactionLinksSyncRole extends TransactionsSyncRole { async loadFromDb(offset: number, count: number): Promise { return await loadDeletedTransactionLinks(this.context.db, offset, count) } -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts index 30706dba3..847be89ba 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/TransactionLinksSync.role.ts @@ -1,7 +1,7 @@ -import { TransactionLinkDb } from '../../valibot.schema' -import { loadTransactionLinks } from '../../database' -import { transactionLinkDbToTransaction } from '../../convert' import { addTransaction } from '../../blockchain' +import { transactionLinkDbToTransaction } from '../../convert' +import { loadTransactionLinks } from '../../database' +import { TransactionLinkDb } from '../../valibot.schema' import { AbstractSyncRole } from './AbstractSync.role' export class TransactionLinksSyncRole extends AbstractSyncRole { @@ -23,4 +23,3 @@ export class TransactionLinksSyncRole extends AbstractSyncRole { @@ -19,10 +19,19 @@ export class TransactionsSyncRole extends AbstractSyncRole { async pushToBlockchain(item: TransactionDb): Promise { const senderCommunityContext = this.context.getCommunityContextByUuid(item.user.communityUuid) - const recipientCommunityContext = this.context.getCommunityContextByUuid(item.linkedUser.communityUuid) + const recipientCommunityContext = this.context.getCommunityContextByUuid( + item.linkedUser.communityUuid, + ) this.context.cache.setHomeCommunityTopicId(senderCommunityContext.topicId) - const transaction = transactionDbToTransaction(item, senderCommunityContext.topicId, recipientCommunityContext.topicId) - await addTransaction(senderCommunityContext.blockchain, recipientCommunityContext.blockchain, transaction) + const transaction = transactionDbToTransaction( + item, + senderCommunityContext.topicId, + recipientCommunityContext.topicId, + ) + await addTransaction( + senderCommunityContext.blockchain, + recipientCommunityContext.blockchain, + transaction, + ) } } - \ No newline at end of file diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts index acdf5011d..d6b40938f 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/UsersSync.role.ts @@ -1,10 +1,9 @@ -import { CreatedUserDb } from '../../valibot.schema' -import { AbstractSyncRole } from './AbstractSync.role' +import { addRegisterAddressTransaction } from '../../blockchain' +import { userDbToTransaction } from '../../convert' import { loadUsers } from '../../database' import { generateKeyPairUserAccount } from '../../keyPair' -import { userDbToTransaction } from '../../convert' -import { addRegisterAddressTransaction } from '../../blockchain' - +import { CreatedUserDb } from '../../valibot.schema' +import { AbstractSyncRole } from './AbstractSync.role' export class UsersSyncRole extends AbstractSyncRole { getDate(): Date { diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts index edef30caa..e67cd70da 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/interaction/syncDbWithBlockchain/syncDbWithBlockchain.context.ts @@ -1,8 +1,8 @@ -import { Context } from '../../Context' import { Profiler } from 'gradido-blockchain-js' -import { TransactionsSyncRole } from './TransactionsSync.role' +import { Context } from '../../Context' import { DeletedTransactionLinksSyncRole } from './DeletedTransactionLinksSync.role' import { TransactionLinksSyncRole } from './TransactionLinksSync.role' +import { TransactionsSyncRole } from './TransactionsSync.role' import { UsersSyncRole } from './UsersSync.role' export async function syncDbWithBlockchainContext(context: Context, batchSize: number) { @@ -11,20 +11,20 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n new UsersSyncRole(context), new TransactionsSyncRole(context), new DeletedTransactionLinksSyncRole(context), - new TransactionLinksSyncRole(context) - ] + new TransactionLinksSyncRole(context), + ] - while (true) { - timeUsed.reset() - const results = await Promise.all(containers.map(c => c.ensureFilled(batchSize))) + while (true) { + timeUsed.reset() + const results = await Promise.all(containers.map((c) => c.ensureFilled(batchSize))) const loadedItemsCount = results.reduce((acc, c) => acc + c, 0) // log only, if at least one new item was loaded if (loadedItemsCount && context.logger.isInfoEnabled()) { context.logger.info(`${loadedItemsCount} new items loaded from db in ${timeUsed.string()}`) } - + // remove empty containers - const available = containers.filter(c => !c.isEmpty()) + const available = containers.filter((c) => !c.isEmpty()) if (available.length === 0) { break } @@ -36,4 +36,3 @@ export async function syncDbWithBlockchainContext(context: Context, batchSize: n await available[0].toBlockchain() } } - diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts index dda017cbd..b3432da80 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/keyPair.ts @@ -1,17 +1,21 @@ -import { CommunityDb, UserDb } from './valibot.schema' -import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' -import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { KeyPairEd25519, MemoryBlock, MemoryBlockPtr } from 'gradido-blockchain-js' import { getLogger } from 'log4js' -import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { KeyPairCacheManager } from '../../cache/KeyPairCacheManager' import { CONFIG } from '../../config' -import { HieroId } from '../../schemas/typeGuard.schema' -import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { LOG4JS_BASE_CATEGORY } from '../../config/const' +import { KeyPairIdentifierLogic } from '../../data/KeyPairIdentifier.logic' import { AccountKeyPairRole } from '../../interactions/resolveKeyPair/AccountKeyPair.role' +import { UserKeyPairRole } from '../../interactions/resolveKeyPair/UserKeyPair.role' +import { HieroId } from '../../schemas/typeGuard.schema' +import { CommunityDb, UserDb } from './valibot.schema' const logger = getLogger(`${LOG4JS_BASE_CATEGORY}.migrations.db-v2.7.0_to_blockchain-v3.6.keyPair`) -export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairCacheManager, topicId: HieroId): void { +export function generateKeyPairCommunity( + community: CommunityDb, + cache: KeyPairCacheManager, + topicId: HieroId, +): void { let seed: MemoryBlock | null = null if (community.foreign) { const randomBuffer = Buffer.alloc(32) @@ -32,33 +36,37 @@ export function generateKeyPairCommunity(community: CommunityDb, cache: KeyPairC } export async function generateKeyPairUserAccount( - user: UserDb, - cache: KeyPairCacheManager, - communityTopicId: HieroId -): Promise<{userKeyPair: MemoryBlockPtr, accountKeyPair: MemoryBlockPtr}> { + user: UserDb, + cache: KeyPairCacheManager, + communityTopicId: HieroId, +): Promise<{ userKeyPair: MemoryBlockPtr; accountKeyPair: MemoryBlockPtr }> { const communityKeyPair = cache.findKeyPair(communityTopicId)! const userKeyPairRole = new UserKeyPairRole(user.gradidoId, communityKeyPair) - const userKeyPairKey = new KeyPairIdentifierLogic({ - communityTopicId: communityTopicId, + const userKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, account: { userUuid: user.gradidoId, - accountNr: 0 - } - }).getKey() - const userKeyPair = await cache.getKeyPair(userKeyPairKey, () => Promise.resolve(userKeyPairRole.generateKeyPair())) - - const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) - const accountKeyPairKey = new KeyPairIdentifierLogic({ - communityTopicId: communityTopicId, - account: { - userUuid: user.gradidoId, - accountNr: 1 - } + accountNr: 0, + }, }).getKey() - const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => Promise.resolve(accountKeyPairRole.generateKeyPair())) + const userKeyPair = await cache.getKeyPair(userKeyPairKey, () => + Promise.resolve(userKeyPairRole.generateKeyPair()), + ) + + const accountKeyPairRole = new AccountKeyPairRole(1, userKeyPair) + const accountKeyPairKey = new KeyPairIdentifierLogic({ + communityTopicId: communityTopicId, + account: { + userUuid: user.gradidoId, + accountNr: 1, + }, + }).getKey() + const accountKeyPair = await cache.getKeyPair(accountKeyPairKey, () => + Promise.resolve(accountKeyPairRole.generateKeyPair()), + ) //logger.info(`Key Pairs for user and account added, user: ${userKeyPairKey}, account: ${accountKeyPairKey}`) return { userKeyPair: userKeyPair.getPublicKey()!, - accountKeyPair: accountKeyPair.getPublicKey()! + accountKeyPair: accountKeyPair.getPublicKey()!, } -} \ No newline at end of file +} diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts index 57ae73137..c9b4eccb9 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/utils.ts @@ -12,4 +12,4 @@ export function calculateOneHashStep(hash: Buffer, data: Buffer): Buffer= 1'), v.maxLength(255, 'expect string length <= 255'), - v.regex(/^[a-zA-Z0-9-_]+$/, - 'expect string to be a valid (alphanumeric, _, -) folder name'), + v.regex(/^[a-zA-Z0-9-_]+$/, 'expect string to be a valid (alphanumeric, _, -) folder name'), ), }) @@ -63,4 +67,4 @@ export type UserDb = v.InferOutput export type CreatedUserDb = v.InferOutput export type TransactionLinkDb = v.InferOutput export type CommunityDb = v.InferOutput -export type CommunityContext = v.InferOutput \ No newline at end of file +export type CommunityContext = v.InferOutput diff --git a/dlt-connector/src/schemas/typeConverter.schema.ts b/dlt-connector/src/schemas/typeConverter.schema.ts index d5ca78ea3..8774bd6c2 100644 --- a/dlt-connector/src/schemas/typeConverter.schema.ts +++ b/dlt-connector/src/schemas/typeConverter.schema.ts @@ -29,10 +29,14 @@ export const dateSchema = v.pipe( ) export const booleanSchema = v.pipe( - v.union([v.boolean('expect boolean type'), v.number('expect boolean number type'), v.string('expect boolean string type')]), + v.union([ + v.boolean('expect boolean type'), + v.number('expect boolean number type'), + v.string('expect boolean string type'), + ]), v.transform((input) => { if (typeof input === 'number') { - return input != 0 + return input !== 0 } else if (typeof input === 'string') { return input === 'true' } diff --git a/dlt-connector/src/utils/time.ts b/dlt-connector/src/utils/time.ts index 4f69ebd98..6ec73a661 100644 --- a/dlt-connector/src/utils/time.ts +++ b/dlt-connector/src/utils/time.ts @@ -43,4 +43,4 @@ export const printTimeDuration = (duration: number): string => { return result } -export const delay = promisify(setTimeout) \ No newline at end of file +export const delay = promisify(setTimeout) From d244cc6b1dc51e0118f7c637a5382cabcde12b72 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:11:23 +0100 Subject: [PATCH 18/33] bug fix --- .../sendToHiero/RegisterAddressTransaction.role.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts index 7bb6e1140..ab07a2f83 100644 --- a/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts +++ b/dlt-connector/src/interactions/sendToHiero/RegisterAddressTransaction.role.test.ts @@ -32,7 +32,7 @@ describe('RegisterAddressTransaction.role', () => { const gradidoTransaction = builder.build() expect(() => new InteractionValidate(gradidoTransaction).run(ValidateType_SINGLE)).not.toThrow() const json = JSON.parse(gradidoTransaction.toJson(true)) - expect(json.bodyBytes.json.registerAddress.nameHash).toBe( + expect(json.bodyBytes.registerAddress.nameHash).toBe( 'bac2c06682808947f140d6766d02943761d4129ec055bb1f84dc3a4201a94c08', ) }) From 842e8be5106757be97242387e52e6afc5d3f3041 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 12:35:53 +0100 Subject: [PATCH 19/33] update inspector> --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index c7fc92da3..c04199a4c 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit c7fc92da31e80a27558d3887543446079dc55b5e +Subproject commit c04199a4cb88d72a515de2cdc571b634dc2dce99 From 9f9b4aad35e4341b83aa0e0452c89f723f16853e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:03:43 +0100 Subject: [PATCH 20/33] fix Dockerfile --- dlt-connector/Dockerfile | 3 ++- dlt-connector/bun.lock | 6 ++++++ dlt-connector/package.json | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/dlt-connector/Dockerfile b/dlt-connector/Dockerfile index 234c1df91..ecbcce596 100644 --- a/dlt-connector/Dockerfile +++ b/dlt-connector/Dockerfile @@ -74,6 +74,7 @@ CMD /bin/sh -c "cd dlt-connector && bun install --no-cache --frozen-lockfile && ################################################################################## FROM base as base-src COPY --chown=app:app ./dlt-connector ./dlt-connector +COPY --chown=app:app ./shared/src ./shared/src ################################################################################## # Build ########################################################################## @@ -81,7 +82,7 @@ COPY --chown=app:app ./dlt-connector ./dlt-connector FROM base-src as build RUN cd dlt-connector && bun install --no-cache --frozen-lockfile -RUN cd dlt-connector && bun typecheck && bun run build +RUN cd dlt-connector && bun run build ################################################################################## # TEST ########################################################################### diff --git a/dlt-connector/bun.lock b/dlt-connector/bun.lock index fb882d0b9..1d12dcaf3 100644 --- a/dlt-connector/bun.lock +++ b/dlt-connector/bun.lock @@ -13,6 +13,8 @@ "@sinclair/typemap": "^0.10.1", "@types/adm-zip": "^0.5.7", "@types/bun": "^1.2.17", + "@types/log4js": "^2.3.5", + "@types/sodium-native": "^2.3.9", "@types/uuid": "^8.3.4", "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", @@ -277,10 +279,14 @@ "@types/istanbul-reports": ["@types/istanbul-reports@3.0.4", "", { "dependencies": { "@types/istanbul-lib-report": "*" } }, "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ=="], + "@types/log4js": ["@types/log4js@2.3.5", "", { "dependencies": { "log4js": "*" } }, "sha512-SwF8LkSHqHy9A8GQ67NAYJiGl8zzP4Qtx65Wa+IOxDGdMHxKeoQZjg7m2M1erIT6VK0DYHpu2aTbdLkdkuMHjw=="], + "@types/node": ["@types/node@24.9.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg=="], "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], + "@types/sodium-native": ["@types/sodium-native@2.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-jZIg5ltGH1okmnH3FrLQsgwjcjOVozMSHwSiEm1/LpMekhOMHbQqp21P4H24mizh1BjwI6Q8qmphmD/HJuAqWg=="], + "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], "@types/uuid": ["@types/uuid@8.3.4", "", {}, "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw=="], diff --git a/dlt-connector/package.json b/dlt-connector/package.json index 57302b3ab..4c90e7b5b 100644 --- a/dlt-connector/package.json +++ b/dlt-connector/package.json @@ -27,6 +27,8 @@ "@sinclair/typemap": "^0.10.1", "@types/adm-zip": "^0.5.7", "@types/bun": "^1.2.17", + "@types/log4js": "^2.3.5", + "@types/sodium-native": "^2.3.9", "@types/uuid": "^8.3.4", "adm-zip": "^0.5.16", "async-mutex": "^0.5.0", From 5db014d9a3e7ec81bcba33c898099afb70f5296d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:25:30 +0100 Subject: [PATCH 21/33] fix github worker test --- .github/workflows/test_dlt_connector.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test_dlt_connector.yml b/.github/workflows/test_dlt_connector.yml index 3ba43063f..791d92586 100644 --- a/.github/workflows/test_dlt_connector.yml +++ b/.github/workflows/test_dlt_connector.yml @@ -58,7 +58,7 @@ jobs: bun-version-file: '.bun-version' - name: install dependencies - run: cd dlt-connector && bun install --frozen-lockfile + run: bun install --filter shared --frozen-lockfile && cd dlt-connector && bun install --frozen-lockfile - name: typecheck && unit test run: | From 703f77b848072b03d9b10b7e5452e9046cf15e45 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 13:39:15 +0100 Subject: [PATCH 22/33] use default version for gradido node version --- deployment/bare_metal/.env.dist | 1 - dlt-connector/.env.template | 1 - 2 files changed, 2 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index a0e449ac2..e5c86f789 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -94,7 +94,6 @@ DLT_CONNECTOR=false DLT_CONNECTOR_PORT=6010 DLT_NODE_SERVER_PORT=8340 DLT_NODE_SERVER_URL=$URL_PROTOCOL://$COMMUNITY_HOST/dlt -DLT_GRADIDO_NODE_SERVER_VERSION=0.9.0 DLT_GRADIDO_NODE_SERVER_HOME_FOLDER=/home/gradido/.gradido # used for combining a newsletter on klicktipp with this gradido community diff --git a/dlt-connector/.env.template b/dlt-connector/.env.template index 18dad36ee..fa5ea0007 100644 --- a/dlt-connector/.env.template +++ b/dlt-connector/.env.template @@ -9,7 +9,6 @@ DLT_CONNECTOR_PORT=$DLT_CONNECTOR_PORT # Gradido Node Server URL DLT_NODE_SERVER_PORT=$DLT_NODE_SERVER_PORT -DLT_GRADIDO_NODE_SERVER_VERSION=$DLT_GRADIDO_NODE_SERVER_VERSION HIERO_ACTIVE=$HIERO_ACTIVE HIERO_HEDERA_NETWORK=$HIERO_HEDERA_NETWORK From 0d8c5d2d199e7273d3a8b1778b4b4d1199c24884 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 14:23:47 +0100 Subject: [PATCH 23/33] update inspector --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index c04199a4c..69ca3baf0 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit c04199a4cb88d72a515de2cdc571b634dc2dce99 +Subproject commit 69ca3baf09d55f768b3949ef9b7e9a53c25e17a9 From 087a1f10700ede404db0dc1c77a995f507b785c2 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 14 Nov 2025 16:43:52 +0100 Subject: [PATCH 24/33] allow communties without users for migrate --- .../migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 7 +++++-- .../db-v2.7.0_to_blockchain-v3.5/valibot.schema.ts | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index c613eb655..05a80806c 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -42,8 +42,11 @@ async function bootstrapCommunities(context: Context): Promise Date: Fri, 14 Nov 2025 16:45:20 +0100 Subject: [PATCH 25/33] fix lint --- .../src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts index 05a80806c..45eff5ffd 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/bootstrap.ts @@ -46,7 +46,7 @@ async function bootstrapCommunities(context: Context): Promise Date: Fri, 14 Nov 2025 17:02:45 +0100 Subject: [PATCH 26/33] ignore not existing folder on removing --- .../src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts index 474df61b8..43459372b 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/binaryExport.ts @@ -87,7 +87,7 @@ function prepareFolder(communityContext: CommunityContext): string { ) const binFilePath = path.join(binFileFolder, 'blk00000001.dat') // make sure we work with a clean folder, rm beforehand with all content - fs.rmSync(binFileFolder, { recursive: true }) + fs.rmSync(binFileFolder, { force: true, recursive: true }) fs.mkdirSync(binFileFolder, { recursive: true }) return binFilePath } From 12e61891ba22805fe8e7b41c90b9b93c5fdc203f Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Mon, 17 Nov 2025 15:14:01 +0100 Subject: [PATCH 27/33] update inspector version --- inspector | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inspector b/inspector index 69ca3baf0..36045150d 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 69ca3baf09d55f768b3949ef9b7e9a53c25e17a9 +Subproject commit 36045150da1d6c9d9a568d801f327cee40176646 From 5f7383a486301b2e58373407d5b5eb11b3ae651d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 13:54:48 +0100 Subject: [PATCH 28/33] better error expression, update gradido node default version, update inspector, allow phpmyadmin importing big sql files --- dlt-connector/src/config/schema.ts | 2 +- .../db-v2.7.0_to_blockchain-v3.5/database.ts | 34 +++++++++---------- docker-compose.override.yml | 1 + inspector | 2 +- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/dlt-connector/src/config/schema.ts b/dlt-connector/src/config/schema.ts index 45ef83831..3abb84f6a 100644 --- a/dlt-connector/src/config/schema.ts +++ b/dlt-connector/src/config/schema.ts @@ -84,7 +84,7 @@ export const configSchema = v.object({ v.string('The version of the DLT node server, for example: 0.9.0'), v.regex(/^\d+\.\d+\.\d+$/), ), - '0.9.1', + '0.9.2', ), DLT_GRADIDO_NODE_SERVER_HOME_FOLDER: v.optional( v.string('The home folder for the gradido dlt node server'), diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index 8f198b5c8..581405207 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -104,23 +104,23 @@ export async function loadTransactions( return result.map((row: any) => { // console.log(row) - // check for consistent data beforehand - const userCreatedAt = new Date(row.user.createdAt) - const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) - const balanceDate = new Date(row.transaction.balanceDate) - if ( - userCreatedAt.getTime() > balanceDate.getTime() || - linkedUserCreatedAd.getTime() > balanceDate.getTime() - ) { - logger.error(`table row: `, row) - throw new Error('at least one user was created after transaction balance date, logic error!') - } - - let amount = GradidoUnit.fromString(row.transaction.amount) - if (row.transaction.typeId === TransactionTypeId.SEND) { - amount = amount.mul(new GradidoUnit(-1)) - } try { + // check for consistent data beforehand + const userCreatedAt = new Date(row.user.createdAt) + const linkedUserCreatedAd = new Date(row.linkedUser.createdAt) + const balanceDate = new Date(row.transaction.balanceDate) + if ( + userCreatedAt.getTime() > balanceDate.getTime() || + linkedUserCreatedAd.getTime() > balanceDate.getTime() + ) { + logger.error(`table row: `, row) + throw new Error('at least one user was created after transaction balance date, logic error!') + } + + let amount = GradidoUnit.fromString(row.transaction.amount) + if (row.transaction.typeId === TransactionTypeId.SEND) { + amount = amount.mul(new GradidoUnit(-1)) + } return v.parse(transactionDbSchema, { ...row.transaction, transactionLinkCode: row.transactionLink ? row.transactionLink.code : null, @@ -128,8 +128,8 @@ export async function loadTransactions( linkedUser: row.linkedUser, }) } catch (e) { + logger.error(`table row: ${JSON.stringify(row, null, 2)}`) if (e instanceof v.ValiError) { - logger.error(`table row: ${JSON.stringify(row, null, 2)}`) logger.error(v.flatten(e.issues)) } throw e diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 3898f9991..8c3d06b39 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -199,6 +199,7 @@ services: - debug environment: - PMA_ARBITRARY=1 + - UPLOAD_LIMIT=200M #restart: always ports: - 8074:80 diff --git a/inspector b/inspector index 36045150d..0c14b7eea 160000 --- a/inspector +++ b/inspector @@ -1 +1 @@ -Subproject commit 36045150da1d6c9d9a568d801f327cee40176646 +Subproject commit 0c14b7eea29b8911cbe3cb303f5b0b61ce9bf6f4 From f70c59f9b33e13fef7a0f363a55d5d818090e3c1 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 19 Nov 2025 14:05:20 +0100 Subject: [PATCH 29/33] fix lint --- .../src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index 581405207..58a5d364e 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -114,7 +114,9 @@ export async function loadTransactions( linkedUserCreatedAd.getTime() > balanceDate.getTime() ) { logger.error(`table row: `, row) - throw new Error('at least one user was created after transaction balance date, logic error!') + throw new Error( + 'at least one user was created after transaction balance date, logic error!', + ) } let amount = GradidoUnit.fromString(row.transaction.amount) From 388c7a795cd4112801c77c121d0b04f3eb1f949d Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 14:45:06 +0100 Subject: [PATCH 30/33] add new env to frontend env template --- frontend/.env.template | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/.env.template b/frontend/.env.template index 9c51e03ca..4fa775098 100644 --- a/frontend/.env.template +++ b/frontend/.env.template @@ -23,4 +23,5 @@ META_KEYWORDS_EN=$META_KEYWORDS_EN META_AUTHOR=$META_AUTHOR GMS_ACTIVE=$GMS_ACTIVE -HUMHUB_ACTIVE=$HUMHUB_ACTIVE \ No newline at end of file +HUMHUB_ACTIVE=$HUMHUB_ACTIVE +DLT_ACTIVE=$DLT_ACTIVE \ No newline at end of file From f91dd859bf7406f0b89c120084ae4627941bd7b8 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 14:48:16 +0100 Subject: [PATCH 31/33] fix link --- frontend/src/components/ContentFooter.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ContentFooter.vue b/frontend/src/components/ContentFooter.vue index d6f120e49..55299d786 100755 --- a/frontend/src/components/ContentFooter.vue +++ b/frontend/src/components/ContentFooter.vue @@ -43,7 +43,7 @@ {{ $t('navigation.support') }} - + {{ $t('footer.inspector') }} From dc8a8181b430bd94c95474fcbae8aabc97d235bd Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Wed, 26 Nov 2025 15:31:04 +0100 Subject: [PATCH 32/33] change default dlt connector url to localhost --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 9a57fed43..ddad28582 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -42,7 +42,7 @@ const COMMUNITY_URL = process.env.COMMUNITY_URL ?? `${URL_PROTOCOL}://${COMMUNIT const DLT_CONNECTOR_PORT = process.env.DLT_CONNECTOR_PORT ?? 6010 const dltConnector = { - DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `${COMMUNITY_URL}:${DLT_CONNECTOR_PORT}`, + DLT_CONNECTOR_URL: process.env.DLT_CONNECTOR_URL ?? `http://localhost:${DLT_CONNECTOR_PORT}`, } const community = { From 59b78766ee80e9fe1c05842ed02b0adde64470f1 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Thu, 4 Dec 2025 08:29:34 +0100 Subject: [PATCH 33/33] sort rows from db additional by id if the dates are the same because of faster seeding --- .../migrations/db-v2.7.0_to_blockchain-v3.5/database.ts | 9 +++++---- .../db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts index 58a5d364e..87cb3eb4a 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/database.ts @@ -40,6 +40,7 @@ export async function loadCommunities(db: MySql2Database): Promise() @@ -65,7 +66,7 @@ export async function loadUsers( const result = await db .select() .from(usersTable) - .orderBy(asc(usersTable.createdAt)) + .orderBy(asc(usersTable.createdAt), asc(usersTable.id)) .limit(count) .offset(offset) @@ -98,7 +99,7 @@ export async function loadTransactions( transactionLinksTable, eq(transactionsTable.transactionLinkId, transactionLinksTable.id), ) - .orderBy(asc(transactionsTable.balanceDate)) + .orderBy(asc(transactionsTable.balanceDate), asc(transactionsTable.id)) .limit(count) .offset(offset) @@ -148,7 +149,7 @@ export async function loadTransactionLinks( .select() .from(transactionLinksTable) .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) - .orderBy(asc(transactionLinksTable.createdAt)) + .orderBy(asc(transactionLinksTable.createdAt), asc(transactionLinksTable.id)) .limit(count) .offset(offset) @@ -170,7 +171,7 @@ export async function loadDeletedTransactionLinks( .from(transactionLinksTable) .leftJoin(usersTable, eq(transactionLinksTable.userId, usersTable.id)) .where(isNotNull(transactionLinksTable.deletedAt)) - .orderBy(asc(transactionLinksTable.deletedAt)) + .orderBy(asc(transactionLinksTable.deletedAt), asc(transactionLinksTable.id)) .limit(count) .offset(offset) diff --git a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts index 59cc6573c..e08231f4d 100644 --- a/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts +++ b/dlt-connector/src/migrations/db-v2.7.0_to_blockchain-v3.5/drizzle.schema.ts @@ -15,6 +15,7 @@ import { export const communitiesTable = mysqlTable( 'communities', { + id: int().autoincrement().notNull(), foreign: tinyint().default(1).notNull(), communityUuid: char('community_uuid', { length: 36 }).default(sql`NULL`), name: varchar({ length: 40 }).default(sql`NULL`),