From e2466cf6cde46a91d7d50ac811e4878e51de14a5 Mon Sep 17 00:00:00 2001 From: Coby Date: Mon, 20 Jan 2025 11:57:28 -0500 Subject: [PATCH 1/8] move block filter up within the query --- src/db/sql/events-actions/queries.ts | 30 +++++++++++++--------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/db/sql/events-actions/queries.ts b/src/db/sql/events-actions/queries.ts index 9483f65..ed461fe 100644 --- a/src/db/sql/events-actions/queries.ts +++ b/src/db/sql/events-actions/queries.ts @@ -2,7 +2,7 @@ import type postgres from 'postgres'; import { ArchiveNodeDatabaseRow } from './types.js'; import { BlockStatusFilter } from '../../../blockchain/types.js'; -function fullChainCTE(db_client: postgres.Sql) { +function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { return db_client` RECURSIVE pending_chain AS ( ( @@ -18,9 +18,12 @@ function fullChainCTE(db_client: postgres.Sql) { b.id, b.state_hash, b.parent_hash, b.parent_id, b.height, b.global_slot_since_genesis, b.global_slot_since_hard_fork, b.timestamp, b.chain_status, b.ledger_hash, b.last_vrf_output FROM blocks b - INNER JOIN pending_chain ON b.id = pending_chain.parent_id - AND pending_chain.id <> pending_chain.parent_id - AND pending_chain.chain_status <> 'canonical' + INNER JOIN pending_chain ON b.id = pending_chain.parent_id + AND pending_chain.id <> pending_chain.parent_id + AND pending_chain.chain_status <> 'canonical' + WHERE 1=1 + ${to ? db_client`AND b.height <= ${to}` : db_client``} + ${from ? db_client`AND b.height >= ${from}` : db_client``} ), full_chain AS ( SELECT @@ -38,6 +41,8 @@ function fullChainCTE(db_client: postgres.Sql) { blocks b WHERE chain_status = 'canonical' + ${to ? db_client`AND b.height <= ${to}` : db_client``} + ${from ? db_client`AND b.height >= ${from}` : db_client``} ) AS full_chain ) `; @@ -61,12 +66,7 @@ function accountIdentifierCTE( )`; } -function blocksAccessedCTE( - db_client: postgres.Sql, - status: BlockStatusFilter, - to?: string, - from?: string -) { +function blocksAccessedCTE(db_client: postgres.Sql, status: BlockStatusFilter) { return db_client` blocks_accessed AS ( @@ -97,8 +97,6 @@ function blocksAccessedCTE( ? db_client`` : db_client`AND chain_status = ${status.toLowerCase()}` } - ${to ? db_client`AND b.height <= ${to}` : db_client``} - ${from ? db_client`AND b.height >= ${from}` : db_client``} )`; } @@ -308,9 +306,9 @@ export function getEventsQuery( ) { return db_client` WITH - ${fullChainCTE(db_client)}, + ${fullChainCTE(db_client, to, from)}, ${accountIdentifierCTE(db_client, address, tokenId)}, - ${blocksAccessedCTE(db_client, status, to, from)}, + ${blocksAccessedCTE(db_client, status)}, ${emittedZkAppCommandsCTE(db_client)}, ${emittedEventsCTE(db_client)} SELECT @@ -360,9 +358,9 @@ export function getActionsQuery( ) { return db_client` WITH - ${fullChainCTE(db_client)}, + ${fullChainCTE(db_client, from, to)}, ${accountIdentifierCTE(db_client, address, tokenId)}, - ${blocksAccessedCTE(db_client, status, to, from)}, + ${blocksAccessedCTE(db_client, status)}, ${emittedZkAppCommandsCTE(db_client)}, ${emittedActionsCTE(db_client)}, ${emittedActionStateCTE(db_client, fromActionState, endActionState)} From bc390bb02c324f291bdc0dba6a3f44ea474a5ee9 Mon Sep 17 00:00:00 2001 From: Coby Date: Mon, 20 Jan 2025 13:03:03 -0500 Subject: [PATCH 2/8] limit queries to 10k block ranges --- src/db/sql/events-actions/queries.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/db/sql/events-actions/queries.ts b/src/db/sql/events-actions/queries.ts index ed461fe..49ffd84 100644 --- a/src/db/sql/events-actions/queries.ts +++ b/src/db/sql/events-actions/queries.ts @@ -22,8 +22,18 @@ function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { AND pending_chain.id <> pending_chain.parent_id AND pending_chain.chain_status <> 'canonical' WHERE 1=1 - ${to ? db_client`AND b.height <= ${to}` : db_client``} - ${from ? db_client`AND b.height >= ${from}` : db_client``} + ${to ? db_client`AND b.height <= ${to}` : db_client``} + ${ + from + ? db_client`AND b.height >= ${from}` + : to + ? db_client`AND b.height >= ${Number(to) - 10000}` + : db_client`AND b.height >= ( + SELECT MAX(b2.height) + FROM blocks b2 + WHERE b2.chain_status = 'canonical' + ) - 10000` + } ), full_chain AS ( SELECT @@ -42,7 +52,17 @@ function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { WHERE chain_status = 'canonical' ${to ? db_client`AND b.height <= ${to}` : db_client``} - ${from ? db_client`AND b.height >= ${from}` : db_client``} + ${ + from + ? db_client`AND b.height >= ${from}` + : to + ? db_client`AND b.height >= ${Number(to) - 10000}` + : db_client`AND b.height >= ( + SELECT MAX(b2.height) + FROM blocks b2 + WHERE b2.chain_status = 'canonical' + ) - 10000` + } ) AS full_chain ) `; From 260283beb0fb8e6e1ee5fbf94713968c93d08584 Mon Sep 17 00:00:00 2001 From: Coby Date: Mon, 20 Jan 2025 14:13:26 -0500 Subject: [PATCH 3/8] invert the params in the events query --- src/db/sql/events-actions/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/sql/events-actions/queries.ts b/src/db/sql/events-actions/queries.ts index 49ffd84..e512332 100644 --- a/src/db/sql/events-actions/queries.ts +++ b/src/db/sql/events-actions/queries.ts @@ -326,7 +326,7 @@ export function getEventsQuery( ) { return db_client` WITH - ${fullChainCTE(db_client, to, from)}, + ${fullChainCTE(db_client, from, to)}, ${accountIdentifierCTE(db_client, address, tokenId)}, ${blocksAccessedCTE(db_client, status)}, ${emittedZkAppCommandsCTE(db_client)}, From 3f362b8db35c7d09057e8292f1ce46321d52257c Mon Sep 17 00:00:00 2001 From: Coby Date: Mon, 20 Jan 2025 16:09:55 -0500 Subject: [PATCH 4/8] edge case typo --- src/db/sql/events-actions/queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/sql/events-actions/queries.ts b/src/db/sql/events-actions/queries.ts index e512332..e16462a 100644 --- a/src/db/sql/events-actions/queries.ts +++ b/src/db/sql/events-actions/queries.ts @@ -31,7 +31,7 @@ function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { : db_client`AND b.height >= ( SELECT MAX(b2.height) FROM blocks b2 - WHERE b2.chain_status = 'canonical' + WHERE b2.chain_status <> 'canonical' ) - 10000` } ), From 052b5b96c5965c61f7cfec44440e8165c14c88e6 Mon Sep 17 00:00:00 2001 From: Coby Date: Tue, 21 Jan 2025 12:57:01 -0500 Subject: [PATCH 5/8] make BLOCK_RANGE_SIZE into a param --- .env.example.compose | 2 ++ .env.example.lightnet | 2 ++ src/db/sql/events-actions/queries.ts | 34 ++++++++++++---------------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.env.example.compose b/.env.example.compose index aadac95..c7e31ba 100644 --- a/.env.example.compose +++ b/.env.example.compose @@ -38,3 +38,5 @@ JAEGER_ENDPOINT=http://jaeger:14268/api/traces COLLECTOR_ZIPKIN_HTTP_PORT=9411 JAEGER_FRONTEND=16686 JAEGER_LOG_PORT=14268 + +BLOCK_RANGE_SIZE=10000 diff --git a/.env.example.lightnet b/.env.example.lightnet index fc5ec82..fe3daf7 100644 --- a/.env.example.lightnet +++ b/.env.example.lightnet @@ -12,3 +12,5 @@ ENABLE_LOGGING="true" ENABLE_JAEGER="true" JAEGER_SERVICE_NAME="archive-api" JAEGER_ENDPOINT='http://localhost:14268/api/traces' + +BLOCK_RANGE_SIZE=10000 diff --git a/src/db/sql/events-actions/queries.ts b/src/db/sql/events-actions/queries.ts index e16462a..201d324 100644 --- a/src/db/sql/events-actions/queries.ts +++ b/src/db/sql/events-actions/queries.ts @@ -2,7 +2,17 @@ import type postgres from 'postgres'; import { ArchiveNodeDatabaseRow } from './types.js'; import { BlockStatusFilter } from '../../../blockchain/types.js'; +const BLOCK_RANGE_SIZE = Number(process.env.BLOCK_RANGE_SIZE) || 10000; + function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { + let toAsNum = to ? Number(to) : undefined; + let fromAsNum = from ? Number(from) : undefined; + if (fromAsNum) { + const maxRange = fromAsNum + BLOCK_RANGE_SIZE; + toAsNum = toAsNum ? Math.min(toAsNum, maxRange) : maxRange; + } else if (toAsNum) { + fromAsNum = toAsNum - BLOCK_RANGE_SIZE; + } return db_client` RECURSIVE pending_chain AS ( ( @@ -22,18 +32,6 @@ function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { AND pending_chain.id <> pending_chain.parent_id AND pending_chain.chain_status <> 'canonical' WHERE 1=1 - ${to ? db_client`AND b.height <= ${to}` : db_client``} - ${ - from - ? db_client`AND b.height >= ${from}` - : to - ? db_client`AND b.height >= ${Number(to) - 10000}` - : db_client`AND b.height >= ( - SELECT MAX(b2.height) - FROM blocks b2 - WHERE b2.chain_status <> 'canonical' - ) - 10000` - } ), full_chain AS ( SELECT @@ -51,17 +49,15 @@ function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { blocks b WHERE chain_status = 'canonical' - ${to ? db_client`AND b.height <= ${to}` : db_client``} ${ - from - ? db_client`AND b.height >= ${from}` - : to - ? db_client`AND b.height >= ${Number(to) - 10000}` + // If fromAsNum is not undefined, then we have also set toAsNum and can safely query the range + // If no params ar provided, then we query the last BLOCK_RANGE_SIZE blocks + fromAsNum + ? db_client`AND b.height >= ${fromAsNum} AND b.height >= ${toAsNum!}` : db_client`AND b.height >= ( SELECT MAX(b2.height) FROM blocks b2 - WHERE b2.chain_status = 'canonical' - ) - 10000` + ) - ${BLOCK_RANGE_SIZE}` } ) AS full_chain ) From 16bc05071b3a17fd60088bf9ba1b58d5a35fbaf1 Mon Sep 17 00:00:00 2001 From: Coby Date: Tue, 21 Jan 2025 16:39:38 -0500 Subject: [PATCH 6/8] adding docs, tests, cleaning up a bit --- schema.graphql | 50 +++++- src/db/sql/events-actions/queries.ts | 5 +- src/errors/error.ts | 6 +- src/resolvers.ts | 1 + src/server/server.ts | 3 +- .../actions-service/actions-service.ts | 16 +- src/services/events-service/events-service.ts | 9 +- tests/resolvers.test.ts | 148 ++++++++++++++---- 8 files changed, 198 insertions(+), 40 deletions(-) diff --git a/schema.graphql b/schema.graphql index 3e236e1..4a9df79 100644 --- a/schema.graphql +++ b/schema.graphql @@ -1,24 +1,66 @@ +""" +Filter for the consensus status of the block +""" enum BlockStatusFilter { + """ + All blocks + """ ALL + """ + Only pending blocks + """ PENDING + """ + Only canonical (finalized) blocks + """ CANONICAL } +""" +Filter events from a specific account + +**WARNING**: The graphQL schema server will limit the block scan range to a fixed number of blocks. The default is 10,000 blocks, but can be changed by the host. +It is the responsibility of the client to use a block range that is within the limit, which will guarantee that all events are eventually returned. It is possible to get a partial result if you do not specify both a `from` and a `to` parameter. +""" input EventFilterOptionsInput { address: String! tokenId: String status: BlockStatusFilter + """ + Mina block height to filter events to, exclusive + """ to: Int + """ + Mina block height to filter events from, inclusive + """ from: Int } +""" +Filter actions from a specific account + +**WARNING**: The graphQL schema server will limit the block scan range to a fixed number of blocks. The default is 10,000 blocks, but can be changed by the host. +It is the responsibility of the client to use a block range that is within the limit, which will guarantee that all actions are eventually returned. It is possible to get a partial result if you do not specify both a `from` and a `to` parameter. +""" input ActionFilterOptionsInput { address: String! tokenId: String status: BlockStatusFilter + """ + Mina block height to filter actions to, exclusive + """ to: Int + """ + Mina block height to filter actions from, inclusive + """ from: Int + """ + Filter for actions that happened after this action state, inclusive + """ fromActionState: String + """ + Filter for actions that happened before this action state, inclusive + """ endActionState: String } @@ -56,7 +98,7 @@ type TransactionInfo { hash: String! memo: String! authorizationKind: String! - sequenceNumber: Int! # TODO: Is it ok to make this required? + sequenceNumber: Int! zkappAccountUpdateIds: [Int]! } @@ -80,7 +122,13 @@ type ActionOutput { actionState: ActionStates! } +""" +Metadata about the network +""" type NetworkStateOutput { + """ + Returns the latest pending and canonical block heights that are synced by the archive node. If the archive node is not fully synced, the pending block height will be lower than the actual network state. Wait some time for the archive node to get back in sync. + """ maxBlockHeight: MaxBlockHeightInfo } diff --git a/src/db/sql/events-actions/queries.ts b/src/db/sql/events-actions/queries.ts index 201d324..fe3e14f 100644 --- a/src/db/sql/events-actions/queries.ts +++ b/src/db/sql/events-actions/queries.ts @@ -1,8 +1,7 @@ import type postgres from 'postgres'; import { ArchiveNodeDatabaseRow } from './types.js'; import { BlockStatusFilter } from '../../../blockchain/types.js'; - -const BLOCK_RANGE_SIZE = Number(process.env.BLOCK_RANGE_SIZE) || 10000; +import { BLOCK_RANGE_SIZE } from '../../../server/server.js'; function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { let toAsNum = to ? Number(to) : undefined; @@ -53,7 +52,7 @@ function fullChainCTE(db_client: postgres.Sql, from?: string, to?: string) { // If fromAsNum is not undefined, then we have also set toAsNum and can safely query the range // If no params ar provided, then we query the last BLOCK_RANGE_SIZE blocks fromAsNum - ? db_client`AND b.height >= ${fromAsNum} AND b.height >= ${toAsNum!}` + ? db_client`AND b.height >= ${fromAsNum} AND b.height < ${toAsNum!}` : db_client`AND b.height >= ( SELECT MAX(b2.height) FROM blocks b2 diff --git a/src/errors/error.ts b/src/errors/error.ts index c7e14b6..3209526 100644 --- a/src/errors/error.ts +++ b/src/errors/error.ts @@ -1,6 +1,6 @@ import { GraphQLError } from 'graphql'; -export { throwGraphQLError, throwActionStateError }; +export { throwGraphQLError, throwActionStateError, throwBlockRangeError }; function throwGraphQLError(message: string, code?: string, status?: number) { throw new GraphQLError(message, { @@ -14,3 +14,7 @@ function throwGraphQLError(message: string, code?: string, status?: number) { function throwActionStateError(message: string) { throwGraphQLError(message, 'ACTION_STATE_NOT_FOUND', 400); } + +function throwBlockRangeError(message: string) { + throwGraphQLError(message, 'BLOCK_RANGE_ERROR', 400); +} diff --git a/src/resolvers.ts b/src/resolvers.ts index 6052eef..69e2390 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -1,6 +1,7 @@ import { makeExecutableSchema } from '@graphql-tools/schema'; import { loadSchemaSync } from '@graphql-tools/load'; import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'; +import { GraphQLError } from 'graphql'; import { Resolvers } from './resolvers-types.js'; import { diff --git a/src/server/server.ts b/src/server/server.ts index 8505839..eeca23b 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -4,9 +4,10 @@ import { Plugin } from '@envelop/core'; import { schema } from '../resolvers.js'; import type { GraphQLContext } from '../context.js'; -export { buildServer }; +export { BLOCK_RANGE_SIZE, buildServer }; const LOG_LEVEL = (process.env.LOG_LEVEL as LogLevel) || 'info'; +const BLOCK_RANGE_SIZE = Number(process.env.BLOCK_RANGE_SIZE) || 10000; function buildServer(context: GraphQLContext, plugins: Plugin[]) { const yoga = createYoga({ diff --git a/src/services/actions-service/actions-service.ts b/src/services/actions-service/actions-service.ts index 03652bf..d99b60b 100644 --- a/src/services/actions-service/actions-service.ts +++ b/src/services/actions-service/actions-service.ts @@ -26,7 +26,14 @@ import { TracingState, extractTraceStateFromOptions, } from '../../tracing/tracer.js'; -import { throwActionStateError } from '../../errors/error.js'; +import { + throwActionStateError, + throwBlockRangeError, +} from '../../errors/error.js'; +import dotenv from 'dotenv'; +import { BLOCK_RANGE_SIZE } from '../../server/server.js'; + +dotenv.config(); export { ActionsService }; @@ -97,7 +104,12 @@ class ActionsService implements IActionsService { tokenId ||= DEFAULT_TOKEN_ID; status ||= BlockStatusFilter.all; if (to && from && to < from) { - throw new Error('to must be greater than from'); + throwBlockRangeError('to must be greater than from'); + } + if (to && from && to - from > BLOCK_RANGE_SIZE) { + throwBlockRangeError( + `The block range is too large. The maximum range is ${BLOCK_RANGE_SIZE}` + ); } return getActionsQuery( diff --git a/src/services/events-service/events-service.ts b/src/services/events-service/events-service.ts index eeff1b4..414b663 100644 --- a/src/services/events-service/events-service.ts +++ b/src/services/events-service/events-service.ts @@ -22,6 +22,8 @@ import { TracingState, extractTraceStateFromOptions, } from '../../tracing/tracer.js'; +import { BLOCK_RANGE_SIZE } from '../../server/server.js'; +import { throwBlockRangeError } from '../../errors/error.js'; export { EventsService }; @@ -67,7 +69,12 @@ class EventsService implements IEventsService { tokenId ||= DEFAULT_TOKEN_ID; status ||= BlockStatusFilter.all; if (to && from && to < from) { - throw new Error('to must be greater than from'); + throwBlockRangeError('to must be greater than from'); + } + if (to && from && to - from > BLOCK_RANGE_SIZE) { + throwBlockRangeError( + `The block range is too large. The maximum range is ${BLOCK_RANGE_SIZE}` + ); } return getEventsQuery( diff --git a/tests/resolvers.test.ts b/tests/resolvers.test.ts index 9344675..6bcf1d4 100644 --- a/tests/resolvers.test.ts +++ b/tests/resolvers.test.ts @@ -45,15 +45,15 @@ import { interface ExecutorResult { data: - | { - events: Array; - } - | { - actions: Array; - } - | { - networkState: NetworkStateOutput; - }; + | { + events: Array; + } + | { + actions: Array; + } + | { + networkState: NetworkStateOutput; + }; } interface EventQueryResult extends ExecutorResult { @@ -149,15 +149,15 @@ const PG_CONN = 'postgresql://postgres:postgres@localhost:5432/archive '; interface ExecutorResult { data: - | { - events: Array; - } - | { - actions: Array; - } - | { - networkState: NetworkStateOutput; - }; + | { + events: Array; + } + | { + actions: Array; + } + | { + networkState: NetworkStateOutput; + }; } interface EventQueryResult extends ExecutorResult { @@ -186,6 +186,8 @@ describe('Query Resolvers', async () => { async function executeActionsQuery(variableInput: { address: string; + from?: string; + to?: string; }): Promise { return (await executor({ variables: { @@ -197,6 +199,8 @@ describe('Query Resolvers', async () => { async function executeEventsQuery(variableInput: { address: string; + from?: string; + to?: string; }): Promise { return (await executor({ variables: { @@ -254,7 +258,7 @@ describe('Query Resolvers', async () => { process.exit(0); }); - describe("NetworkState", async () => { + describe('NetworkState', async () => { let blockResponse: NetworkStateOutput; let results: NetworkQueryResult; let fetchedBlockchainLength: number; @@ -265,35 +269,43 @@ describe('Query Resolvers', async () => { fetchedBlockchainLength = await fetchNetworkState(zkApp, senderKeypair); }); - test("Fetching the max block height should not throw", async () => { + test('Fetching the max block height should not throw', async () => { assert.doesNotThrow(async () => { await executeNetworkStateQuery(); }); }); - test("Fetching the max block height should return the max block height", async () => { + test('Fetching the max block height should return the max block height', async () => { blockResponse = results.data.networkState; assert.ok(blockResponse.maxBlockHeight.canonicalMaxBlockHeight > 0); assert.ok(blockResponse.maxBlockHeight.pendingMaxBlockHeight > 0); - assert.ok(blockResponse.maxBlockHeight.pendingMaxBlockHeight > blockResponse.maxBlockHeight.canonicalMaxBlockHeight); + assert.ok( + blockResponse.maxBlockHeight.pendingMaxBlockHeight > + blockResponse.maxBlockHeight.canonicalMaxBlockHeight + ); }); - test("Fetched max block height from archive node should match with the one from mina node", async () => { - assert.deepStrictEqual(blockResponse.maxBlockHeight.pendingMaxBlockHeight, fetchedBlockchainLength); + test('Fetched max block height from archive node should match with the one from mina node', async () => { + assert.deepStrictEqual( + blockResponse.maxBlockHeight.pendingMaxBlockHeight, + fetchedBlockchainLength + ); }); - - describe("Advance a block", async () => { + + describe('Advance a block', async () => { before(async () => { await new Promise((resolve) => setTimeout(resolve, 25000)); // wait for new lightnet block results = await executeNetworkStateQuery(); blockResponse = results.data.networkState; fetchedBlockchainLength = await fetchNetworkState(zkApp, senderKeypair); }); - test("Fetched max block height from archive node should match the one from mina node after one block", () => { - assert.deepStrictEqual(blockResponse.maxBlockHeight.pendingMaxBlockHeight, fetchedBlockchainLength); + test('Fetched max block height from archive node should match the one from mina node after one block', () => { + assert.deepStrictEqual( + blockResponse.maxBlockHeight.pendingMaxBlockHeight, + fetchedBlockchainLength + ); }); }); - }); describe('Events', async () => { @@ -316,6 +328,44 @@ describe('Query Resolvers', async () => { assert.strictEqual(results.data.events.length, 0); }); + test('Fetching events with from block greater than to block should throw', async () => { + assert.rejects( + async () => { + await executeEventsQuery({ + address: zkApp.address.toBase58(), + from: '100', + to: '10', + }); + }, + (err: Error) => { + assert.strictEqual(err.message, 'to must be greater than from'); + return true; + } + ); + }); + + test('Fetching events with to block more than BLOCK_RANGE_SIZE greater than from should throw', async () => { + const resetValue = process.env.BLOCK_RANGE_SIZE; + process.env.BLOCK_RANGE_SIZE = '10'; + assert.rejects( + async () => { + await executeEventsQuery({ + address: zkApp.address.toBase58(), + from: '100', + to: '111', + }); + }, + (err: Error) => { + assert.strictEqual( + err.message, + 'The block range is too large. The maximum range is 10' + ); + return true; + } + ); + process.env.BLOCK_RANGE_SIZE = resetValue; + }); + describe('After emitting an event with a single field once', async () => { before(async () => { await emitSingleEvent(zkApp, senderKeypair); @@ -487,6 +537,44 @@ describe('Query Resolvers', async () => { assert.strictEqual(results.data.actions.length, 0); }); + test('Fetching actions with from block greater than to block should throw', async () => { + assert.rejects( + async () => { + await executeActionsQuery({ + address: zkApp.address.toBase58(), + from: '100', + to: '10', + }); + }, + (err: Error) => { + assert.strictEqual(err.message, 'to must be greater than from'); + return true; + } + ); + }); + + test('Fetching actions with to block more than BLOCK_RANGE_SIZE greater than from should throw', async () => { + const resetValue = process.env.BLOCK_RANGE_SIZE; + process.env.BLOCK_RANGE_SIZE = '10'; + assert.rejects( + async () => { + await executeActionsQuery({ + address: zkApp.address.toBase58(), + from: '100', + to: '111', + }); + }, + (err: Error) => { + assert.strictEqual( + err.message, + 'The block range is too large. The maximum range is 10' + ); + return true; + } + ); + process.env.BLOCK_RANGE_SIZE = resetValue; + }); + describe('After emitting an action', async () => { const [s1, s2, s3] = [randomStruct(), randomStruct(), randomStruct()]; const testStructArray = { @@ -588,10 +676,8 @@ describe('Query Resolvers', async () => { }); }); }); - }); - function structToAction(s: TestStruct) { return [ s.x.toString(), From e7aacc0b39c6acfd5bf9f1b9cbd12ad8bf320143 Mon Sep 17 00:00:00 2001 From: Coby Date: Tue, 21 Jan 2025 16:42:25 -0500 Subject: [PATCH 7/8] fix linting error --- src/resolvers.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/resolvers.ts b/src/resolvers.ts index 69e2390..6052eef 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -1,7 +1,6 @@ import { makeExecutableSchema } from '@graphql-tools/schema'; import { loadSchemaSync } from '@graphql-tools/load'; import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'; -import { GraphQLError } from 'graphql'; import { Resolvers } from './resolvers-types.js'; import { From 2d73fe8a0b38fe9fa2f238985cbccc696a4d77af Mon Sep 17 00:00:00 2001 From: Coby Date: Tue, 21 Jan 2025 17:05:38 -0500 Subject: [PATCH 8/8] fix dotenv usages --- src/server/server.ts | 3 +++ src/services/actions-service/actions-service.ts | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/server.ts b/src/server/server.ts index eeca23b..21364cf 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -3,6 +3,9 @@ import { createServer } from 'http'; import { Plugin } from '@envelop/core'; import { schema } from '../resolvers.js'; import type { GraphQLContext } from '../context.js'; +import dotenv from 'dotenv'; + +dotenv.config(); export { BLOCK_RANGE_SIZE, buildServer }; diff --git a/src/services/actions-service/actions-service.ts b/src/services/actions-service/actions-service.ts index d99b60b..f35d73f 100644 --- a/src/services/actions-service/actions-service.ts +++ b/src/services/actions-service/actions-service.ts @@ -30,11 +30,8 @@ import { throwActionStateError, throwBlockRangeError, } from '../../errors/error.js'; -import dotenv from 'dotenv'; import { BLOCK_RANGE_SIZE } from '../../server/server.js'; -dotenv.config(); - export { ActionsService }; class ActionsService implements IActionsService {