@proto-kit/module 0.1.1-develop.165 → 0.1.1-develop.1661

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 (118) hide show
  1. package/dist/factories/MethodIdFactory.d.ts +9 -0
  2. package/dist/factories/MethodIdFactory.d.ts.map +1 -0
  3. package/dist/factories/MethodIdFactory.js +11 -0
  4. package/dist/factories/MethodIdFactory.js.map +1 -0
  5. package/dist/index.d.ts +5 -7
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +6 -7
  8. package/dist/index.js.map +1 -0
  9. package/dist/messages/OutgoingMessage.d.ts +96 -0
  10. package/dist/messages/OutgoingMessage.d.ts.map +1 -0
  11. package/dist/messages/OutgoingMessage.js +68 -0
  12. package/dist/messages/OutgoingMessage.js.map +1 -0
  13. package/dist/messages/OutgoingMessages.d.ts +215 -0
  14. package/dist/messages/OutgoingMessages.d.ts.map +1 -0
  15. package/dist/messages/OutgoingMessages.js +66 -0
  16. package/dist/messages/OutgoingMessages.js.map +1 -0
  17. package/dist/method/MethodParameterEncoder.d.ts +26 -0
  18. package/dist/method/MethodParameterEncoder.d.ts.map +1 -0
  19. package/dist/method/MethodParameterEncoder.js +169 -0
  20. package/dist/method/MethodParameterEncoder.js.map +1 -0
  21. package/dist/method/runtimeMethod.d.ts +22 -5
  22. package/dist/method/runtimeMethod.d.ts.map +1 -1
  23. package/dist/method/runtimeMethod.js +79 -24
  24. package/dist/method/runtimeMethod.js.map +1 -0
  25. package/dist/module/decorator.js +1 -0
  26. package/dist/module/decorator.js.map +1 -0
  27. package/dist/runtime/MethodIdResolver.d.ts +20 -0
  28. package/dist/runtime/MethodIdResolver.d.ts.map +1 -0
  29. package/dist/runtime/MethodIdResolver.js +91 -0
  30. package/dist/runtime/MethodIdResolver.js.map +1 -0
  31. package/dist/runtime/Runtime.d.ts +22 -28
  32. package/dist/runtime/Runtime.d.ts.map +1 -1
  33. package/dist/runtime/Runtime.js +116 -70
  34. package/dist/runtime/Runtime.js.map +1 -0
  35. package/dist/runtime/RuntimeEnvironment.d.ts +10 -0
  36. package/dist/runtime/RuntimeEnvironment.d.ts.map +1 -0
  37. package/dist/runtime/RuntimeEnvironment.js +2 -0
  38. package/dist/runtime/RuntimeEnvironment.js.map +1 -0
  39. package/dist/runtime/RuntimeModule.d.ts +23 -14
  40. package/dist/runtime/RuntimeModule.d.ts.map +1 -1
  41. package/dist/runtime/RuntimeModule.js +47 -10
  42. package/dist/runtime/RuntimeModule.js.map +1 -0
  43. package/dist/state/InMemoryStateService.d.ts +11 -10
  44. package/dist/state/InMemoryStateService.d.ts.map +1 -1
  45. package/dist/state/InMemoryStateService.js +11 -8
  46. package/dist/state/InMemoryStateService.js.map +1 -0
  47. package/dist/state/decorator.d.ts.map +1 -1
  48. package/dist/state/decorator.js +2 -4
  49. package/dist/state/decorator.js.map +1 -0
  50. package/dist/testing/TestingRuntime.d.ts +8 -0
  51. package/dist/testing/TestingRuntime.d.ts.map +1 -0
  52. package/dist/testing/TestingRuntime.js +31 -0
  53. package/dist/testing/TestingRuntime.js.map +1 -0
  54. package/jest.config.cjs +12 -1
  55. package/package.json +10 -11
  56. package/src/factories/MethodIdFactory.ts +13 -0
  57. package/src/index.ts +5 -7
  58. package/src/messages/OutgoingMessages.ts +122 -0
  59. package/src/method/MethodParameterEncoder.ts +260 -0
  60. package/src/method/runtimeMethod.ts +146 -31
  61. package/src/runtime/MethodIdResolver.ts +108 -0
  62. package/src/runtime/Runtime.ts +191 -112
  63. package/src/runtime/RuntimeEnvironment.ts +16 -0
  64. package/src/runtime/RuntimeModule.ts +77 -27
  65. package/src/state/InMemoryStateService.ts +14 -18
  66. package/test/Runtime.test.ts +69 -36
  67. package/test/TestingRuntime.ts +43 -0
  68. package/test/messages/message.test.ts +42 -0
  69. package/test/method/MethodParameterEncoder.test.ts +121 -0
  70. package/test/method/runtimeMethod-fail.test.ts +50 -0
  71. package/{src/method/decorator.test.ts → test/method/runtimeMethod.test.ts} +3 -3
  72. package/test/modules/Admin.ts +4 -4
  73. package/test/modules/Balances.test.ts +92 -78
  74. package/test/modules/Balances.ts +19 -16
  75. package/test/modules/MethodIdResolver.test.ts +73 -0
  76. package/test/modules/State.test.ts +81 -0
  77. package/test/runtimeMethod.test.ts +192 -20
  78. package/test/tsconfig.json +7 -0
  79. package/tsconfig.json +2 -2
  80. package/dist/chain/Chain.d.ts +0 -109
  81. package/dist/chain/Chain.d.ts.map +0 -1
  82. package/dist/chain/Chain.js +0 -229
  83. package/dist/method/MethodExecutionContext.d.ts +0 -73
  84. package/dist/method/MethodExecutionContext.d.ts.map +0 -1
  85. package/dist/method/MethodExecutionContext.js +0 -112
  86. package/dist/method/MethodParameterDecoder.d.ts +0 -22
  87. package/dist/method/MethodParameterDecoder.d.ts.map +0 -1
  88. package/dist/method/MethodParameterDecoder.js +0 -33
  89. package/dist/method/RuntimeMethodExecutionContext.d.ts +0 -57
  90. package/dist/method/RuntimeMethodExecutionContext.d.ts.map +0 -1
  91. package/dist/method/RuntimeMethodExecutionContext.js +0 -92
  92. package/dist/method/assert.d.ts +0 -12
  93. package/dist/method/assert.d.ts.map +0 -1
  94. package/dist/method/assert.js +0 -23
  95. package/dist/method/decorator.d.ts +0 -45
  96. package/dist/method/decorator.d.ts.map +0 -1
  97. package/dist/method/decorator.js +0 -140
  98. package/dist/state/State.d.ts +0 -65
  99. package/dist/state/State.d.ts.map +0 -1
  100. package/dist/state/State.js +0 -114
  101. package/dist/state/StateMap.d.ts +0 -37
  102. package/dist/state/StateMap.d.ts.map +0 -1
  103. package/dist/state/StateMap.js +0 -56
  104. package/dist/state/StateServiceProvider.d.ts +0 -10
  105. package/dist/state/StateServiceProvider.d.ts.map +0 -1
  106. package/dist/state/StateServiceProvider.js +0 -34
  107. package/src/method/MethodParameterDecoder.ts +0 -68
  108. package/src/method/RuntimeMethodExecutionContext.ts +0 -111
  109. package/src/method/assert.test.ts +0 -49
  110. package/src/method/assert.ts +0 -27
  111. package/src/state/State.ts +0 -154
  112. package/src/state/StateMap.ts +0 -69
  113. package/src/state/StateServiceProvider.ts +0 -24
  114. package/src/state/decorator.ts +0 -65
  115. package/test/state/MerkleTree.test.ts +0 -95
  116. package/test/state/MockAsyncMerkleStore.ts +0 -28
  117. package/test/transaction.test.ts +0 -82
  118. package/tsconfig.test.json +0 -9
@@ -1,16 +1,25 @@
1
- import { Bool, Field, FlexibleProvable, Struct } from "snarkyjs";
1
+ import { Bool, Field, FlexibleProvablePure, Poseidon } from "o1js";
2
2
  import { container } from "tsyringe";
3
3
  import {
4
- StateTransition,
5
- DefaultProvableHashList,
6
4
  ProvableStateTransition,
7
5
  MethodPublicOutput,
6
+ RuntimeMethodExecutionContext,
7
+ StateTransitionReductionList,
8
+ DefaultProvableHashList,
8
9
  } from "@proto-kit/protocol";
9
- import { DecoratedMethod, toProver, ZkProgrammable } from "@proto-kit/common";
10
+ import {
11
+ DecoratedMethod,
12
+ toProver,
13
+ ZkProgrammable,
14
+ ArgumentTypes,
15
+ } from "@proto-kit/common";
10
16
 
11
17
  import type { RuntimeModule } from "../runtime/RuntimeModule.js";
12
18
 
13
- import { RuntimeMethodExecutionContext } from "./RuntimeMethodExecutionContext.js";
19
+ import {
20
+ MethodParameterEncoder,
21
+ checkArgsProvable,
22
+ } from "./MethodParameterEncoder";
14
23
 
15
24
  const errors = {
16
25
  runtimeNotProvided: (name: string) =>
@@ -20,13 +29,19 @@ const errors = {
20
29
  new Error(
21
30
  "Method execution inputs not provided, provide them via context.inputs"
22
31
  ),
32
+
33
+ runtimeNameNotSet: () => new Error("Runtime name was not set"),
34
+
35
+ fieldNotConstant: (name: string) =>
36
+ new Error(
37
+ `In-circuit field ${name} not a constant, this is likely a framework bug`
38
+ ),
23
39
  };
24
40
 
25
41
  export function toStateTransitionsHash(
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- stateTransitions: StateTransition<any>[]
42
+ stateTransitions: { toProvable: () => ProvableStateTransition }[]
28
43
  ) {
29
- const stateTransitionsHashList = new DefaultProvableHashList(
44
+ const stateTransitionsHashList = new StateTransitionReductionList(
30
45
  ProvableStateTransition
31
46
  );
32
47
 
@@ -40,39 +55,102 @@ export function toStateTransitionsHash(
40
55
  .toField();
41
56
  }
42
57
 
43
- // eslint-disable-next-line etc/prefer-interface
44
- export type WrappedMethod = (...args: unknown[]) => MethodPublicOutput;
58
+ export function toEventsHash(
59
+ events: {
60
+ eventType: FlexibleProvablePure<any>;
61
+ event: any;
62
+ eventName: string;
63
+ condition: Bool;
64
+ }[]
65
+ ) {
66
+ return events.reduce((acc, event) => {
67
+ const hashList = new DefaultProvableHashList(event.eventType, acc);
68
+ hashList.pushIf(event.event, event.condition);
69
+ return hashList.commitment;
70
+ }, Field(0));
71
+ }
72
+
73
+ export type WrappedMethod = (...args: ArgumentTypes) => MethodPublicOutput;
74
+ export type AsyncWrappedMethod = (
75
+ ...args: ArgumentTypes
76
+ ) => Promise<MethodPublicOutput>;
45
77
 
46
78
  export function toWrappedMethod(
47
79
  this: RuntimeModule<unknown>,
48
80
  methodName: string,
49
- moduleMethod: (...args: unknown[]) => unknown
50
- ) {
81
+ moduleMethod: (...args: ArgumentTypes) => Promise<any>,
82
+ options: {
83
+ invocationType: RuntimeMethodInvocationType;
84
+ }
85
+ ): AsyncWrappedMethod {
51
86
  const executionContext = container.resolve<RuntimeMethodExecutionContext>(
52
87
  RuntimeMethodExecutionContext
53
88
  );
54
89
 
55
- const wrappedMethod: WrappedMethod = (...args): MethodPublicOutput => {
56
- Reflect.apply(moduleMethod, this, args);
90
+ const wrappedMethod: AsyncWrappedMethod = async (
91
+ ...args
92
+ ): Promise<MethodPublicOutput> => {
93
+ await Reflect.apply(moduleMethod, this, args);
57
94
  const {
58
- result: { stateTransitions, status },
59
- input,
95
+ result: { stateTransitions, status, events },
60
96
  } = executionContext.current();
61
97
 
62
98
  const stateTransitionsHash = toStateTransitionsHash(stateTransitions);
99
+ const eventsHash = toEventsHash(events);
100
+
101
+ const { name, parent: runtime } = this;
102
+
103
+ if (name === undefined) {
104
+ throw errors.runtimeNameNotSet();
105
+ }
106
+ if (runtime === undefined) {
107
+ throw errors.runtimeNotProvided(name);
108
+ }
109
+
110
+ const { transaction, networkState } = executionContext.witnessInput();
111
+ const { methodIdResolver } = runtime;
63
112
 
64
- if (input === undefined) {
65
- throw errors.methodInputsNotProvided();
113
+ // Assert that the given transaction has the correct methodId
114
+ const thisMethodId = Field(methodIdResolver.getMethodId(name, methodName));
115
+ if (!thisMethodId.isConstant()) {
116
+ throw errors.fieldNotConstant("methodId");
66
117
  }
67
118
 
68
- const transactionHash = input.transaction.hash();
69
- const networkStateHash = input.networkState.hash();
119
+ transaction.methodId.assertEquals(
120
+ thisMethodId,
121
+ "Runtimemethod called with wrong methodId on the transaction object"
122
+ );
123
+
124
+ /**
125
+ * Use the type info obtained previously to convert
126
+ * the args passed to fields
127
+ */
128
+ const { fields } = MethodParameterEncoder.fromMethod(
129
+ this,
130
+ methodName
131
+ ).encode(args);
132
+
133
+ // Assert that the argsHash that has been signed matches the given arguments
134
+ const argsHash = Poseidon.hash(fields);
135
+
136
+ transaction.argsHash.assertEquals(
137
+ argsHash,
138
+ "argsHash and therefore arguments of transaction and runtime call does not match"
139
+ );
140
+
141
+ const isMessage = Bool(options.invocationType === "INCOMING_MESSAGE");
142
+ transaction.assertTransactionType(Bool(isMessage));
143
+
144
+ const transactionHash = transaction.hash();
145
+ const networkStateHash = networkState.hash();
70
146
 
71
147
  return new MethodPublicOutput({
72
148
  stateTransitionsHash,
73
149
  status,
74
150
  transactionHash,
75
151
  networkStateHash,
152
+ isMessage,
153
+ eventsHash,
76
154
  });
77
155
  };
78
156
 
@@ -92,6 +170,8 @@ export function combineMethodName(
92
170
  }
93
171
 
94
172
  export const runtimeMethodMetadataKey = "yab-method";
173
+ export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
174
+ export const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
95
175
 
96
176
  /**
97
177
  * Checks the metadata of the provided runtime module and its method,
@@ -110,26 +190,50 @@ export function isRuntimeMethod(
110
190
  );
111
191
  }
112
192
 
113
- export function runtimeMethod() {
193
+ export type RuntimeMethodInvocationType = "SIGNATURE" | "INCOMING_MESSAGE";
194
+
195
+ function runtimeMethodInternal(options: {
196
+ invocationType: RuntimeMethodInvocationType;
197
+ }) {
114
198
  return (
115
199
  target: RuntimeModule<unknown>,
116
200
  methodName: string,
117
- descriptor: PropertyDescriptor
201
+ descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<any>>
118
202
  ) => {
203
+ checkArgsProvable(target, methodName);
119
204
  const executionContext = container.resolve<RuntimeMethodExecutionContext>(
120
205
  RuntimeMethodExecutionContext
121
206
  );
122
207
 
208
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
209
+ let data: string[] | undefined = Reflect.getMetadata(
210
+ runtimeMethodNamesMetadataKey,
211
+ target
212
+ );
213
+ if (data !== undefined) {
214
+ data.push(methodName);
215
+ } else {
216
+ data = [methodName];
217
+ }
218
+ Reflect.defineMetadata(runtimeMethodNamesMetadataKey, data, target);
219
+
123
220
  Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
124
221
 
222
+ Reflect.defineMetadata(
223
+ runtimeMethodTypeMetadataKey,
224
+ options.invocationType,
225
+ target,
226
+ methodName
227
+ );
228
+
125
229
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
126
230
  const simulatedMethod = descriptor.value as DecoratedMethod;
127
231
 
128
- descriptor.value = function value(
232
+ descriptor.value = async function value(
129
233
  this: RuntimeModule<unknown>,
130
- ...args: FlexibleProvable<unknown>[]
234
+ ...args: ArgumentTypes
131
235
  ) {
132
- const constructorName = this.constructor.name;
236
+ const constructorName = this.name!;
133
237
 
134
238
  /**
135
239
  * If its a top level method call, wrap it into a wrapped method,
@@ -141,6 +245,7 @@ export function runtimeMethod() {
141
245
  const simulatedWrappedMethod = Reflect.apply(toWrappedMethod, this, [
142
246
  methodName,
143
247
  simulatedMethod,
248
+ options,
144
249
  ]);
145
250
 
146
251
  /**
@@ -148,7 +253,7 @@ export function runtimeMethod() {
148
253
  * RuntimeMethodExecutionContext state, meaning it enters and exits
149
254
  * the context properly.
150
255
  */
151
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
+
152
257
  async function prover(this: ZkProgrammable<any, any>) {
153
258
  executionContext.beforeMethod(constructorName, methodName, args);
154
259
  const innerProver = toProver(
@@ -157,7 +262,6 @@ export function runtimeMethod() {
157
262
  false,
158
263
  ...args
159
264
  ).bind(this);
160
- // eslint-disable-next-line @typescript-eslint/init-declarations
161
265
  let result: Awaited<ReturnType<typeof innerProver>>;
162
266
  try {
163
267
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -172,16 +276,15 @@ export function runtimeMethod() {
172
276
  executionContext.beforeMethod(constructorName, methodName, args);
173
277
 
174
278
  if (executionContext.isTopLevel) {
175
- if (!this.runtime) {
279
+ if (!this.parent) {
176
280
  throw errors.runtimeNotProvided(constructorName);
177
281
  }
178
- executionContext.setProver(prover.bind(this.runtime.zkProgrammable));
282
+ executionContext.setProver(prover.bind(this.parent.zkProgrammable));
179
283
  }
180
284
 
181
- // eslint-disable-next-line @typescript-eslint/init-declarations
182
285
  let result: unknown;
183
286
  try {
184
- result = Reflect.apply(simulatedMethod, this, args);
287
+ result = await Reflect.apply(simulatedMethod, this, args);
185
288
  } finally {
186
289
  executionContext.afterMethod();
187
290
  }
@@ -190,3 +293,15 @@ export function runtimeMethod() {
190
293
  };
191
294
  };
192
295
  }
296
+
297
+ export function runtimeMessage() {
298
+ return runtimeMethodInternal({
299
+ invocationType: "INCOMING_MESSAGE",
300
+ });
301
+ }
302
+
303
+ export function runtimeMethod() {
304
+ return runtimeMethodInternal({
305
+ invocationType: "SIGNATURE",
306
+ });
307
+ }
@@ -0,0 +1,108 @@
1
+ import { filterNonUndefined } from "@proto-kit/common";
2
+ import { stringToField, RuntimeMethodIdMapping } from "@proto-kit/protocol";
3
+ import { Poseidon } from "o1js";
4
+ import { inject, injectable } from "tsyringe";
5
+
6
+ import {
7
+ RuntimeMethodInvocationType,
8
+ runtimeMethodTypeMetadataKey,
9
+ } from "../method/runtimeMethod";
10
+
11
+ import type { Runtime, RuntimeModulesRecord } from "./Runtime";
12
+
13
+ /**
14
+ * Please see `getMethodId` to learn more about
15
+ * methodId encoding
16
+ */
17
+ @injectable()
18
+ export class MethodIdResolver {
19
+ private readonly dictionary: {
20
+ [key: string]: { moduleName: string; methodName: string };
21
+ } = {};
22
+
23
+ public constructor(
24
+ @inject("Runtime") private readonly runtime: Runtime<RuntimeModulesRecord>
25
+ ) {
26
+ this.dictionary = runtime.runtimeModuleNames.reduce<
27
+ Record<string, { moduleName: string; methodName: string }>
28
+ >((dict, moduleName) => {
29
+ this.runtime.assertIsValidModuleName(moduleName);
30
+
31
+ runtime.resolve(moduleName).runtimeMethodNames.forEach((methodName) => {
32
+ dict[this.getMethodId(moduleName, methodName).toString()] = {
33
+ moduleName,
34
+ methodName,
35
+ };
36
+ });
37
+
38
+ return dict;
39
+ }, {});
40
+ }
41
+
42
+ /**
43
+ * The purpose of this method is to provide a dictionary where
44
+ * we can look up properties like methodId and invocationType
45
+ * for each runtimeMethod using their module name and method name
46
+ */
47
+ public methodIdMap(): RuntimeMethodIdMapping {
48
+ const methodIdResolver =
49
+ this.runtime.dependencyContainer.resolve<MethodIdResolver>(
50
+ "MethodIdResolver"
51
+ );
52
+
53
+ const rawMappings = this.runtime.moduleNames.flatMap((moduleName) => {
54
+ const module = this.runtime.resolve(moduleName);
55
+ return module.runtimeMethodNames.map((method) => {
56
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
57
+ const type = Reflect.getMetadata(
58
+ runtimeMethodTypeMetadataKey,
59
+ module,
60
+ method
61
+ ) as RuntimeMethodInvocationType | undefined;
62
+
63
+ if (type !== undefined) {
64
+ return {
65
+ name: `${moduleName}.${method}`,
66
+ methodId: methodIdResolver.getMethodId(moduleName, method),
67
+ type,
68
+ } as const;
69
+ }
70
+
71
+ return undefined;
72
+ });
73
+ });
74
+
75
+ return rawMappings
76
+ .filter(filterNonUndefined)
77
+ .reduce<RuntimeMethodIdMapping>((acc, entry) => {
78
+ acc[entry.name] = {
79
+ methodId: entry.methodId,
80
+ type: entry.type,
81
+ };
82
+ return acc;
83
+ }, {});
84
+ }
85
+
86
+ public getMethodNameFromId(methodId: bigint): [string, string] | undefined {
87
+ const methodPath = this.dictionary[methodId.toString()];
88
+
89
+ if (methodPath === undefined) {
90
+ return undefined;
91
+ }
92
+
93
+ const { moduleName, methodName } = methodPath;
94
+
95
+ this.runtime.assertIsValidModuleName(moduleName);
96
+
97
+ return [moduleName, methodName];
98
+ }
99
+
100
+ public getMethodId(moduleName: string, methodName: string): bigint {
101
+ this.runtime.assertIsValidModuleName(moduleName);
102
+
103
+ return Poseidon.hash([
104
+ stringToField(moduleName),
105
+ stringToField(methodName),
106
+ ]).toBigInt();
107
+ }
108
+ }