From f2bed052798b5c7e434834123a386fbd449c4347 Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Wed, 18 Oct 2023 16:28:57 +0530 Subject: [PATCH 1/7] :bug: Fixed events API when queried with different topics --- framework/src/database/util.js | 13 ++-- .../functional/database/mysql/mysql.test.js | 26 ++++++++ .../shared/dataService/business/events.js | 63 ++++++++----------- tests/integration/api_v3/rpc/events.test.js | 21 ++++--- 4 files changed, 71 insertions(+), 52 deletions(-) diff --git a/framework/src/database/util.js b/framework/src/database/util.js index c8ee347e9b..1571a8ee63 100644 --- a/framework/src/database/util.js +++ b/framework/src/database/util.js @@ -81,7 +81,7 @@ const resolveQueryParams = params => { 'sort', 'limit', 'offset', 'propBetweens', 'andWhere', 'orWhere', 'orWhereWith', 'whereNot', 'whereIn', 'whereNotIn', 'orWhereIn', 'whereBetween', 'whereJsonSupersetOf', 'search', 'aggregate', 'distinct', 'order', 'orSearch', 'whereNull', 'whereNotNull', 'leftOuterJoin', 'rightOuterJoin', - 'innerJoin', 'groupBy', 'orderByRaw', + 'innerJoin', 'groupBy', 'orderByRaw', 'havingRaw', ]; const queryParams = Object.keys(params) .filter(key => !KNOWN_QUERY_PARAMS.includes(key)) @@ -199,6 +199,10 @@ const getTableInstance = (tableConfig, knex) => { }); } + if (params.havingRaw) { + query.having(knex.raw(params.havingRaw)); + } + if (params.aggregate) { query.sum(`${params.aggregate} as total`); } @@ -268,9 +272,10 @@ const getTableInstance = (tableConfig, knex) => { } if (params.andWhere) { - const { andWhere } = params; - query.where(function () { - this.where(andWhere); + params.andWhere = Array.isArray(params.andWhere) ? params.andWhere : [params.andWhere]; + + params.andWhere.forEach(andWhere => { + query.where(andWhere); }); } diff --git a/framework/tests/functional/database/mysql/mysql.test.js b/framework/tests/functional/database/mysql/mysql.test.js index 114bf03e68..1069579ff2 100644 --- a/framework/tests/functional/database/mysql/mysql.test.js +++ b/framework/tests/functional/database/mysql/mysql.test.js @@ -711,6 +711,32 @@ describe('Test MySQL', () => { expect(result).toBeInstanceOf(Array); expect(result.length).toBe(0); }); + + it('should apply HAVING clause with havingRaw', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); + + const params = { + groupBy: 'height', + havingRaw: 'height > 50', + }; + + const result = await blocksTable.find(params, ['id', 'height']); + expect(result).toBeInstanceOf(Array); + expect(result.length).toBeGreaterThan(1); + }); + + it('should apply complex HAVING clause with havingRaw', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); + + const params = { + groupBy: 'height', + havingRaw: 'SUM(height) > 50', + }; + + const result = await blocksTable.find(params, ['id', 'height']); + expect(result).toBeInstanceOf(Array); + expect(result.length).toBeGreaterThan(1); + }); }); describe('With EXPLICIT DB transaction (non-auto commit mode)', () => { diff --git a/services/blockchain-indexer/shared/dataService/business/events.js b/services/blockchain-indexer/shared/dataService/business/events.js index 49d20d4853..a22dea1729 100644 --- a/services/blockchain-indexer/shared/dataService/business/events.js +++ b/services/blockchain-indexer/shared/dataService/business/events.js @@ -101,6 +101,7 @@ const deleteEventsFromCache = async (height) => eventCache.delete(height); const getEvents = async (params) => { let queryParams = _.cloneDeep(params); + delete queryParams.topic; const blocksTable = await getBlocksTable(); const eventsTable = await getEventsTable(); @@ -119,24 +120,14 @@ const getEvents = async (params) => { queryParams = normalizeRangeParam(queryParams, 'timestamp'); } - if (params.topic) { - const { topic, ...remQueryParams } = queryParams; - queryParams = remQueryParams; - - queryParams.whereIn = { - property: 'topic', - values: topic.split(','), - }; - } - if (params.transactionID) { const { transactionID, ...remQueryParams } = queryParams; queryParams = remQueryParams; if (!params.topic) { - queryParams.topic = transactionID; + params.topic = transactionID; } else { - queryParams.andWhere = { topic: transactionID }; + params.topic = `${params.topic},${transactionID}`; } } @@ -145,13 +136,13 @@ const getEvents = async (params) => { queryParams = remQueryParams; if (!params.topic) { - queryParams.topic = senderAddress; + params.topic = senderAddress; } else { - queryParams.andWhere = { topic: senderAddress }; + params.topic = `${params.topic},${senderAddress}`; } } - if (params.blockID) { + if ('blockID' in params) { const { blockID, ...remQueryParams } = queryParams; queryParams = remQueryParams; @@ -176,16 +167,24 @@ const getEvents = async (params) => { queryParams.height = block.height; } - const isTopicInQuery = !!params.topic || !!queryParams.topic; - - queryParams.leftOuterJoin = { - targetTable: eventsTableSchema.tableName, - leftColumn: `${eventsTableSchema.tableName}.id`, - rightColumn: `${eventTopicsTableSchema.tableName}.eventID`, - }; + if (params.topic) { + const { topic } = params; + + const response = await eventTopicsTable.find( + { + whereIn: { property: 'topic', values: topic.split(',') }, + distinct: 'eventID', + groupBy: 'eventID', + havingRaw: `COUNT(DISTINCT topic) = ${topic.split(',').length}`, + }, + ['eventID'], + ); + const eventIDs = response.map(entry => entry.eventID); + queryParams.whereIn = { property: 'id', values: eventIDs }; + } - const eventsInfo = await eventTopicsTable.find( - { ...queryParams, distinct: 'eventID' }, + const eventsInfo = await eventsTable.find( + queryParams, ['eventStr', 'height', 'index'], ); @@ -211,20 +210,8 @@ const getEvents = async (params) => { { concurrency: eventsInfo.length }, ); - let total; - const { order, sort, ...remQueryParams } = queryParams; - - if (isTopicInQuery) { - total = await eventTopicsTable.count( - { ...remQueryParams, distinct: 'eventID' }, - ['eventID'], - ); - } else { - // If params doesn't contain event_topics specific column data - // then count all rows of event table for query optimization. - const { leftOuterJoin, ...remParamsWithoutJoin } = remQueryParams; - total = await eventsTable.count(remParamsWithoutJoin, ['id']); - } + const { order, sort, ...queryParamsWithoutOrderAndSort } = queryParams; + const total = await eventsTable.count({ ...queryParamsWithoutOrderAndSort, distinct: 'id' }); events.meta = { count: events.data.length, diff --git a/tests/integration/api_v3/rpc/events.test.js b/tests/integration/api_v3/rpc/events.test.js index f6e85d525a..96684664cb 100644 --- a/tests/integration/api_v3/rpc/events.test.js +++ b/tests/integration/api_v3/rpc/events.test.js @@ -25,6 +25,7 @@ const { invalidParamsSchema, metaSchema, serverErrorSchema, + invalidRequestSchema, } = require('../../../schemas/rpcGenerics.schema'); const { @@ -89,19 +90,19 @@ describe('Method get.events', () => { expect(result.meta).toMap(metaSchema); }); - it('should return bad request for invalid limit', async () => { + it('should return invalid params for invalid limit', async () => { for (let i = 0; i < invalidLimits.length; i++) { // eslint-disable-next-line no-await-in-loop const response = await getEvents({ limit: invalidLimits[i] }); - expect(response).toMap(serverErrorSchema); + expect(response).toMap(invalidParamsSchema); } }); - it('should return bad request for invalid offset', async () => { + it('should return invalid params for invalid offset', async () => { for (let i = 0; i < invalidOffsets.length; i++) { // eslint-disable-next-line no-await-in-loop const response = await getEvents({ offset: invalidOffsets[i] }); - expect(response).toMap(serverErrorSchema); + expect(response).toMap(invalidParamsSchema); } }); }); @@ -148,16 +149,16 @@ describe('Method get.events', () => { expect(result.meta).toMap(metaSchema); }); - it('should return server error for empty blockID', async () => { + it('should return invalid request for empty blockID', async () => { const response = await getEvents({ blockID: '' }); - expect(response).toMap(serverErrorSchema); + expect(response).toMap(invalidRequestSchema); }); - it('should return bad request for invalid block ID', async () => { + it('should return invalid params for invalid block ID', async () => { for (let i = 0; i < invalidBlockIDs.length; i++) { // eslint-disable-next-line no-await-in-loop const response = await getEvents({ blockID: invalidBlockIDs[i] }); - expect(response).toMap(serverErrorSchema); + expect(response).toMap(invalidParamsSchema); } }); }); @@ -196,11 +197,11 @@ describe('Method get.events', () => { expect(response).toMap(invalidParamsSchema); }); - it('should return bad request for invalid senderAddress', async () => { + it('should return invalid params for invalid senderAddress', async () => { for (let i = 0; i < invalidBlockIDs.length; i++) { // eslint-disable-next-line no-await-in-loop const response = await getEvents({ senderAddress: invalidAddresses[i] }); - expect(response).toMap(serverErrorSchema); + expect(response).toMap(invalidParamsSchema); } }); }); From e72288dc2ee681198097c531aad9ec43edcfd86e Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Wed, 18 Oct 2023 17:34:56 +0530 Subject: [PATCH 2/7] Updated framework --- .../dist/lisk-service-framework-1.6.1.tgz | Bin 0 -> 70752 bytes framework/package.json | 2 +- framework/src/database/util.js | 7 ++--- .../tests/unit/shared/constants/events.js | 28 ++---------------- 4 files changed, 7 insertions(+), 30 deletions(-) create mode 100644 framework/dist/lisk-service-framework-1.6.1.tgz diff --git a/framework/dist/lisk-service-framework-1.6.1.tgz b/framework/dist/lisk-service-framework-1.6.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..61bb776de85fab0fd2e351c6ced1c25ec4d20c98 GIT binary patch literal 70752 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%0DNd^CCS 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 literal 0 HcmV?d00001 diff --git a/framework/package.json b/framework/package.json index a2b1dd4dde..f74b65d0dc 100644 --- a/framework/package.json +++ b/framework/package.json @@ -1,6 +1,6 @@ { "name": "lisk-service-framework", - "version": "1.6.0", + "version": "1.6.1", "description": "Lisk Service Framework", "keywords": [ "lisk", diff --git a/framework/src/database/util.js b/framework/src/database/util.js index 1571a8ee63..9f81c67de8 100644 --- a/framework/src/database/util.js +++ b/framework/src/database/util.js @@ -272,10 +272,9 @@ const getTableInstance = (tableConfig, knex) => { } if (params.andWhere) { - params.andWhere = Array.isArray(params.andWhere) ? params.andWhere : [params.andWhere]; - - params.andWhere.forEach(andWhere => { - query.where(andWhere); + const { andWhere } = params; + query.where(function () { + this.where(andWhere); }); } diff --git a/services/blockchain-indexer/tests/unit/shared/constants/events.js b/services/blockchain-indexer/tests/unit/shared/constants/events.js index 39c0a21dcb..f051e578c8 100644 --- a/services/blockchain-indexer/tests/unit/shared/constants/events.js +++ b/services/blockchain-indexer/tests/unit/shared/constants/events.js @@ -321,37 +321,15 @@ const getEventsResult = { }; const mockEventTopicsQueryParams = { - sort: 'timestamp:desc', - order: 'index:asc', - limit: 10, - offset: 0, - propBetweens: [ - { - property: 'height', - from: 1, - to: 1000, - }, - { - property: 'timestamp', - from: 1, - to: 1000000000, - }, - ], whereIn: { property: 'topic', values: [ '03', + 'lskw68y3kyus7ota9mykr726aby44mw574m8dkngu', ], }, - height: 123, - leftOuterJoin: { - targetTable: 'events', - leftColumn: 'events.id', - rightColumn: 'event_topics.eventID', - }, - andWhere: { - topic: 'lskw68y3kyus7ota9mykr726aby44mw574m8dkngu', - }, + groupBy: 'eventID', + havingRaw: 'COUNT(DISTINCT topic) = 2', distinct: 'eventID', }; From 06c1f29ebccb938f09c7442e30bc350b8b3d8ae6 Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Wed, 18 Oct 2023 17:41:36 +0530 Subject: [PATCH 3/7] Updated framework in all services --- services/blockchain-app-registry/package.json | 2 +- services/blockchain-app-registry/yarn.lock | 36 +++++++++++++++++-- services/blockchain-connector/package.json | 2 +- services/blockchain-connector/yarn.lock | 36 +++++++++++++++++-- services/blockchain-coordinator/package.json | 2 +- services/blockchain-coordinator/yarn.lock | 36 +++++++++++++++++-- services/blockchain-indexer/package.json | 2 +- services/blockchain-indexer/yarn.lock | 36 +++++++++++++++++-- services/export/package.json | 2 +- services/export/yarn.lock | 36 +++++++++++++++++-- services/fee-estimator/package.json | 2 +- services/fee-estimator/yarn.lock | 36 +++++++++++++++++-- services/gateway/package.json | 2 +- services/gateway/yarn.lock | 36 +++++++++++++++++-- services/market/package.json | 2 +- services/market/yarn.lock | 36 +++++++++++++++++-- services/template/package.json | 2 +- services/template/yarn.lock | 36 +++++++++++++++++-- services/transaction-statistics/package.json | 2 +- services/transaction-statistics/yarn.lock | 36 +++++++++++++++++-- 20 files changed, 340 insertions(+), 40 deletions(-) diff --git a/services/blockchain-app-registry/package.json b/services/blockchain-app-registry/package.json index d3d8be424c..7858b31b79 100644 --- a/services/blockchain-app-registry/package.json +++ b/services/blockchain-app-registry/package.json @@ -33,7 +33,7 @@ }, "dependencies": { "bluebird": "^3.7.2", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "lodash": "^4.17.21", "octokit": "^2.0.4", "tar": "^6.1.11" diff --git a/services/blockchain-app-registry/yarn.lock b/services/blockchain-app-registry/yarn.lock index 63d2ee1ea0..a36c7b2f7b 100644 --- a/services/blockchain-app-registry/yarn.lock +++ b/services/blockchain-app-registry/yarn.lock @@ -3084,9 +3084,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/blockchain-connector/package.json b/services/blockchain-connector/package.json index bcf05c63d6..285dbb07a2 100644 --- a/services/blockchain-connector/package.json +++ b/services/blockchain-connector/package.json @@ -39,7 +39,7 @@ "big-json": "^3.1.0", "bluebird": "^3.7.2", "knex": "^2.4.0", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "moment": "^2.29.4", "signals": "^1.0.0", "tar": "^6.1.11" diff --git a/services/blockchain-connector/yarn.lock b/services/blockchain-connector/yarn.lock index a64aae67db..9f7bb23a00 100644 --- a/services/blockchain-connector/yarn.lock +++ b/services/blockchain-connector/yarn.lock @@ -3926,9 +3926,39 @@ lines-and-columns@^1.1.6: resolved "https://npm.lisk.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/blockchain-coordinator/package.json b/services/blockchain-coordinator/package.json index a6d9c48b6e..a64684f598 100644 --- a/services/blockchain-coordinator/package.json +++ b/services/blockchain-coordinator/package.json @@ -31,7 +31,7 @@ "dependencies": { "bluebird": "^3.7.2", "bull": "^4.8.1", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz" + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz" }, "devDependencies": { "@babel/preset-env": "^7.14.0", diff --git a/services/blockchain-coordinator/yarn.lock b/services/blockchain-coordinator/yarn.lock index cfa2f14d50..6ff47e9c0f 100644 --- a/services/blockchain-coordinator/yarn.lock +++ b/services/blockchain-coordinator/yarn.lock @@ -3482,9 +3482,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/blockchain-indexer/package.json b/services/blockchain-indexer/package.json index 6947e1f15e..54eda4b45e 100644 --- a/services/blockchain-indexer/package.json +++ b/services/blockchain-indexer/package.json @@ -38,7 +38,7 @@ "bull": "^4.8.1", "camelcase": "^6.3.0", "ioredis": "^4.28.5", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "lodash": "^4.17.21", "require-all": "^3.0.0" }, diff --git a/services/blockchain-indexer/yarn.lock b/services/blockchain-indexer/yarn.lock index b27c1048c0..3ada4e6e63 100644 --- a/services/blockchain-indexer/yarn.lock +++ b/services/blockchain-indexer/yarn.lock @@ -3638,9 +3638,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/export/package.json b/services/export/package.json index 81829008f8..104b044eb8 100644 --- a/services/export/package.json +++ b/services/export/package.json @@ -36,7 +36,7 @@ "bull": "^3.29.2", "exceljs": "^4.3.0", "json2csv": "^5.0.6", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "minio": "^7.0.21", "moment": "^2.29.4", "moment-range": "^4.0.2", diff --git a/services/export/yarn.lock b/services/export/yarn.lock index 62f8a8d1bf..807c670901 100644 --- a/services/export/yarn.lock +++ b/services/export/yarn.lock @@ -3158,9 +3158,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/fee-estimator/package.json b/services/fee-estimator/package.json index 0e7e004ba5..9979d16633 100644 --- a/services/fee-estimator/package.json +++ b/services/fee-estimator/package.json @@ -34,7 +34,7 @@ "@liskhq/lisk-cryptography": "4.0.0-rc.1", "@liskhq/lisk-transactions": "6.0.0-rc.1", "bluebird": "^3.7.2", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz" + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz" }, "devDependencies": { "@babel/preset-env": "^7.14.0", diff --git a/services/fee-estimator/yarn.lock b/services/fee-estimator/yarn.lock index f2be0d8f2b..6a7c5d671e 100644 --- a/services/fee-estimator/yarn.lock +++ b/services/fee-estimator/yarn.lock @@ -3611,9 +3611,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/gateway/package.json b/services/gateway/package.json index ab84aa0f03..456b443e77 100644 --- a/services/gateway/package.json +++ b/services/gateway/package.json @@ -33,7 +33,7 @@ "bluebird": "^3.7.2", "fastest-validator": "^1.10.1", "ioredis": "^4.27.1", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "moleculer": "^0.14.13", "moment": "^2.29.4", "rate-limiter-flexible": "^2.2.4", diff --git a/services/gateway/yarn.lock b/services/gateway/yarn.lock index 1b2110bc6a..ba7c824343 100644 --- a/services/gateway/yarn.lock +++ b/services/gateway/yarn.lock @@ -2728,9 +2728,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/market/package.json b/services/market/package.json index 068a9e7d60..d48643a9e0 100644 --- a/services/market/package.json +++ b/services/market/package.json @@ -32,7 +32,7 @@ "dependencies": { "bluebird": "^3.7.2", "joi": "^17.4.0", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "moment": "^2.29.4", "node-cron": "=2.0.3" }, diff --git a/services/market/yarn.lock b/services/market/yarn.lock index bf077d2a9b..d094a6448f 100644 --- a/services/market/yarn.lock +++ b/services/market/yarn.lock @@ -2768,9 +2768,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/template/package.json b/services/template/package.json index 062c712c23..e9fd864448 100644 --- a/services/template/package.json +++ b/services/template/package.json @@ -30,7 +30,7 @@ "watch": "supervisor -w . -i ./node_modules app.js" }, "dependencies": { - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "node-cron": "=2.0.3" } } diff --git a/services/template/yarn.lock b/services/template/yarn.lock index dbef9bc6ac..36a6e66f2f 100644 --- a/services/template/yarn.lock +++ b/services/template/yarn.lock @@ -1022,9 +1022,39 @@ leven@2.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" integrity sha512-nvVPLpIHUxCUoRLrFqTgSxXJ614d8AgQoWl7zPe/2VadE8+1dpU3LBhowRuBAcuwruWtOdD8oYC9jDNJjXDPyA== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" diff --git a/services/transaction-statistics/package.json b/services/transaction-statistics/package.json index 98add14528..fdd1f15e12 100644 --- a/services/transaction-statistics/package.json +++ b/services/transaction-statistics/package.json @@ -32,7 +32,7 @@ "dependencies": { "big-number": "=2.0.0", "bluebird": "^3.7.2", - "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz", + "lisk-service-framework": "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz", "moment": "^2.29.4" }, "devDependencies": { diff --git a/services/transaction-statistics/yarn.lock b/services/transaction-statistics/yarn.lock index f51a5062b4..ed28f8b15e 100644 --- a/services/transaction-statistics/yarn.lock +++ b/services/transaction-statistics/yarn.lock @@ -3437,9 +3437,39 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz": - version "1.6.0" - resolved "https://github.com/LiskHQ/lisk-service/raw/b29df9637584d43ce25b89843637c46ebbcbe628/framework/dist/lisk-service-framework-1.6.0.tgz#22d99e35771f13c9e00d6a36b20dc453e83f799a" +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/c290db8943b1ad0ad7e6ec913bd43c2a3c36030e/framework/dist/lisk-service-framework-1.6.1.tgz#bf7089c595b9e1893ac55c64acf2f2163e154695" + dependencies: + "@keyv/redis" "^2.1.2" + "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" + axios "^0.21.2" + better-sqlite3 "^8.5.0" + bull "^3.29.3" + debug "^4.3.1" + fastest-validator "^1.10.1" + http-status-codes "^1.4.0" + json-colorizer "^2.2.2" + keyv "^4.0.3" + keyv-lru "^3.0.4" + knex "^2.5.1" + log4js "^6.5.2" + moleculer "^0.14.21" + moleculer-web "^0.10.4" + moment "^2.29.4" + mysql2 "^3.5.2" + nats "^1.4.12" + node-cron "^2.0.3" + prettyjson "^1.2.1" + require-all "^3.0.0" + signals "^1.0.0" + socket.io "^4.4.1" + socket.io-client "^4.0.1" + stack-trace "0.0.10" + +"lisk-service-framework@https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz": + version "1.6.1" + resolved "https://github.com/LiskHQ/lisk-service/raw/e72288dc2ee681198097c531aad9ec43edcfd86e/framework/dist/lisk-service-framework-1.6.1.tgz#730da995d0279f62f94e3285747424511537998d" dependencies: "@keyv/redis" "^2.1.2" "@log4js-node/gelf" "github:MichalTuleja/log4js-node-gelf#89d9933" From 93f5d79d76cc1452adc2c7e7a187125b22207a85 Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Wed, 18 Oct 2023 20:57:16 +0530 Subject: [PATCH 4/7] Applied suggestions --- .../blockchain-indexer/shared/dataService/business/events.js | 3 +-- .../blockchain-indexer/tests/unit/shared/constants/events.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/services/blockchain-indexer/shared/dataService/business/events.js b/services/blockchain-indexer/shared/dataService/business/events.js index a22dea1729..0eb2c929d2 100644 --- a/services/blockchain-indexer/shared/dataService/business/events.js +++ b/services/blockchain-indexer/shared/dataService/business/events.js @@ -173,7 +173,6 @@ const getEvents = async (params) => { const response = await eventTopicsTable.find( { whereIn: { property: 'topic', values: topic.split(',') }, - distinct: 'eventID', groupBy: 'eventID', havingRaw: `COUNT(DISTINCT topic) = ${topic.split(',').length}`, }, @@ -211,7 +210,7 @@ const getEvents = async (params) => { ); const { order, sort, ...queryParamsWithoutOrderAndSort } = queryParams; - const total = await eventsTable.count({ ...queryParamsWithoutOrderAndSort, distinct: 'id' }); + const total = await eventsTable.count({ ...queryParamsWithoutOrderAndSort }); events.meta = { count: events.data.length, diff --git a/services/blockchain-indexer/tests/unit/shared/constants/events.js b/services/blockchain-indexer/tests/unit/shared/constants/events.js index f051e578c8..80c604bbd6 100644 --- a/services/blockchain-indexer/tests/unit/shared/constants/events.js +++ b/services/blockchain-indexer/tests/unit/shared/constants/events.js @@ -330,7 +330,6 @@ const mockEventTopicsQueryParams = { }, groupBy: 'eventID', havingRaw: 'COUNT(DISTINCT topic) = 2', - distinct: 'eventID', }; module.exports = { From 682b9774a1e65daacf9ebb4c20197d68e5fb433e Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Thu, 19 Oct 2023 15:25:59 +0530 Subject: [PATCH 5/7] Applied suggestions --- framework/package.json | 2 +- .../functional/database/mysql/mysql.test.js | 76 ++++++++++++++++--- .../shared/dataService/business/events.js | 33 ++++---- 3 files changed, 82 insertions(+), 29 deletions(-) diff --git a/framework/package.json b/framework/package.json index f74b65d0dc..17f83bc5a7 100644 --- a/framework/package.json +++ b/framework/package.json @@ -25,7 +25,7 @@ "scripts": { "release:github": "npm pack && mv lisk-service-framework-$npm_package_version.tgz ./dist/lisk-service-framework-$npm_package_version.tgz", "test:unit": "./node_modules/.bin/jest --config=tests/unit.config.js --detectOpenHandles --forceExit", - "test:functional": "./node_modules/.bin/jest --config=tests/functional.config.js --detectOpenHandles --forceExit" + "test:functional": "./node_modules/.bin/jest --config=tests/functional.config.js --detectOpenHandles --runInBand --forceExit" }, "bin": { "moleculer_client": "./bin/moleculer_client.js" diff --git a/framework/tests/functional/database/mysql/mysql.test.js b/framework/tests/functional/database/mysql/mysql.test.js index 1069579ff2..9d11e45f8b 100644 --- a/framework/tests/functional/database/mysql/mysql.test.js +++ b/framework/tests/functional/database/mysql/mysql.test.js @@ -82,6 +82,10 @@ describe('Test MySQL', () => { describe('With IMPLICIT DB transaction (auto-commit mode)', () => { afterAll(() => blocksTable.rawQuery(`TRUNCATE ${tableName}`)); + afterEach(async () => { + blocksTable.rawQuery(`DELETE FROM ${tableName}`); + }); + it('should insert row', async () => { await blocksTable.upsert([emptyBlock]); const result = await blocksTable.find(); @@ -90,6 +94,7 @@ describe('Test MySQL', () => { }); it('should get rows', async () => { + await blocksTable.upsert([emptyBlock]); const result = await blocksTable.find({ id: emptyBlock.id }, ['id']); expect(result).toBeInstanceOf(Array); expect(result.length).toBe(1); @@ -312,6 +317,7 @@ describe('Test MySQL', () => { }); it('should increment column value', async () => { + await blocksTable.upsert([emptyBlock]); const [currentBlock] = await blocksTable.find({ id: emptyBlock.id }, ['timestamp']); const currentTimestamp = currentBlock.timestamp; @@ -326,6 +332,7 @@ describe('Test MySQL', () => { }); it('should decrement column value', async () => { + await blocksTable.upsert([emptyBlock]); const [currentBlock] = await blocksTable.find({ id: emptyBlock.id }, ['timestamp']); const currentTimestamp = currentBlock.timestamp; @@ -340,6 +347,7 @@ describe('Test MySQL', () => { }); it('should delete row by primary key', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); const [existingBlock] = await blocksTable.find(); const existingBlockId = existingBlock[`${blocksTableSchema.primaryKey}`]; const count = await blocksTable.deleteByPrimaryKey([existingBlockId]); @@ -398,6 +406,7 @@ describe('Test MySQL', () => { }); it('should execute update method', async () => { + await blocksTable.upsert([emptyBlock]); const [retrievedBlock] = await blocksTable.find({ id: emptyBlock.id }, ['timestamp']); expect(retrievedBlock.timestamp).toBe(emptyBlock.timestamp); @@ -717,12 +726,12 @@ describe('Test MySQL', () => { const params = { groupBy: 'height', - havingRaw: 'height > 50', + havingRaw: `height < ${Math.max(emptyBlock.height, nonEmptyBlock.height)}`, }; const result = await blocksTable.find(params, ['id', 'height']); expect(result).toBeInstanceOf(Array); - expect(result.length).toBeGreaterThan(1); + expect(result.length).toBe(1); }); it('should apply complex HAVING clause with havingRaw', async () => { @@ -730,18 +739,22 @@ describe('Test MySQL', () => { const params = { groupBy: 'height', - havingRaw: 'SUM(height) > 50', + havingRaw: `SUM(height) < ${Math.max(emptyBlock.height, nonEmptyBlock.height)}`, }; const result = await blocksTable.find(params, ['id', 'height']); expect(result).toBeInstanceOf(Array); - expect(result.length).toBeGreaterThan(1); + expect(result.length).toBe(1); }); }); describe('With EXPLICIT DB transaction (non-auto commit mode)', () => { afterAll(() => blocksTable.rawQuery(`TRUNCATE ${tableName}`)); + afterEach(async () => { + blocksTable.rawQuery(`DELETE FROM ${tableName}`); + }); + it('should insert row', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); @@ -850,7 +863,7 @@ describe('Test MySQL', () => { it('should sort the rows in ascending order based on their height', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); - await blocksTable.upsert([{ ...emptyBlock, size: 50 }], trx); + await blocksTable.upsert([{ ...emptyBlock, size: 50 }, nonEmptyBlock], trx); await commitDBTransaction(trx); const result = await blocksTable.find({ sort: 'height:asc' }); @@ -862,7 +875,7 @@ describe('Test MySQL', () => { it('should sort the rows in descending order based on their height', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); - await blocksTable.upsert([{ ...emptyBlock, size: 50 }], trx); + await blocksTable.upsert([{ ...emptyBlock, size: 50 }, nonEmptyBlock], trx); await commitDBTransaction(trx); const result = await blocksTable.find({ sort: 'height:desc' }); @@ -874,7 +887,7 @@ describe('Test MySQL', () => { it('should order the rows in ascending order based on their height', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); - await blocksTable.upsert([{ ...emptyBlock, size: 50 }], trx); + await blocksTable.upsert([{ ...emptyBlock, size: 50 }, nonEmptyBlock], trx); await commitDBTransaction(trx); const result = await blocksTable.find({ order: 'height:asc' }); @@ -886,7 +899,7 @@ describe('Test MySQL', () => { it('should order the rows in descending order based on their height', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); - await blocksTable.upsert([{ ...emptyBlock, size: 50 }], trx); + await blocksTable.upsert([{ ...emptyBlock, size: 50 }, nonEmptyBlock], trx); await commitDBTransaction(trx); const result = await blocksTable.find({ order: 'height:desc' }); @@ -898,7 +911,7 @@ describe('Test MySQL', () => { it('should order the rows in ascending order based on their height using orderByRaw query', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); - await blocksTable.upsert([{ ...emptyBlock, size: 50 }], trx); + await blocksTable.upsert([{ ...emptyBlock, size: 50 }, nonEmptyBlock], trx); await commitDBTransaction(trx); const result = await blocksTable.find({ orderByRaw: ['height asc'] }); @@ -910,7 +923,7 @@ describe('Test MySQL', () => { it('should order the rows in descending order based on their height', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); - await blocksTable.upsert([{ ...emptyBlock, size: 50 }], trx); + await blocksTable.upsert([{ ...emptyBlock, size: 50 }, nonEmptyBlock], trx); await commitDBTransaction(trx); const result = await blocksTable.find({ orderByRaw: ['height desc'] }); @@ -970,6 +983,7 @@ describe('Test MySQL', () => { }); it('should increment column value', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); const connection = await getDBConnection(); const trx = await startDBTransaction(connection); await blocksTable.increment({ @@ -983,6 +997,7 @@ describe('Test MySQL', () => { }); it('should decrement row by primary key', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); const connection = await getDBConnection(); const trx = await startDBTransaction(connection); const [existingBlock] = await blocksTable.find(); @@ -1091,6 +1106,7 @@ describe('Test MySQL', () => { }); it('should perform update method', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); const [retrievedBlock] = await blocksTable.find({ id: emptyBlock.id }, ['timestamp']); expect(retrievedBlock.timestamp).toBe(emptyBlock.timestamp); @@ -1345,9 +1361,49 @@ describe('Test MySQL', () => { expect(firstRow.height).toBe(nonEmptyBlock.height); expect(firstRow.id).toBe(tokenTransferTransaction.id); }); + + it('should apply HAVING clause with havingRaw', async () => { + // Insert a test record. + const connection = await getDBConnection(); + const trx = await startDBTransaction(connection); + await blocksTable.upsert([emptyBlock, nonEmptyBlock], trx); + await transactionsTable.upsert([tokenTransferTransaction], trx); + + const params = { + groupBy: 'height', + havingRaw: `height < ${Math.max(emptyBlock.height, nonEmptyBlock.height)}`, + }; + + const result = await blocksTable.find(params, ['id', 'height'], trx); + await commitDBTransaction(trx); + expect(result).toBeInstanceOf(Array); + expect(result.length).toBe(1); + }); + + it('should apply complex HAVING clause with havingRaw', async () => { + // Insert a test record. + const connection = await getDBConnection(); + const trx = await startDBTransaction(connection); + await blocksTable.upsert([emptyBlock, nonEmptyBlock], trx); + await transactionsTable.upsert([tokenTransferTransaction], trx); + + const params = { + groupBy: 'height', + havingRaw: `SUM(height) < ${Math.max(emptyBlock.height, nonEmptyBlock.height)}`, + }; + + const result = await blocksTable.find(params, ['id', 'height'], trx); + await commitDBTransaction(trx); + expect(result).toBeInstanceOf(Array); + expect(result.length).toBe(1); + }); }); describe('Transactional atomicity guarantees (non-auto commit mode)', () => { + afterEach(async () => { + blocksTable.rawQuery(`DELETE FROM ${tableName}`); + }); + it('should perform a successful transaction commit', async () => { const connection = await getDBConnection(); const trx = await startDBTransaction(connection); diff --git a/services/blockchain-indexer/shared/dataService/business/events.js b/services/blockchain-indexer/shared/dataService/business/events.js index 0eb2c929d2..654ea4a2be 100644 --- a/services/blockchain-indexer/shared/dataService/business/events.js +++ b/services/blockchain-indexer/shared/dataService/business/events.js @@ -14,7 +14,6 @@ * */ const BluebirdPromise = require('bluebird'); -const _ = require('lodash'); const { CacheLRU, @@ -100,9 +99,6 @@ const cacheEventsByBlockID = async (blockID, events) => { const deleteEventsFromCache = async (height) => eventCache.delete(height); const getEvents = async (params) => { - let queryParams = _.cloneDeep(params); - delete queryParams.topic; - const blocksTable = await getBlocksTable(); const eventsTable = await getEventsTable(); const eventTopicsTable = await getEventTopicsTable(); @@ -113,16 +109,16 @@ const getEvents = async (params) => { }; if (params.height && typeof params.height === 'string' && params.height.includes(':')) { - queryParams = normalizeRangeParam(queryParams, 'height'); + params = normalizeRangeParam(params, 'height'); } if (params.timestamp && params.timestamp.includes(':')) { - queryParams = normalizeRangeParam(queryParams, 'timestamp'); + params = normalizeRangeParam(params, 'timestamp'); } if (params.transactionID) { - const { transactionID, ...remQueryParams } = queryParams; - queryParams = remQueryParams; + const { transactionID, ...remParams } = params; + params = remParams; if (!params.topic) { params.topic = transactionID; @@ -132,8 +128,8 @@ const getEvents = async (params) => { } if (params.senderAddress) { - const { senderAddress, ...remQueryParams } = queryParams; - queryParams = remQueryParams; + const { senderAddress, ...remParams } = params; + params = remParams; if (!params.topic) { params.topic = senderAddress; @@ -143,8 +139,8 @@ const getEvents = async (params) => { } if ('blockID' in params) { - const { blockID, ...remQueryParams } = queryParams; - queryParams = remQueryParams; + const { blockID, ...remParams } = params; + params = remParams; const [block] = await blocksTable.find({ id: blockID, limit: 1 }, ['height']); if (!block || !block.height) { @@ -164,11 +160,12 @@ const getEvents = async (params) => { throw new NotFoundException(`Invalid combination of blockID: ${blockID} and height: ${params.height}`); } } - queryParams.height = block.height; + params.height = block.height; } if (params.topic) { - const { topic } = params; + const { topic, ...remParams } = params; + params = remParams; const response = await eventTopicsTable.find( { @@ -179,11 +176,11 @@ const getEvents = async (params) => { ['eventID'], ); const eventIDs = response.map(entry => entry.eventID); - queryParams.whereIn = { property: 'id', values: eventIDs }; + params.whereIn = { property: 'id', values: eventIDs }; } const eventsInfo = await eventsTable.find( - queryParams, + params, ['eventStr', 'height', 'index'], ); @@ -209,8 +206,8 @@ const getEvents = async (params) => { { concurrency: eventsInfo.length }, ); - const { order, sort, ...queryParamsWithoutOrderAndSort } = queryParams; - const total = await eventsTable.count({ ...queryParamsWithoutOrderAndSort }); + const { order, sort, ...remParamsWithoutOrderAndSort } = params; + const total = await eventsTable.count({ ...remParamsWithoutOrderAndSort }); events.meta = { count: events.data.length, From 97029723101d4f7d1e72425eedf25f539ef1531b Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Thu, 19 Oct 2023 16:02:31 +0530 Subject: [PATCH 6/7] Updated unit tests for events --- .../shared/dataService/business/events.js | 2 +- .../tests/unit/shared/constants/events.js | 33 ++++++++++++------- .../dataservice/business/events.test.js | 1 + 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/services/blockchain-indexer/shared/dataService/business/events.js b/services/blockchain-indexer/shared/dataService/business/events.js index 654ea4a2be..097eae4c9c 100644 --- a/services/blockchain-indexer/shared/dataService/business/events.js +++ b/services/blockchain-indexer/shared/dataService/business/events.js @@ -207,7 +207,7 @@ const getEvents = async (params) => { ); const { order, sort, ...remParamsWithoutOrderAndSort } = params; - const total = await eventsTable.count({ ...remParamsWithoutOrderAndSort }); + const total = await eventsTable.count(remParamsWithoutOrderAndSort); events.meta = { count: events.data.length, diff --git a/services/blockchain-indexer/tests/unit/shared/constants/events.js b/services/blockchain-indexer/tests/unit/shared/constants/events.js index 80c604bbd6..e6cecc505e 100644 --- a/services/blockchain-indexer/tests/unit/shared/constants/events.js +++ b/services/blockchain-indexer/tests/unit/shared/constants/events.js @@ -69,52 +69,52 @@ const mockEventTopics = [ const mockEventsForEventTopics = [ { - eventStr: '{"data":{"address":"lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp"],"height":125247,"id":"392eadd8f1703efd2b9d5fae72e272da1806fc3fb667c67e0ef71035f941710f"}', + eventStr: '{"data":{"address":"lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125247,"id":"392eadd8f1703efd2b9d5fae72e272da1806fc3fb667c67e0ef71035f941710f"}', height: 125247, index: 0, }, { - eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp"],"height":125247,"id":"180fccd1d16dd9806454e2a5f48da020aa5590df0100c72659e713ab502ca4b0"}', + eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125247,"id":"180fccd1d16dd9806454e2a5f48da020aa5590df0100c72659e713ab502ca4b0"}', height: 125247, index: 1, }, { - eventStr: '{"data":{"address":"lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c"],"height":125246,"id":"51291dcc8010176f33f2a250d00869d5c423ad053204a204ebcb4a1b5dd19bc4"}', + eventStr: '{"data":{"address":"lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125246,"id":"51291dcc8010176f33f2a250d00869d5c423ad053204a204ebcb4a1b5dd19bc4"}', height: 125246, index: 0, }, { - eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c"],"height":125246,"id":"75ae7452e1d304b846e1531c73f696d169b38926a603df4092cd4c2c924fbe75"}', + eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125246,"id":"75ae7452e1d304b846e1531c73f696d169b38926a603df4092cd4c2c924fbe75"}', height: 125246, index: 1, }, { - eventStr: '{"data":{"address":"lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg"],"height":125245,"id":"af100a3fcfc221b0c62edb60bc88a78633e17f5bda449dc43216c2dedda3f20c"}', + eventStr: '{"data":{"address":"lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125245,"id":"af100a3fcfc221b0c62edb60bc88a78633e17f5bda449dc43216c2dedda3f20c"}', height: 125245, index: 0, }, { - eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg"],"height":125245,"id":"5f31caae2e0a606a86b1425d49ab1d6543d06fe42b39b97397e9739d8ed87785"}', + eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125245,"id":"5f31caae2e0a606a86b1425d49ab1d6543d06fe42b39b97397e9739d8ed87785"}', height: 125245, index: 1, }, { - eventStr: '{"data":{"address":"lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg"],"height":125244,"id":"6d15e5798dbc1e7b43fdd9d9c66d95f181dc4349ed8821e8209aa73c28939406"}', + eventStr: '{"data":{"address":"lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125244,"id":"6d15e5798dbc1e7b43fdd9d9c66d95f181dc4349ed8821e8209aa73c28939406"}', height: 125244, index: 0, }, { - eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg"],"height":125244,"id":"0d39438acc199f647af69ecfb675775f31bf8b1dcbd3cf5f0d6fdecfb68a7910"}', + eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125244,"id":"0d39438acc199f647af69ecfb675775f31bf8b1dcbd3cf5f0d6fdecfb68a7910"}', height: 125244, index: 1, }, { - eventStr: '{"data":{"address":"lskw68y3kyus7ota9mykr726aby44mw574m8dkngu","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskw68y3kyus7ota9mykr726aby44mw574m8dkngu"],"height":125243,"id":"48131594ec7324a815f43d0e5e6122104a0c0573e97760abb53c5930ac1f481b"}', + eventStr: '{"data":{"address":"lskw68y3kyus7ota9mykr726aby44mw574m8dkngu","tokenID":"0400000000000000","amount":"94953271","result":0},"index":0,"module":"token","name":"mint","topics":["03","lskw68y3kyus7ota9mykr726aby44mw574m8dkngu","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125243,"id":"48131594ec7324a815f43d0e5e6122104a0c0573e97760abb53c5930ac1f481b"}', height: 125243, index: 0, }, { - eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskw68y3kyus7ota9mykr726aby44mw574m8dkngu"],"height":125243,"id":"8c50ade215fd89a9e351a338cd8389bec6d64babb03dbc8611d5bdd433cec181"}', + eventStr: '{"data":{"amount":"94953271","reduction":0},"index":1,"module":"dynamicReward","name":"rewardMinted","topics":["03","lskw68y3kyus7ota9mykr726aby44mw574m8dkngu","c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b"],"height":125243,"id":"8c50ade215fd89a9e351a338cd8389bec6d64babb03dbc8611d5bdd433cec181"}', height: 125243, index: 1, }, @@ -135,6 +135,7 @@ const getEventsResult = { topics: [ '03', 'lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125247, id: '392eadd8f1703efd2b9d5fae72e272da1806fc3fb667c67e0ef71035f941710f', @@ -153,6 +154,7 @@ const getEventsResult = { topics: [ '03', 'lskfonwc5wpgy5873ckejqujwp3uwvtagejrjftpp', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125247, id: '180fccd1d16dd9806454e2a5f48da020aa5590df0100c72659e713ab502ca4b0', @@ -173,6 +175,7 @@ const getEventsResult = { topics: [ '03', 'lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125246, id: '51291dcc8010176f33f2a250d00869d5c423ad053204a204ebcb4a1b5dd19bc4', @@ -191,6 +194,7 @@ const getEventsResult = { topics: [ '03', 'lskd2ohufqtv7fqtnv75ca2w23krz2692mxvj8q3c', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125246, id: '75ae7452e1d304b846e1531c73f696d169b38926a603df4092cd4c2c924fbe75', @@ -211,6 +215,7 @@ const getEventsResult = { topics: [ '03', 'lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125245, id: 'af100a3fcfc221b0c62edb60bc88a78633e17f5bda449dc43216c2dedda3f20c', @@ -229,6 +234,7 @@ const getEventsResult = { topics: [ '03', 'lskfok9nevnkj8pzh8nr6rtmrtn4zmrp9g66ygbqg', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125245, id: '5f31caae2e0a606a86b1425d49ab1d6543d06fe42b39b97397e9739d8ed87785', @@ -249,6 +255,7 @@ const getEventsResult = { topics: [ '03', 'lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125244, id: '6d15e5798dbc1e7b43fdd9d9c66d95f181dc4349ed8821e8209aa73c28939406', @@ -267,6 +274,7 @@ const getEventsResult = { topics: [ '03', 'lskbnqdbfhxefdr5q6ovtcynrbhzvhf6d9qhsyntg', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125244, id: '0d39438acc199f647af69ecfb675775f31bf8b1dcbd3cf5f0d6fdecfb68a7910', @@ -287,6 +295,7 @@ const getEventsResult = { topics: [ '03', 'lskw68y3kyus7ota9mykr726aby44mw574m8dkngu', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125243, id: '48131594ec7324a815f43d0e5e6122104a0c0573e97760abb53c5930ac1f481b', @@ -305,6 +314,7 @@ const getEventsResult = { topics: [ '03', 'lskw68y3kyus7ota9mykr726aby44mw574m8dkngu', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', ], height: 125243, id: '8c50ade215fd89a9e351a338cd8389bec6d64babb03dbc8611d5bdd433cec181', @@ -325,11 +335,12 @@ const mockEventTopicsQueryParams = { property: 'topic', values: [ '03', + 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', 'lskw68y3kyus7ota9mykr726aby44mw574m8dkngu', ], }, groupBy: 'eventID', - havingRaw: 'COUNT(DISTINCT topic) = 2', + havingRaw: 'COUNT(DISTINCT topic) = 3', }; module.exports = { diff --git a/services/blockchain-indexer/tests/unit/shared/dataservice/business/events.test.js b/services/blockchain-indexer/tests/unit/shared/dataservice/business/events.test.js index 8cac013b8a..6c5438b55c 100644 --- a/services/blockchain-indexer/tests/unit/shared/dataservice/business/events.test.js +++ b/services/blockchain-indexer/tests/unit/shared/dataservice/business/events.test.js @@ -245,6 +245,7 @@ describe('getEvents', () => { blockID, topic: '03', senderAddress: 'lskw68y3kyus7ota9mykr726aby44mw574m8dkngu', + transactionID: 'c8ee3933cc841287d834f74f278ac12f145f320d0593a612e11b67b4a58cd17b', timestamp: '1:1000000000', height: '1:1000', sort: 'timestamp:desc', From cb90ac606130a318018da34c98645b8ff3bc9f67 Mon Sep 17 00:00:00 2001 From: Vardan Nadkarni Date: Thu, 19 Oct 2023 17:38:04 +0530 Subject: [PATCH 7/7] Applied suggestions --- .../functional/database/mysql/mysql.test.js | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/framework/tests/functional/database/mysql/mysql.test.js b/framework/tests/functional/database/mysql/mysql.test.js index 9d11e45f8b..b2b1fc11ab 100644 --- a/framework/tests/functional/database/mysql/mysql.test.js +++ b/framework/tests/functional/database/mysql/mysql.test.js @@ -80,10 +80,8 @@ describe('Test MySQL', () => { }); describe('With IMPLICIT DB transaction (auto-commit mode)', () => { - afterAll(() => blocksTable.rawQuery(`TRUNCATE ${tableName}`)); - afterEach(async () => { - blocksTable.rawQuery(`DELETE FROM ${tableName}`); + await blocksTable.rawQuery(`TRUNCATE ${tableName}`); }); it('should insert row', async () => { @@ -217,6 +215,7 @@ describe('Test MySQL', () => { }); it('should get row count', async () => { + await blocksTable.upsert([emptyBlock, nonEmptyBlock]); const count = await blocksTable.count(); expect(count).toBe(2); }); @@ -749,10 +748,8 @@ describe('Test MySQL', () => { }); describe('With EXPLICIT DB transaction (non-auto commit mode)', () => { - afterAll(() => blocksTable.rawQuery(`TRUNCATE ${tableName}`)); - afterEach(async () => { - blocksTable.rawQuery(`DELETE FROM ${tableName}`); + await blocksTable.rawQuery(`TRUNCATE ${tableName}`); }); it('should insert row', async () => { @@ -766,6 +763,11 @@ describe('Test MySQL', () => { }); it('should get rows', async () => { + const connection = await getDBConnection(); + const trx = await startDBTransaction(connection); + await blocksTable.upsert([emptyBlock], trx); + await commitDBTransaction(trx); + const result = await blocksTable.find({ id: emptyBlock.id }, ['id']); expect(result).toBeInstanceOf(Array); expect(result.length).toBe(1); @@ -933,6 +935,11 @@ describe('Test MySQL', () => { }); it('should get row count', async () => { + const connection = await getDBConnection(); + const trx = await startDBTransaction(connection); + await blocksTable.upsert([emptyBlock, nonEmptyBlock], trx); + await commitDBTransaction(trx); + const count = await blocksTable.count(); expect(count).toBe(2); }); @@ -1401,7 +1408,7 @@ describe('Test MySQL', () => { describe('Transactional atomicity guarantees (non-auto commit mode)', () => { afterEach(async () => { - blocksTable.rawQuery(`DELETE FROM ${tableName}`); + await blocksTable.rawQuery(`TRUNCATE ${tableName}`); }); it('should perform a successful transaction commit', async () => {