diff --git a/packages/api/src/graphql/GraphqlSequencerModule.ts b/packages/api/src/graphql/GraphqlSequencerModule.ts index 5342e3702..fd4adef7f 100644 --- a/packages/api/src/graphql/GraphqlSequencerModule.ts +++ b/packages/api/src/graphql/GraphqlSequencerModule.ts @@ -1,16 +1,19 @@ -import assert from "node:assert"; - +import { buildSchemaSync, NonEmptyArray } from "type-graphql"; import { Closeable, closeable, SequencerModule } from "@proto-kit/sequencer"; import { ChildContainerProvider, Configurable, + CombinedModuleContainerConfig, log, ModuleContainer, ModulesRecord, TypedClass, } from "@proto-kit/common"; +import { GraphQLSchema } from "graphql/type"; +import { stitchSchemas } from "@graphql-tools/stitch"; +import { createYoga } from "graphql-yoga"; +import Koa from "koa"; -import { GraphqlServer } from "./GraphqlServer"; import { GraphqlModule, ResolverFactoryGraphqlModule, @@ -21,11 +24,46 @@ export type GraphqlModulesRecord = ModulesRecord< TypedClass> >; +export interface GraphqlServerConfig { + host: string; + port: number; + graphiql: boolean; +} + +export type GraphqlSequencerModuleConfig< + GraphQLModules extends GraphqlModulesRecord, +> = CombinedModuleContainerConfig; + +type Server = ReturnType; + +function assertArrayIsNotEmpty( + array: readonly T[], + errorMessage: string +): asserts array is NonEmptyArray { + if (array.length === 0) { + throw new Error(errorMessage); + } +} + @closeable() export class GraphqlSequencerModule - extends ModuleContainer + extends ModuleContainer implements Configurable, SequencerModule, Closeable { + private readonly modules: TypedClass>[] = []; + + private readonly schemas: GraphQLSchema[] = []; + + private resolvers: NonEmptyArray | undefined; + + private server?: Server; + + private context: {} = {}; + + public get serverConfig(): GraphqlServerConfig { + return this.ownConfig; + } + public static from( definition: GraphQLModules ): TypedClass> { @@ -36,19 +74,33 @@ export class GraphqlSequencerModule }; } - private graphqlServer?: GraphqlServer; + public constructor(definition: GraphQLModules) { + super(definition); - public create(childContainerProvider: ChildContainerProvider) { - super.create(childContainerProvider); + // Configure own config keys + ["host", "port", "graphiql"].forEach((key) => { + this.ownConfigKeys.add(key); + }); + } - this.graphqlServer = this.container.resolve("GraphqlServer"); + public setContext(newContext: {}) { + this.context = newContext; } - public async start(): Promise { - assert(this.graphqlServer !== undefined); + public registerResolvers(resolvers: NonEmptyArray) { + if (this.resolvers === undefined) { + this.resolvers = resolvers; + } else { + this.resolvers = [...this.resolvers, ...resolvers]; + } + } - this.graphqlServer.setContainer(this.container); + public create(childContainerProvider: ChildContainerProvider) { + super.create(childContainerProvider); + this.container.register("GraphqlServer", { useValue: this }); + } + public async start(): Promise { // eslint-disable-next-line guard-for-in for (const moduleName in this.definition) { const moduleClass = this.definition[moduleName]; @@ -65,9 +117,9 @@ export class GraphqlSequencerModule moduleName ) as ResolverFactoryGraphqlModule; // eslint-disable-next-line no-await-in-loop - this.graphqlServer.registerResolvers(await module.resolvers()); + this.registerResolvers(await module.resolvers()); } else { - this.graphqlServer.registerModule(moduleClass); + this.modules.push(moduleClass); if ( Object.prototype.isPrototypeOf.call( @@ -80,16 +132,91 @@ export class GraphqlSequencerModule const module = this.resolve( moduleName ) as SchemaGeneratingGraphqlModule; - this.graphqlServer.registerSchema(module.generateSchema()); + this.schemas.push(module.generateSchema()); } } } - await this.graphqlServer.startServer(); + await this.startServer(); + } + + // Server logic + + private async startServer() { + const { modules, container: dependencyContainer } = this; + + const resolvers = [...modules, ...(this.resolvers || [])]; + + assertArrayIsNotEmpty( + resolvers, + "At least one module has to be provided to GraphqlServer" + ); + + // Building schema + const resolverSchema = buildSchemaSync({ + resolvers, + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + container: { get: (cls) => dependencyContainer.resolve(cls) }, + validate: { + enableDebugMessages: true, + }, + }); + + // Instantiate all modules at startup + modules.forEach((module) => { + dependencyContainer.resolve(module); + }); + + const schema = [resolverSchema, ...this.schemas].reduce( + (schema1, schema2) => + stitchSchemas({ + subschemas: [{ schema: schema1 }, { schema: schema2 }], + }) + ); + + const app = new Koa(); + + const { graphiql, port, host } = this.serverConfig; + + const yoga = createYoga({ + schema, + graphiql, + context: this.context, + }); + + // Bind GraphQL Yoga to `/graphql` endpoint + app.use(async (ctx) => { + // Second parameter adds Koa's context into GraphQL Context + const response = await yoga.handleNodeRequest(ctx.req, ctx); + + // Set status code + ctx.status = response.status; + + // Set headers + response.headers.forEach((value, key) => { + ctx.append(key, value); + }); + + // Converts ReadableStream to a NodeJS Stream + ctx.body = response.body; + }); + + this.server = app.listen({ port, host }, () => { + log.info(`GraphQL Server listening on ${host}:${port}`); + }); } public async close() { - if (this.graphqlServer !== undefined) { - await this.graphqlServer.close(); + if (this.server !== undefined) { + const { server } = this; + + await new Promise((res) => { + server.close((error) => { + if (error !== undefined) { + log.error(error); + } + res(); + }); + }); } } } diff --git a/packages/cli/src/scripts/graphqlDocs/generateGqlDocs.ts b/packages/cli/src/scripts/graphqlDocs/generateGqlDocs.ts index 0ed012519..551d76767 100644 --- a/packages/cli/src/scripts/graphqlDocs/generateGqlDocs.ts +++ b/packages/cli/src/scripts/graphqlDocs/generateGqlDocs.ts @@ -19,7 +19,7 @@ export default async function (args: { VanillaProtocolModules, VanillaRuntimeModules, } = await import("@proto-kit/library"); - const { GraphqlSequencerModule, GraphqlServer, VanillaGraphqlModules } = + const { GraphqlSequencerModule, VanillaGraphqlModules } = await import("@proto-kit/api"); const { Runtime } = await import("@proto-kit/module"); const { port } = args; @@ -30,7 +30,6 @@ export default async function (args: { Protocol: Protocol.from(VanillaProtocolModules.with({})), Sequencer: Sequencer.from( InMemorySequencerModules.with({ - GraphqlServer: GraphqlServer, Graphql: GraphqlSequencerModule.from(VanillaGraphqlModules.with({})), }) ), @@ -45,7 +44,7 @@ export default async function (args: { Sequencer: { Database: {}, TaskQueue: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), Mempool: {}, BlockProducerModule: {}, SequencerStartupModule: {}, @@ -53,8 +52,12 @@ export default async function (args: { FeeStrategy: {}, BaseLayer: {}, BatchProducerModule: {}, - Graphql: VanillaGraphqlModules.defaultConfig(), - GraphqlServer: { port, host: "localhost", graphiql: true }, + Graphql: { + ...VanillaGraphqlModules.defaultConfig(), + port, + host: "localhost", + graphiql: true, + }, }, }); diff --git a/packages/cli/src/utils/create-environment.ts b/packages/cli/src/utils/create-environment.ts index cdafadf58..f95eecb80 100644 --- a/packages/cli/src/utils/create-environment.ts +++ b/packages/cli/src/utils/create-environment.ts @@ -339,10 +339,10 @@ export function generateWorkerConfig(answers: WizardAnswers): string { const presetEnv = PRESET_ENV_NAMES[answers.preset]; const taskWorkerImports = answers.settlementEnabled ? "" - : " LocalTaskWorkerModule, VanillaTaskWorkerModules"; + : " WorkerModule, VanillaTaskWorkerModules"; const withoutSettlementTask = answers.settlementEnabled ? "" - : `LocalTaskWorkerModule: LocalTaskWorkerModule.from( + : `WorkerModule: WorkerModule.from( VanillaTaskWorkerModules.withoutSettlement() ), `; diff --git a/packages/common/src/config/ModuleContainer.ts b/packages/common/src/config/ModuleContainer.ts index 7424759c9..89ffea6d9 100644 --- a/packages/common/src/config/ModuleContainer.ts +++ b/packages/common/src/config/ModuleContainer.ts @@ -98,6 +98,11 @@ export type ModulesConfig = { : never; }; +export type CombinedModuleContainerConfig< + Modules extends ModulesRecord, + OwnConfig = NoConfig, +> = OwnConfig & ModulesConfig; + /** * This type make any config partial (i.e. optional) up to the first level * So { Module: { a: { b: string } } } @@ -139,9 +144,16 @@ export interface ModuleContainerLike { /** * Reusable module container facilitating registration, resolution * configuration, decoration and validation of modules + * + * @typeParam Modules - The record of child module classes. + * @typeParam OwnConfig - Optional config type for keys that belong to the + * container itself (not forwarded to child modules). Defaults to NoConfig. */ -export class ModuleContainer - extends ConfigurableModule> +export class ModuleContainer< + Modules extends ModulesRecord, + OwnConfig = NoConfig, +> + extends ConfigurableModule> implements ModuleContainerLike { /** @@ -155,10 +167,28 @@ export class ModuleContainer private eventEmitterProxy: EventEmitterProxy | undefined = undefined; + /** + * Set of config key names that belong to the container + */ + protected readonly ownConfigKeys: Set = new Set(); + public constructor(public definition: Modules) { super(); } + /** + * Returns an object containing the keys listed in ownConfigKeys. + */ + public get ownConfig(): OwnConfig { + const fullConfig = this.config; + const result: Record = {}; + for (const key of this.ownConfigKeys) { + result[key] = fullConfig[key]; + } + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + return result as OwnConfig; + } + /** * @returns list of module names */ @@ -296,25 +326,28 @@ export class ModuleContainer * before the first resolution. * @param config */ - public configure(config: ModulesConfig) { + public configure(config: CombinedModuleContainerConfig) { this.config = config; } - public configurePartial(config: RecursivePartial>) { - this.config = merge< - ModulesConfig | NoConfig, - RecursivePartial> - >(this.currentConfig ?? {}, config); + public configurePartial( + config: RecursivePartial> + ) { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + this.config = merge( + this.currentConfig ?? {}, + config + ) as CombinedModuleContainerConfig; } public get config() { return super.config; } - public set config(config: ModulesConfig) { + public set config(config: CombinedModuleContainerConfig) { super.config = merge< - ModulesConfig | NoConfig, - ModulesConfig + CombinedModuleContainerConfig | NoConfig, + CombinedModuleContainerConfig >(this.currentConfig ?? {}, config); } @@ -365,6 +398,10 @@ export class ModuleContainer moduleName: StringKeyOf, containedModule: InstanceType]> ) { + if (this.ownConfigKeys.has(moduleName)) { + return; + } + const config = super.config?.[moduleName]; // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!config) { diff --git a/packages/common/src/events/EventEmitterProxy.ts b/packages/common/src/events/EventEmitterProxy.ts index cb7e46b4c..b38a96f1b 100644 --- a/packages/common/src/events/EventEmitterProxy.ts +++ b/packages/common/src/events/EventEmitterProxy.ts @@ -42,7 +42,9 @@ export type FlattenedContainerEvents = export class EventEmitterProxy< Modules extends ModulesRecord, > extends EventEmitter>> { - public constructor(private readonly container: ModuleContainer) { + public constructor( + private readonly container: ModuleContainer + ) { super(); container.moduleNames.forEach((moduleName) => { if (container.isValidModuleName(container.definition, moduleName)) { diff --git a/packages/deployment/src/queue/BullQueue.ts b/packages/deployment/src/queue/BullQueue.ts index 2a4f4e640..2f459b81b 100644 --- a/packages/deployment/src/queue/BullQueue.ts +++ b/packages/deployment/src/queue/BullQueue.ts @@ -116,6 +116,6 @@ export class BullQueue public async close() { await this.closeQueues(); - // Closing of active workers is handled by the LocalTaskWorkerModule + // Closing of active workers is handled by the WorkerModule } } diff --git a/packages/indexer/src/api/GeneratedResolverFactoryGraphqlModule.ts b/packages/indexer/src/api/GeneratedResolverFactoryGraphqlModule.ts index 9c631c48b..fd31b1814 100644 --- a/packages/indexer/src/api/GeneratedResolverFactoryGraphqlModule.ts +++ b/packages/indexer/src/api/GeneratedResolverFactoryGraphqlModule.ts @@ -1,5 +1,6 @@ import { - GraphqlServer, + GraphqlModulesRecord, + GraphqlSequencerModule, ResolverFactoryGraphqlModule, graphqlModule, } from "@proto-kit/api"; @@ -97,7 +98,8 @@ export function ValidateTakeArg() { @graphqlModule() export class GeneratedResolverFactoryGraphqlModule extends ResolverFactoryGraphqlModule { public constructor( - @inject("GraphqlServer") public graphqlServer: GraphqlServer + @inject("GraphqlServer") + public graphqlServer: GraphqlSequencerModule ) { super(); } diff --git a/packages/indexer/test/GeneratedResolverFactoryGraphqlModule.test.ts b/packages/indexer/test/GeneratedResolverFactoryGraphqlModule.test.ts index 3ef0ffe06..4956cddb2 100644 --- a/packages/indexer/test/GeneratedResolverFactoryGraphqlModule.test.ts +++ b/packages/indexer/test/GeneratedResolverFactoryGraphqlModule.test.ts @@ -1,9 +1,5 @@ import "reflect-metadata"; -import { - GraphqlSequencerModule, - GraphqlServer, - graphqlModule, -} from "@proto-kit/api"; +import { GraphqlSequencerModule, graphqlModule } from "@proto-kit/api"; import { log } from "@proto-kit/common"; import { jest } from "@jest/globals"; @@ -30,21 +26,18 @@ class MockedGeneratedResolverFactoryGraphqlModule extends GeneratedResolverFacto describe("GeneratedResolverFactoryGraphqlModule", () => { const indexer = Indexer.from({ - GraphqlServer: GraphqlServer, Graphql: GraphqlSequencerModule.from({ GeneratedResolverFactory: MockedGeneratedResolverFactoryGraphqlModule, }), }); indexer.configurePartial({ - GraphqlServer: { + Graphql: { + GeneratedResolverFactory: {}, port, host: "0.0.0.0", graphiql: true, }, - Graphql: { - GeneratedResolverFactory: {}, - }, }); beforeAll(async () => { @@ -136,6 +129,6 @@ describe("GeneratedResolverFactoryGraphqlModule", () => { }); afterAll(async () => { - await indexer.resolve("GraphqlServer").close(); + await indexer.resolve("Graphql").close(); }); }); diff --git a/packages/indexer/test/IndexBlockTask.test.ts b/packages/indexer/test/IndexBlockTask.test.ts index b5432e5a3..abdc583c0 100644 --- a/packages/indexer/test/IndexBlockTask.test.ts +++ b/packages/indexer/test/IndexBlockTask.test.ts @@ -3,7 +3,7 @@ import { BlockWithResult, InMemoryDatabase, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, TaskPayload, } from "@proto-kit/sequencer"; @@ -14,7 +14,7 @@ describe("IndexBlockTask", () => { const indexer = Indexer.from({ Database: InMemoryDatabase, TaskQueue: LocalTaskQueue, - LocalTaskWorkerModule: LocalTaskWorkerModule.from({ + WorkerModule: WorkerModule.from({ IndexBlockTask: IndexBlockTask, }), }); @@ -22,7 +22,7 @@ describe("IndexBlockTask", () => { indexer.configurePartial({ Database: {}, TaskQueue: {}, - LocalTaskWorkerModule: { + WorkerModule: { IndexBlockTask: {}, }, }); @@ -30,8 +30,8 @@ describe("IndexBlockTask", () => { it("should listen to block indexing tasks", async () => { await indexer.start(); const taskQueue = indexer.resolve("TaskQueue"); - const localTaskWorker = indexer.resolve("LocalTaskWorkerModule"); - const indexBlockTask = localTaskWorker.resolve("IndexBlockTask"); + const workerModule = indexer.resolve("WorkerModule"); + const indexBlockTask = workerModule.resolve("IndexBlockTask"); const queue = await taskQueue.getQueue(indexBlockTask.name); const block = BlockWithResult.createEmpty(); diff --git a/packages/indexer/test/IndexerNotifier.test.ts b/packages/indexer/test/IndexerNotifier.test.ts index ddd37b498..3a740b64f 100644 --- a/packages/indexer/test/IndexerNotifier.test.ts +++ b/packages/indexer/test/IndexerNotifier.test.ts @@ -90,7 +90,7 @@ function createAppChain() { BlockTrigger: {}, Mempool: {}, BlockProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, BatchProducerModule: {}, TaskQueue: { diff --git a/packages/library/src/sequencer/InMemorySequencerModules.ts b/packages/library/src/sequencer/InMemorySequencerModules.ts index f880b33d2..4a61cb4cd 100644 --- a/packages/library/src/sequencer/InMemorySequencerModules.ts +++ b/packages/library/src/sequencer/InMemorySequencerModules.ts @@ -2,7 +2,7 @@ import { BatchProducerModule, InMemoryDatabase, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, ManualBlockTrigger, NoopBaseLayer, PrivateMempool, @@ -18,9 +18,7 @@ import { TypedClass } from "@proto-kit/common"; export type InMemorySequencerModulesRecord = { Database: typeof InMemoryDatabase; Mempool: typeof PrivateMempool; - LocalTaskWorkerModule: TypedClass< - LocalTaskWorkerModule - >; + WorkerModule: TypedClass>; BaseLayer: typeof NoopBaseLayer; BatchProducerModule: typeof BatchProducerModule; BlockProducerModule: typeof BlockProducerModule; @@ -37,7 +35,7 @@ export class InMemorySequencerModules { return { Database: InMemoryDatabase, Mempool: PrivateMempool, - LocalTaskWorkerModule: LocalTaskWorkerModule.from({ + WorkerModule: WorkerModule.from({ ...VanillaTaskWorkerModules.withoutSettlement(), }), FeeStrategy: ConstantFeeStrategy, diff --git a/packages/library/src/sequencer/SimpleSequencerModules.ts b/packages/library/src/sequencer/SimpleSequencerModules.ts index 2d50200e4..835ab1ea1 100644 --- a/packages/library/src/sequencer/SimpleSequencerModules.ts +++ b/packages/library/src/sequencer/SimpleSequencerModules.ts @@ -1,6 +1,6 @@ import { BatchProducerModule, - LocalTaskWorkerModule, + WorkerModule, PrivateMempool, SequencerModulesRecord, BlockProducerModule, @@ -37,8 +37,8 @@ export type AdditionalSequencerModules = SequencerModulesRecord & MinimumAdditionalSequencerModules; export type SimpleSequencerWorkerModulesRecord = { - LocalTaskWorkerModule: TypedClass< - LocalTaskWorkerModule> + WorkerModule: TypedClass< + WorkerModule> >; TaskQueue: TypedClass; }; @@ -49,9 +49,7 @@ export class SimpleSequencerModules { SequencerModules extends SequencerModulesRecord, >(queue: TypedClass, additionalModules: SequencerModules) { return { - LocalTaskWorkerModule: LocalTaskWorkerModule.from( - VanillaTaskWorkerModules.allTasks() - ), + WorkerModule: WorkerModule.from(VanillaTaskWorkerModules.allTasks()), TaskQueue: queue, ...additionalModules, } satisfies SimpleSequencerWorkerModulesRecord; @@ -96,9 +94,7 @@ export class SimpleSequencerModules { public static defaultConfig() { return { - BlockProducerModule: { - allowEmptyBlock: true, - }, + BlockProducerModule: {}, Mempool: {}, BatchProducerModule: {}, @@ -108,9 +104,9 @@ export class SimpleSequencerModules { public static defaultWorkerConfig() { return { - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), } satisfies ModulesConfig< - Pick + Pick >; } } diff --git a/packages/persistance/src/PrismaRedisDatabase.ts b/packages/persistance/src/PrismaRedisDatabase.ts index 87ef9af46..298f0a7fd 100644 --- a/packages/persistance/src/PrismaRedisDatabase.ts +++ b/packages/persistance/src/PrismaRedisDatabase.ts @@ -5,6 +5,8 @@ import { Database, closeable, Tracer, + DatabasePruneModule, + DatabasePruneConfig, } from "@proto-kit/sequencer"; import { ChildContainerProvider, dependencyFactory } from "@proto-kit/common"; import { PrismaClient } from "@prisma/client"; @@ -27,6 +29,7 @@ import { PrismaLinkedLeafStore } from "./services/prisma/PrismaLinkedLeafStore"; export interface PrismaRedisCombinedConfig { prisma: PrismaDatabaseConfig; redis: RedisConnectionConfig; + databasePruneModule?: DatabasePruneConfig; } @sequencerModule() @@ -40,10 +43,13 @@ export class PrismaRedisDatabase public redis: RedisConnectionModule; + private databasePruneModule: DatabasePruneModule; + public constructor(@inject("Tracer") private readonly tracer: Tracer) { super(); this.prisma = new PrismaDatabaseConnection(tracer); this.redis = new RedisConnectionModule(tracer); + this.databasePruneModule = new DatabasePruneModule(this); } public get prismaClient(): PrismaClient { @@ -62,6 +68,7 @@ export class PrismaRedisDatabase super.create(childContainerProvider); this.prisma.create(childContainerProvider); this.redis.create(childContainerProvider); + this.databasePruneModule.create(childContainerProvider); } public static dependencies(): StorageDependencyMinimumDependencies { @@ -99,6 +106,9 @@ export class PrismaRedisDatabase this.redis.config = this.config.redis; await this.redis.start(); + + this.databasePruneModule.config = this.config.databasePruneModule ?? {}; + await this.databasePruneModule.start(); } public async close() { diff --git a/packages/persistance/test-integration/PrismaBlockProduction.test.ts b/packages/persistance/test-integration/PrismaBlockProduction.test.ts index 5589b2275..bd91bbb0d 100644 --- a/packages/persistance/test-integration/PrismaBlockProduction.test.ts +++ b/packages/persistance/test-integration/PrismaBlockProduction.test.ts @@ -34,6 +34,9 @@ describe("Prisma block production", () => { log: [{ level: "query", emit: "event" }], }, redis: redisConfig, + databasePruneModule: { + pruneOnStartup: true, + }, } as never ); }); diff --git a/packages/persistance/test-integration/SequencerRestart.test.ts b/packages/persistance/test-integration/SequencerRestart.test.ts index 2864424b9..8980d8512 100644 --- a/packages/persistance/test-integration/SequencerRestart.test.ts +++ b/packages/persistance/test-integration/SequencerRestart.test.ts @@ -29,11 +29,6 @@ describe("sequencer restart", () => { Signer: { signer: sender, }, - Sequencer: { - DatabasePruneModule: { - pruneOnStartup: false, - }, - }, }); await appChain.start(false, container.createChildContainer()); diff --git a/packages/persistance/test-integration/utils.ts b/packages/persistance/test-integration/utils.ts index e62050794..361d27088 100644 --- a/packages/persistance/test-integration/utils.ts +++ b/packages/persistance/test-integration/utils.ts @@ -25,7 +25,7 @@ import { import { BatchProducerModule, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, ManualBlockTrigger, NoopBaseLayer, PrivateMempool, @@ -33,7 +33,6 @@ import { BlockProducerModule, VanillaTaskWorkerModules, SequencerStartupModule, - DatabasePruneModule, } from "@proto-kit/sequencer"; import { Bool, PrivateKey, PublicKey, Struct } from "o1js"; @@ -92,7 +91,8 @@ export class MintableBalances extends Balances { export function createPrismaAppchain( prismaConnection: PrismaDatabaseConfig["connection"], - redisConnection: RedisConnectionConfig + redisConnection: RedisConnectionConfig, + pruneOnStartup = false ) { const appChain = ClientAppChain.from({ Protocol: Protocol.from(VanillaProtocolModules.mandatoryModules({})), @@ -100,11 +100,10 @@ export function createPrismaAppchain( Balances: MintableBalances, }), Sequencer: Sequencer.from({ - DatabasePruneModule, Database: PrismaRedisDatabase, Mempool: PrivateMempool, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( + WorkerModule: WorkerModule.from( VanillaTaskWorkerModules.withoutSettlement() ), BaseLayer: NoopBaseLayer, @@ -139,20 +138,20 @@ export function createPrismaAppchain( connection: prismaConnection, }, redis: redisConnection, + databasePruneModule: { + pruneOnStartup, + }, }, BlockTrigger: {}, Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, BlockProducerModule: {}, TaskQueue: { simulatedDuration: 0, }, SequencerStartupModule: {}, - DatabasePruneModule: { - pruneOnStartup: true, - }, }, Signer: { signer: PrivateKey.random(), diff --git a/packages/processor/src/api/ResolverFactoryGraphqlModule.ts b/packages/processor/src/api/ResolverFactoryGraphqlModule.ts index a110b0be6..3ac532073 100644 --- a/packages/processor/src/api/ResolverFactoryGraphqlModule.ts +++ b/packages/processor/src/api/ResolverFactoryGraphqlModule.ts @@ -1,5 +1,6 @@ import { - GraphqlServer, + GraphqlModulesRecord, + GraphqlSequencerModule, ResolverFactoryGraphqlModule as BaseResolverFactoryGraphqlModule, graphqlModule, } from "@proto-kit/api"; @@ -61,7 +62,9 @@ export class ResolverFactoryGraphqlModule< public database: PrismaDatabaseConnection | undefined; - public constructor(public graphqlServer: GraphqlServer) { + public constructor( + public graphqlServer: GraphqlSequencerModule + ) { super(); } diff --git a/packages/sdk/src/testing/TestingAppChain.ts b/packages/sdk/src/testing/TestingAppChain.ts index 3487a4175..6d6c2c234 100644 --- a/packages/sdk/src/testing/TestingAppChain.ts +++ b/packages/sdk/src/testing/TestingAppChain.ts @@ -67,7 +67,7 @@ export class TestingAppChain< BlockTrigger: {}, Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, BlockProducerModule: {}, SequencerStartupModule: {}, diff --git a/packages/sequencer/src/index.ts b/packages/sequencer/src/index.ts index 7da10194e..316e0a432 100644 --- a/packages/sequencer/src/index.ts +++ b/packages/sequencer/src/index.ts @@ -20,7 +20,7 @@ export * from "./worker/queue/LocalTaskQueue"; export * from "./worker/queue/ListenerList"; export * from "./worker/queue/AbstractTaskQueue"; export * from "./worker/worker/FlowTaskWorker"; -export * from "./worker/worker/LocalTaskWorkerModule"; +export * from "./worker/worker/WorkerModule"; export * from "./worker/worker/TaskWorkerModule"; export * from "./worker/worker/WorkerReadyModule"; export * from "./protocol/baselayer/BaseLayer"; @@ -64,6 +64,7 @@ export * from "./protocol/production/tracing/BlockTracingService"; export * from "./protocol/production/tracing/BatchTracingService"; export * from "./protocol/production/tracing/StateTransitionTracingService"; export * from "./protocol/production/tracing/TransactionTracingService"; +export * from "./sequencer/SequencerCoreModule"; export * from "./sequencer/SequencerStartupModule"; export * from "./sequencer/SettlementStartupModule"; export * from "./sequencer/builder/StartableModule"; diff --git a/packages/sequencer/src/mempool/Mempool.ts b/packages/sequencer/src/mempool/Mempool.ts index 5770df70b..37e779a10 100644 --- a/packages/sequencer/src/mempool/Mempool.ts +++ b/packages/sequencer/src/mempool/Mempool.ts @@ -25,4 +25,6 @@ export interface Mempool< removeTxs: (included: string[], dropped: string[]) => Promise; length: () => Promise; + + getTargetBlockSize: () => number; } diff --git a/packages/sequencer/src/mempool/private/PrivateMempool.ts b/packages/sequencer/src/mempool/private/PrivateMempool.ts index 277a6957d..e3c2f6d70 100644 --- a/packages/sequencer/src/mempool/private/PrivateMempool.ts +++ b/packages/sequencer/src/mempool/private/PrivateMempool.ts @@ -17,6 +17,7 @@ import { DefaultMempoolSorting } from "../sorting/DefaultMempoolSorting"; type PrivateMempoolConfig = { type?: "hybrid" | "private" | "based"; + targetBlockSize?: number; }; @sequencerModule() @@ -46,6 +47,10 @@ export class PrivateMempool return this.config.type ?? "hybrid"; } + public getTargetBlockSize(): number { + return this.config.targetBlockSize ?? 20; + } + public async length(): Promise { const numUserTxs = await this.transactionStorage.countPendingUserTransactions(); diff --git a/packages/sequencer/src/protocol/production/sequencing/BlockBuilder.ts b/packages/sequencer/src/protocol/production/sequencing/BlockBuilder.ts index 6ebe0b43c..b1a684cfd 100644 --- a/packages/sequencer/src/protocol/production/sequencing/BlockBuilder.ts +++ b/packages/sequencer/src/protocol/production/sequencing/BlockBuilder.ts @@ -62,8 +62,7 @@ export class BlockBuilder { public async buildBlock( asyncStateService: CachedStateService, networkState: NetworkState, - state: BlockTrackers, - maximumBlockSize: number + state: BlockTrackers ): Promise<{ blockState: BlockTrackers; executionResults: TransactionExecutionResultStatus[]; @@ -74,7 +73,8 @@ export class BlockBuilder { const networkStateHash = networkState.hash(); - const ordering = new Ordering(this.mempool, maximumBlockSize); + const targetBlockSize = this.mempool.getTargetBlockSize(); + const ordering = new Ordering(this.mempool, targetBlockSize); let tx: PendingTransaction | undefined; // eslint-disable-next-line no-await-in-loop,no-cond-assign diff --git a/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts b/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts index 278de217a..b90059d9f 100644 --- a/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts +++ b/packages/sequencer/src/protocol/production/sequencing/BlockProducerModule.ts @@ -32,8 +32,7 @@ import { BlockProductionService } from "./BlockProductionService"; import { BlockResultService } from "./BlockResultService"; export interface BlockConfig { - allowEmptyBlock?: boolean; - maximumBlockSize?: number; + skipEmptyBlocks?: boolean; } @sequencerModule() @@ -61,12 +60,8 @@ export class BlockProducerModule extends SequencerModule { super(); } - private allowEmptyBlock() { - return this.config.allowEmptyBlock ?? true; - } - - private maximumBlockSize() { - return this.config.maximumBlockSize ?? 20; + private skipEmptyBlocks() { + return this.config.skipEmptyBlocks ?? false; } private prettyPrintBlockContents(block: Block) { @@ -143,7 +138,7 @@ export class BlockProducerModule extends SequencerModule { const block = await this.produceBlock(); if (block === undefined) { - if (!this.allowEmptyBlock()) { + if (this.skipEmptyBlocks()) { log.info("No transactions in mempool, skipping production"); } else { log.error("Something wrong happened, skipping block"); @@ -192,15 +187,14 @@ export class BlockProducerModule extends SequencerModule { const blockResult = await this.productionService.createBlock( this.unprovenStateService, metadata, - this.allowEmptyBlock(), - this.maximumBlockSize() + this.skipEmptyBlocks() ); if (blockResult !== undefined) { const { block, stateChanges, orderingMetadata } = blockResult; // Skip production if no transactions are available for now - if (block.transactions.length === 0 && !this.allowEmptyBlock()) { + if (block.transactions.length === 0 && this.skipEmptyBlocks()) { return undefined; } diff --git a/packages/sequencer/src/protocol/production/sequencing/BlockProductionService.ts b/packages/sequencer/src/protocol/production/sequencing/BlockProductionService.ts index 95ad398a4..ceaba6a79 100644 --- a/packages/sequencer/src/protocol/production/sequencing/BlockProductionService.ts +++ b/packages/sequencer/src/protocol/production/sequencing/BlockProductionService.ts @@ -102,8 +102,7 @@ export class BlockProductionService { public async createBlock( asyncStateService: AsyncStateService, lastBlockWithResult: BlockWithResult, - allowEmptyBlocks: boolean, - maximumBlockSize: number + skipEmptyBlocks: boolean ): Promise< | { block: Block; @@ -151,14 +150,13 @@ export class BlockProductionService { } = await this.blockBuilder.buildBlock( stateService, networkState, - blockState, - maximumBlockSize + blockState ); const previousBlockHash = lastResult.blockHash === 0n ? undefined : Field(lastResult.blockHash); - if (executionResults.length === 0 && !allowEmptyBlocks) { + if (executionResults.length === 0 && skipEmptyBlocks) { log.info( "After sequencing, block has no sequenceable transactions left, skipping block" ); diff --git a/packages/sequencer/src/protocol/production/sequencing/Ordering.ts b/packages/sequencer/src/protocol/production/sequencing/Ordering.ts index 9cc8132ae..b27a3aaec 100644 --- a/packages/sequencer/src/protocol/production/sequencing/Ordering.ts +++ b/packages/sequencer/src/protocol/production/sequencing/Ordering.ts @@ -77,7 +77,7 @@ export class PathResolution { export class Ordering { public constructor( private readonly mempool: Mempool, - private sizeLimit: number + private targetBlockSize: number ) {} mandatoryTransactionsCompleted = false; @@ -140,7 +140,7 @@ export class Ordering { } private space() { - return this.sizeLimit - this.ordered; + return this.targetBlockSize - this.ordered; } private mandoQueue: PendingTransaction[] = []; diff --git a/packages/sequencer/src/sequencer/SequencerCoreModule.ts b/packages/sequencer/src/sequencer/SequencerCoreModule.ts new file mode 100644 index 000000000..6bfc4cf1b --- /dev/null +++ b/packages/sequencer/src/sequencer/SequencerCoreModule.ts @@ -0,0 +1,133 @@ +import { + DependencyDeclaration, + DependencyRecord, + dependencyFactory, + NoConfig, +} from "@proto-kit/common"; +import { inject } from "tsyringe"; + +import { + BlockConfig, + BlockProducerModule, +} from "../protocol/production/sequencing/BlockProducerModule"; +import { BatchProducerModule } from "../protocol/production/BatchProducerModule"; + +import { SequencerModule, sequencerModule } from "./builder/SequencerModule"; +import { closeable } from "./builder/Closeable"; +import { SequencerStartupModule } from "./SequencerStartupModule"; + +export interface InMemorySequencerCoreDependencies extends DependencyRecord { + sequencerStartupModule: DependencyDeclaration< + SequencerStartupModule, + InMemorySequencerCoreModule + >; + blockProducerModule: DependencyDeclaration< + BlockProducerModule, + InMemorySequencerCoreModule + >; +} + +export interface SequencerCoreDependencies extends DependencyRecord { + sequencerStartupModule: DependencyDeclaration< + SequencerStartupModule, + SequencerCoreModule + >; + blockProducerModule: DependencyDeclaration< + BlockProducerModule, + SequencerCoreModule + >; + batchProducerModule: DependencyDeclaration< + BatchProducerModule, + SequencerCoreModule + >; +} + +export interface InMemorySequencerCoreConfig { + SequencerStartupModule: NoConfig; + BlockProducerModule: BlockConfig; +} + +export interface SequencerCoreConfig extends InMemorySequencerCoreConfig { + BatchProducerModule: NoConfig; +} + +@sequencerModule() +@closeable() +@dependencyFactory() +export class InMemorySequencerCoreModule extends SequencerModule { + public constructor( + @inject("SequencerStartupModule") + private readonly sequencerStartupModule: SequencerStartupModule, + @inject("BlockProducerModule") + private readonly blockProducerModule: BlockProducerModule + ) { + super(); + } + + public static dependencies(): InMemorySequencerCoreDependencies { + return { + sequencerStartupModule: { + useClass: SequencerStartupModule, + }, + blockProducerModule: { + useClass: BlockProducerModule, + }, + }; + } + + public async start(): Promise { + this.sequencerStartupModule.config = this.config.SequencerStartupModule; + this.blockProducerModule.config = this.config.BlockProducerModule; + + await this.sequencerStartupModule.start(); + await this.blockProducerModule.start(); + } + + public async close(): Promise { + await this.sequencerStartupModule.close(); + } +} + +@sequencerModule() +@closeable() +@dependencyFactory() +export class SequencerCoreModule extends SequencerModule { + public constructor( + @inject("SequencerStartupModule") + private readonly sequencerStartupModule: SequencerStartupModule, + @inject("BlockProducerModule") + private readonly blockProducerModule: BlockProducerModule, + @inject("BatchProducerModule") + private readonly batchProducerModule: BatchProducerModule + ) { + super(); + } + + public static dependencies(): SequencerCoreDependencies { + return { + sequencerStartupModule: { + useClass: SequencerStartupModule, + }, + blockProducerModule: { + useClass: BlockProducerModule, + }, + batchProducerModule: { + useClass: BatchProducerModule, + }, + }; + } + + public async start(): Promise { + this.sequencerStartupModule.config = this.config.SequencerStartupModule; + this.blockProducerModule.config = this.config.BlockProducerModule; + this.batchProducerModule.config = this.config.BatchProducerModule; + + await this.sequencerStartupModule.start(); + await this.blockProducerModule.start(); + await this.batchProducerModule.start(); + } + + public async close(): Promise { + await this.sequencerStartupModule.close(); + } +} diff --git a/packages/sequencer/src/storage/DatabasePruneModule.ts b/packages/sequencer/src/storage/DatabasePruneModule.ts index e2b3e5689..9aabd8791 100644 --- a/packages/sequencer/src/storage/DatabasePruneModule.ts +++ b/packages/sequencer/src/storage/DatabasePruneModule.ts @@ -1,4 +1,3 @@ -import { inject } from "tsyringe"; import { noop, log } from "@proto-kit/common"; import { @@ -14,7 +13,7 @@ export type DatabasePruneConfig = { @sequencerModule() export class DatabasePruneModule extends SequencerModule { - public constructor(@inject("Database") private readonly database: Database) { + public constructor(private readonly database: Database) { super(); } diff --git a/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts b/packages/sequencer/src/worker/worker/WorkerModule.ts similarity index 92% rename from packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts rename to packages/sequencer/src/worker/worker/WorkerModule.ts index 85fa05663..2cdefc3a0 100644 --- a/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts +++ b/packages/sequencer/src/worker/worker/WorkerModule.ts @@ -44,7 +44,7 @@ export type TaskWorkerModulesRecord = ModulesRecord< TypedClass> >; -type LocalTaskWorkerModuleEvents = { ready: [boolean] }; +type WorkerModuleEvents = { ready: [boolean] }; /** * This module spins up a worker in the current local node instance. @@ -54,15 +54,13 @@ type LocalTaskWorkerModuleEvents = { ready: [boolean] }; */ @sequencerModule() @closeable() -export class LocalTaskWorkerModule +export class WorkerModule extends ModuleContainer - implements - SequencerModule, - EventEmittingContainer + implements SequencerModule, EventEmittingContainer { public static presets: Presets = {}; - public containerEvents = new EventEmitter(); + public containerEvents = new EventEmitter(); private worker?: FlowTaskWorker< InstanceType[StringKeyOf]>[] @@ -70,8 +68,8 @@ export class LocalTaskWorkerModule public static from( modules: Tasks - ): TypedClass> { - return class ScopedTaskWorkerModule extends LocalTaskWorkerModule { + ): TypedClass> { + return class ScopedWorkerModule extends WorkerModule { public constructor() { super(modules); } diff --git a/packages/sequencer/src/worker/worker/WorkerReadyModule.ts b/packages/sequencer/src/worker/worker/WorkerReadyModule.ts index 1f7a82a9b..01a986830 100644 --- a/packages/sequencer/src/worker/worker/WorkerReadyModule.ts +++ b/packages/sequencer/src/worker/worker/WorkerReadyModule.ts @@ -1,6 +1,6 @@ import { inject, injectable } from "tsyringe"; -import { LocalTaskWorkerModule } from "./LocalTaskWorkerModule"; +import { WorkerModule } from "./WorkerModule"; /** * Module to safely wait for the finish of the worker startup @@ -9,16 +9,14 @@ import { LocalTaskWorkerModule } from "./LocalTaskWorkerModule"; @injectable() export class WorkerReadyModule { public constructor( - @inject("LocalTaskWorkerModule", { isOptional: true }) - private readonly localTaskWorkerModule: - | LocalTaskWorkerModule - | undefined + @inject("WorkerModule", { isOptional: true }) + private readonly workerModule: WorkerModule | undefined ) {} // eslint-disable-next-line consistent-return public async waitForReady() { - if (this.localTaskWorkerModule !== undefined) { - const module = this.localTaskWorkerModule; + if (this.workerModule !== undefined) { + const module = this.workerModule; return await new Promise((res, rej) => { module.containerEvents.on("ready", (ready) => { if (ready) { diff --git a/packages/sequencer/test-integration/benchmarks/tps.test.ts b/packages/sequencer/test-integration/benchmarks/tps.test.ts index 68e2dd5a0..258f56123 100644 --- a/packages/sequencer/test-integration/benchmarks/tps.test.ts +++ b/packages/sequencer/test-integration/benchmarks/tps.test.ts @@ -25,7 +25,6 @@ import { afterEach } from "@jest/globals"; import { BlockProducerModule, ConsoleTracer, - DatabasePruneModule, ManualBlockTrigger, Sequencer, } from "../../src"; @@ -65,7 +64,6 @@ export async function createAppChain() { ), Protocol: Protocol.from(VanillaProtocolModules.with({})), Sequencer: Sequencer.from({ - DatabasePruneModule, Database: PrismaRedisDatabase, Mempool: PrivateMempool, BlockProducerModule: BlockProducerModule, @@ -86,9 +84,6 @@ export async function createAppChain() { ...VanillaProtocolModules.defaultConfig(), }, Sequencer: { - DatabasePruneModule: { - pruneOnStartup: true, - }, Database: { redis: { host: "localhost", @@ -99,12 +94,15 @@ export async function createAppChain() { connection: "postgresql://admin:password@localhost:5432/protokit?schema=public", }, + databasePruneModule: { + pruneOnStartup: true, + }, }, - BlockProducerModule: { - maximumBlockSize: 100, - }, + BlockProducerModule: {}, BlockTrigger: {}, - Mempool: {}, + Mempool: { + targetBlockSize: 100, + }, }, Signer: { signer: PrivateKey.random(), diff --git a/packages/sequencer/test-integration/workers/WorkerModules.ts b/packages/sequencer/test-integration/workers/WorkerModules.ts index e1d640aa3..e2b280655 100644 --- a/packages/sequencer/test-integration/workers/WorkerModules.ts +++ b/packages/sequencer/test-integration/workers/WorkerModules.ts @@ -1,6 +1,6 @@ -import { LocalTaskWorkerModule, TaskQueue, TypedClass } from "../../src"; +import { WorkerModule, TaskQueue, TypedClass } from "../../src"; export interface MinimumWorkerModules { TaskQueue: TypedClass; - LocalTaskWorkerModule: TypedClass>; + WorkerModule: TypedClass>; } diff --git a/packages/sequencer/test-integration/workers/worker.ts b/packages/sequencer/test-integration/workers/worker.ts index c9210b74b..f8b903aed 100644 --- a/packages/sequencer/test-integration/workers/worker.ts +++ b/packages/sequencer/test-integration/workers/worker.ts @@ -6,7 +6,7 @@ import { log, sleep } from "@proto-kit/common"; import { AppChain, - LocalTaskWorkerModule, + WorkerModule, Sequencer, VanillaTaskWorkerModules, } from "../../src"; @@ -25,7 +25,7 @@ async function main() { const sequencerClass = Sequencer.from({ TaskQueue: BullQueue, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( + WorkerModule: WorkerModule.from( VanillaTaskWorkerModules.withoutSettlement() ), } satisfies MinimumWorkerModules); @@ -40,7 +40,7 @@ async function main() { ...runtimeProtocolConfig, Sequencer: { TaskQueue: BullConfig, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), }, }); @@ -56,7 +56,7 @@ async function main() { const ready = await new Promise((res) => { app .resolve("Sequencer") - .resolve("LocalTaskWorkerModule") + .resolve("WorkerModule") .containerEvents.on("ready", res); }); diff --git a/packages/sequencer/test-integration/workers/workers-proven.test.ts b/packages/sequencer/test-integration/workers/workers-proven.test.ts index 047a92913..4df7e74a4 100644 --- a/packages/sequencer/test-integration/workers/workers-proven.test.ts +++ b/packages/sequencer/test-integration/workers/workers-proven.test.ts @@ -91,11 +91,11 @@ describe("worker-proven", () => { Sequencer: { Database: {}, BlockTrigger: {}, - Mempool: {}, - BatchProducerModule: {}, - BlockProducerModule: { - maximumBlockSize: 5, + Mempool: { + targetBlockSize: 5, }, + BatchProducerModule: {}, + BlockProducerModule: {}, // BaseLayer: {}, TaskQueue: BullConfig, FeeStrategy: {}, diff --git a/packages/sequencer/test-proven/Proven.test.ts b/packages/sequencer/test-proven/Proven.test.ts index 14e41f9dd..b2f7fd16b 100644 --- a/packages/sequencer/test-proven/Proven.test.ts +++ b/packages/sequencer/test-proven/Proven.test.ts @@ -89,12 +89,12 @@ describe("Proven", () => { Sequencer: { Database: {}, BlockTrigger: {}, - Mempool: {}, - BatchProducerModule: {}, - BlockProducerModule: { - maximumBlockSize: 5, + Mempool: { + targetBlockSize: 5, }, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + BatchProducerModule: {}, + BlockProducerModule: {}, + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), TaskQueue: {}, FeeStrategy: {}, SequencerStartupModule: {}, diff --git a/packages/sequencer/test-proven/settlement-worker.ts b/packages/sequencer/test-proven/settlement-worker.ts index b4d53ff8d..3d27bc1ee 100644 --- a/packages/sequencer/test-proven/settlement-worker.ts +++ b/packages/sequencer/test-proven/settlement-worker.ts @@ -17,7 +17,7 @@ import { } from "../test/settlement/Settlement"; import { AppChain, - LocalTaskWorkerModule, + WorkerModule, Sequencer, VanillaTaskWorkerModules, } from "../src"; @@ -36,9 +36,7 @@ async function main() { const sequencerClass = Sequencer.from({ TaskQueue: BullQueue, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( - VanillaTaskWorkerModules.allTasks() - ), + WorkerModule: WorkerModule.from(VanillaTaskWorkerModules.allTasks()), } satisfies MinimumWorkerModules); const app = AppChain.from({ @@ -52,7 +50,7 @@ async function main() { Protocol: protocolModulesConfig, Sequencer: { TaskQueue: BullConfig, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), }, }); diff --git a/packages/sequencer/test/TestingSequencer.ts b/packages/sequencer/test/TestingSequencer.ts index cb42747e5..99e6cdb9f 100644 --- a/packages/sequencer/test/TestingSequencer.ts +++ b/packages/sequencer/test/TestingSequencer.ts @@ -4,7 +4,7 @@ import { BatchProducerModule, InMemoryDatabase, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, ManualBlockTrigger, NoopBaseLayer, PrivateMempool, @@ -19,7 +19,7 @@ import { ConstantFeeStrategy } from "../src/protocol/baselayer/fees/ConstantFeeS export type DefaultTestingSequencerModules = { Database: typeof InMemoryDatabase; Mempool: typeof PrivateMempool; - LocalTaskWorkerModule: TypedClass>; + WorkerModule: TypedClass>; BaseLayer: typeof NoopBaseLayer; BatchProducerModule: typeof BatchProducerModule; BlockProducerModule: typeof BlockProducerModule; @@ -36,7 +36,7 @@ export function testingSequencerModules< modules: AdditionalModules, additionalTaskWorkerModules?: AdditionalTaskWorkerModules ) { - const taskWorkerModule = LocalTaskWorkerModule.from({ + const taskWorkerModule = WorkerModule.from({ ...VanillaTaskWorkerModules.withoutSettlement(), ...additionalTaskWorkerModules, }); @@ -45,7 +45,7 @@ export function testingSequencerModules< Database: InMemoryDatabase, Mempool: PrivateMempool, BaseLayer: NoopBaseLayer, - LocalTaskWorkerModule: taskWorkerModule, + WorkerModule: taskWorkerModule, BatchProducerModule, BlockProducerModule, BlockTrigger: ManualBlockTrigger, @@ -58,7 +58,7 @@ export function testingSequencerModules< ...defaultModules, ...modules, // We need to make sure that the taskworkermodule is initialized last - LocalTaskWorkerModule: defaultModules.LocalTaskWorkerModule, + WorkerModule: defaultModules.WorkerModule, SequencerStartupModule: defaultModules.SequencerStartupModule, } satisfies SequencerModulesRecord; } diff --git a/packages/sequencer/test/integration/Block-order.test.ts b/packages/sequencer/test/integration/Block-order.test.ts index e65aa9cd8..945ec444b 100644 --- a/packages/sequencer/test/integration/Block-order.test.ts +++ b/packages/sequencer/test/integration/Block-order.test.ts @@ -103,7 +103,7 @@ describe.each([["InMemory", InMemoryDatabase]])( FeeStrategy: {}, BatchProducerModule: {}, BlockProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, SequencerStartupModule: {}, @@ -250,7 +250,7 @@ describe.each([["InMemory", InMemoryDatabase]])( it("transactions are returned in right order in multiple distinct blocks - hardest", async () => { expect.assertions(18); - sequencer.resolve("BlockProducerModule").config.maximumBlockSize = 3; + sequencer.resolve("Mempool").config.targetBlockSize = 3; const txStorage = sequencer.resolve("TransactionStorage"); const getTxsSpy = jest.spyOn(txStorage, "getPendingUserTransactions"); diff --git a/packages/sequencer/test/integration/BlockProduction-test.ts b/packages/sequencer/test/integration/BlockProduction-test.ts index 8e2764a42..836d2cabb 100644 --- a/packages/sequencer/test/integration/BlockProduction-test.ts +++ b/packages/sequencer/test/integration/BlockProduction-test.ts @@ -31,10 +31,8 @@ import { Sequencer, SequencerModule, VanillaTaskWorkerModules, - DatabasePruneModule, AsyncLinkedLeafStore, AppChain, - BlockProducerModule, DatabaseDependencyFactory, } from "../../src"; import { @@ -125,7 +123,6 @@ export function testBlockProduction< }); const sequencerClass = Sequencer.from({ - DatabasePruneModule, ...testingSequencerModules({}), Database: database, }); @@ -145,15 +142,12 @@ export function testBlockProduction< app.configure({ Sequencer: { - DatabasePruneModule: { - pruneOnStartup: true, - }, Database: databaseConfig, BlockTrigger: {}, Mempool: {}, BatchProducerModule: {}, BlockProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, FeeStrategy: {}, @@ -697,10 +691,9 @@ export function testBlockProduction< async (numBlocks) => { log.setLevel("INFO"); - (sequencer.resolve("BlockProducerModule") as BlockProducerModule).config = - { - maximumBlockSize: 5, - }; + sequencer.resolve("Mempool").config = { + targetBlockSize: 5, + }; const privateKey = PrivateKey.random(); diff --git a/packages/sequencer/test/integration/BlockProductionSize.test.ts b/packages/sequencer/test/integration/BlockProductionSize.test.ts index 67d6d7ca6..4f6c4cce1 100644 --- a/packages/sequencer/test/integration/BlockProductionSize.test.ts +++ b/packages/sequencer/test/integration/BlockProductionSize.test.ts @@ -70,12 +70,12 @@ describe("block limit", () => { Sequencer: { Database: {}, BlockTrigger: {}, - Mempool: {}, - BatchProducerModule: {}, - BlockProducerModule: { - maximumBlockSize: maxBlockSize, + Mempool: { + targetBlockSize: maxBlockSize, }, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + BatchProducerModule: {}, + BlockProducerModule: {}, + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, FeeStrategy: {}, diff --git a/packages/sequencer/test/integration/MempoolTxRemoved.test.ts b/packages/sequencer/test/integration/MempoolTxRemoved.test.ts index 02fae71f5..818dc4407 100644 --- a/packages/sequencer/test/integration/MempoolTxRemoved.test.ts +++ b/packages/sequencer/test/integration/MempoolTxRemoved.test.ts @@ -50,7 +50,7 @@ describe("mempool removal mechanism", () => { Mempool: {}, BatchProducerModule: {}, BlockProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, FeeStrategy: {}, diff --git a/packages/sequencer/test/integration/StorageIntegration.test.ts b/packages/sequencer/test/integration/StorageIntegration.test.ts index c4df190c6..8ccbad72a 100644 --- a/packages/sequencer/test/integration/StorageIntegration.test.ts +++ b/packages/sequencer/test/integration/StorageIntegration.test.ts @@ -95,7 +95,7 @@ describe.each([["InMemory", InMemoryDatabase]])( Mempool: {}, BatchProducerModule: {}, BlockProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, FeeStrategy: {}, diff --git a/packages/sequencer/test/production/tracing/StateTransitionTracingService.test.ts b/packages/sequencer/test/production/tracing/StateTransitionTracingService.test.ts index a670b41c6..8dd0e317b 100644 --- a/packages/sequencer/test/production/tracing/StateTransitionTracingService.test.ts +++ b/packages/sequencer/test/production/tracing/StateTransitionTracingService.test.ts @@ -75,7 +75,7 @@ async function applyBatchesToTree( // const SequencerC = Sequencer.from({ // modules: { // TaskQueue: LocalTaskQueue, -// LocalTaskWorkerModule: LocalTaskWorkerModule.from({ +// WorkerModule: WorkerModule.from({ // StateTransitionTask, // StateTransitionReductionTask, // }), @@ -103,7 +103,7 @@ async function applyBatchesToTree( // // const sequencer = new SequencerC(); // sequencer.configure({ -// LocalTaskWorkerModule: { +// WorkerModule: { // StateTransitionTask: {}, // StateTransitionReductionTask: {}, // }, diff --git a/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts b/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts index 79dccbcd4..63f68d5e4 100644 --- a/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts +++ b/packages/sequencer/test/protocol/production/sequencing/atomic-block-production.test.ts @@ -53,7 +53,7 @@ describe("atomic block production", () => { Mempool: {}, BatchProducerModule: {}, BlockProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, FeeStrategy: {}, diff --git a/packages/sequencer/test/settlement/Settlement-only.ts b/packages/sequencer/test/settlement/Settlement-only.ts index c894bfbcf..621d2ebc7 100644 --- a/packages/sequencer/test/settlement/Settlement-only.ts +++ b/packages/sequencer/test/settlement/Settlement-only.ts @@ -115,7 +115,7 @@ export const settlementOnlyTestFn = ( BlockTrigger: {}, Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: { + WorkerModule: { ...VanillaTaskWorkerModules.defaultConfig(), }, BaseLayer: baseLayerConfig, diff --git a/packages/sequencer/test/settlement/Settlement.ts b/packages/sequencer/test/settlement/Settlement.ts index 40adaf414..027ff7953 100644 --- a/packages/sequencer/test/settlement/Settlement.ts +++ b/packages/sequencer/test/settlement/Settlement.ts @@ -58,7 +58,7 @@ import { Sequencer, InMemoryMinaSigner, CircuitAnalysisModule, - LocalTaskWorkerModule, + WorkerModule, InMemoryDatabase, BatchProducerModule, BlockProducerModule, @@ -170,7 +170,7 @@ export const settlementTestFn = ( MinaBaseLayer.prototype["isSignedSettlement"] = () => settlementType === "signed"; - const taskWorkerModule = LocalTaskWorkerModule.from( + const taskWorkerModule = WorkerModule.from( VanillaTaskWorkerModules.allTasks() ); @@ -189,7 +189,7 @@ export const settlementTestFn = ( ...(bullQueueConfig !== undefined ? {} : { - LocalTaskWorkerModule: taskWorkerModule, + WorkerModule: taskWorkerModule, }), SequencerStartupModule, }); @@ -215,7 +215,7 @@ export const settlementTestFn = ( BlockTrigger: {}, Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: { + WorkerModule: { ...VanillaTaskWorkerModules.defaultConfig(), }, BaseLayer: baseLayerConfig, diff --git a/packages/stack/src/presets/modules/index.ts b/packages/stack/src/presets/modules/index.ts index 68f3bb86f..0a8403bca 100644 --- a/packages/stack/src/presets/modules/index.ts +++ b/packages/stack/src/presets/modules/index.ts @@ -1,7 +1,6 @@ import { VanillaGraphqlModules, GraphqlSequencerModule, - GraphqlServer, OpenTelemetryServer, } from "@proto-kit/api"; import { @@ -10,13 +9,12 @@ import { TimedBlockTrigger, BlockProducerModule, SequencerStartupModule, - LocalTaskWorkerModule, + WorkerModule, VanillaTaskWorkerModules, MinaBaseLayer, ConstantFeeStrategy, BatchProducerModule, SettlementModule, - DatabasePruneModule, InMemoryDatabase, LocalTaskQueue, AppChainModulesRecord, @@ -71,7 +69,6 @@ import { export class DefaultModules { static api() { return { - GraphqlServer, Graphql: GraphqlSequencerModule.from(VanillaGraphqlModules.with({})), } satisfies SequencerModulesRecord; } @@ -115,13 +112,12 @@ export class DefaultModules { return { Database: PrismaRedisDatabase, TaskQueue: BullQueue, - TaskWorker: LocalTaskWorkerModule.from({ + TaskWorker: WorkerModule.from({ IndexBlockTask, IndexPendingTxTask, IndexBatchTask, IndexSettlementTask, }), - GraphqlServer, Graphql: GraphqlSequencerModule.from({ GeneratedResolverFactory: GeneratedResolverFactoryGraphqlModule, }), @@ -133,7 +129,6 @@ export class DefaultModules { handlers: HandlersRecord ) { return { - GraphqlServer, GraphqlSequencerModule: GraphqlSequencerModule.from({ ResolverFactory: ResolverFactoryGraphqlModule.from(resolvers), }), @@ -152,13 +147,12 @@ export class DefaultModules { static prismaRedisDatabase() { return { Database: PrismaRedisDatabase, - DatabasePruneModule, } satisfies SequencerModulesRecord; } static localWorker(options?: { settlementEnabled?: boolean }) { return { - LocalTaskWorkerModule: LocalTaskWorkerModule.from( + WorkerModule: WorkerModule.from( options?.settlementEnabled === true ? VanillaTaskWorkerModules.allTasks() : VanillaTaskWorkerModules.withoutSettlement() @@ -176,9 +170,7 @@ export class DefaultModules { static remoteWorker() { return { TaskQueue: BullQueue, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( - VanillaTaskWorkerModules.allTasks() - ), + WorkerModule: WorkerModule.from(VanillaTaskWorkerModules.allTasks()), } satisfies SequencerModulesRecord; } @@ -195,9 +187,7 @@ export class DefaultModules { ...DefaultModules.settlement(), Mempool: PrivateMempool, TaskQueue: LocalTaskQueue, - LocalTaskWorker: LocalTaskWorkerModule.from( - VanillaTaskWorkerModules.allTasks() - ), + WorkerModule: WorkerModule.from(VanillaTaskWorkerModules.allTasks()), SequencerStartupModule, BridgingModule: BridgingModule, } satisfies SequencerModulesRecord; @@ -208,12 +198,15 @@ export class DefaultConfigs { preset?: Environment; overrides?: Partial; }) { + const serverConfig = DefaultConfigs.graphqlServer({ + preset: options?.preset, + overrides: options?.overrides, + }); return { - Graphql: VanillaGraphqlModules.defaultConfig(), - ...DefaultConfigs.graphqlServer({ - preset: options?.preset, - overrides: options?.overrides, - }), + Graphql: { + ...VanillaGraphqlModules.defaultConfig(), + ...serverConfig.GraphqlServer, + }, }; } @@ -259,7 +252,7 @@ export class DefaultConfigs { BlockProducerModule: {}, BlockTrigger: blockTriggerConfig, SequencerStartupModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), ...settlementConfig, }; } @@ -329,9 +322,9 @@ export class DefaultConfigs { IndexPendingTxTask: {}, IndexSettlementTask: {}, }, - ...graphqlServerConfig, Graphql: { GeneratedResolverFactory: {}, + ...graphqlServerConfig.GraphqlServer, }, }; } @@ -361,9 +354,9 @@ export class DefaultConfigs { Trigger: { interval: Number(config.blockInterval) / 5, }, - ...graphqlServerConfig, GraphqlSequencerModule: { ResolverFactory: {}, + ...graphqlServerConfig.GraphqlServer, }, }; } @@ -410,7 +403,7 @@ export class DefaultConfigs { }, FeeStrategy: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), }; } @@ -434,9 +427,9 @@ export class DefaultConfigs { prisma: { connection: config.databaseUrl, }, - }, - DatabasePruneModule: { - pruneOnStartup: config.pruneOnStartup, + databasePruneModule: { + pruneOnStartup: config.pruneOnStartup, + }, }, }; } @@ -444,7 +437,7 @@ export class DefaultConfigs { static localWorker() { return { TaskQueue: {}, - LocalTaskWorkerModule: { + WorkerModule: { ...VanillaTaskWorkerModules.defaultConfig(), }, } satisfies ModulesConfig>; @@ -524,7 +517,7 @@ export class DefaultConfigs { return { ...taskQueueConfig, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), }; } diff --git a/packages/stack/src/scripts/graphql/server.ts b/packages/stack/src/scripts/graphql/server.ts index 2cdaf2604..4ac77c36b 100644 --- a/packages/stack/src/scripts/graphql/server.ts +++ b/packages/stack/src/scripts/graphql/server.ts @@ -22,7 +22,7 @@ import { BatchProducerModule, InMemoryDatabase, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, NoopBaseLayer, PrivateMempool, Sequencer, @@ -34,7 +34,6 @@ import { import { BatchStorageResolver, GraphqlSequencerModule, - GraphqlServer, MempoolResolver, LinkedMerkleWitnessResolver as MerkleWitnessResolver, NodeStatusResolver, @@ -99,8 +98,7 @@ export async function startServer() { OpenTelemetryServer, Mempool: PrivateMempool, - GraphqlServer, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( + WorkerModule: WorkerModule.from( VanillaTaskWorkerModules.withoutSettlement() ), @@ -151,19 +149,12 @@ export async function startServer() { }, Sequencer: { - GraphqlServer: { - port: 8080, - host: "0.0.0.0", - graphiql: true, - }, SequencerStartupModule: {}, - // SettlementModule: { - // address: PrivateKey.random().toPublicKey(), - // feepayer: PrivateKey.random(), - // }, - Graphql: { + port: 8080, + host: "0.0.0.0", + graphiql: true, QueryGraphqlModule: {}, MempoolResolver: {}, BatchStorageResolver: {}, @@ -205,13 +196,11 @@ export async function startServer() { Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, - BlockProducerModule: { - allowEmptyBlock: true, - }, + BlockProducerModule: {}, BlockTrigger: { blockInterval: 10000, diff --git a/packages/stack/src/scripts/worker/sequencer.ts b/packages/stack/src/scripts/worker/sequencer.ts index db0a3433d..cceb6d3fc 100644 --- a/packages/stack/src/scripts/worker/sequencer.ts +++ b/packages/stack/src/scripts/worker/sequencer.ts @@ -9,14 +9,9 @@ import { InMemoryDatabase, MinaBaseLayer, TimedBlockTrigger, - DatabasePruneModule, AppChain, } from "@proto-kit/sequencer"; -import { - VanillaGraphqlModules, - GraphqlSequencerModule, - GraphqlServer, -} from "@proto-kit/api"; +import { VanillaGraphqlModules, GraphqlSequencerModule } from "@proto-kit/api"; import { app } from "./app"; @@ -29,8 +24,6 @@ export const sequencer = AppChain.from({ Database: InMemoryDatabase, BaseLayer: MinaBaseLayer, BlockTrigger: TimedBlockTrigger, - DatabasePruneModule: DatabasePruneModule, - GraphqlServer: GraphqlServer, Graphql: GraphqlSequencerModule.from(VanillaGraphqlModules.with({})), }) ), @@ -62,13 +55,10 @@ sequencer.configure({ }, }, SequencerStartupModule: {}, - GraphqlServer: { + Graphql: { host: "0.0.0.0", port: 8080, graphiql: true, - }, - - Graphql: { QueryGraphqlModule: {}, MempoolResolver: {}, BatchStorageResolver: {}, diff --git a/packages/stack/test-integration/caching/caching.test.ts b/packages/stack/test-integration/caching/caching.test.ts index 896cdf645..5d0d33b08 100644 --- a/packages/stack/test-integration/caching/caching.test.ts +++ b/packages/stack/test-integration/caching/caching.test.ts @@ -20,7 +20,7 @@ import { BlockProducerModule, InMemoryDatabase, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, ManualBlockTrigger, NoopBaseLayer, PrivateMempool, @@ -49,7 +49,7 @@ export async function startAppChain() { Database: InMemoryDatabase, Mempool: PrivateMempool, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( + WorkerModule: WorkerModule.from( VanillaTaskWorkerModules.withoutSettlement() ), @@ -92,13 +92,11 @@ export async function startAppChain() { Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, - BlockProducerModule: { - allowEmptyBlock: true, - }, + BlockProducerModule: {}, BlockTrigger: {}, diff --git a/packages/stack/test/graphql/graphql-server.ts b/packages/stack/test/graphql/graphql-server.ts index 3318b9c7f..781a0b7aa 100644 --- a/packages/stack/test/graphql/graphql-server.ts +++ b/packages/stack/test/graphql/graphql-server.ts @@ -20,7 +20,7 @@ import { BatchProducerModule, InMemoryDatabase, LocalTaskQueue, - LocalTaskWorkerModule, + WorkerModule, NoopBaseLayer, PrivateMempool, Sequencer, @@ -32,7 +32,6 @@ import { import { BatchStorageResolver, GraphqlSequencerModule, - GraphqlServer, MempoolResolver, MerkleWitnessResolver, NodeStatusResolver, @@ -60,8 +59,7 @@ export async function startGraphqlServer() { // Database: PrismaRedisDatabase, Mempool: PrivateMempool, - GraphqlServer, - LocalTaskWorkerModule: LocalTaskWorkerModule.from( + WorkerModule: WorkerModule.from( VanillaTaskWorkerModules.withoutSettlement() ), @@ -108,11 +106,6 @@ export async function startGraphqlServer() { }, Sequencer: { - GraphqlServer: { - port: 8080, - host: "0.0.0.0", - graphiql: true, - }, SequencerStartupModule: {}, // SettlementModule: { @@ -121,6 +114,9 @@ export async function startGraphqlServer() { // }, Graphql: { + port: 8080, + host: "0.0.0.0", + graphiql: true, QueryGraphqlModule: {}, MempoolResolver: {}, BatchStorageResolver: {}, @@ -150,13 +146,11 @@ export async function startGraphqlServer() { Mempool: {}, BatchProducerModule: {}, - LocalTaskWorkerModule: VanillaTaskWorkerModules.defaultConfig(), + WorkerModule: VanillaTaskWorkerModules.defaultConfig(), BaseLayer: {}, TaskQueue: {}, - BlockProducerModule: { - allowEmptyBlock: true, - }, + BlockProducerModule: {}, BlockTrigger: {}, },