@proto-kit/common 0.1.1-develop.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +201 -0
- package/dist/compiling/AtomicCompileHelper.d.ts +13 -0
- package/dist/compiling/AtomicCompileHelper.d.ts.map +1 -0
- package/dist/compiling/AtomicCompileHelper.js +40 -0
- package/dist/compiling/AtomicCompileHelper.js.map +1 -0
- package/dist/compiling/CompilableModule.d.ts +6 -0
- package/dist/compiling/CompilableModule.d.ts.map +1 -0
- package/dist/compiling/CompilableModule.js +2 -0
- package/dist/compiling/CompilableModule.js.map +1 -0
- package/dist/compiling/CompileRegistry.d.ts +26 -0
- package/dist/compiling/CompileRegistry.d.ts.map +1 -0
- package/dist/compiling/CompileRegistry.js +68 -0
- package/dist/compiling/CompileRegistry.js.map +1 -0
- package/dist/compiling/services/ChildVerificationKeyService.d.ts +10 -0
- package/dist/compiling/services/ChildVerificationKeyService.d.ts.map +1 -0
- package/dist/compiling/services/ChildVerificationKeyService.js +27 -0
- package/dist/compiling/services/ChildVerificationKeyService.js.map +1 -0
- package/dist/config/ChildContainerCreatable.d.ts +5 -0
- package/dist/config/ChildContainerCreatable.d.ts.map +1 -0
- package/dist/config/ChildContainerCreatable.js +2 -0
- package/dist/config/ChildContainerCreatable.js.map +1 -0
- package/dist/config/ChildContainerProvider.d.ts +5 -0
- package/dist/config/ChildContainerProvider.d.ts.map +1 -0
- package/dist/config/ChildContainerProvider.js +2 -0
- package/dist/config/ChildContainerProvider.js.map +1 -0
- package/dist/config/ConfigurableModule.d.ts +25 -0
- package/dist/config/ConfigurableModule.d.ts.map +1 -0
- package/dist/config/ConfigurableModule.js +24 -0
- package/dist/config/ConfigurableModule.js.map +1 -0
- package/dist/config/ModuleContainer.d.ts +162 -0
- package/dist/config/ModuleContainer.d.ts.map +1 -0
- package/dist/config/ModuleContainer.js +289 -0
- package/dist/config/ModuleContainer.js.map +1 -0
- package/dist/config/injectAlias.d.ts +18 -0
- package/dist/config/injectAlias.d.ts.map +1 -0
- package/dist/config/injectAlias.js +47 -0
- package/dist/config/injectAlias.js.map +1 -0
- package/dist/dependencyFactory/DependencyFactory.d.ts +29 -0
- package/dist/dependencyFactory/DependencyFactory.d.ts.map +1 -0
- package/dist/dependencyFactory/DependencyFactory.js +2 -0
- package/dist/dependencyFactory/DependencyFactory.js.map +1 -0
- package/dist/dependencyFactory/injectOptional.d.ts +16 -0
- package/dist/dependencyFactory/injectOptional.d.ts.map +1 -0
- package/dist/dependencyFactory/injectOptional.js +40 -0
- package/dist/dependencyFactory/injectOptional.js.map +1 -0
- package/dist/dummyVerificationKey.d.ts +3 -0
- package/dist/dummyVerificationKey.d.ts.map +1 -0
- package/dist/dummyVerificationKey.js +8 -0
- package/dist/dummyVerificationKey.js.map +1 -0
- package/dist/events/EventEmitter.d.ts +19 -0
- package/dist/events/EventEmitter.d.ts.map +1 -0
- package/dist/events/EventEmitter.js +35 -0
- package/dist/events/EventEmitter.js.map +1 -0
- package/dist/events/EventEmitterProxy.d.ts +18 -0
- package/dist/events/EventEmitterProxy.d.ts.map +1 -0
- package/dist/events/EventEmitterProxy.js +35 -0
- package/dist/events/EventEmitterProxy.js.map +1 -0
- package/dist/events/EventEmittingComponent.d.ts +9 -0
- package/dist/events/EventEmittingComponent.d.ts.map +1 -0
- package/dist/events/EventEmittingComponent.js +2 -0
- package/dist/events/EventEmittingComponent.js.map +1 -0
- package/dist/events/ReplayingSingleUseEventEmitter.d.ts +17 -0
- package/dist/events/ReplayingSingleUseEventEmitter.d.ts.map +1 -0
- package/dist/events/ReplayingSingleUseEventEmitter.js +34 -0
- package/dist/events/ReplayingSingleUseEventEmitter.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +37 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +114 -0
- package/dist/log.js.map +1 -0
- package/dist/trees/InMemoryMerkleTreeStorage.d.ts +11 -0
- package/dist/trees/InMemoryMerkleTreeStorage.d.ts.map +1 -0
- package/dist/trees/InMemoryMerkleTreeStorage.js +13 -0
- package/dist/trees/InMemoryMerkleTreeStorage.js.map +1 -0
- package/dist/trees/MerkleTreeStore.d.ts +5 -0
- package/dist/trees/MerkleTreeStore.d.ts.map +1 -0
- package/dist/trees/MerkleTreeStore.js +2 -0
- package/dist/trees/MerkleTreeStore.js.map +1 -0
- package/dist/trees/MockAsyncMerkleStore.d.ts +9 -0
- package/dist/trees/MockAsyncMerkleStore.d.ts.map +1 -0
- package/dist/trees/MockAsyncMerkleStore.js +20 -0
- package/dist/trees/MockAsyncMerkleStore.js.map +1 -0
- package/dist/trees/RollupMerkleTree.d.ts +147 -0
- package/dist/trees/RollupMerkleTree.d.ts.map +1 -0
- package/dist/trees/RollupMerkleTree.js +218 -0
- package/dist/trees/RollupMerkleTree.js.map +1 -0
- package/dist/trees/VirtualMerkleTreeStore.d.ts +13 -0
- package/dist/trees/VirtualMerkleTreeStore.d.ts.map +1 -0
- package/dist/trees/VirtualMerkleTreeStore.js +18 -0
- package/dist/trees/VirtualMerkleTreeStore.js.map +1 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +48 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +113 -0
- package/dist/utils.js.map +1 -0
- package/dist/zkProgrammable/ProvableMethodExecutionContext.d.ts +54 -0
- package/dist/zkProgrammable/ProvableMethodExecutionContext.d.ts.map +1 -0
- package/dist/zkProgrammable/ProvableMethodExecutionContext.js +97 -0
- package/dist/zkProgrammable/ProvableMethodExecutionContext.js.map +1 -0
- package/dist/zkProgrammable/ZkProgrammable.d.ts +40 -0
- package/dist/zkProgrammable/ZkProgrammable.d.ts.map +1 -0
- package/dist/zkProgrammable/ZkProgrammable.js +79 -0
- package/dist/zkProgrammable/ZkProgrammable.js.map +1 -0
- package/dist/zkProgrammable/provableMethod.d.ts +19 -0
- package/dist/zkProgrammable/provableMethod.d.ts.map +1 -0
- package/dist/zkProgrammable/provableMethod.js +71 -0
- package/dist/zkProgrammable/provableMethod.js.map +1 -0
- package/jest.config.cjs +12 -0
- package/package.json +34 -0
- package/src/compiling/AtomicCompileHelper.ts +62 -0
- package/src/compiling/CompilableModule.ts +6 -0
- package/src/compiling/CompileRegistry.ts +78 -0
- package/src/compiling/services/ChildVerificationKeyService.ts +26 -0
- package/src/config/ChildContainerCreatable.ts +5 -0
- package/src/config/ChildContainerProvider.ts +5 -0
- package/src/config/ConfigurableModule.ts +57 -0
- package/src/config/ModuleContainer.ts +487 -0
- package/src/config/injectAlias.ts +70 -0
- package/src/dependencyFactory/DependencyFactory.ts +57 -0
- package/src/dependencyFactory/injectOptional.ts +41 -0
- package/src/dummyVerificationKey.ts +10 -0
- package/src/events/EventEmitter.ts +61 -0
- package/src/events/EventEmitterProxy.ts +83 -0
- package/src/events/EventEmittingComponent.ts +11 -0
- package/src/events/ReplayingSingleUseEventEmitter.ts +42 -0
- package/src/index.ts +25 -0
- package/src/log.ts +143 -0
- package/src/trees/InMemoryMerkleTreeStorage.ts +17 -0
- package/src/trees/MerkleTreeStore.ts +5 -0
- package/src/trees/MockAsyncMerkleStore.ts +30 -0
- package/src/trees/RollupMerkleTree.ts +356 -0
- package/src/trees/VirtualMerkleTreeStore.ts +20 -0
- package/src/types.ts +58 -0
- package/src/utils.ts +200 -0
- package/src/zkProgrammable/ProvableMethodExecutionContext.ts +122 -0
- package/src/zkProgrammable/ZkProgrammable.ts +151 -0
- package/src/zkProgrammable/provableMethod.ts +124 -0
- package/test/config/ContainerEvents.test.ts +67 -0
- package/test/config/ModuleContainer.test.ts +215 -0
- package/test/config/injectAlias.test.ts +28 -0
- package/test/trees/MerkleTree.test.ts +106 -0
- package/test/tsconfig.json +7 -0
- package/test/zkProgrammable/ZkProgrammable.test.ts +304 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Proof } from "o1js";
|
|
2
|
+
import { singleton } from "tsyringe";
|
|
3
|
+
import uniqueId from "lodash/uniqueId";
|
|
4
|
+
|
|
5
|
+
import type { ArgumentTypes } from "./provableMethod";
|
|
6
|
+
|
|
7
|
+
const errors = {
|
|
8
|
+
moduleOrMethodNameNotSet: () => new Error("Module or method name not set"),
|
|
9
|
+
|
|
10
|
+
proverNotSet: (moduleName: string, methodName: string) =>
|
|
11
|
+
new Error(
|
|
12
|
+
`Prover not set for '${moduleName}.${methodName}', did you forget to decorate your method?`
|
|
13
|
+
),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export class ProvableMethodExecutionResult {
|
|
17
|
+
public moduleName?: string;
|
|
18
|
+
|
|
19
|
+
public methodName?: string;
|
|
20
|
+
|
|
21
|
+
public args?: ArgumentTypes;
|
|
22
|
+
|
|
23
|
+
public prover?: () => Promise<Proof<unknown, unknown>>;
|
|
24
|
+
|
|
25
|
+
public async prove<
|
|
26
|
+
ProofType extends Proof<unknown, unknown>,
|
|
27
|
+
>(): Promise<ProofType> {
|
|
28
|
+
if (!this.prover) {
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
|
30
|
+
if (!this.moduleName || !this.methodName) {
|
|
31
|
+
throw errors.moduleOrMethodNameNotSet();
|
|
32
|
+
}
|
|
33
|
+
throw errors.proverNotSet(this.moduleName, this.methodName);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// turn the prover result into the desired proof type
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
38
|
+
return (await this.prover()) as ProofType;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Execution context used to wrap runtime module methods,
|
|
44
|
+
* allowing them to post relevant information (such as execution status)
|
|
45
|
+
* into the context without any unnecessary 'prop drilling'.
|
|
46
|
+
*/
|
|
47
|
+
@singleton()
|
|
48
|
+
export class ProvableMethodExecutionContext {
|
|
49
|
+
public id = uniqueId();
|
|
50
|
+
|
|
51
|
+
public methods: string[] = [];
|
|
52
|
+
|
|
53
|
+
public result: ProvableMethodExecutionResult =
|
|
54
|
+
new ProvableMethodExecutionResult();
|
|
55
|
+
|
|
56
|
+
// TODO See if we should make this class generic, bc I think we can persist the type
|
|
57
|
+
/**
|
|
58
|
+
* Adds a method prover to the current execution context,
|
|
59
|
+
* which can be collected and ran asynchronously at a later point in time.
|
|
60
|
+
*
|
|
61
|
+
* @param prove - Prover function to be ran later,
|
|
62
|
+
* when the method execution needs to be proven
|
|
63
|
+
*/
|
|
64
|
+
public setProver(prover: () => Promise<Proof<unknown, unknown>>) {
|
|
65
|
+
this.result.prover = prover;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Adds a method to the method execution stack, reseting the execution context
|
|
70
|
+
* in a case a new top-level (non nested) method call is made.
|
|
71
|
+
*
|
|
72
|
+
* @param methodName - Name of the method being captured in the context
|
|
73
|
+
*/
|
|
74
|
+
public beforeMethod(
|
|
75
|
+
moduleName: string,
|
|
76
|
+
methodName: string,
|
|
77
|
+
args: ArgumentTypes
|
|
78
|
+
) {
|
|
79
|
+
if (this.isFinished) {
|
|
80
|
+
this.clear();
|
|
81
|
+
this.result.moduleName = moduleName;
|
|
82
|
+
this.result.methodName = methodName;
|
|
83
|
+
this.result.args = args;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this.methods.push(methodName);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Removes the latest method from the execution context stack,
|
|
91
|
+
* keeping track of the amount of 'unfinished' methods. Allowing
|
|
92
|
+
* for the context to distinguish between top-level and nested method calls.
|
|
93
|
+
*/
|
|
94
|
+
public afterMethod() {
|
|
95
|
+
this.methods.pop();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public get isTopLevel() {
|
|
99
|
+
return this.methods.length === 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public get isFinished() {
|
|
103
|
+
return this.methods.length === 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @returns - Current execution context state
|
|
108
|
+
*/
|
|
109
|
+
public current() {
|
|
110
|
+
return {
|
|
111
|
+
isFinished: this.isFinished,
|
|
112
|
+
result: this.result,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Manually clears/resets the execution context
|
|
118
|
+
*/
|
|
119
|
+
public clear() {
|
|
120
|
+
this.result = new ProvableMethodExecutionResult();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { ZkProgram, FlexibleProvablePure, Proof, Field, Provable } from "o1js";
|
|
2
|
+
import { Memoize } from "typescript-memoize";
|
|
3
|
+
|
|
4
|
+
import { log } from "../log";
|
|
5
|
+
import { dummyVerificationKey } from "../dummyVerificationKey";
|
|
6
|
+
import { reduceSequential } from "../utils";
|
|
7
|
+
import type { CompileRegistry } from "../compiling/CompileRegistry";
|
|
8
|
+
|
|
9
|
+
import { MOCK_PROOF } from "./provableMethod";
|
|
10
|
+
|
|
11
|
+
const errors = {
|
|
12
|
+
areProofsEnabledNotSet: (name: string) =>
|
|
13
|
+
new Error(`AreProofsEnabled was not injected for: ${name}`),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export interface CompileArtifact {
|
|
17
|
+
verificationKey: {
|
|
18
|
+
data: string;
|
|
19
|
+
hash: Field;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AreProofsEnabled {
|
|
24
|
+
areProofsEnabled: boolean;
|
|
25
|
+
setProofsEnabled: (areProofsEnabled: boolean) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Verify<PublicInput, PublicOutput> {
|
|
29
|
+
(proof: Proof<PublicInput, PublicOutput>): Promise<boolean>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface Compile {
|
|
33
|
+
(): Promise<CompileArtifact>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface PlainZkProgram<PublicInput = undefined, PublicOutput = void> {
|
|
37
|
+
name: string;
|
|
38
|
+
compile: Compile;
|
|
39
|
+
verify: Verify<PublicInput, PublicOutput>;
|
|
40
|
+
Proof: ReturnType<
|
|
41
|
+
typeof ZkProgram.Proof<
|
|
42
|
+
FlexibleProvablePure<PublicInput>,
|
|
43
|
+
FlexibleProvablePure<PublicOutput>
|
|
44
|
+
>
|
|
45
|
+
>;
|
|
46
|
+
methods: Record<
|
|
47
|
+
string,
|
|
48
|
+
| ((...args: any) => Promise<Proof<PublicInput, PublicOutput>>)
|
|
49
|
+
| ((
|
|
50
|
+
publicInput: PublicInput,
|
|
51
|
+
...args: any
|
|
52
|
+
) => Promise<Proof<PublicInput, PublicOutput>>)
|
|
53
|
+
>;
|
|
54
|
+
analyzeMethods: () => Promise<
|
|
55
|
+
Record<string, Awaited<ReturnType<typeof Provable.constraintSystem>>>
|
|
56
|
+
>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function verifyToMockable<PublicInput, PublicOutput>(
|
|
60
|
+
verify: Verify<PublicInput, PublicOutput>,
|
|
61
|
+
{ areProofsEnabled }: AreProofsEnabled
|
|
62
|
+
) {
|
|
63
|
+
return async (proof: Proof<PublicInput, PublicOutput>) => {
|
|
64
|
+
if (areProofsEnabled) {
|
|
65
|
+
let verified = false;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
verified = await verify(proof);
|
|
69
|
+
} catch (error: unknown) {
|
|
70
|
+
// silently fail verification
|
|
71
|
+
log.error(error);
|
|
72
|
+
verified = false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return verified;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return proof.proof === MOCK_PROOF;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const MOCK_VERIFICATION_KEY = dummyVerificationKey();
|
|
83
|
+
|
|
84
|
+
export function compileToMockable(
|
|
85
|
+
compile: Compile,
|
|
86
|
+
{ areProofsEnabled }: AreProofsEnabled
|
|
87
|
+
): () => Promise<CompileArtifact> {
|
|
88
|
+
return async () => {
|
|
89
|
+
if (areProofsEnabled) {
|
|
90
|
+
return await compile();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
verificationKey: MOCK_VERIFICATION_KEY,
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export abstract class ZkProgrammable<
|
|
100
|
+
PublicInput = undefined,
|
|
101
|
+
PublicOutput = void,
|
|
102
|
+
> {
|
|
103
|
+
public abstract get areProofsEnabled(): AreProofsEnabled | undefined;
|
|
104
|
+
|
|
105
|
+
public abstract zkProgramFactory(): PlainZkProgram<
|
|
106
|
+
PublicInput,
|
|
107
|
+
PublicOutput
|
|
108
|
+
>[];
|
|
109
|
+
|
|
110
|
+
private zkProgramSingleton?: PlainZkProgram<PublicInput, PublicOutput>[];
|
|
111
|
+
|
|
112
|
+
@Memoize()
|
|
113
|
+
public get zkProgram(): PlainZkProgram<PublicInput, PublicOutput>[] {
|
|
114
|
+
if (this.zkProgramSingleton === undefined) {
|
|
115
|
+
this.zkProgramSingleton = this.zkProgramFactory();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return this.zkProgramSingleton.map((bucket) => {
|
|
119
|
+
if (!this.areProofsEnabled) {
|
|
120
|
+
throw errors.areProofsEnabledNotSet(this.constructor.name);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
...bucket,
|
|
124
|
+
verify: verifyToMockable(bucket.verify, this.areProofsEnabled),
|
|
125
|
+
compile: compileToMockable(bucket.compile, this.areProofsEnabled),
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public async compile(registry: CompileRegistry) {
|
|
131
|
+
return await reduceSequential(
|
|
132
|
+
this.zkProgram,
|
|
133
|
+
async (acc, program) => {
|
|
134
|
+
const result = await registry.compile(program);
|
|
135
|
+
return {
|
|
136
|
+
...acc,
|
|
137
|
+
[program.name]: result,
|
|
138
|
+
};
|
|
139
|
+
},
|
|
140
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
141
|
+
{} as Record<string, CompileArtifact>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface WithZkProgrammable<
|
|
147
|
+
PublicInput = undefined,
|
|
148
|
+
PublicOutput = void,
|
|
149
|
+
> {
|
|
150
|
+
zkProgrammable: ZkProgrammable<PublicInput, PublicOutput>;
|
|
151
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { Proof, DynamicProof } from "o1js";
|
|
2
|
+
import { container } from "tsyringe";
|
|
3
|
+
|
|
4
|
+
import { ProvableMethodExecutionContext } from "./ProvableMethodExecutionContext";
|
|
5
|
+
import type { WithZkProgrammable, ZkProgrammable } from "./ZkProgrammable";
|
|
6
|
+
|
|
7
|
+
// Now, in o1js provable types are normal js objects, therefore any
|
|
8
|
+
export type O1JSPrimitive = object | string | boolean | number;
|
|
9
|
+
export type ArgumentTypes = (
|
|
10
|
+
| O1JSPrimitive
|
|
11
|
+
| Proof<unknown, unknown>
|
|
12
|
+
| DynamicProof<unknown, unknown>
|
|
13
|
+
)[];
|
|
14
|
+
|
|
15
|
+
export type DecoratedMethod = (...args: ArgumentTypes) => Promise<unknown>;
|
|
16
|
+
|
|
17
|
+
export const MOCK_PROOF = "mock-proof";
|
|
18
|
+
// (await Proof.dummy(Field(0), Field(0), 2)).proof as string;
|
|
19
|
+
|
|
20
|
+
export function toProver(
|
|
21
|
+
methodName: string,
|
|
22
|
+
simulatedMethod: DecoratedMethod,
|
|
23
|
+
isFirstParameterPublicInput: boolean,
|
|
24
|
+
...args: ArgumentTypes
|
|
25
|
+
) {
|
|
26
|
+
return async function prover(this: ZkProgrammable<any, any>) {
|
|
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);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// create a mock proof by simulating method> execution in JS
|
|
43
|
+
const publicOutput = await Reflect.apply(simulatedMethod, this, args);
|
|
44
|
+
|
|
45
|
+
return new zkProgram.Proof({
|
|
46
|
+
proof: MOCK_PROOF,
|
|
47
|
+
|
|
48
|
+
// TODO: provide undefined if public input is not used
|
|
49
|
+
publicInput: isFirstParameterPublicInput ? args[0] : undefined,
|
|
50
|
+
publicOutput,
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* We set this to the max possible number, to avoid having
|
|
54
|
+
* to manually count in-circuit proof verifications
|
|
55
|
+
*/
|
|
56
|
+
maxProofsVerified: 2,
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Decorates a provable method on a 'prover class', depending on
|
|
63
|
+
* if proofs are enabled or not, either runs the respective zkProgram prover,
|
|
64
|
+
* or simulates the method execution and issues a mock proof.
|
|
65
|
+
*
|
|
66
|
+
* @param isFirstParameterPublicInput
|
|
67
|
+
* @param executionContext
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
export function provableMethod(
|
|
71
|
+
isFirstParameterPublicInput = true,
|
|
72
|
+
executionContext: ProvableMethodExecutionContext = container.resolve<ProvableMethodExecutionContext>(
|
|
73
|
+
ProvableMethodExecutionContext
|
|
74
|
+
)
|
|
75
|
+
) {
|
|
76
|
+
return <
|
|
77
|
+
Target extends WithZkProgrammable<any, any> | ZkProgrammable<any, any>,
|
|
78
|
+
>(
|
|
79
|
+
target: Target,
|
|
80
|
+
methodName: string,
|
|
81
|
+
descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<any> | any>
|
|
82
|
+
) => {
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
84
|
+
const simulatedMethod = descriptor.value as DecoratedMethod;
|
|
85
|
+
|
|
86
|
+
descriptor.value = async function value(
|
|
87
|
+
this: ZkProgrammable<unknown, unknown>,
|
|
88
|
+
...args: ArgumentTypes
|
|
89
|
+
) {
|
|
90
|
+
const prover = toProver(
|
|
91
|
+
methodName,
|
|
92
|
+
simulatedMethod,
|
|
93
|
+
isFirstParameterPublicInput,
|
|
94
|
+
...args
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
executionContext.beforeMethod(this.constructor.name, methodName, args);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if the method is called at the top level,
|
|
101
|
+
* if yes then create a prover.
|
|
102
|
+
*/
|
|
103
|
+
if (executionContext.isTopLevel) {
|
|
104
|
+
executionContext.setProver(prover.bind(this));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Regardless of if the method is called from the top level
|
|
109
|
+
* or not, execute its simulated (Javascript) version and
|
|
110
|
+
* return the result.
|
|
111
|
+
*/
|
|
112
|
+
let result: unknown;
|
|
113
|
+
try {
|
|
114
|
+
result = Reflect.apply(simulatedMethod, this, args);
|
|
115
|
+
} finally {
|
|
116
|
+
executionContext.afterMethod();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
return descriptor;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { injectable, container as tsyringeContainer } from "tsyringe";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
BaseModuleInstanceType,
|
|
6
|
+
ConfigurableModule,
|
|
7
|
+
EventEmitter,
|
|
8
|
+
EventEmittingComponent,
|
|
9
|
+
ModuleContainer,
|
|
10
|
+
ModulesRecord,
|
|
11
|
+
} from "../../src";
|
|
12
|
+
|
|
13
|
+
class TestContainer<
|
|
14
|
+
Modules extends ModulesRecord,
|
|
15
|
+
> extends ModuleContainer<Modules> {}
|
|
16
|
+
|
|
17
|
+
type TestEvents = {
|
|
18
|
+
test: [string];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
@injectable()
|
|
22
|
+
class TestModule
|
|
23
|
+
extends ConfigurableModule<{}>
|
|
24
|
+
implements BaseModuleInstanceType, EventEmittingComponent<TestEvents>
|
|
25
|
+
{
|
|
26
|
+
events = new EventEmitter<TestEvents>();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
type TestEvents2 = {
|
|
30
|
+
test2: [number];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
class TestModule2
|
|
34
|
+
extends ConfigurableModule<{}>
|
|
35
|
+
implements BaseModuleInstanceType, EventEmittingComponent<TestEvents2>
|
|
36
|
+
{
|
|
37
|
+
events = new EventEmitter<TestEvents2>();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("test event propagation", () => {
|
|
41
|
+
it("should propagate events up", () => {
|
|
42
|
+
expect.assertions(1);
|
|
43
|
+
|
|
44
|
+
const container = new TestContainer({
|
|
45
|
+
modules: {
|
|
46
|
+
test: TestModule,
|
|
47
|
+
test2: TestModule2,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
container.configure({
|
|
52
|
+
test: {},
|
|
53
|
+
test2: {},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
container.create(() => tsyringeContainer.createChildContainer());
|
|
57
|
+
|
|
58
|
+
const testvalue = "testString123";
|
|
59
|
+
|
|
60
|
+
container.events.on("test", (value: string) => {
|
|
61
|
+
expect(value).toStrictEqual(testvalue);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const module = container.resolve("test");
|
|
65
|
+
module.events.emit("test", testvalue);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { container as tsyringeContainer, inject, injectable } from "tsyringe";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
ConfigurableModule,
|
|
6
|
+
NoConfig,
|
|
7
|
+
} from "../../src/config/ConfigurableModule";
|
|
8
|
+
import {
|
|
9
|
+
ModuleContainer,
|
|
10
|
+
ModulesRecord,
|
|
11
|
+
} from "../../src/config/ModuleContainer";
|
|
12
|
+
import { TypedClass } from "../../src/types";
|
|
13
|
+
import { DependencyFactory, expectDefined } from "../../src";
|
|
14
|
+
import { injectAlias } from "../../src/config/injectAlias";
|
|
15
|
+
|
|
16
|
+
// module container will accept modules that extend this type
|
|
17
|
+
class BaseTestModule<Config> extends ConfigurableModule<Config> {}
|
|
18
|
+
|
|
19
|
+
type TestModulesRecord = ModulesRecord<TypedClass<BaseTestModule<unknown>>>;
|
|
20
|
+
|
|
21
|
+
interface TestModuleConfig {
|
|
22
|
+
testConfigProperty: number;
|
|
23
|
+
testConfigProperty2?: number;
|
|
24
|
+
testConfigProperty3?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@injectable()
|
|
28
|
+
@injectAlias(["child-alias", "multi-alias"])
|
|
29
|
+
class ChildModule extends BaseTestModule<NoConfig> {
|
|
30
|
+
public constructor(@inject("TestModule") public readonly testModule: any) {
|
|
31
|
+
super();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
x() {
|
|
35
|
+
return "dependency factory works";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@injectAlias(["base-alias", "multi-alias"])
|
|
40
|
+
class TestModule
|
|
41
|
+
extends BaseTestModule<TestModuleConfig>
|
|
42
|
+
implements DependencyFactory
|
|
43
|
+
{
|
|
44
|
+
public dependencies() {
|
|
45
|
+
return {
|
|
46
|
+
dependencyModule1: {
|
|
47
|
+
useClass: ChildModule,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface OtherTestModuleConfig {
|
|
54
|
+
otherTestConfigProperty: number;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
class OtherTestModule extends BaseTestModule<OtherTestModuleConfig> {
|
|
58
|
+
public x() {
|
|
59
|
+
return "";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Showcases a wrongly typed/defined module as
|
|
65
|
+
* per the TestModuleContainer requirements
|
|
66
|
+
*/
|
|
67
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
68
|
+
class WrongTestModule {}
|
|
69
|
+
|
|
70
|
+
class TestModuleContainer<
|
|
71
|
+
Modules extends TestModulesRecord,
|
|
72
|
+
> extends ModuleContainer<Modules> {
|
|
73
|
+
public get dependencyContainer() {
|
|
74
|
+
return this.container;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
describe("moduleContainer", () => {
|
|
79
|
+
let container: TestModuleContainer<{
|
|
80
|
+
TestModule: typeof TestModule;
|
|
81
|
+
OtherTestModule: typeof OtherTestModule;
|
|
82
|
+
}>;
|
|
83
|
+
const testConfigProperty = 0;
|
|
84
|
+
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
container = new TestModuleContainer({
|
|
87
|
+
modules: {
|
|
88
|
+
TestModule,
|
|
89
|
+
OtherTestModule,
|
|
90
|
+
// this module would not be assignable to TestModuleContainer
|
|
91
|
+
// WrongTestModule,
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("should resolve dependency factory dependencies correctly", () => {
|
|
97
|
+
container.configure({
|
|
98
|
+
TestModule: {
|
|
99
|
+
testConfigProperty,
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
OtherTestModule: {
|
|
103
|
+
otherTestConfigProperty: testConfigProperty,
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
container.create(() => tsyringeContainer.createChildContainer());
|
|
108
|
+
|
|
109
|
+
// Unfortunately we still need this so that the dependencies are registered
|
|
110
|
+
container.resolve("TestModule");
|
|
111
|
+
const dm = container.resolve("DependencyModule1");
|
|
112
|
+
|
|
113
|
+
expect(dm.x()).toBe("dependency factory works");
|
|
114
|
+
expect(dm.testModule).toBeDefined();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should throw on resolution, if config was not provided", () => {
|
|
118
|
+
expect.assertions(1);
|
|
119
|
+
|
|
120
|
+
container.create(() => tsyringeContainer.createChildContainer());
|
|
121
|
+
|
|
122
|
+
expect(() => {
|
|
123
|
+
container.resolve("TestModule");
|
|
124
|
+
}).toThrow();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should resolve the registered module with the provided config", () => {
|
|
128
|
+
expect.assertions(1);
|
|
129
|
+
|
|
130
|
+
container.configure({
|
|
131
|
+
TestModule: {
|
|
132
|
+
testConfigProperty,
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
OtherTestModule: {
|
|
136
|
+
otherTestConfigProperty: testConfigProperty,
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
container.create(() => tsyringeContainer.createChildContainer());
|
|
140
|
+
|
|
141
|
+
const testModule = container.resolve("TestModule");
|
|
142
|
+
|
|
143
|
+
expect(testModule.config.testConfigProperty).toBe(testConfigProperty);
|
|
144
|
+
|
|
145
|
+
const dependency = container.resolve("DependencyModule1");
|
|
146
|
+
dependency.x();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("should stack configurations correctly", () => {
|
|
150
|
+
container.configure({
|
|
151
|
+
TestModule: {
|
|
152
|
+
testConfigProperty: 1,
|
|
153
|
+
},
|
|
154
|
+
OtherTestModule: {
|
|
155
|
+
otherTestConfigProperty: 4,
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
container.configurePartial({
|
|
160
|
+
TestModule: {
|
|
161
|
+
testConfigProperty2: 2,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
container.configurePartial({
|
|
166
|
+
TestModule: {
|
|
167
|
+
testConfigProperty: 3,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
container.create(() => tsyringeContainer.createChildContainer());
|
|
172
|
+
|
|
173
|
+
const { config } = container.resolve("TestModule");
|
|
174
|
+
|
|
175
|
+
expect(config.testConfigProperty).toBe(3);
|
|
176
|
+
expect(config.testConfigProperty2).toBe(2);
|
|
177
|
+
expect(config.testConfigProperty3).toBe(undefined);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("should resolve dependencies correctly via alias", () => {
|
|
181
|
+
container.configure({
|
|
182
|
+
TestModule: {
|
|
183
|
+
testConfigProperty,
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
OtherTestModule: {
|
|
187
|
+
otherTestConfigProperty: testConfigProperty,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
container.create(() => tsyringeContainer.createChildContainer());
|
|
192
|
+
|
|
193
|
+
// Unfortunately we still need this so that the dependencies are registered
|
|
194
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
195
|
+
const m1 = container.resolve("base-alias" as any);
|
|
196
|
+
const m2 = container.resolve("TestModule");
|
|
197
|
+
|
|
198
|
+
expectDefined(m1);
|
|
199
|
+
// Check if its the same reference
|
|
200
|
+
expect(m1).toBe(m2);
|
|
201
|
+
|
|
202
|
+
const dm1 = container.resolve("child-alias" as any) as ChildModule;
|
|
203
|
+
const dm2 = container.resolve("DependencyModule1");
|
|
204
|
+
|
|
205
|
+
expect(dm1.x()).toBe("dependency factory works");
|
|
206
|
+
expect(dm1.testModule).toBeDefined();
|
|
207
|
+
expect(dm1).toBe(dm2);
|
|
208
|
+
|
|
209
|
+
const multi =
|
|
210
|
+
container.dependencyContainer.resolveAll<BaseTestModule<unknown>>(
|
|
211
|
+
"multi-alias"
|
|
212
|
+
);
|
|
213
|
+
expect(multi).toHaveLength(2);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { getInjectAliases, injectAlias } from "../../src/config/injectAlias";
|
|
3
|
+
|
|
4
|
+
@injectAlias(["foo", "bar"])
|
|
5
|
+
class TestClass {}
|
|
6
|
+
|
|
7
|
+
@injectAlias(["ayy"])
|
|
8
|
+
class TestClass2 extends TestClass {}
|
|
9
|
+
|
|
10
|
+
describe("injectAlias metadata", () => {
|
|
11
|
+
it("set and retrieve", () => {
|
|
12
|
+
expect.assertions(2);
|
|
13
|
+
|
|
14
|
+
const aliases = getInjectAliases(TestClass);
|
|
15
|
+
|
|
16
|
+
expect(aliases).toHaveLength(2);
|
|
17
|
+
expect(aliases).toStrictEqual(["foo", "bar"]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("recursive", () => {
|
|
21
|
+
expect.assertions(2);
|
|
22
|
+
|
|
23
|
+
const aliases = getInjectAliases(TestClass2);
|
|
24
|
+
|
|
25
|
+
expect(aliases).toHaveLength(3);
|
|
26
|
+
expect(aliases).toStrictEqual(["ayy", "foo", "bar"]);
|
|
27
|
+
});
|
|
28
|
+
});
|