Skip to content

Commit e56a02c

Browse files
authored
Merge pull request #210 from proto-kit/feature/enable-proving
Enable proving 1: Batch proving
2 parents 2e78899 + a627060 commit e56a02c

File tree

58 files changed

+1494
-585
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1494
-585
lines changed

package-lock.json

Lines changed: 246 additions & 124 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/api/src/graphql/modules/BatchStorageResolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class ComputedBlockModel {
2121
blockHashes.map(
2222
(blockHash) => blocks.find((block) => block?.hash === blockHash)!
2323
),
24-
proof.proof === MOCK_PROOF ? "mock-proof" : JSON.stringify(proof)
24+
proof.proof === MOCK_PROOF ? MOCK_PROOF : JSON.stringify(proof)
2525
);
2626
}
2727

packages/common/src/events/EventEmitterProxy.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import type {
66
import { StringKeyOf, UnionToIntersection } from "../types";
77

88
import { EventEmitter } from "./EventEmitter";
9-
import { EventEmittingComponent, EventsRecord } from "./EventEmittingComponent";
9+
import {
10+
EventEmittingComponent,
11+
EventEmittingContainer,
12+
EventsRecord,
13+
} from "./EventEmittingComponent";
1014

1115
export type CastToEventsRecord<Record> = Record extends EventsRecord
1216
? Record
@@ -17,7 +21,13 @@ export type ModuleEvents<ModuleType extends BaseModuleType> =
1721
? Events
1822
: InstanceType<ModuleType> extends ModuleContainer<infer NestedModules>
1923
? CastToEventsRecord<ContainerEvents<NestedModules>>
20-
: EventsRecord;
24+
: // &
25+
// (InstanceType<ModuleType> extends EventEmittingContainer<
26+
// infer ContainerEvents
27+
// >
28+
// ? ContainerEvents
29+
// : {})
30+
EventsRecord;
2131

2232
export type ContainerEvents<Modules extends ModulesRecord> = {
2333
[Key in StringKeyOf<Modules>]: ModuleEvents<Modules[Key]>;
@@ -27,7 +37,7 @@ export type FlattenObject<Target extends Record<string, EventsRecord>> =
2737
UnionToIntersection<Target[keyof Target]>;
2838

2939
export type FlattenedContainerEvents<Modules extends ModulesRecord> =
30-
FlattenObject<ContainerEvents<Modules>>;
40+
FlattenObject<ContainerEvents<Modules>>; // & FlattenObject<any>;
3141

3242
export class EventEmitterProxy<
3343
Modules extends ModulesRecord,
@@ -45,10 +55,24 @@ export class EventEmitterProxy<
4555
this.emit(events, ...args);
4656
});
4757
}
58+
if (this.isEventEmittingContainer(module)) {
59+
module.containerEvents.onAll((events: any, args: any[]) => {
60+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
61+
this.emit(events, ...args);
62+
});
63+
}
4864
}
4965
});
5066
}
5167

68+
private isEventEmittingContainer(
69+
module: any
70+
): module is EventEmittingContainer<EventsRecord> {
71+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
72+
const emitter = module.containerEvents;
73+
return emitter !== undefined && emitter instanceof EventEmitter;
74+
}
75+
5276
private isEventEmitter(
5377
module: any
5478
): module is EventEmittingComponent<EventsRecord> {

packages/common/src/events/EventEmittingComponent.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ export type EventsRecord = Record<string, unknown[]>;
55
export interface EventEmittingComponent<Events extends EventsRecord> {
66
events: EventEmitter<Events>;
77
}
8+
9+
export interface EventEmittingContainer<Events extends EventsRecord> {
10+
containerEvents: EventEmitter<Events>;
11+
}

packages/common/src/log.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,26 @@ function logProvable(
2525
}
2626
/* eslint-enable */
2727

28+
const timeMap: Record<string, number> = {};
29+
30+
function time(label = "time") {
31+
timeMap[label] = Date.now();
32+
}
33+
34+
function timeLog(label = "time"): string {
35+
const prev = timeMap[label];
36+
if (prev === undefined) {
37+
return "Label not found";
38+
}
39+
return `${label} took ${Date.now() - prev}ms`;
40+
}
41+
42+
function timeEnd(label = "time"): string {
43+
const str = timeLog(label);
44+
delete timeMap[label];
45+
return str;
46+
}
47+
2848
export const log = {
2949
provable: {
3050
info: (...args: unknown[]) => {
@@ -48,6 +68,24 @@ export const log = {
4868
},
4969
},
5070

71+
time,
72+
73+
timeLog: {
74+
info: (label?: string) => loglevel.info(timeLog(label)),
75+
debug: (label?: string) => loglevel.debug(timeLog(label)),
76+
error: (label?: string) => loglevel.error(timeLog(label)),
77+
trace: (label?: string) => loglevel.trace(timeLog(label)),
78+
warn: (label?: string) => loglevel.warn(timeLog(label)),
79+
},
80+
81+
timeEnd: {
82+
info: (label?: string) => loglevel.info(timeEnd(label)),
83+
debug: (label?: string) => loglevel.debug(timeEnd(label)),
84+
error: (label?: string) => loglevel.error(timeEnd(label)),
85+
trace: (label?: string) => loglevel.trace(timeEnd(label)),
86+
warn: (label?: string) => loglevel.warn(timeEnd(label)),
87+
},
88+
5189
info: (...args: unknown[]) => {
5290
loglevel.info(...args);
5391
},

packages/common/src/zkProgrammable/ZkProgrammable.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { dummyVerificationKey } from "../dummyVerificationKey";
77
import { MOCK_PROOF } from "./provableMethod";
88

99
const errors = {
10-
appChainNotSet: (name: string) =>
11-
new Error(`Appchain was not injected for: ${name}`),
10+
areProofsEnabledNotSet: (name: string) =>
11+
new Error(`AreProofsEnabled was not injected for: ${name}`),
1212
};
1313

1414
export interface CompileArtifact {
@@ -72,6 +72,8 @@ export function verifyToMockable<PublicInput, PublicOutput>(
7272
return verified;
7373
}
7474

75+
console.log("VerifyMocked");
76+
7577
return proof.proof === MOCK_PROOF;
7678
};
7779
}
@@ -97,25 +99,29 @@ export abstract class ZkProgrammable<
9799
PublicInput = undefined,
98100
PublicOutput = void,
99101
> {
100-
public abstract get appChain(): AreProofsEnabled | undefined;
102+
public abstract get areProofsEnabled(): AreProofsEnabled | undefined;
101103

102104
public abstract zkProgramFactory(): PlainZkProgram<
103105
PublicInput,
104106
PublicOutput
105107
>[];
106108

109+
private zkProgramSingleton?: PlainZkProgram<PublicInput, PublicOutput>[];
110+
107111
@Memoize()
108112
public get zkProgram(): PlainZkProgram<PublicInput, PublicOutput>[] {
109-
const zkProgram = this.zkProgramFactory();
113+
if (this.zkProgramSingleton === undefined) {
114+
this.zkProgramSingleton = this.zkProgramFactory();
115+
}
110116

111-
return zkProgram.map((bucket) => {
112-
if (!this.appChain) {
113-
throw errors.appChainNotSet(this.constructor.name);
117+
return this.zkProgramSingleton.map((bucket) => {
118+
if (!this.areProofsEnabled) {
119+
throw errors.areProofsEnabledNotSet(this.constructor.name);
114120
}
115121
return {
116122
...bucket,
117-
verify: verifyToMockable(bucket.verify, this.appChain),
118-
compile: compileToMockable(bucket.compile, this.appChain),
123+
verify: verifyToMockable(bucket.verify, this.areProofsEnabled),
124+
compile: compileToMockable(bucket.compile, this.areProofsEnabled),
119125
};
120126
});
121127
}

packages/common/src/zkProgrammable/provableMethod.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,23 @@ export function toProver(
2424
...args: ArgumentTypes
2525
) {
2626
return async function prover(this: ZkProgrammable<any, any>) {
27-
const areProofsEnabled = this.appChain?.areProofsEnabled;
28-
if (areProofsEnabled ?? false) {
29-
for (const prog of this.zkProgram) {
30-
if (Object.keys(prog.methods).includes(methodName)) {
31-
const programProvableMethod = prog.methods[methodName];
32-
// eslint-disable-next-line no-await-in-loop
33-
return await Reflect.apply(programProvableMethod, this, args);
34-
}
35-
}
27+
const { areProofsEnabled } = this.areProofsEnabled!;
28+
29+
const zkProgram = this.zkProgram.find((prog) =>
30+
Object.keys(prog.methods).includes(methodName)
31+
);
32+
33+
if (zkProgram === undefined) {
34+
throw new Error("Correct ZkProgram not found");
35+
}
36+
37+
if (areProofsEnabled) {
38+
const programProvableMethod = zkProgram.methods[methodName];
39+
return await Reflect.apply(programProvableMethod, this, args);
3640
}
3741

38-
// create a mock proof by simulating method execution in JS
42+
// create a mock proof by simulating method> execution in JS
3943
const publicOutput = await Reflect.apply(simulatedMethod, this, args);
40-
const zkProgram =
41-
this.zkProgram.find((prog) => {
42-
return Object.keys(prog.methods).includes(methodName);
43-
}) ?? this.zkProgram[0];
4444

4545
return new zkProgram.Proof({
4646
proof: MOCK_PROOF,

packages/common/test/zkProgrammable/ZkProgrammable.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class TestProgrammable extends ZkProgrammable<
3939
TestPublicInput,
4040
TestPublicOutput
4141
> {
42-
public appChain: AreProofsEnabled = appChainMock;
42+
public areProofsEnabled: AreProofsEnabled = appChainMock;
4343

4444
@provableMethod()
4545
public async foo(publicInput: TestPublicInput, bar: Balance) {
@@ -97,7 +97,7 @@ class TestProgrammable extends ZkProgrammable<
9797
}
9898

9999
class OtherTestProgrammable extends ZkProgrammable<undefined, void> {
100-
public appChain: AreProofsEnabled = appChainMock;
100+
public areProofsEnabled: AreProofsEnabled = appChainMock;
101101

102102
public constructor(public testProgrammable: TestProgrammable) {
103103
super();
@@ -183,7 +183,7 @@ describe("zkProgrammable", () => {
183183
(areProofsEnabled, { verificationKey, shouldVerifyMockProofs }) => {
184184
beforeAll(async () => {
185185
testProgrammable = new TestProgrammable();
186-
testProgrammable.appChain.setProofsEnabled(areProofsEnabled);
186+
testProgrammable.areProofsEnabled.setProofsEnabled(areProofsEnabled);
187187
zkProgramFactorySpy = jest.spyOn(testProgrammable, "zkProgramFactory");
188188
artifact = await testProgrammable.zkProgram[0].compile();
189189
}, 500_000);

packages/deployment/src/queue/BullQueue.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export interface BullQueueConfig {
1414
port: number;
1515
username?: string;
1616
password?: string;
17+
db?: number;
1718
};
1819
retryAttempts?: number;
1920
}
@@ -25,17 +26,41 @@ export class BullQueue
2526
extends SequencerModule<BullQueueConfig>
2627
implements TaskQueue
2728
{
29+
private activePromise?: Promise<void>;
30+
2831
public createWorker(
2932
name: string,
3033
executor: (data: TaskPayload) => Promise<TaskPayload>,
3134
options?: { concurrency?: number }
3235
): Closeable {
3336
const worker = new Worker<TaskPayload, TaskPayload>(
3437
name,
35-
async (job) => await executor(job.data),
38+
async (job) => {
39+
// This weird promise logic is needed to make sure the worker is not proving in parallel
40+
// This is by far not optimal - since it still picks up 1 task per queue but waits until
41+
// computing them, so that leads to bad performance over multiple workers.
42+
// For that we need to restructure tasks to be flowing through a single queue however
43+
while (this.activePromise !== undefined) {
44+
// eslint-disable-next-line no-await-in-loop
45+
await this.activePromise;
46+
}
47+
let resOutside: () => void = () => {};
48+
const promise = new Promise<void>((res) => {
49+
resOutside = res;
50+
});
51+
this.activePromise = promise;
52+
53+
const result = await executor(job.data);
54+
this.activePromise = undefined;
55+
void resOutside();
56+
57+
return result;
58+
},
3659
{
3760
concurrency: options?.concurrency ?? 1,
3861
connection: this.config.redis,
62+
stalledInterval: 60000, // 1 minute
63+
lockDuration: 60000, // 1 minute
3964

4065
metrics: { maxDataPoints: MetricsTime.ONE_HOUR * 24 },
4166
}
@@ -68,6 +93,7 @@ export class BullQueue
6893
name: queueName,
6994

7095
async addTask(payload: TaskPayload): Promise<{ taskId: string }> {
96+
log.debug("Adding task: ", payload);
7197
const job = await queue.add(queueName, payload, {
7298
attempts: retryAttempts ?? 2,
7399
});
@@ -76,14 +102,25 @@ export class BullQueue
76102

77103
async onCompleted(listener: (payload: TaskPayload) => Promise<void>) {
78104
events.on("completed", async (result) => {
79-
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
80-
await listener(JSON.parse(result.returnvalue) as TaskPayload);
105+
log.debug("Completed task: ", result);
106+
try {
107+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
108+
await listener(result.returnvalue as unknown as TaskPayload);
109+
} catch (e) {
110+
// Catch error explicitly since this promise is dangling,
111+
// therefore any error will be voided as well
112+
log.error(e);
113+
}
114+
});
115+
events.on("error", async (error) => {
116+
log.error("Error in worker", error);
81117
});
82118
await events.waitUntilReady();
83119
},
84120

85121
async close(): Promise<void> {
86122
await events.close();
123+
await queue.drain();
87124
await queue.close();
88125
},
89126
};

packages/library/src/sequencer/SimpleSequencerModules.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ import {
1010
BlockTrigger,
1111
Database,
1212
SequencerModule,
13-
ProtocolStartupModule,
13+
SequencerStartupModule,
1414
} from "@proto-kit/sequencer";
1515
import { TypedClass, ModulesConfig } from "@proto-kit/common";
1616

1717
type PreconfiguredSimpleSequencerModulesRecord = {
1818
Mempool: typeof PrivateMempool;
1919
BatchProducerModule: typeof BatchProducerModule;
2020
BlockProducerModule: typeof BlockProducerModule;
21-
ProtocolStartupModule: TypedClass<
22-
ProtocolStartupModule & SequencerModule<unknown>
21+
SequencerStartupModule: TypedClass<
22+
SequencerStartupModule & SequencerModule<unknown>
2323
>;
2424
};
2525

@@ -90,7 +90,7 @@ export class SimpleSequencerModules {
9090
BlockTrigger,
9191
TaskQueue,
9292
...reducedModules,
93-
ProtocolStartupModule,
93+
SequencerStartupModule,
9494
} satisfies SimpleSequencerModulesRecord;
9595
}
9696

@@ -102,7 +102,7 @@ export class SimpleSequencerModules {
102102

103103
Mempool: {},
104104
BatchProducerModule: {},
105-
ProtocolStartupModule: {},
105+
SequencerStartupModule: {},
106106
} satisfies ModulesConfig<PreconfiguredSimpleSequencerModulesRecord>;
107107
}
108108

0 commit comments

Comments
 (0)