diff --git a/packages/common/src/compiling/services/ChildVerificationKeyService.ts b/packages/common/src/compiling/services/ChildVerificationKeyService.ts index 1e90738d1..526b522ef 100644 --- a/packages/common/src/compiling/services/ChildVerificationKeyService.ts +++ b/packages/common/src/compiling/services/ChildVerificationKeyService.ts @@ -23,4 +23,12 @@ export class ChildVerificationKeyService { } return artifact.verificationKey; } + + public getAsConstant(name: string) { + const vk = this.getVerificationKey(name); + if (!vk.hash.isConstant()) { + throw new Error("Sanity check - vk hash has to be constant"); + } + return vk; + } } diff --git a/packages/protocol/src/prover/block/BlockProvable.ts b/packages/protocol/src/prover/block/BlockProvable.ts index 7ceef4e5a..361df387e 100644 --- a/packages/protocol/src/prover/block/BlockProvable.ts +++ b/packages/protocol/src/prover/block/BlockProvable.ts @@ -1,7 +1,19 @@ -import { Bool, Field, Poseidon, Proof, Provable, Struct } from "o1js"; +// eslint-disable-next-line max-classes-per-file +import { + Bool, + DynamicProof, + Field, + Poseidon, + Proof, + Provable, + Struct, +} from "o1js"; import { CompilableModule, WithZkProgrammable } from "@proto-kit/common"; -import { StateTransitionProof } from "../statetransition/StateTransitionProvable"; +import { + StateTransitionProverPublicInput, + StateTransitionProverPublicOutput, +} from "../statetransition/StateTransitionProvable"; import { NetworkState } from "../../model/network/NetworkState"; import { TransactionHashList } from "../accumulators/TransactionHashList"; import { MinaActionsHashList } from "../../utils/MinaPrefixedProvableHashList"; @@ -10,7 +22,10 @@ import { WitnessedRootHashList, WitnessedRootWitness, } from "../accumulators/WitnessedRootHashList"; -import { TransactionProof } from "../transaction/TransactionProvable"; +import { + TransactionProverPublicInput, + TransactionProverPublicOutput, +} from "../transaction/TransactionProvable"; import { BundleHashList, FieldTransition } from "../accumulators/BlockHashList"; import { NonMethods } from "../../utils/utils"; import { Constants } from "../../Constants"; @@ -345,6 +360,28 @@ export class BlockProverState { } } +export class DynamicSTProof extends DynamicProof< + StateTransitionProverPublicInput, + StateTransitionProverPublicOutput +> { + static publicInputType = StateTransitionProverPublicInput; + + static publicOutputType = StateTransitionProverPublicOutput; + + static maxProofsVerified = 2 as const; +} + +export class DynamicTransactionProof extends DynamicProof< + TransactionProverPublicInput, + TransactionProverPublicOutput +> { + static publicInputType = TransactionProverPublicInput; + + static publicOutputType = TransactionProverPublicOutput; + + static maxProofsVerified = 2 as const; +} + export type BlockProof = Proof; export interface BlockProvable @@ -368,8 +405,8 @@ export interface BlockProvable batch: BlockArgumentsBatch, deferSTProof: Bool, deferTransactionProof: Bool, - stateTransitionProof: StateTransitionProof, - transactionProof: TransactionProof + stateTransitionProof: DynamicSTProof, + transactionProof: DynamicTransactionProof ) => Promise; merge: ( diff --git a/packages/protocol/src/prover/block/BlockProver.ts b/packages/protocol/src/prover/block/BlockProver.ts index 6f600d896..643229794 100644 --- a/packages/protocol/src/prover/block/BlockProver.ts +++ b/packages/protocol/src/prover/block/BlockProver.ts @@ -2,6 +2,7 @@ import { Bool, Field, Provable, SelfProof, ZkProgram } from "o1js"; import { container, inject, injectable, injectAll } from "tsyringe"; import { AreProofsEnabled, + ChildVerificationKeyService, CompilableModule, CompileArtifact, CompileRegistry, @@ -16,7 +17,6 @@ import { import { ProtocolModule } from "../../protocol/ProtocolModule"; import { - StateTransitionProof, StateTransitionProvable, StateTransitionProverPublicInput, StateTransitionProverPublicOutput, @@ -35,7 +35,6 @@ import { assertEqualsIf } from "../../utils/utils"; import { StateServiceProvider } from "../../state/StateServiceProvider"; import { executeHooks } from "../utils"; import { - TransactionProof, TransactionProvable, TransactionProverPublicInput, TransactionProverPublicOutput, @@ -51,6 +50,8 @@ import { BlockProverPublicOutput, BlockProverState, BlockProverStateInput, + DynamicSTProof, + DynamicTransactionProof, } from "./BlockProvable"; import { BlockHashMerkleTreeWitness, @@ -74,16 +75,9 @@ export class BlockProverProgrammable extends ZkProgrammable< > { public constructor( private readonly prover: BlockProver, - public readonly stateTransitionProver: ZkProgrammable< - StateTransitionProverPublicInput, - StateTransitionProverPublicOutput - >, - public readonly transactionProver: ZkProgrammable< - TransactionProverPublicInput, - TransactionProverPublicOutput - >, private readonly blockHooks: ProvableBlockHook[], - private readonly stateServiceProvider: StateServiceProvider + private readonly stateServiceProvider: StateServiceProvider, + private readonly childVerificationKeyService: ChildVerificationKeyService ) { super(); } @@ -141,7 +135,7 @@ export class BlockProverProgrammable extends ZkProgrammable< } public includeSTProof( - stateTransitionProof: StateTransitionProof, + stateTransitionProof: DynamicSTProof, apply: Bool, stateRoot: Field, pendingSTBatchesHash: Field, @@ -224,7 +218,7 @@ export class BlockProverProgrammable extends ZkProgrammable< private verifySTProof( state: BlockProverState, - stateTransitionProof: StateTransitionProof, + stateTransitionProof: DynamicSTProof, deferSTProof: Bool ) { // Verify ST Proof only if STs have been emitted, @@ -233,7 +227,12 @@ export class BlockProverProgrammable extends ZkProgrammable< const batchesEmpty = state.pendingSTBatches.commitment.equals(Field(0)); const verifyStProof = deferSTProof.not().and(batchesEmpty.not()); log.provable.debug("Verify STProof", verifyStProof); - stateTransitionProof.verifyIf(verifyStProof); + + // Brought in as a constant + const stProofVk = this.childVerificationKeyService.getAsConstant( + "StateTransitionProver" + ); + stateTransitionProof.verifyIf(stProofVk, verifyStProof); // Apply STProof if not deferred const stateProofResult = this.includeSTProof( @@ -250,7 +249,7 @@ export class BlockProverProgrammable extends ZkProgrammable< private verifyTransactionProof( state: BlockProverState, - transactionProof: TransactionProof, + transactionProof: DynamicTransactionProof, deferTransactionProof: Bool ) { // Verify Transaction proof if it has at least 1 tx and it isn't deferred @@ -259,7 +258,11 @@ export class BlockProverProgrammable extends ZkProgrammable< state.bundleList.isEmpty().not() ); - transactionProof.verifyIf(verifyTransactionProof); + // Brought in as a constant + const transactionProofVk = this.childVerificationKeyService.getAsConstant( + "StateTransitionProver" + ); + transactionProof.verifyIf(transactionProofVk, verifyTransactionProof); // Fast-forward transaction trackers by the results of the aggregated transaction proof // Implicitly, the 'from' values here are asserted against the publicInput, since the hashlists @@ -402,8 +405,8 @@ export class BlockProverProgrammable extends ZkProgrammable< batch: BlockArgumentsBatch, deferSTProof: Bool, deferTransactionProof: Bool, - stateTransitionProof: StateTransitionProof, - transactionProof: TransactionProof + stateTransitionProof: DynamicSTProof, + transactionProof: DynamicTransactionProof ) { const finalize = deferTransactionProof.or(deferSTProof).not(); @@ -432,8 +435,8 @@ export class BlockProverProgrammable extends ZkProgrammable< deferSTProof: Bool, deferTransactionProof: Bool, finalize: Bool, - stateTransitionProof?: StateTransitionProof, - transactionProof?: TransactionProof + stateTransitionProof?: DynamicSTProof, + transactionProof?: DynamicTransactionProof ): Promise { let state = this.parseState( publicInput, @@ -621,9 +624,7 @@ export class BlockProverProgrammable extends ZkProgrammable< BlockProverPublicInput, BlockProverPublicOutput >[] { - const { prover, stateTransitionProver, transactionProver } = this; - const StateTransitionProofClass = stateTransitionProver.zkProgram[0].Proof; - const TransactionProofClass = transactionProver.zkProgram[0].Proof; + const { prover } = this; const proveBlockBatchWithProofs = prover.proveBlockBatchWithProofs.bind(prover); const proveBlockBatchNoProofs = prover.proveBlockBatchNoProofs.bind(prover); @@ -643,8 +644,8 @@ export class BlockProverProgrammable extends ZkProgrammable< BlockArgumentsBatch, Bool, Bool, - StateTransitionProofClass, - TransactionProofClass, + DynamicSTProof, + DynamicTransactionProof, ], async method( publicInput: BlockProverPublicInput, @@ -654,8 +655,8 @@ export class BlockProverProgrammable extends ZkProgrammable< batch: BlockArgumentsBatch, deferSTProof: Bool, deferTransactionProof: Bool, - stateTransitionProof: StateTransitionProof, - transactionProof: TransactionProof + stateTransitionProof: DynamicSTProof, + transactionProof: DynamicTransactionProof ) { return { publicOutput: await proveBlockBatchWithProofs( @@ -768,24 +769,26 @@ export class BlockProver @injectAll("ProvableBlockHook") blockHooks: ProvableBlockHook[], @inject("StateServiceProvider") - stateServiceProvider: StateServiceProvider + stateServiceProvider: StateServiceProvider, + childVerificationKeyService: ChildVerificationKeyService ) { super(); this.zkProgrammable = new BlockProverProgrammable( this, - stateTransitionProver.zkProgrammable, - transactionProver.zkProgrammable, blockHooks, - stateServiceProvider + stateServiceProvider, + childVerificationKeyService ); } public async compile( registry: CompileRegistry ): Promise | undefined> { - return await registry.proverNeeded(async () => { + await registry.sideloaded(async () => { await this.stateTransitionProver.compile(registry); await this.transactionProver.compile(registry); + }); + return await registry.proverNeeded(async () => { return await this.zkProgrammable.compile(registry); }); } @@ -816,8 +819,8 @@ export class BlockProver batch: BlockArgumentsBatch, deferSTProof: Bool, deferTransactionProof: Bool, - stateTransitionProof: StateTransitionProof, - transactionProof: TransactionProof + stateTransitionProof: DynamicSTProof, + transactionProof: DynamicTransactionProof ): Promise { return this.zkProgrammable.proveBlockBatchWithProofs( publicInput, diff --git a/packages/protocol/src/settlement/contracts/settlement/SettlementBase.ts b/packages/protocol/src/settlement/contracts/settlement/SettlementBase.ts index 050543b5f..c44857d1b 100644 --- a/packages/protocol/src/settlement/contracts/settlement/SettlementBase.ts +++ b/packages/protocol/src/settlement/contracts/settlement/SettlementBase.ts @@ -150,8 +150,8 @@ export abstract class SettlementBase throw new Error("Sanity check - vk hash has to be constant"); } // Verify the blockproof - blockProof.verify(blockProofVk); + // Get and assert on-chain values const stateRoot = this.stateRoot.getAndRequireEquals(); const networkStateHash = this.networkStateHash.getAndRequireEquals(); diff --git a/packages/sdk/src/query/StateServiceQueryModule.ts b/packages/sdk/src/query/StateServiceQueryModule.ts index 399fdb617..8d91da199 100644 --- a/packages/sdk/src/query/StateServiceQueryModule.ts +++ b/packages/sdk/src/query/StateServiceQueryModule.ts @@ -31,7 +31,7 @@ export class StateServiceQueryModule } public get treeStore(): AsyncLinkedLeafStore { - return this.sequencer.dependencyContainer.resolve("AsyncLinkedMerkleStore"); + return this.sequencer.dependencyContainer.resolve("AsyncLinkedLeafStore"); } public get(key: Field) { diff --git a/packages/sequencer/src/protocol/production/tasks/NewBlockTask.ts b/packages/sequencer/src/protocol/production/tasks/NewBlockTask.ts index bac58cf3c..ff85dafb2 100644 --- a/packages/sequencer/src/protocol/production/tasks/NewBlockTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/NewBlockTask.ts @@ -15,6 +15,8 @@ import { BlockArgumentsBatch, BlockProverStateInput, ProtocolConstants, + DynamicSTProof, + DynamicTransactionProof, } from "@proto-kit/protocol"; import { Bool } from "o1js"; import { @@ -143,6 +145,8 @@ export class NewBlockTask // deferSTProof.or(deferTransactionProof) ); } else { + const stProof = DynamicSTProof.fromProof(input1); + const txProof = DynamicTransactionProof.fromProof(input2); await this.blockProver.proveBlockBatchWithProofs( publicInput, stateWitness, @@ -151,8 +155,8 @@ export class NewBlockTask blockArgumentBatch, deferSTProof, deferTransactionProof, - input1, - input2 + stProof, + txProof ); } } diff --git a/packages/sequencer/src/protocol/production/tasks/compile/CircuitCompileTask.ts b/packages/sequencer/src/protocol/production/tasks/compile/CircuitCompileTask.ts index b6cdc656c..aa1218a6d 100644 --- a/packages/sequencer/src/protocol/production/tasks/compile/CircuitCompileTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/compile/CircuitCompileTask.ts @@ -5,6 +5,7 @@ import { CompileRegistry, CompilableModule, safeParseJson, + NoConfig, } from "@proto-kit/common"; import { Protocol, @@ -29,10 +30,9 @@ export type CompilerTaskParams = { isSignedSettlement?: boolean; }; -export abstract class CircuitCompileTask extends UnpreparingTask< - CompilerTaskParams, - ArtifactRecord -> { +export abstract class CircuitCompileTask< + Config = NoConfig, +> extends UnpreparingTask { protected constructor( protected readonly protocol: Protocol, protected readonly compileRegistry: CompileRegistry, diff --git a/packages/sequencer/src/protocol/production/tasks/compile/ProtocolCompileTask.ts b/packages/sequencer/src/protocol/production/tasks/compile/ProtocolCompileTask.ts index fba628ca9..dc2b59001 100644 --- a/packages/sequencer/src/protocol/production/tasks/compile/ProtocolCompileTask.ts +++ b/packages/sequencer/src/protocol/production/tasks/compile/ProtocolCompileTask.ts @@ -1,4 +1,4 @@ -import { inject, injectable, Lifecycle, scoped } from "tsyringe"; +import { inject, injectable } from "tsyringe"; import { CompilableModule, CompileRegistry } from "@proto-kit/common"; import { ContractArgsRegistry, @@ -9,9 +9,8 @@ import { import { CircuitCompileTask } from "./CircuitCompileTask"; @injectable() -@scoped(Lifecycle.ContainerScoped) export class ProtocolCompileTask extends CircuitCompileTask { - public name = "compile-protocol"; + public name = "undefined"; public constructor( @inject("Protocol") @@ -20,9 +19,36 @@ export class ProtocolCompileTask extends CircuitCompileTask { contractArgsRegistry: ContractArgsRegistry ) { super(protocol, compileRegistry, contractArgsRegistry); + + this.name = `compile-${this.getTargetProtocolModule().toLowerCase()}`; + } + + public getTargetProtocolModule(): string { + throw new Error(""); } public async getTargets(): Promise { - return [this.protocol.blockProver]; + return [this.protocol.resolveOrFail(this.getTargetProtocolModule())]; + } +} + +@injectable() +export class BlockProverCompileTask extends ProtocolCompileTask { + public getTargetProtocolModule() { + return "BlockProver"; + } +} + +@injectable() +export class STProverCompileTask extends ProtocolCompileTask { + public getTargetProtocolModule() { + return "StateTransitionProver"; + } +} + +@injectable() +export class TransactionProverCompileTask extends ProtocolCompileTask { + public getTargetProtocolModule() { + return "TransactionProver"; } } diff --git a/packages/sequencer/src/sequencer/SequencerStartupModule.ts b/packages/sequencer/src/sequencer/SequencerStartupModule.ts index 2e37e8bf1..1f7aaec7b 100644 --- a/packages/sequencer/src/sequencer/SequencerStartupModule.ts +++ b/packages/sequencer/src/sequencer/SequencerStartupModule.ts @@ -13,6 +13,7 @@ import { CompileRegistry, AreProofsEnabled, CompileArtifact, + mapSequential, } from "@proto-kit/common"; import { Flow, FlowCreator } from "../worker/flow/Flow"; @@ -21,11 +22,18 @@ import { VerificationKeyService } from "../protocol/runtime/RuntimeVerificationK import type { MinaBaseLayer } from "../protocol/baselayer/MinaBaseLayer"; import { NoopBaseLayer } from "../protocol/baselayer/NoopBaseLayer"; import { RuntimeCompileTask } from "../protocol/production/tasks/compile/RuntimeCompileTask"; -import { ProtocolCompileTask } from "../protocol/production/tasks/compile/ProtocolCompileTask"; import { SettlementCompileTask } from "../protocol/production/tasks/compile/SettlementCompileTask"; -import { CompilerTaskParams } from "../protocol/production/tasks/compile/CircuitCompileTask"; +import { + CircuitCompileTask, + CompilerTaskParams, +} from "../protocol/production/tasks/compile/CircuitCompileTask"; import { Task } from "../worker/flow/Task"; import { SettlementModule } from "../settlement/SettlementModule"; +import { + BlockProverCompileTask, + STProverCompileTask, + TransactionProverCompileTask, +} from "../protocol/production/tasks/compile/ProtocolCompileTask"; import { SequencerModule, sequencerModule } from "./builder/SequencerModule"; import { Closeable, closeable } from "./builder/Closeable"; @@ -40,9 +48,11 @@ export class SequencerStartupModule private readonly flowCreator: FlowCreator, @inject("Protocol") private readonly protocol: Protocol, - private readonly runtimeCompilerTask: RuntimeCompileTask, - private readonly protocolCompilerTask: ProtocolCompileTask, - private readonly settlementCompilerTask: SettlementCompileTask, + private readonly runtimeCompileTask: RuntimeCompileTask, + private readonly stProverCompileTask: STProverCompileTask, + private readonly transactionProverCompileTask: TransactionProverCompileTask, + private readonly blockProverCompileTask: BlockProverCompileTask, + private readonly settlementCompileTask: SettlementCompileTask, private readonly verificationKeyService: VerificationKeyService, private readonly registrationFlow: WorkerRegistrationFlow, private readonly compileRegistry: CompileRegistry, @@ -72,7 +82,7 @@ export class SequencerStartupModule public async compileRuntime(flow: Flow<{}>) { const artifacts = await this.pushCompileTask( flow, - this.runtimeCompilerTask, + this.runtimeCompileTask, { existingArtifacts: {}, runtimeVKRoot: undefined, @@ -96,7 +106,7 @@ export class SequencerStartupModule private async compileBridge(flow: Flow<{}>, isSignedSettlement?: boolean) { const result = await flow.withFlow(async (res, rej) => { await flow.pushTask( - this.settlementCompilerTask, + this.settlementCompileTask, { existingArtifacts: this.compileRegistry.getAllArtifacts(), runtimeVKRoot: undefined, @@ -111,10 +121,14 @@ export class SequencerStartupModule return result; } - private async compileProtocol(flow: Flow<{}>, runtimeVkTreeRoot: bigint) { + private async compileProtocol( + flow: Flow<{}>, + task: CircuitCompileTask, + runtimeVkTreeRoot: bigint + ) { const result = await flow.withFlow(async (res, rej) => { await flow.pushTask( - this.protocolCompilerTask, + task, { existingArtifacts: this.compileRegistry.getAllArtifacts(), runtimeVKRoot: runtimeVkTreeRoot.toString(), @@ -153,7 +167,14 @@ export class SequencerStartupModule const root = await this.compileRuntime(flow); - await this.compileProtocol(flow, root); + const tasks = [ + this.blockProverCompileTask, + this.stProverCompileTask, + this.transactionProverCompileTask, + ]; + await mapSequential(tasks, async (task) => { + await this.compileProtocol(flow, task, root); + }); let bridgeVk: CompileArtifact | undefined = undefined; diff --git a/packages/sequencer/src/worker/flow/UnpreparingTask.ts b/packages/sequencer/src/worker/flow/UnpreparingTask.ts index 4ec71f076..c6eb3ff93 100644 --- a/packages/sequencer/src/worker/flow/UnpreparingTask.ts +++ b/packages/sequencer/src/worker/flow/UnpreparingTask.ts @@ -1,4 +1,4 @@ -import { noop } from "@proto-kit/common"; +import { NoConfig, noop } from "@proto-kit/common"; import { TaskWorkerModule } from "../worker/TaskWorkerModule"; @@ -8,8 +8,8 @@ import { Task, TaskSerializer } from "./Task"; * Contract: * Doesn't implement prepare() */ -export abstract class UnpreparingTask - extends TaskWorkerModule +export abstract class UnpreparingTask + extends TaskWorkerModule implements Task { abstract name: string; diff --git a/packages/sequencer/src/worker/queue/LocalTaskQueue.ts b/packages/sequencer/src/worker/queue/LocalTaskQueue.ts index 5ce6826f3..df03e90a3 100644 --- a/packages/sequencer/src/worker/queue/LocalTaskQueue.ts +++ b/packages/sequencer/src/worker/queue/LocalTaskQueue.ts @@ -149,6 +149,10 @@ export class LocalTaskQueue }); this.queuedTasks[queueName] = []; return functions; + } else if (tasks.length > 0) { + log.warn( + `Tasks found in queue ${queueName} but no worker registered` + ); } return []; @@ -161,11 +165,17 @@ export class LocalTaskQueue this.taskInProgress = false; // In case new tasks came up in the meantime, execute them as well - if (tasksToExecute.length > 0) { + if (this.hasTasksQueued()) { await this.workNextTasks(); } } + private hasTasksQueued() { + return Object.entries(this.queuedTasks).some( + ([, tasks]) => tasks.length > 0 + ); + } + public createWorker( queueName: string, executor: (data: TaskPayload) => Promise, diff --git a/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts b/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts index 715ad045b..fc81159e8 100644 --- a/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts +++ b/packages/sequencer/src/worker/worker/LocalTaskWorkerModule.ts @@ -30,8 +30,12 @@ import { BlockReductionTask } from "../../protocol/production/tasks/BlockReducti import { TransactionReductionTask } from "../../protocol/production/tasks/TransactionReductionTask"; import { WorkerRegistrationTask } from "../startup/WorkerRegistrationTask"; import { RuntimeCompileTask } from "../../protocol/production/tasks/compile/RuntimeCompileTask"; -import { ProtocolCompileTask } from "../../protocol/production/tasks/compile/ProtocolCompileTask"; import { SettlementCompileTask } from "../../protocol/production/tasks/compile/SettlementCompileTask"; +import { + BlockProverCompileTask, + STProverCompileTask, + TransactionProverCompileTask, +} from "../../protocol/production/tasks/compile/ProtocolCompileTask"; import { FlowTaskWorker } from "./FlowTaskWorker"; import { TaskWorkerModule } from "./TaskWorkerModule"; @@ -43,7 +47,7 @@ export { TypedClass }; export type TaskWorkerModulesRecord = ModulesRecord< // TODO any -> unknown - TypedClass> + TypedClass & Task> >; type LocalTaskWorkerModuleEvents = { ready: [boolean] }; @@ -143,7 +147,9 @@ export class VanillaTaskWorkerModules { NewBlockTask, WorkerRegistrationTask, RuntimeCompileTask, - ProtocolCompileTask, + STProverCompileTask, + BlockProverCompileTask, + TransactionProverCompileTask, } satisfies TaskWorkerModulesRecord; } @@ -167,7 +173,9 @@ export class VanillaTaskWorkerModules { SettlementProvingTask: {}, WorkerRegistrationTask: {}, RuntimeCompileTask: {}, - ProtocolCompileTask: {}, + STProverCompileTask: {}, + BlockProverCompileTask: {}, + TransactionProverCompileTask: {}, SettlementCompileTask: {}, } satisfies ModulesConfig< ReturnType diff --git a/packages/sequencer/src/worker/worker/TaskWorkerModule.ts b/packages/sequencer/src/worker/worker/TaskWorkerModule.ts index 35ca7b3f8..d2f46144d 100644 --- a/packages/sequencer/src/worker/worker/TaskWorkerModule.ts +++ b/packages/sequencer/src/worker/worker/TaskWorkerModule.ts @@ -1,3 +1,5 @@ import { ConfigurableModule, NoConfig } from "@proto-kit/common"; -export abstract class TaskWorkerModule extends ConfigurableModule {} +export abstract class TaskWorkerModule< + Config = NoConfig, +> extends ConfigurableModule {}