@proto-kit/module 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.
Files changed (72) hide show
  1. package/LICENSE.md +201 -0
  2. package/README.md +114 -0
  3. package/dist/factories/MethodIdFactory.d.ts +10 -0
  4. package/dist/factories/MethodIdFactory.d.ts.map +1 -0
  5. package/dist/factories/MethodIdFactory.js +11 -0
  6. package/dist/factories/MethodIdFactory.js.map +1 -0
  7. package/dist/index.d.ts +11 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +11 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/method/MethodParameterEncoder.d.ts +26 -0
  12. package/dist/method/MethodParameterEncoder.d.ts.map +1 -0
  13. package/dist/method/MethodParameterEncoder.js +169 -0
  14. package/dist/method/MethodParameterEncoder.js.map +1 -0
  15. package/dist/method/runtimeMethod.d.ts +33 -0
  16. package/dist/method/runtimeMethod.d.ts.map +1 -0
  17. package/dist/method/runtimeMethod.js +169 -0
  18. package/dist/method/runtimeMethod.js.map +1 -0
  19. package/dist/module/decorator.d.ts +8 -0
  20. package/dist/module/decorator.d.ts.map +1 -0
  21. package/dist/module/decorator.js +16 -0
  22. package/dist/module/decorator.js.map +1 -0
  23. package/dist/runtime/MethodIdResolver.d.ts +20 -0
  24. package/dist/runtime/MethodIdResolver.d.ts.map +1 -0
  25. package/dist/runtime/MethodIdResolver.js +91 -0
  26. package/dist/runtime/MethodIdResolver.js.map +1 -0
  27. package/dist/runtime/Runtime.d.ts +72 -0
  28. package/dist/runtime/Runtime.d.ts.map +1 -0
  29. package/dist/runtime/Runtime.js +231 -0
  30. package/dist/runtime/Runtime.js.map +1 -0
  31. package/dist/runtime/RuntimeEnvironment.d.ts +10 -0
  32. package/dist/runtime/RuntimeEnvironment.d.ts.map +1 -0
  33. package/dist/runtime/RuntimeEnvironment.js +2 -0
  34. package/dist/runtime/RuntimeEnvironment.js.map +1 -0
  35. package/dist/runtime/RuntimeModule.d.ts +37 -0
  36. package/dist/runtime/RuntimeModule.d.ts.map +1 -0
  37. package/dist/runtime/RuntimeModule.js +80 -0
  38. package/dist/runtime/RuntimeModule.js.map +1 -0
  39. package/dist/state/InMemoryStateService.d.ts +15 -0
  40. package/dist/state/InMemoryStateService.d.ts.map +1 -0
  41. package/dist/state/InMemoryStateService.js +24 -0
  42. package/dist/state/InMemoryStateService.js.map +1 -0
  43. package/dist/state/decorator.d.ts +7 -0
  44. package/dist/state/decorator.d.ts.map +1 -0
  45. package/dist/state/decorator.js +40 -0
  46. package/dist/state/decorator.js.map +1 -0
  47. package/jest.config.cjs +12 -0
  48. package/package.json +35 -0
  49. package/src/factories/MethodIdFactory.ts +13 -0
  50. package/src/index.ts +10 -0
  51. package/src/method/MethodParameterEncoder.ts +260 -0
  52. package/src/method/runtimeMethod.ts +308 -0
  53. package/src/module/decorator.ts +21 -0
  54. package/src/runtime/MethodIdResolver.ts +108 -0
  55. package/src/runtime/Runtime.ts +395 -0
  56. package/src/runtime/RuntimeEnvironment.ts +16 -0
  57. package/src/runtime/RuntimeModule.ts +112 -0
  58. package/src/state/InMemoryStateService.ts +25 -0
  59. package/src/state/decorator.ts +61 -0
  60. package/test/Runtime.test.ts +70 -0
  61. package/test/TestingRuntime.ts +45 -0
  62. package/test/method/MethodParameterEncoder.test.ts +121 -0
  63. package/test/method/runtimeMethod-fail.test.ts +50 -0
  64. package/test/method/runtimeMethod.test.ts +46 -0
  65. package/test/modules/Admin.ts +19 -0
  66. package/test/modules/Balances.test.ts +337 -0
  67. package/test/modules/Balances.ts +54 -0
  68. package/test/modules/MethodIdResolver.test.ts +73 -0
  69. package/test/modules/State.test.ts +81 -0
  70. package/test/runtimeMethod.test.ts +215 -0
  71. package/test/tsconfig.json +7 -0
  72. package/tsconfig.json +8 -0
@@ -0,0 +1,395 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-argument */
2
+ import { ZkProgram } from "o1js";
3
+ import { container, DependencyContainer, injectable } from "tsyringe";
4
+ import {
5
+ StringKeyOf,
6
+ ModuleContainer,
7
+ ModulesConfig,
8
+ ModulesRecord,
9
+ TypedClass,
10
+ ZkProgrammable,
11
+ PlainZkProgram,
12
+ AreProofsEnabled,
13
+ ChildContainerProvider,
14
+ CompilableModule,
15
+ CompileRegistry,
16
+ } from "@proto-kit/common";
17
+ import {
18
+ MethodPublicOutput,
19
+ StateServiceProvider,
20
+ SimpleAsyncStateService,
21
+ RuntimeMethodExecutionContext,
22
+ RuntimeTransaction,
23
+ NetworkState,
24
+ } from "@proto-kit/protocol";
25
+
26
+ import {
27
+ combineMethodName,
28
+ isRuntimeMethod,
29
+ runtimeMethodTypeMetadataKey,
30
+ toWrappedMethod,
31
+ AsyncWrappedMethod,
32
+ } from "../method/runtimeMethod";
33
+ import { MethodIdFactory } from "../factories/MethodIdFactory";
34
+
35
+ import { RuntimeModule } from "./RuntimeModule";
36
+ import { MethodIdResolver } from "./MethodIdResolver";
37
+ import { RuntimeEnvironment } from "./RuntimeEnvironment";
38
+
39
+ export function getAllPropertyNames(obj: any) {
40
+ let currentPrototype: any | undefined = obj;
41
+ let keys: (string | symbol)[] = [];
42
+ // if primitive (primitives still have keys) skip the first iteration
43
+ if (!(obj instanceof Object)) {
44
+ currentPrototype = Object.getPrototypeOf(obj);
45
+ }
46
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
47
+ while (currentPrototype) {
48
+ keys = keys.concat(Reflect.ownKeys(currentPrototype));
49
+ currentPrototype = Object.getPrototypeOf(currentPrototype);
50
+ }
51
+ return keys;
52
+ }
53
+
54
+ /**
55
+ * Record of modules accepted by the Runtime module container.
56
+ *
57
+ * We have to use TypedClass since RuntimeModule
58
+ * is an abstract class
59
+ */
60
+ export type RuntimeModulesRecord = ModulesRecord<
61
+ TypedClass<RuntimeModule<unknown>>
62
+ >;
63
+
64
+ const errors = {
65
+ methodNotFound: (methodKey: string) =>
66
+ new Error(`Unable to find method with id ${methodKey}`),
67
+ };
68
+
69
+ /**
70
+ * Definition / required arguments for the Runtime class
71
+ */
72
+ export interface RuntimeDefinition<Modules extends RuntimeModulesRecord> {
73
+ modules: Modules;
74
+ config?: ModulesConfig<Modules>;
75
+ }
76
+
77
+ export class RuntimeZkProgrammable<
78
+ Modules extends RuntimeModulesRecord,
79
+ > extends ZkProgrammable<undefined, MethodPublicOutput> {
80
+ public constructor(public runtime: Runtime<Modules>) {
81
+ super();
82
+ }
83
+
84
+ public get areProofsEnabled() {
85
+ return this.runtime.areProofsEnabled;
86
+ }
87
+
88
+ public zkProgramFactory(): PlainZkProgram<undefined, MethodPublicOutput>[] {
89
+ type Methods = Record<
90
+ string,
91
+ {
92
+ privateInputs: any;
93
+ method: AsyncWrappedMethod;
94
+ }
95
+ >;
96
+ // We need to use explicit type annotations here,
97
+ // therefore we can't use destructuring
98
+
99
+ // eslint-disable-next-line prefer-destructuring
100
+ const runtime: Runtime<Modules> = this.runtime;
101
+
102
+ const MAXIMUM_METHODS_PER_ZK_PROGRAM = 8;
103
+
104
+ const runtimeMethods = runtime.runtimeModuleNames.reduce<Methods>(
105
+ (allMethods, runtimeModuleName) => {
106
+ runtime.isValidModuleName(
107
+ runtime.definition.modules,
108
+ runtimeModuleName
109
+ );
110
+
111
+ /**
112
+ * Couldnt find a better way to circumvent the type assertion
113
+ * regarding resolving only known modules. We assert in the line above
114
+ * but we cast it to any anyways to satisfy the proof system.
115
+ */
116
+
117
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
118
+ const runtimeModule = runtime.resolve(runtimeModuleName as any);
119
+
120
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
121
+ const modulePrototype = Object.getPrototypeOf(runtimeModule) as Record<
122
+ string,
123
+ // Technically not all methods have to be async, but for this context it's ok
124
+ (...args: unknown[]) => Promise<unknown>
125
+ >;
126
+
127
+ const modulePrototypeMethods = getAllPropertyNames(runtimeModule).map(
128
+ (method) => method.toString()
129
+ );
130
+
131
+ const moduleMethods = modulePrototypeMethods.reduce<Methods>(
132
+ (allModuleMethods, methodName) => {
133
+ if (isRuntimeMethod(runtimeModule, methodName)) {
134
+ const combinedMethodName = combineMethodName(
135
+ runtimeModuleName,
136
+ methodName
137
+ );
138
+ const method = modulePrototype[methodName];
139
+ const invocationType = Reflect.getMetadata(
140
+ runtimeMethodTypeMetadataKey,
141
+ runtimeModule,
142
+ methodName
143
+ );
144
+
145
+ const wrappedMethod: AsyncWrappedMethod = Reflect.apply(
146
+ toWrappedMethod,
147
+ runtimeModule,
148
+ [methodName, method, { invocationType }]
149
+ );
150
+
151
+ const privateInputs = Reflect.getMetadata(
152
+ "design:paramtypes",
153
+ runtimeModule,
154
+ methodName
155
+ );
156
+
157
+ return {
158
+ ...allModuleMethods,
159
+
160
+ [combinedMethodName]: {
161
+ privateInputs,
162
+ method: wrappedMethod,
163
+ },
164
+ };
165
+ }
166
+
167
+ return allModuleMethods;
168
+ },
169
+ {}
170
+ );
171
+
172
+ return {
173
+ ...allMethods,
174
+ ...moduleMethods,
175
+ };
176
+ },
177
+ {}
178
+ );
179
+
180
+ const sortedRuntimeMethods = Object.fromEntries(
181
+ Object.entries(runtimeMethods).sort()
182
+ );
183
+
184
+ const splitRuntimeMethods = () => {
185
+ const buckets: Array<
186
+ Record<
187
+ string,
188
+ {
189
+ privateInputs: any;
190
+ method: AsyncWrappedMethod;
191
+ }
192
+ >
193
+ > = [];
194
+ Object.entries(sortedRuntimeMethods).forEach(
195
+ async ([methodName, method]) => {
196
+ let methodAdded = false;
197
+ for (const bucket of buckets) {
198
+ if (buckets.length === 0) {
199
+ const record: Record<
200
+ string,
201
+ {
202
+ privateInputs: any;
203
+ method: AsyncWrappedMethod;
204
+ }
205
+ > = {};
206
+ record[methodName] = method;
207
+ buckets.push(record);
208
+ methodAdded = true;
209
+ break;
210
+ } else if (
211
+ Object.keys(bucket).length <=
212
+ MAXIMUM_METHODS_PER_ZK_PROGRAM - 1
213
+ ) {
214
+ bucket[methodName] = method;
215
+ methodAdded = true;
216
+ break;
217
+ }
218
+ }
219
+ if (!methodAdded) {
220
+ const record: Record<
221
+ string,
222
+ {
223
+ privateInputs: any;
224
+ method: AsyncWrappedMethod;
225
+ }
226
+ > = {};
227
+ record[methodName] = method;
228
+ buckets.push(record);
229
+ }
230
+ }
231
+ );
232
+ return buckets;
233
+ };
234
+
235
+ return splitRuntimeMethods().map((bucket, index) => {
236
+ const name = `RuntimeProgram-${index}`;
237
+ const program = ZkProgram({
238
+ name,
239
+ publicOutput: MethodPublicOutput,
240
+ methods: bucket,
241
+ });
242
+
243
+ const SelfProof = ZkProgram.Proof(program);
244
+
245
+ const methods = Object.keys(bucket).reduce<Record<string, any>>(
246
+ (boundMethods, methodName) => {
247
+ boundMethods[methodName] = program[methodName].bind(program);
248
+ return boundMethods;
249
+ },
250
+ {}
251
+ );
252
+
253
+ return {
254
+ name,
255
+ compile: program.compile.bind(program),
256
+ verify: program.verify.bind(program),
257
+ analyzeMethods: program.analyzeMethods.bind(program),
258
+ Proof: SelfProof,
259
+ methods,
260
+ };
261
+ });
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Wrapper for an application specific runtime, which helps orchestrate
267
+ * runtime modules into an interoperable runtime.
268
+ */
269
+ @injectable()
270
+ export class Runtime<Modules extends RuntimeModulesRecord>
271
+ extends ModuleContainer<Modules>
272
+ implements RuntimeEnvironment, CompilableModule
273
+ {
274
+ public static from<Modules extends RuntimeModulesRecord>(
275
+ definition: RuntimeDefinition<Modules>
276
+ ): TypedClass<Runtime<Modules>> {
277
+ return class RuntimeScoped extends Runtime<Modules> {
278
+ public constructor() {
279
+ super(definition);
280
+ }
281
+ };
282
+ }
283
+
284
+ // runtime modules composed into a ZkProgram
285
+ public program?: ReturnType<typeof ZkProgram>;
286
+
287
+ public definition: RuntimeDefinition<Modules>;
288
+
289
+ public zkProgrammable: ZkProgrammable<undefined, MethodPublicOutput>;
290
+
291
+ /**
292
+ * Creates a new Runtime from the provided config
293
+ *
294
+ * @param modules - Configuration object for the constructed Runtime
295
+ */
296
+ public constructor(definition: RuntimeDefinition<Modules>) {
297
+ super(definition);
298
+ this.definition = definition;
299
+ this.zkProgrammable = new RuntimeZkProgrammable<Modules>(this);
300
+ }
301
+
302
+ // TODO Remove after changing DFs to type-based approach
303
+ public create(childContainerProvider: ChildContainerProvider) {
304
+ super.create(childContainerProvider);
305
+
306
+ this.useDependencyFactory(this.container.resolve(MethodIdFactory));
307
+ }
308
+
309
+ public get areProofsEnabled(): AreProofsEnabled | undefined {
310
+ return this.container.resolve<AreProofsEnabled>("AreProofsEnabled");
311
+ }
312
+
313
+ public get stateServiceProvider(): StateServiceProvider {
314
+ return this.dependencyContainer.resolve<StateServiceProvider>(
315
+ "StateServiceProvider"
316
+ );
317
+ }
318
+
319
+ public get stateService(): SimpleAsyncStateService {
320
+ return this.stateServiceProvider.stateService;
321
+ }
322
+
323
+ public get methodIdResolver(): MethodIdResolver {
324
+ return this.container.resolve<MethodIdResolver>("MethodIdResolver");
325
+ }
326
+
327
+ /**
328
+ * @returns The dependency injection container of this runtime
329
+ */
330
+ public get dependencyContainer(): DependencyContainer {
331
+ return this.container;
332
+ }
333
+
334
+ /**
335
+ * @param methodId The encoded name of the method to call.
336
+ * Encoding: "stringToField(module.name) << 128 + stringToField(method-name)"
337
+ */
338
+ public getMethodById(
339
+ methodId: bigint
340
+ ): ((...args: unknown[]) => Promise<unknown>) | undefined {
341
+ const methodDescriptor =
342
+ this.methodIdResolver.getMethodNameFromId(methodId);
343
+
344
+ if (methodDescriptor === undefined) {
345
+ return undefined;
346
+ }
347
+ const [moduleName, methodName] = methodDescriptor;
348
+
349
+ this.assertIsValidModuleName(moduleName);
350
+ const module = this.resolve(moduleName);
351
+
352
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
353
+ const method = (module as any)[methodName];
354
+ if (method === undefined) {
355
+ throw errors.methodNotFound(`${moduleName}.${methodName}`);
356
+ }
357
+
358
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
359
+ return (method as (...args: unknown[]) => Promise<unknown>).bind(module);
360
+ }
361
+
362
+ /**
363
+ * Add a name and other respective properties required by RuntimeModules,
364
+ * that come from the current Runtime
365
+ *
366
+ * @param moduleName - Name of the runtime module to decorate
367
+ * @param containedModule
368
+ */
369
+ public decorateModule(
370
+ moduleName: StringKeyOf<Modules>,
371
+ containedModule: InstanceType<Modules[StringKeyOf<Modules>]>
372
+ ) {
373
+ containedModule.name = moduleName;
374
+ containedModule.runtime = this;
375
+
376
+ super.decorateModule(moduleName, containedModule);
377
+ }
378
+
379
+ /**
380
+ * @returns A list of names of all the registered module names
381
+ */
382
+ public get runtimeModuleNames() {
383
+ return Object.keys(this.definition.modules);
384
+ }
385
+
386
+ public async compile(registry: CompileRegistry) {
387
+ const context = container.resolve(RuntimeMethodExecutionContext);
388
+ context.setup({
389
+ transaction: RuntimeTransaction.dummyTransaction(),
390
+ networkState: NetworkState.empty(),
391
+ });
392
+ return await this.zkProgrammable.compile(registry);
393
+ }
394
+ }
395
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-argument */
@@ -0,0 +1,16 @@
1
+ import { AreProofsEnabled, WithZkProgrammable } from "@proto-kit/common";
2
+ import {
3
+ MethodPublicOutput,
4
+ SimpleAsyncStateService,
5
+ StateServiceProvider,
6
+ } from "@proto-kit/protocol";
7
+
8
+ import { MethodIdResolver } from "./MethodIdResolver";
9
+
10
+ export interface RuntimeEnvironment
11
+ extends WithZkProgrammable<undefined, MethodPublicOutput> {
12
+ get areProofsEnabled(): AreProofsEnabled | undefined;
13
+ get stateService(): SimpleAsyncStateService;
14
+ get stateServiceProvider(): StateServiceProvider;
15
+ get methodIdResolver(): MethodIdResolver;
16
+ }
@@ -0,0 +1,112 @@
1
+ import { ConfigurableModule, NoConfig, Presets } from "@proto-kit/common";
2
+ import { container, injectable } from "tsyringe";
3
+ import {
4
+ NetworkState,
5
+ RuntimeTransaction,
6
+ RuntimeMethodExecutionContext,
7
+ RuntimeMethodExecutionData,
8
+ RuntimeMethodExecutionDataStruct,
9
+ } from "@proto-kit/protocol";
10
+ import { FlexibleProvablePure, Provable, Bool } from "o1js";
11
+
12
+ import { runtimeMethodNamesMetadataKey } from "../method/runtimeMethod";
13
+
14
+ import { RuntimeEnvironment } from "./RuntimeEnvironment";
15
+
16
+ const errors = {
17
+ inputDataNotSet: () => new Error("Input data for runtime execution not set"),
18
+ };
19
+
20
+ type EventRecord = Record<string, FlexibleProvablePure<any>>;
21
+
22
+ type InferProvable<T extends FlexibleProvablePure<any>> =
23
+ T extends Provable<infer U> ? U : never;
24
+
25
+ export class RuntimeEvents<Events extends EventRecord> {
26
+ public constructor(private readonly events: Events) {}
27
+
28
+ public emitIf<Key extends keyof Events>(
29
+ condition: Bool,
30
+ eventName: Key,
31
+ event: InferProvable<Events[Key]>
32
+ ) {
33
+ if (this.events === undefined) {
34
+ throw new Error(
35
+ "'events' property not defined, make sure to define the event types on your runtimemodule"
36
+ );
37
+ }
38
+ const eventType: FlexibleProvablePure<any> = this.events[eventName];
39
+ if (typeof eventName !== "string") {
40
+ throw new Error("Only string");
41
+ }
42
+ return container
43
+ .resolve(RuntimeMethodExecutionContext)
44
+ .addEvent(eventType, event, eventName, condition);
45
+ }
46
+
47
+ public emit<Key extends keyof Events>(
48
+ eventName: Key,
49
+ event: InferProvable<Events[Key]>
50
+ ) {
51
+ this.emitIf(Bool(true), eventName, event);
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Base class for runtime modules providing the necessary utilities.
57
+ */
58
+ @injectable()
59
+ export class RuntimeModule<
60
+ Config = NoConfig,
61
+ > extends ConfigurableModule<Config> {
62
+ public static presets: Presets<unknown> = {};
63
+
64
+ /**
65
+ * Holds all method names that are callable throw transactions
66
+ */
67
+ public readonly runtimeMethodNames: string[] = [];
68
+
69
+ /**
70
+ * This property exists only to typecheck that the RuntimeModule
71
+ * was extended correctly in e.g. a decorator. We need at least
72
+ * one non-optional property in this class to make the typechecking work.
73
+ */
74
+ public isRuntimeModule = true;
75
+
76
+ public name?: string;
77
+
78
+ public runtime?: RuntimeEnvironment;
79
+
80
+ public events?: RuntimeEvents<any> = undefined;
81
+
82
+ public constructor() {
83
+ super();
84
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
85
+ const methodNames: string[] | undefined = Reflect.getMetadata(
86
+ runtimeMethodNamesMetadataKey,
87
+ this
88
+ );
89
+ this.runtimeMethodNames = methodNames ?? [];
90
+ }
91
+
92
+ public getInputs(): RuntimeMethodExecutionData {
93
+ return Provable.witness(RuntimeMethodExecutionDataStruct, () => {
94
+ const { input } = container.resolve<RuntimeMethodExecutionContext>(
95
+ RuntimeMethodExecutionContext
96
+ );
97
+ if (input === undefined) {
98
+ throw errors.inputDataNotSet();
99
+ }
100
+
101
+ return input;
102
+ });
103
+ }
104
+
105
+ public get transaction(): RuntimeTransaction {
106
+ return this.getInputs().transaction;
107
+ }
108
+
109
+ public get network(): NetworkState {
110
+ return this.getInputs().networkState;
111
+ }
112
+ }
@@ -0,0 +1,25 @@
1
+ import { Field } from "o1js";
2
+ import { SimpleAsyncStateService } from "@proto-kit/protocol";
3
+
4
+ /**
5
+ * Naive implementation of an in-memory variant of the StateService interface
6
+ */
7
+ export class InMemoryStateService implements SimpleAsyncStateService {
8
+ /**
9
+ * This mapping container null values if the specific entry has been deleted.
10
+ * This is used by the CachedState service to keep track of deletions
11
+ */
12
+ public values: Record<string, Field[] | null> = {};
13
+
14
+ public async get(key: Field): Promise<Field[] | undefined> {
15
+ return this.values[key.toString()] ?? undefined;
16
+ }
17
+
18
+ public async set(key: Field, value: Field[] | undefined) {
19
+ if (value === undefined) {
20
+ this.values[key.toString()] = null;
21
+ } else {
22
+ this.values[key.toString()] = value;
23
+ }
24
+ }
25
+ }
@@ -0,0 +1,61 @@
1
+ import { Path, State } from "@proto-kit/protocol";
2
+
3
+ import type { RuntimeModule } from "../runtime/RuntimeModule.js";
4
+
5
+ const errors = {
6
+ missingName: (className: string) =>
7
+ new Error(
8
+ `Unable to provide a unique identifier for state, ${className} is missing a name.
9
+ Did you forget to extend your runtime module with 'extends RuntimeModule'?`
10
+ ),
11
+
12
+ missingRuntime: (className: string) =>
13
+ new Error(
14
+ `Unable to provide 'runtime' for state, ${className} is missing a name.
15
+ Did you forget to extend your runtime module with 'extends RuntimeModule'?`
16
+ ),
17
+ };
18
+
19
+ /**
20
+ * Decorates a runtime module property as state, passing down some
21
+ * underlying values to improve developer experience.
22
+ */
23
+ export function state() {
24
+ return <TargetRuntimeModule extends RuntimeModule<unknown>>(
25
+ target: TargetRuntimeModule,
26
+ propertyKey: string
27
+ ) => {
28
+ let value: State<unknown> | undefined;
29
+
30
+ Object.defineProperty(target, propertyKey, {
31
+ enumerable: true,
32
+
33
+ get: function get() {
34
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
35
+ const self = this as TargetRuntimeModule;
36
+
37
+ if (self.name === undefined) {
38
+ throw errors.missingName(self.constructor.name);
39
+ }
40
+
41
+ if (!self.runtime) {
42
+ throw errors.missingRuntime(self.constructor.name);
43
+ }
44
+
45
+ const path = Path.fromProperty(self.name, propertyKey);
46
+ if (value) {
47
+ value.path = path;
48
+
49
+ // TODO: why is this complaining about `any`?
50
+
51
+ value.stateServiceProvider = self.runtime.stateServiceProvider;
52
+ }
53
+ return value;
54
+ },
55
+
56
+ set: (newValue: State<unknown>) => {
57
+ value = newValue;
58
+ },
59
+ });
60
+ };
61
+ }
@@ -0,0 +1,70 @@
1
+ describe("noop", () => {
2
+ it("noop", () => {
3
+ expect(1).toBe(1);
4
+ });
5
+ });
6
+
7
+ // TODO disabled because of the reflect-metadata error in the CI
8
+ // import "reflect-metadata";
9
+ // import { container } from "tsyringe";
10
+ // import {
11
+ // RuntimeMethodExecutionContext,
12
+ // RuntimeTransaction,
13
+ // NetworkState,
14
+ // } from "@proto-kit/protocol";
15
+ //
16
+ // import { MethodIdResolver } from "../src";
17
+ //
18
+ // import { Balances } from "./modules/Balances";
19
+ // import { createTestingRuntime } from "./TestingRuntime";
20
+ //
21
+ // describe.skip("runtime", () => {
22
+ // it("should encode methodnames correctly", () => {
23
+ // expect.assertions(2);
24
+ //
25
+ // const { runtime } = createTestingRuntime(
26
+ // {
27
+ // Balances,
28
+ // },
29
+ // {
30
+ // Balances: {},
31
+ // }
32
+ // );
33
+ //
34
+ // const balances = runtime.resolve("Balances");
35
+ //
36
+ // expect(balances).toBeDefined();
37
+ //
38
+ // console.log(Object.keys(balances));
39
+ // console.log(balances.getTotalSupply);
40
+ //
41
+ // const moduleName = "Balances";
42
+ // const methodName = "getTotalSupply";
43
+ //
44
+ // const methodId = runtime.dependencyContainer
45
+ // .resolve<MethodIdResolver>("MethodIdResolver")
46
+ // .getMethodId(moduleName, methodName);
47
+ // const method = runtime.getMethodById(methodId);
48
+ //
49
+ // expect(method).toBeDefined();
50
+ // });
51
+ //
52
+ // it("regression - check that analyzeMethods works on runtime", async () => {
53
+ // const { runtime } = createTestingRuntime(
54
+ // {
55
+ // Balances,
56
+ // },
57
+ // {
58
+ // Balances: {},
59
+ // }
60
+ // );
61
+ //
62
+ // const context = container.resolve(RuntimeMethodExecutionContext);
63
+ // context.setup({
64
+ // transaction: RuntimeTransaction.dummyTransaction(),
65
+ // networkState: NetworkState.empty(),
66
+ // });
67
+ //
68
+ // await runtime.zkProgrammable.zkProgram.analyzeMethods();
69
+ // });
70
+ // });