@proto-kit/module 0.1.1-develop.153

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 (75) hide show
  1. package/LICENSE.md +201 -0
  2. package/README.md +114 -0
  3. package/dist/chain/Chain.d.ts +109 -0
  4. package/dist/chain/Chain.d.ts.map +1 -0
  5. package/dist/chain/Chain.js +229 -0
  6. package/dist/index.d.ts +13 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +12 -0
  9. package/dist/method/MethodExecutionContext.d.ts +73 -0
  10. package/dist/method/MethodExecutionContext.d.ts.map +1 -0
  11. package/dist/method/MethodExecutionContext.js +112 -0
  12. package/dist/method/MethodParameterDecoder.d.ts +20 -0
  13. package/dist/method/MethodParameterDecoder.d.ts.map +1 -0
  14. package/dist/method/MethodParameterDecoder.js +30 -0
  15. package/dist/method/RuntimeMethodExecutionContext.d.ts +57 -0
  16. package/dist/method/RuntimeMethodExecutionContext.d.ts.map +1 -0
  17. package/dist/method/RuntimeMethodExecutionContext.js +92 -0
  18. package/dist/method/assert.d.ts +12 -0
  19. package/dist/method/assert.d.ts.map +1 -0
  20. package/dist/method/assert.js +20 -0
  21. package/dist/method/decorator.d.ts +45 -0
  22. package/dist/method/decorator.d.ts.map +1 -0
  23. package/dist/method/decorator.js +140 -0
  24. package/dist/method/runtimeMethod.d.ts +18 -0
  25. package/dist/method/runtimeMethod.d.ts.map +1 -0
  26. package/dist/method/runtimeMethod.js +114 -0
  27. package/dist/module/decorator.d.ts +8 -0
  28. package/dist/module/decorator.d.ts.map +1 -0
  29. package/dist/module/decorator.js +15 -0
  30. package/dist/runtime/Runtime.d.ts +71 -0
  31. package/dist/runtime/Runtime.d.ts.map +1 -0
  32. package/dist/runtime/Runtime.js +185 -0
  33. package/dist/runtime/RuntimeModule.d.ts +30 -0
  34. package/dist/runtime/RuntimeModule.d.ts.map +1 -0
  35. package/dist/runtime/RuntimeModule.js +44 -0
  36. package/dist/state/InMemoryStateService.d.ts +14 -0
  37. package/dist/state/InMemoryStateService.d.ts.map +1 -0
  38. package/dist/state/InMemoryStateService.js +21 -0
  39. package/dist/state/State.d.ts +65 -0
  40. package/dist/state/State.d.ts.map +1 -0
  41. package/dist/state/State.js +114 -0
  42. package/dist/state/StateMap.d.ts +37 -0
  43. package/dist/state/StateMap.d.ts.map +1 -0
  44. package/dist/state/StateMap.js +56 -0
  45. package/dist/state/StateServiceProvider.d.ts +10 -0
  46. package/dist/state/StateServiceProvider.d.ts.map +1 -0
  47. package/dist/state/StateServiceProvider.js +34 -0
  48. package/dist/state/decorator.d.ts +7 -0
  49. package/dist/state/decorator.d.ts.map +1 -0
  50. package/dist/state/decorator.js +42 -0
  51. package/jest.config.cjs +1 -0
  52. package/package.json +36 -0
  53. package/src/index.ts +12 -0
  54. package/src/method/MethodParameterDecoder.ts +55 -0
  55. package/src/method/RuntimeMethodExecutionContext.ts +111 -0
  56. package/src/method/assert.test.ts +49 -0
  57. package/src/method/assert.ts +23 -0
  58. package/src/method/decorator.test.ts +46 -0
  59. package/src/method/runtimeMethod.ts +192 -0
  60. package/src/module/decorator.ts +21 -0
  61. package/src/runtime/Runtime.ts +304 -0
  62. package/src/runtime/RuntimeModule.ts +68 -0
  63. package/src/state/InMemoryStateService.ts +29 -0
  64. package/src/state/State.ts +154 -0
  65. package/src/state/StateMap.ts +69 -0
  66. package/src/state/StateServiceProvider.ts +24 -0
  67. package/src/state/decorator.ts +65 -0
  68. package/test/Runtime.test.ts +37 -0
  69. package/test/modules/Admin.ts +19 -0
  70. package/test/modules/Balances.test.ts +340 -0
  71. package/test/modules/Balances.ts +51 -0
  72. package/test/runtimeMethod.test.ts +43 -0
  73. package/test/transaction.test.ts +82 -0
  74. package/tsconfig.json +8 -0
  75. package/tsconfig.test.json +9 -0
@@ -0,0 +1,192 @@
1
+ import { Bool, Field, FlexibleProvable, Struct } from "snarkyjs";
2
+ import { container } from "tsyringe";
3
+ import {
4
+ StateTransition,
5
+ DefaultProvableHashList,
6
+ ProvableStateTransition,
7
+ MethodPublicOutput,
8
+ } from "@proto-kit/protocol";
9
+ import { DecoratedMethod, toProver, ZkProgrammable } from "@proto-kit/common";
10
+
11
+ import type { RuntimeModule } from "../runtime/RuntimeModule.js";
12
+
13
+ import { RuntimeMethodExecutionContext } from "./RuntimeMethodExecutionContext.js";
14
+
15
+ const errors = {
16
+ runtimeNotProvided: (name: string) =>
17
+ new Error(`Runtime was not provided for module: ${name}`),
18
+
19
+ methodInputsNotProvided: () =>
20
+ new Error(
21
+ "Method execution inputs not provided, provide them via context.inputs"
22
+ ),
23
+ };
24
+
25
+ export function toStateTransitionsHash(
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ stateTransitions: StateTransition<any>[]
28
+ ) {
29
+ const stateTransitionsHashList = new DefaultProvableHashList(
30
+ ProvableStateTransition
31
+ );
32
+
33
+ return stateTransitions
34
+ .map((stateTransition) => stateTransition.toProvable())
35
+ .reduce(
36
+ (allStateTransitionsHashList, stateTransition) =>
37
+ allStateTransitionsHashList.push(stateTransition),
38
+ stateTransitionsHashList
39
+ )
40
+ .toField();
41
+ }
42
+
43
+ // eslint-disable-next-line etc/prefer-interface
44
+ export type WrappedMethod = (...args: unknown[]) => MethodPublicOutput;
45
+
46
+ export function toWrappedMethod(
47
+ this: RuntimeModule<unknown>,
48
+ methodName: string,
49
+ moduleMethod: (...args: unknown[]) => unknown
50
+ ) {
51
+ const executionContext = container.resolve<RuntimeMethodExecutionContext>(
52
+ RuntimeMethodExecutionContext
53
+ );
54
+
55
+ const wrappedMethod: WrappedMethod = (...args): MethodPublicOutput => {
56
+ Reflect.apply(moduleMethod, this, args);
57
+ const {
58
+ result: { stateTransitions, status },
59
+ input,
60
+ } = executionContext.current();
61
+
62
+ const stateTransitionsHash = toStateTransitionsHash(stateTransitions);
63
+
64
+ if (input === undefined) {
65
+ throw errors.methodInputsNotProvided();
66
+ }
67
+
68
+ const transactionHash = input.transaction.hash();
69
+ const networkStateHash = input.networkState.hash();
70
+
71
+ return new MethodPublicOutput({
72
+ stateTransitionsHash,
73
+ status,
74
+ transactionHash,
75
+ networkStateHash,
76
+ });
77
+ };
78
+
79
+ Object.defineProperty(wrappedMethod, "name", {
80
+ value: `wrapped_${methodName}`,
81
+ writable: false,
82
+ });
83
+
84
+ return wrappedMethod;
85
+ }
86
+
87
+ export function combineMethodName(
88
+ runtimeModuleName: string,
89
+ methodName: string
90
+ ) {
91
+ return `${runtimeModuleName}.${methodName}`;
92
+ }
93
+
94
+ export const runtimeMethodMetadataKey = "yab-method";
95
+
96
+ /**
97
+ * Checks the metadata of the provided runtime module and its method,
98
+ * to see if it has been decorated with @runtimeMethod()
99
+ *
100
+ * @param target - Runtime module to check
101
+ * @param propertyKey - Name of the method to check in the prior runtime module
102
+ * @returns - If the provided method name is a runtime method or not
103
+ */
104
+ export function isRuntimeMethod(
105
+ target: RuntimeModule<unknown>,
106
+ propertyKey: string
107
+ ) {
108
+ return Boolean(
109
+ Reflect.getMetadata(runtimeMethodMetadataKey, target, propertyKey)
110
+ );
111
+ }
112
+
113
+ export function runtimeMethod() {
114
+ return (
115
+ target: RuntimeModule<unknown>,
116
+ methodName: string,
117
+ descriptor: PropertyDescriptor
118
+ ) => {
119
+ const executionContext = container.resolve<RuntimeMethodExecutionContext>(
120
+ RuntimeMethodExecutionContext
121
+ );
122
+
123
+ Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
124
+
125
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
126
+ const simulatedMethod = descriptor.value as DecoratedMethod;
127
+
128
+ descriptor.value = function value(
129
+ this: RuntimeModule<unknown>,
130
+ ...args: FlexibleProvable<unknown>[]
131
+ ) {
132
+ const constructorName = this.constructor.name;
133
+
134
+ /**
135
+ * If its a top level method call, wrap it into a wrapped method,
136
+ * since it'll be turned into a real/mock prover in provableMethod().
137
+ *
138
+ * Otherwise provableMethod() will just call the originalMethod provided
139
+ * if method is not called at the top level.
140
+ */
141
+ const simulatedWrappedMethod = Reflect.apply(toWrappedMethod, this, [
142
+ methodName,
143
+ simulatedMethod,
144
+ ]);
145
+
146
+ /**
147
+ * Before the prover runs, make sure it is operating on the correct
148
+ * RuntimeMethodExecutionContext state, meaning it enters and exits
149
+ * the context properly.
150
+ */
151
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
152
+ async function prover(this: ZkProgrammable<any, any>) {
153
+ executionContext.beforeMethod(constructorName, methodName, args);
154
+ const innerProver = toProver(
155
+ combineMethodName(constructorName, methodName),
156
+ simulatedWrappedMethod,
157
+ false,
158
+ ...args
159
+ ).bind(this);
160
+ // eslint-disable-next-line @typescript-eslint/init-declarations
161
+ let result: Awaited<ReturnType<typeof innerProver>>;
162
+ try {
163
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
164
+ result = await Reflect.apply(innerProver, this, args);
165
+ } finally {
166
+ executionContext.afterMethod();
167
+ }
168
+
169
+ return result;
170
+ }
171
+
172
+ executionContext.beforeMethod(constructorName, methodName, args);
173
+
174
+ if (executionContext.isTopLevel) {
175
+ if (!this.runtime) {
176
+ throw errors.runtimeNotProvided(constructorName);
177
+ }
178
+ executionContext.setProver(prover.bind(this.runtime.zkProgrammable));
179
+ }
180
+
181
+ // eslint-disable-next-line @typescript-eslint/init-declarations
182
+ let result: unknown;
183
+ try {
184
+ result = Reflect.apply(simulatedMethod, this, args);
185
+ } finally {
186
+ executionContext.afterMethod();
187
+ }
188
+
189
+ return result;
190
+ };
191
+ };
192
+ }
@@ -0,0 +1,21 @@
1
+ import { injectable } from "tsyringe";
2
+ import { StaticConfigurableModule, TypedClass } from "@proto-kit/common";
3
+
4
+ import { RuntimeModule } from "../runtime/RuntimeModule.js";
5
+
6
+ /**
7
+ * Marks the decorated class as a runtime module, while also
8
+ * making it injectable with our dependency injection solution.
9
+ */
10
+ export function runtimeModule() {
11
+ return (
12
+ /**
13
+ * Check if the target class extends RuntimeModule, while
14
+ * also providing static config presets
15
+ */
16
+ target: StaticConfigurableModule<unknown> &
17
+ TypedClass<RuntimeModule<unknown>>
18
+ ) => {
19
+ injectable()(target);
20
+ };
21
+ }
@@ -0,0 +1,304 @@
1
+ // eslint-disable-next-line max-len
2
+ /* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-assignment */
3
+ import { Experimental } from "snarkyjs";
4
+ import { DependencyContainer, injectable } from "tsyringe";
5
+ import {
6
+ StringKeyOf,
7
+ ModuleContainer,
8
+ ModulesConfig,
9
+ ModulesRecord,
10
+ TypedClass,
11
+ ZkProgrammable,
12
+ PlainZkProgram,
13
+ WithZkProgrammable,
14
+ AreProofsEnabled,
15
+ } from "@proto-kit/common";
16
+ import {
17
+ fieldToString,
18
+ stringToField,
19
+ MethodPublicOutput,
20
+ } from "@proto-kit/protocol";
21
+
22
+ import {
23
+ combineMethodName,
24
+ isRuntimeMethod,
25
+ toWrappedMethod,
26
+ WrappedMethod,
27
+ } from "../method/runtimeMethod.js";
28
+ import { StateService } from "../state/InMemoryStateService.js";
29
+ import { StateServiceProvider } from "../state/StateServiceProvider";
30
+
31
+ import { RuntimeModule } from "./RuntimeModule.js";
32
+
33
+ /**
34
+ * Record of modules accepted by the Runtime module container.
35
+ *
36
+ * We have to use TypedClass since RuntimeModule
37
+ * is an abstract class
38
+ */
39
+ export type RuntimeModulesRecord = ModulesRecord<
40
+ TypedClass<RuntimeModule<unknown>>
41
+ >;
42
+
43
+ const errors = {
44
+ methodNotFound: (methodKey: string) =>
45
+ new Error(`Unable to find method with id ${methodKey}`),
46
+ };
47
+
48
+ /**
49
+ * Definition / required arguments for the Runtime class
50
+ */
51
+ export interface RuntimeDefinition<Modules extends RuntimeModulesRecord> {
52
+ state: StateService;
53
+ modules: Modules;
54
+ config?: ModulesConfig<Modules>;
55
+ }
56
+
57
+ export class RuntimeZkProgrammable<
58
+ Modules extends RuntimeModulesRecord
59
+ > extends ZkProgrammable<undefined, MethodPublicOutput> {
60
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
61
+ public constructor(public runtime: Runtime<Modules>) {
62
+ super();
63
+ }
64
+
65
+ public get appChain() {
66
+ return this.runtime.appChain;
67
+ }
68
+
69
+ public zkProgramFactory(): PlainZkProgram<undefined, MethodPublicOutput> {
70
+ type Methods = Record<
71
+ string,
72
+ {
73
+ privateInputs: any;
74
+ method: WrappedMethod;
75
+ }
76
+ >;
77
+ // We need to use explicit type annotations here,
78
+ // therefore we can't use destructuring
79
+ // eslint-disable-next-line max-len
80
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define,prefer-destructuring,putout/putout
81
+ const runtime: Runtime<Modules> = this.runtime;
82
+
83
+ const runtimeMethods = runtime.runtimeModuleNames.reduce<Methods>(
84
+ (allMethods, runtimeModuleName) => {
85
+ runtime.isValidModuleName(
86
+ runtime.definition.modules,
87
+ runtimeModuleName
88
+ );
89
+
90
+ /**
91
+ * Couldnt find a better way to circumvent the type assertion
92
+ * regarding resolving only known modules. We assert in the line above
93
+ * but we cast it to any anyways to satisfy the proof system.
94
+ */
95
+ // eslint-disable-next-line max-len
96
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
97
+ const runtimeModule = runtime.resolve(runtimeModuleName as any);
98
+
99
+ // eslint-disable-next-line max-len
100
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
101
+ const modulePrototype = Object.getPrototypeOf(runtimeModule) as Record<
102
+ string,
103
+ (...args: unknown[]) => unknown
104
+ >;
105
+
106
+ const modulePrototypeMethods =
107
+ Object.getOwnPropertyNames(modulePrototype);
108
+
109
+ const moduleMethods = modulePrototypeMethods.reduce<Methods>(
110
+ (allModuleMethods, methodName) => {
111
+ if (isRuntimeMethod(runtimeModule, methodName)) {
112
+ const combinedMethodName = combineMethodName(
113
+ runtimeModuleName,
114
+ methodName
115
+ );
116
+ const method = modulePrototype[methodName];
117
+ const wrappedMethod = Reflect.apply(
118
+ toWrappedMethod,
119
+ runtimeModule,
120
+ [methodName, method]
121
+ );
122
+
123
+ // eslint-disable-next-line no-warning-comments
124
+ // TODO: find out how to import the Tuple type
125
+
126
+ const privateInputs = Reflect.getMetadata(
127
+ "design:paramtypes",
128
+ runtimeModule,
129
+ methodName
130
+ );
131
+
132
+ return {
133
+ ...allModuleMethods,
134
+
135
+ [combinedMethodName]: {
136
+ privateInputs,
137
+ method: wrappedMethod,
138
+ },
139
+ };
140
+ }
141
+
142
+ return allModuleMethods;
143
+ },
144
+ {}
145
+ );
146
+
147
+ return {
148
+ ...allMethods,
149
+ ...moduleMethods,
150
+ };
151
+ },
152
+ {}
153
+ );
154
+
155
+ const sortedRuntimeMethods = Object.fromEntries(
156
+ // eslint-disable-next-line @typescript-eslint/require-array-sort-compare
157
+ Object.entries(runtimeMethods).sort()
158
+ );
159
+
160
+ const program = Experimental.ZkProgram({
161
+ publicOutput: MethodPublicOutput,
162
+ methods: sortedRuntimeMethods,
163
+ });
164
+
165
+ const SelfProof = Experimental.ZkProgram.Proof(program);
166
+
167
+ const methods = Object.keys(sortedRuntimeMethods).reduce<
168
+ Record<string, any>
169
+ >((boundMethods, methodName) => {
170
+ boundMethods[methodName] = program[methodName].bind(program);
171
+ return boundMethods;
172
+ }, {});
173
+
174
+ return {
175
+ compile: program.compile.bind(program),
176
+ verify: program.verify.bind(program),
177
+ Proof: SelfProof,
178
+ methods,
179
+ };
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Wrapper for an application specific runtime, which helps orchestrate
185
+ * runtime modules into an interoperable runtime.
186
+ */
187
+ @injectable()
188
+ export class Runtime<Modules extends RuntimeModulesRecord>
189
+ extends ModuleContainer<Modules>
190
+ implements WithZkProgrammable<undefined, MethodPublicOutput>
191
+ {
192
+ public static from<Modules extends RuntimeModulesRecord>(
193
+ definition: RuntimeDefinition<Modules>
194
+ ) {
195
+ return new Runtime(definition);
196
+ }
197
+
198
+ // runtime modules composed into a ZkProgram
199
+ public program?: ReturnType<typeof Experimental.ZkProgram>;
200
+
201
+ public definition: RuntimeDefinition<Modules>;
202
+
203
+ public zkProgrammable: ZkProgrammable<undefined, MethodPublicOutput>;
204
+
205
+ // eslint-disable-next-line no-warning-comments
206
+ // TODO DI
207
+ private readonly stateServiceProviderInstance = new StateServiceProvider(
208
+ this.definition.state
209
+ );
210
+
211
+ /**
212
+ * Creates a new Runtime from the provided config
213
+ *
214
+ * @param modules - Configuration object for the constructed Runtime
215
+ */
216
+ public constructor(definition: RuntimeDefinition<Modules>) {
217
+ super(definition);
218
+ this.definition = definition;
219
+ this.zkProgrammable = new RuntimeZkProgrammable<Modules>(this);
220
+ // this.registerValue({
221
+ // Runtime: this,
222
+ // });
223
+ }
224
+
225
+ public get appChain(): AreProofsEnabled | undefined {
226
+ return this.container.resolve<AreProofsEnabled>("AppChain");
227
+ }
228
+
229
+ public get stateService(): StateService {
230
+ return this.stateServiceProviderInstance.stateService;
231
+ }
232
+
233
+ public get stateServiceProvider(): StateServiceProvider {
234
+ return this.stateServiceProviderInstance;
235
+ }
236
+
237
+ /**
238
+ * @returns The dependency injection container of this runtime
239
+ */
240
+ public get dependencyContainer(): DependencyContainer {
241
+ return this.container;
242
+ }
243
+
244
+ /**
245
+ * @param methodId The encoded name of the method to call.
246
+ * Encoding: "stringToField(module.name) << 128 + stringToField(method-name)"
247
+ */
248
+ public getMethodById(methodId: bigint): (...args: unknown[]) => unknown {
249
+ const [moduleName, methodName] = this.getMethodNameFromId(methodId);
250
+
251
+ this.isValidModuleName(this.definition.modules, moduleName);
252
+ const module = this.resolve(moduleName);
253
+
254
+ // eslint-disable-next-line max-len
255
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-unsafe-member-access
256
+ const method = (module as any)[methodName];
257
+ if (method === undefined) {
258
+ throw errors.methodNotFound(`${moduleName}.${methodName}`);
259
+ }
260
+
261
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
262
+ return (method as (...args: unknown[]) => unknown).bind(module);
263
+ }
264
+
265
+ public getMethodNameFromId(methodId: bigint): [string, string] {
266
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
267
+ const moduleName = fieldToString(methodId >> 128n);
268
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
269
+ const methodName = fieldToString(methodId % 2n ** 128n);
270
+
271
+ return [moduleName, methodName];
272
+ }
273
+
274
+ public getMethodId(moduleName: string, methodName: string): bigint {
275
+ return (
276
+ // eslint-disable-next-line @typescript-eslint/no-magic-numbers
277
+ (stringToField(moduleName).toBigInt() << 128n) +
278
+ stringToField(methodName).toBigInt()
279
+ );
280
+ }
281
+
282
+ /**
283
+ * Add a name and other respective properties required by RuntimeModules,
284
+ * that come from the current Runtime
285
+ *
286
+ * @param name - Name of the runtime module to decorate
287
+ */
288
+ public decorateModule(
289
+ moduleName: StringKeyOf<Modules>,
290
+ containedModule: InstanceType<Modules[StringKeyOf<Modules>]>
291
+ ) {
292
+ containedModule.name = moduleName;
293
+ containedModule.runtime = this;
294
+
295
+ super.decorateModule(moduleName, containedModule);
296
+ }
297
+
298
+ /**
299
+ * @returns A list of names of all the registered module names
300
+ */
301
+ public get runtimeModuleNames() {
302
+ return Object.keys(this.definition.modules);
303
+ }
304
+ }
@@ -0,0 +1,68 @@
1
+ import { ConfigurableModule, Presets } from "@proto-kit/common";
2
+ import { container, injectable } from "tsyringe";
3
+ import { NetworkState, RuntimeTransaction } from "@proto-kit/protocol";
4
+
5
+ import {
6
+ RuntimeMethodExecutionContext,
7
+ RuntimeMethodExecutionData,
8
+ } from "../method/RuntimeMethodExecutionContext";
9
+ import { StateService } from "../state/InMemoryStateService";
10
+
11
+ import type {
12
+ Runtime,
13
+ RuntimeDefinition,
14
+ RuntimeModulesRecord,
15
+ } from "./Runtime";
16
+
17
+ const errors = {
18
+ inputDataNotSet: () => new Error("Input data for runtime execution not set"),
19
+ };
20
+
21
+ /**
22
+ * This type exists to carry over certain runtime properties
23
+ * to runtime modules, until we can inject them through DI.
24
+ */
25
+ export interface PartialRuntime
26
+ extends Pick<Runtime<RuntimeModulesRecord>, "zkProgrammable"> {
27
+ definition: Pick<RuntimeDefinition<RuntimeModulesRecord>, "state">;
28
+
29
+ get stateService(): StateService;
30
+ }
31
+
32
+ /**
33
+ * Base class for runtime modules providing the necessary utilities.
34
+ */
35
+ @injectable()
36
+ export class RuntimeModule<Config> extends ConfigurableModule<Config> {
37
+ public static presets: Presets<unknown> = {};
38
+
39
+ /**
40
+ * This property exists only to typecheck that the RuntimeModule
41
+ * was extended correctly in e.g. a decorator. We need at least
42
+ * one non-optional property in this class to make the typechecking work.
43
+ */
44
+ public isRuntimeModule = true;
45
+
46
+ public name?: string;
47
+
48
+ public runtime?: Runtime<RuntimeModulesRecord>;
49
+
50
+ private getInputs(): RuntimeMethodExecutionData {
51
+ const { input } = container.resolve<RuntimeMethodExecutionContext>(
52
+ RuntimeMethodExecutionContext
53
+ );
54
+
55
+ if (input === undefined) {
56
+ throw errors.inputDataNotSet();
57
+ }
58
+ return input;
59
+ }
60
+
61
+ public get transaction(): RuntimeTransaction {
62
+ return this.getInputs().transaction;
63
+ }
64
+
65
+ public get network(): NetworkState {
66
+ return this.getInputs().networkState;
67
+ }
68
+ }
@@ -0,0 +1,29 @@
1
+ import { Field } from "snarkyjs";
2
+
3
+ export interface StateService {
4
+ get: (key: Field) => Field[] | undefined;
5
+ set: (key: Field, value: Field[] | undefined) => void;
6
+ }
7
+
8
+ /**
9
+ * Naive implementation of a StateService for testing purposes
10
+ */
11
+ export class InMemoryStateService implements StateService {
12
+ public values: Record<string, Field[] | undefined> = {};
13
+
14
+ public get(key: Field): Field[] | undefined {
15
+ return this.values[key.toString()];
16
+ }
17
+
18
+ public set(key: Field, value: Field[] | undefined) {
19
+ if (
20
+ value === undefined &&
21
+ Object.prototype.hasOwnProperty.call(this.values, key.toString())
22
+ ) {
23
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
24
+ delete this.values[key.toString()];
25
+ } else {
26
+ this.values[key.toString()] = value;
27
+ }
28
+ }
29
+ }