Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NetworkState Service #113

Merged
merged 10 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@
distanceFromMaxBlockHeight: Int!
}

type MaxBlockHeightInfo {

Check notice on line 49 in schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Type 'MaxBlockHeightInfo' was added

Type 'MaxBlockHeightInfo' was added
canonicalMaxBlockHeight: Int!
pendingMaxBlockHeight: Int!
}

type TransactionInfo {
status: String!
hash: String!
Expand Down Expand Up @@ -75,7 +80,12 @@
actionState: ActionStates!
}

type NetworkStateOutput {

Check notice on line 83 in schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Type 'NetworkStateOutput' was added

Type 'NetworkStateOutput' was added
maxBlockHeight: MaxBlockHeightInfo
}

type Query {
events(input: EventFilterOptionsInput!): [EventOutput]!
actions(input: ActionFilterOptionsInput!): [ActionOutput]!
networkState: NetworkStateOutput!

Check notice on line 90 in schema.graphql

View workflow job for this annotation

GitHub Actions / GraphQL Inspector

Field 'networkState' was added to object type 'Query'

Field 'networkState' was added to object type 'Query'
}
9 changes: 9 additions & 0 deletions src/blockchain/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ export type Action = {
data: string[];
};

export type NetworkState = {
maxBlockHeight: MaxBlockHeightInfo;
};

export type MaxBlockHeightInfo = {
canonicalMaxBlockHeight: number;
pendingMaxBlockHeight: number;
};

export type BlockInfo = {
height: number;
stateHash: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import type { EventFilterOptionsInput } from '../../resolvers-types.js';
import type { Actions, Events } from '../../blockchain/types.js';
import type {
Actions,
Events,
NetworkState,
} from '../../blockchain/types.js';

export interface DatabaseAdapter {
getEvents(input: EventFilterOptionsInput, options?: unknown): Promise<Events>;
getActions(
input: EventFilterOptionsInput,
options?: unknown
): Promise<Actions>;
getNetworkState(options?: unknown): Promise<NetworkState>;
}
14 changes: 13 additions & 1 deletion src/db/archive-node-adapter/archive-node-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import postgres from 'postgres';
import type { Actions, Events } from '../../blockchain/types.js';
import type {
Actions,
Events,
NetworkState,
} from '../../blockchain/types.js';
import type { DatabaseAdapter } from './archive-node-adapter.interface.js';
import type {
ActionFilterOptionsInput,
Expand All @@ -10,6 +14,8 @@ import { EventsService } from '../../services/events-service/events-service.js';
import { IEventsService } from '../../services/events-service/events-service.interface.js';
import { ActionsService } from '../../services/actions-service/actions-service.js';
import { IActionsService } from '../../services/actions-service/actions-service.interface.js';
import { NetworkService } from '../../services/network-service/network-service.js';
import { INetworkService } from '../../services/network-service/network-service.interface.js';

export class ArchiveNodeAdapter implements DatabaseAdapter {
/**
Expand All @@ -21,6 +27,7 @@ export class ArchiveNodeAdapter implements DatabaseAdapter {
private client: postgres.Sql;
private eventsService: IEventsService;
private actionsService: IActionsService;
private networkService: INetworkService;

constructor(connectionString: string | undefined) {
if (!connectionString)
Expand All @@ -30,6 +37,7 @@ export class ArchiveNodeAdapter implements DatabaseAdapter {
this.client = postgres(connectionString);
this.eventsService = new EventsService(this.client);
this.actionsService = new ActionsService(this.client);
this.networkService = new NetworkService(this.client);
}

async getEvents(
Expand All @@ -46,6 +54,10 @@ export class ArchiveNodeAdapter implements DatabaseAdapter {
return this.actionsService.getActions(input, options);
}

async getNetworkState(options: unknown): Promise<NetworkState> {
return this.networkService.getNetworkState(options);
}

async checkSQLSchema() {
let tables;
try {
Expand Down
18 changes: 18 additions & 0 deletions src/db/sql/events-actions/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,24 @@ export function getActionsQuery(
`;
}

export function getNetworkStateQuery(db_client: postgres.Sql) {
return db_client`
WITH max_heights AS (
SELECT
chain_status,
MAX(height) AS max_height
FROM blocks
WHERE chain_status IN ('canonical', 'pending')
GROUP BY chain_status
)
SELECT b.*
FROM blocks b
JOIN max_heights mh
ON b.chain_status = mh.chain_status
AND b.height = mh.max_height;
`;
}

export function checkActionState(db_client: postgres.Sql, actionState: string) {
return db_client`
SELECT field FROM zkapp_field WHERE field = ${actionState}
Expand Down
19 changes: 19 additions & 0 deletions src/resolvers-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ export type BlockInfo = {
timestamp: Scalars['String']['output'];
};

export type NetworkStateOutput = {
__typename?: 'NetworkStateOutput';
maxBlockHeight: MaxBlockHeightInfo
};

export type MaxBlockHeightInfo = {
__typename?: 'MaxBlockHeightInfo';
canonicalMaxBlockHeight: Scalars['Int']['output'];
pendingMaxBlockHeight: Scalars['Int']['output'];
};

export { BlockStatusFilter };

export type EventData = {
Expand Down Expand Up @@ -110,6 +121,7 @@ export type Query = {
__typename?: 'Query';
actions: Array<Maybe<ActionOutput>>;
events: Array<Maybe<EventOutput>>;
networkState: Maybe<NetworkStateOutput>;
};

export type QueryActionsArgs = {
Expand Down Expand Up @@ -242,6 +254,8 @@ export type ResolversTypes = {
ActionOutput: ResolverTypeWrapper<ActionOutput>;
ActionStates: ResolverTypeWrapper<ActionStates>;
BlockInfo: ResolverTypeWrapper<BlockInfo>;
NetworkStateOutput: ResolverTypeWrapper<NetworkStateOutput>;
MaxBlockHeightInfo: ResolverTypeWrapper<MaxBlockHeightInfo>;
BlockStatusFilter: BlockStatusFilter;
Boolean: ResolverTypeWrapper<Scalars['Boolean']['output']>;
EventData: ResolverTypeWrapper<EventData>;
Expand Down Expand Up @@ -438,6 +452,11 @@ export type QueryResolvers<
ContextType,
RequireFields<QueryEventsArgs, 'input'>
>;
networkState?: Resolver<
Maybe<ResolversTypes['NetworkStateOutput']>,
ParentType,
ContextType
>;
};

export type TransactionInfoResolvers<
Expand Down
10 changes: 10 additions & 0 deletions src/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ const resolvers: Resolvers = {
tracingState: new TracingState(graphQLSpan),
});
},

networkState: async (_, __, context) => {
const graphQLSpan = setSpanNameFromGraphQLContext(
context,
'networkState.graphql'
);
return context.db_client.getNetworkState({
tracingState: new TracingState(graphQLSpan),
});
},
},
};

Expand Down
5 changes: 5 additions & 0 deletions src/services/network-service/network-service.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { NetworkState } from '../../blockchain/types.js';

export interface INetworkService {
getNetworkState(options: unknown): Promise<NetworkState>;
}
53 changes: 53 additions & 0 deletions src/services/network-service/network-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import type postgres from 'postgres';
import { NetworkState } from '../../blockchain/types.js';
import { getNetworkStateQuery } from '../../db/sql/events-actions/queries.js';

import { INetworkService } from './network-service.interface.js';
import {
TracingState,
extractTraceStateFromOptions,
} from '../../tracing/tracer.js';

export { NetworkService };

class NetworkService implements INetworkService {
private readonly client: postgres.Sql;

constructor(client: postgres.Sql) {
this.client = client;
}

async getNetworkState(options: unknown): Promise<NetworkState> {
const tracingState = extractTraceStateFromOptions(options);
return (await this.getNetworkStateData({ tracingState })) ?? [];
}

async getNetworkStateData({
tracingState,
}: {
tracingState: TracingState;
}): Promise<NetworkState> {
const sqlSpan = tracingState.startSpan('networkState.SQL');
const rows = await this.executeNetworkStateQuery();
sqlSpan.end();

const processingSpan = tracingState.startSpan('networkState.processing');
const maxBlockHeightInfo = {
canonicalMaxBlockHeight: Number(
rows.filter((row) => row.chain_status === 'canonical')[0].height
),
pendingMaxBlockHeight: Number(
rows.filter((row) => row.chain_status === 'pending')[0].height
),
};
const networkState = {
maxBlockHeight: maxBlockHeightInfo
}
processingSpan.end();
return networkState;
}

private async executeNetworkStateQuery() {
return getNetworkStateQuery(this.client);
}
}
Loading
Loading