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

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 (110) 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 +12 -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/OutgoingMessages.d.ts +215 -0
  10. package/dist/messages/OutgoingMessages.d.ts.map +1 -0
  11. package/dist/messages/OutgoingMessages.js +66 -0
  12. package/dist/messages/OutgoingMessages.js.map +1 -0
  13. package/dist/method/MethodParameterEncoder.d.ts +26 -0
  14. package/dist/method/MethodParameterEncoder.d.ts.map +1 -0
  15. package/dist/method/MethodParameterEncoder.js +169 -0
  16. package/dist/method/MethodParameterEncoder.js.map +1 -0
  17. package/dist/method/runtimeMethod.d.ts +22 -5
  18. package/dist/method/runtimeMethod.d.ts.map +1 -1
  19. package/dist/method/runtimeMethod.js +79 -24
  20. package/dist/method/runtimeMethod.js.map +1 -0
  21. package/dist/module/decorator.js +1 -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 +22 -28
  28. package/dist/runtime/Runtime.d.ts.map +1 -1
  29. package/dist/runtime/Runtime.js +116 -70
  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 +23 -14
  36. package/dist/runtime/RuntimeModule.d.ts.map +1 -1
  37. package/dist/runtime/RuntimeModule.js +47 -10
  38. package/dist/runtime/RuntimeModule.js.map +1 -0
  39. package/dist/state/InMemoryStateService.d.ts +11 -10
  40. package/dist/state/InMemoryStateService.d.ts.map +1 -1
  41. package/dist/state/InMemoryStateService.js +11 -8
  42. package/dist/state/InMemoryStateService.js.map +1 -0
  43. package/jest.config.cjs +12 -1
  44. package/package.json +10 -11
  45. package/src/factories/MethodIdFactory.ts +15 -0
  46. package/src/index.ts +5 -7
  47. package/src/messages/OutgoingMessages.ts +122 -0
  48. package/src/method/MethodParameterEncoder.ts +260 -0
  49. package/src/method/runtimeMethod.ts +146 -31
  50. package/src/runtime/MethodIdResolver.ts +108 -0
  51. package/src/runtime/Runtime.ts +191 -112
  52. package/src/runtime/RuntimeEnvironment.ts +16 -0
  53. package/src/runtime/RuntimeModule.ts +77 -27
  54. package/src/state/InMemoryStateService.ts +14 -18
  55. package/test/Runtime.test.ts +69 -36
  56. package/test/TestingRuntime.ts +43 -0
  57. package/test/messages/message.test.ts +42 -0
  58. package/test/method/MethodParameterEncoder.test.ts +121 -0
  59. package/test/method/runtimeMethod-fail.test.ts +50 -0
  60. package/{src/method/decorator.test.ts → test/method/runtimeMethod.test.ts} +3 -3
  61. package/test/modules/Admin.ts +4 -4
  62. package/test/modules/Balances.test.ts +92 -78
  63. package/test/modules/Balances.ts +19 -16
  64. package/test/modules/MethodIdResolver.test.ts +73 -0
  65. package/test/modules/State.test.ts +81 -0
  66. package/test/runtimeMethod.test.ts +192 -20
  67. package/test/tsconfig.json +7 -0
  68. package/tsconfig.json +2 -2
  69. package/dist/chain/Chain.d.ts +0 -109
  70. package/dist/chain/Chain.d.ts.map +0 -1
  71. package/dist/chain/Chain.js +0 -229
  72. package/dist/method/MethodExecutionContext.d.ts +0 -73
  73. package/dist/method/MethodExecutionContext.d.ts.map +0 -1
  74. package/dist/method/MethodExecutionContext.js +0 -112
  75. package/dist/method/MethodParameterDecoder.d.ts +0 -22
  76. package/dist/method/MethodParameterDecoder.d.ts.map +0 -1
  77. package/dist/method/MethodParameterDecoder.js +0 -33
  78. package/dist/method/RuntimeMethodExecutionContext.d.ts +0 -57
  79. package/dist/method/RuntimeMethodExecutionContext.d.ts.map +0 -1
  80. package/dist/method/RuntimeMethodExecutionContext.js +0 -92
  81. package/dist/method/assert.d.ts +0 -12
  82. package/dist/method/assert.d.ts.map +0 -1
  83. package/dist/method/assert.js +0 -23
  84. package/dist/method/decorator.d.ts +0 -45
  85. package/dist/method/decorator.d.ts.map +0 -1
  86. package/dist/method/decorator.js +0 -140
  87. package/dist/state/State.d.ts +0 -65
  88. package/dist/state/State.d.ts.map +0 -1
  89. package/dist/state/State.js +0 -114
  90. package/dist/state/StateMap.d.ts +0 -37
  91. package/dist/state/StateMap.d.ts.map +0 -1
  92. package/dist/state/StateMap.js +0 -56
  93. package/dist/state/StateServiceProvider.d.ts +0 -10
  94. package/dist/state/StateServiceProvider.d.ts.map +0 -1
  95. package/dist/state/StateServiceProvider.js +0 -34
  96. package/dist/state/decorator.d.ts +0 -7
  97. package/dist/state/decorator.d.ts.map +0 -1
  98. package/dist/state/decorator.js +0 -42
  99. package/src/method/MethodParameterDecoder.ts +0 -68
  100. package/src/method/RuntimeMethodExecutionContext.ts +0 -111
  101. package/src/method/assert.test.ts +0 -49
  102. package/src/method/assert.ts +0 -27
  103. package/src/state/State.ts +0 -154
  104. package/src/state/StateMap.ts +0 -69
  105. package/src/state/StateServiceProvider.ts +0 -24
  106. package/src/state/decorator.ts +0 -65
  107. package/test/state/MerkleTree.test.ts +0 -95
  108. package/test/state/MockAsyncMerkleStore.ts +0 -28
  109. package/test/transaction.test.ts +0 -82
  110. package/tsconfig.test.json +0 -9
package/src/index.ts CHANGED
@@ -1,12 +1,10 @@
1
- export * from "./method/RuntimeMethodExecutionContext";
2
- export * from "./method/assert";
3
1
  export * from "./method/runtimeMethod";
4
2
  export * from "./module/decorator";
5
3
  export * from "./runtime/RuntimeModule";
4
+ export * from "./runtime/RuntimeEnvironment";
6
5
  export * from "./runtime/Runtime";
7
6
  export * from "./state/InMemoryStateService";
8
- export * from "./state/State";
9
- export * from "./state/StateMap";
10
- export * from "./state/StateServiceProvider";
11
- export * from "./state/decorator";
12
- export * from "./method/MethodParameterDecoder";
7
+ export * from "./method/MethodParameterEncoder";
8
+ export * from "./runtime/MethodIdResolver";
9
+ export * from "./factories/MethodIdFactory";
10
+ export * from "./messages/OutgoingMessages";
@@ -0,0 +1,122 @@
1
+ import {
2
+ Field,
3
+ FlexibleProvablePure,
4
+ InferProvable,
5
+ Struct,
6
+ TokenId,
7
+ } from "o1js";
8
+ import {
9
+ OutgoingMessageEvent,
10
+ OutgoingMessageKeyStruct,
11
+ PROTOKIT_FIELD_PREFIXES,
12
+ RuntimeMethodExecutionContext,
13
+ state as stateDecorator,
14
+ StateMap,
15
+ WithPath,
16
+ WithStateServiceProvider,
17
+ } from "@proto-kit/protocol";
18
+ // eslint-disable-next-line import/no-extraneous-dependencies
19
+ import { Mixin } from "ts-mixer";
20
+ import { prefixToField, StringKeyOf } from "@proto-kit/common";
21
+ import { container } from "tsyringe";
22
+
23
+ export type OutgoingMessagesRecord = Record<string, FlexibleProvablePure<any>>;
24
+
25
+ export const outgoingMessage = stateDecorator;
26
+
27
+ export class OutgoingMessages<
28
+ Messages extends OutgoingMessagesRecord,
29
+ > extends Mixin(WithPath, WithStateServiceProvider) {
30
+ public readonly eventTypes: Record<
31
+ string,
32
+ {
33
+ messageType: FlexibleProvablePure<{ messageType: Field; value: any }>;
34
+ eventType: FlexibleProvablePure<{
35
+ key: OutgoingMessageKeyStruct;
36
+ value: any;
37
+ messageType: Field;
38
+ }>;
39
+ }
40
+ >;
41
+
42
+ public constructor(private readonly messages: Messages) {
43
+ super();
44
+ this.eventTypes = this.computeEventTypes();
45
+ }
46
+
47
+ private counterState() {
48
+ const state = new StateMap(Field, Field);
49
+ state.path = PROTOKIT_FIELD_PREFIXES.OUTGOING_MESSAGE_COUNTER_PATH;
50
+ state.stateServiceProvider = this.stateServiceProvider;
51
+ return state;
52
+ }
53
+
54
+ public static getEventName(key: string) {
55
+ return `outgoing-${key}`;
56
+ }
57
+
58
+ public computeEventTypes() {
59
+ return Object.fromEntries(
60
+ Object.entries(this.messages).map(([key, type]) => {
61
+ class OutgoingMessageEventStruct extends Struct({
62
+ key: OutgoingMessageKeyStruct,
63
+ value: type,
64
+ messageType: Field,
65
+ }) {}
66
+
67
+ class OutgoingMessageStruct extends Struct({
68
+ value: type,
69
+ messageType: Field,
70
+ }) {}
71
+
72
+ return [
73
+ OutgoingMessages.getEventName(key),
74
+ {
75
+ messageType: OutgoingMessageStruct,
76
+ eventType: OutgoingMessageEventStruct,
77
+ },
78
+ ];
79
+ })
80
+ );
81
+ }
82
+
83
+ private emitEvent<Key extends StringKeyOf<Messages>>(
84
+ eventName: string,
85
+ value: OutgoingMessageEvent<InferProvable<Messages[Key]>>
86
+ ) {
87
+ const outgoingMessageType = this.eventTypes[eventName].eventType;
88
+
89
+ return container
90
+ .resolve(RuntimeMethodExecutionContext)
91
+ .addEvent<
92
+ OutgoingMessageEvent<InferProvable<Messages[Key]>>
93
+ >(outgoingMessageType, value, eventName);
94
+ }
95
+
96
+ public async emitMessage<Key extends StringKeyOf<Messages>>(
97
+ key: Key,
98
+ value: InferProvable<Messages[Key]>,
99
+ tokenId: Field = TokenId.default
100
+ ) {
101
+ const eventName = OutgoingMessages.getEventName(key);
102
+
103
+ const stateMap = new StateMap(
104
+ OutgoingMessageKeyStruct,
105
+ this.eventTypes[eventName].messageType
106
+ );
107
+ stateMap.path = PROTOKIT_FIELD_PREFIXES.OUTGOING_MESSAGE_BASE_PATH;
108
+ stateMap.stateServiceProvider = this.stateServiceProvider;
109
+
110
+ const counterState = this.counterState();
111
+ const counterOption = await counterState.get(tokenId);
112
+ const counter = counterOption.orElse(Field(0));
113
+
114
+ const messageKey = { index: counter, tokenId };
115
+ const messageType = prefixToField(key);
116
+
117
+ await counterState.set(tokenId, counter.add(1));
118
+ await stateMap.set(messageKey, { messageType, value });
119
+
120
+ this.emitEvent(eventName, { key: messageKey, value, messageType });
121
+ }
122
+ }
@@ -0,0 +1,260 @@
1
+ /* eslint-disable @typescript-eslint/consistent-type-assertions */
2
+ import {
3
+ Field,
4
+ Proof,
5
+ Provable,
6
+ DynamicProof,
7
+ FlexibleProvablePure,
8
+ } from "o1js";
9
+ import {
10
+ ArgumentTypes,
11
+ ProofTypes,
12
+ ToFieldableStatic,
13
+ TypedClass,
14
+ filterNonUndefined,
15
+ } from "@proto-kit/common";
16
+
17
+ import type { RuntimeModule } from "../runtime/RuntimeModule";
18
+
19
+ const errors = {
20
+ fieldLengthNotMatching: (expected: number, actual: number) =>
21
+ new Error(`Expected ${expected} field elements, got ${actual}`),
22
+
23
+ typeNotCompatible: (name: string, error?: string) =>
24
+ new Error(
25
+ `Cannot decode type ${name}, it has to be either a Struct, CircuitValue or built-in snarkyjs type.${
26
+ error !== undefined ? `Caused by: ${error}` : ""
27
+ }`
28
+ ),
29
+ };
30
+
31
+ type ArgumentType =
32
+ | FlexibleProvablePure<any>
33
+ | typeof Proof<unknown, unknown>
34
+ | typeof DynamicProof<unknown, unknown>;
35
+
36
+ type ArgTypeArray = ArgumentType[];
37
+
38
+ type ArgArray = ArgumentTypes[];
39
+
40
+ function isProofType(type: unknown): type is typeof Proof {
41
+ return (type as unknown as TypedClass<unknown>).prototype instanceof Proof;
42
+ }
43
+
44
+ function isDynamicProofType(type: unknown): type is typeof DynamicProof {
45
+ return (
46
+ (type as unknown as TypedClass<unknown>).prototype instanceof DynamicProof
47
+ );
48
+ }
49
+
50
+ function isProofBaseType(
51
+ type: unknown
52
+ ): type is typeof Proof | typeof DynamicProof {
53
+ return isProofType(type) || isDynamicProofType(type);
54
+ }
55
+
56
+ function getAllPropertyNamesOfPrototypeChain(type: unknown): string[] {
57
+ if (type === undefined || type === null) {
58
+ return [];
59
+ }
60
+ return Object.getOwnPropertyNames(type).concat(
61
+ ...getAllPropertyNamesOfPrototypeChain(Object.getPrototypeOf(type))
62
+ );
63
+ }
64
+
65
+ export function isFlexibleProvablePure(
66
+ type: unknown
67
+ ): type is FlexibleProvablePure<unknown> {
68
+ // The required properties are defined on the prototype for Structs and CircuitValues
69
+ // but on the constructor function itself for Field and Bool
70
+ // For aliases like Balance in library, it can even be 2 steps upwards the prototype chain
71
+ const props = getAllPropertyNamesOfPrototypeChain(type);
72
+ const mandatory = ["toFields", "fromFields", "sizeInFields"];
73
+ return mandatory.every((prop) => props.includes(prop));
74
+ }
75
+
76
+ export function checkArgsProvable(
77
+ target: RuntimeModule<unknown>,
78
+ methodName: string
79
+ ) {
80
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
81
+ const paramtypes: ArgTypeArray = Reflect.getMetadata(
82
+ "design:paramtypes",
83
+ target,
84
+ methodName
85
+ );
86
+
87
+ if (paramtypes === undefined) {
88
+ throw new Error(
89
+ `Method with name ${methodName} doesn't exist on this module`
90
+ );
91
+ }
92
+
93
+ const indizes = paramtypes
94
+ .map((type, index) => {
95
+ if (isProofBaseType(type) || isFlexibleProvablePure(type)) {
96
+ return undefined;
97
+ }
98
+ return `${index}`;
99
+ })
100
+ .filter(filterNonUndefined);
101
+ if (indizes.length > 0) {
102
+ const indexString = indizes.reduce((a, b) => `${a}, ${b}`);
103
+ throw new Error(
104
+ `Not all arguments of method '${target.name}.${methodName}' are provable types or proofs (indizes: [${indexString}])`
105
+ );
106
+ }
107
+ return paramtypes;
108
+ }
109
+
110
+ export class MethodParameterEncoder {
111
+ public static fromMethod(target: RuntimeModule<unknown>, methodName: string) {
112
+ const paramtypes = checkArgsProvable(target, methodName);
113
+
114
+ return new MethodParameterEncoder(paramtypes);
115
+ }
116
+
117
+ public static fieldSize(type: ArgumentType): number | undefined {
118
+ if (isProofBaseType(type)) {
119
+ return (
120
+ (MethodParameterEncoder.fieldSize(type.publicInputType) ?? 0) +
121
+ (MethodParameterEncoder.fieldSize(type.publicOutputType) ?? 0)
122
+ );
123
+ }
124
+ // as any, since we shouldn't be using this workaround in the first place
125
+ return (type as FlexibleProvablePure<unknown>).sizeInFields();
126
+ }
127
+
128
+ public constructor(private readonly types: ArgTypeArray) {}
129
+
130
+ public decode(fields: Field[], auxiliary: string[]): Promise<ArgArray> {
131
+ if (fields.length < this.fieldSize()) {
132
+ throw errors.fieldLengthNotMatching(this.fieldSize(), fields.length);
133
+ }
134
+
135
+ let stack = fields.slice();
136
+ const auxiliaryStack = auxiliary.slice();
137
+
138
+ return Promise.all(
139
+ this.types.map((type) => {
140
+ const numberFieldsNeeded = MethodParameterEncoder.fieldSize(type) ?? -1;
141
+ if (numberFieldsNeeded === -1) {
142
+ throw errors.typeNotCompatible(type.constructor.name);
143
+ }
144
+ const structFields = stack.slice(0, numberFieldsNeeded);
145
+ stack = stack.slice(numberFieldsNeeded);
146
+
147
+ // Decode proof
148
+ if (isProofBaseType(type)) {
149
+ const auxiliaryData = auxiliaryStack.shift();
150
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
151
+ const proofData: { proof: string; maxProofsVerified: 0 | 1 | 2 } =
152
+ JSON.parse(auxiliaryData!);
153
+
154
+ const inputFieldSize = MethodParameterEncoder.fieldSize(
155
+ type.publicInputType
156
+ )!;
157
+ const input = structFields
158
+ .slice(0, inputFieldSize)
159
+ .map((x) => x.toString());
160
+ const output = structFields
161
+ .slice(inputFieldSize)
162
+ .map((x) => x.toString());
163
+
164
+ // fromJSON has incompatible signature for Proof and DynamicProof
165
+ if (isProofType(type)) {
166
+ return type.fromJSON({
167
+ ...proofData,
168
+ publicInput: input,
169
+ publicOutput: output,
170
+ });
171
+ }
172
+ if (isDynamicProofType(type)) {
173
+ return type.fromJSON({
174
+ ...proofData,
175
+ publicInput: input,
176
+ publicOutput: output,
177
+ });
178
+ }
179
+ }
180
+
181
+ return (type as FlexibleProvablePure<unknown>).fromFields(
182
+ structFields
183
+ ) as any;
184
+ })
185
+ );
186
+ }
187
+
188
+ /**
189
+ * Variant of encode() for provable code that skips the unprovable
190
+ * json encoding
191
+ */
192
+ public encode(args: ArgumentTypes) {
193
+ /**
194
+ * Use the type info obtained previously to convert
195
+ * the args passed to fields
196
+ */
197
+ return args
198
+ .map((argument, index) => {
199
+ if (argument instanceof Proof || argument instanceof DynamicProof) {
200
+ const argumentType = this.types[index] as ProofTypes;
201
+
202
+ const { publicOutputType, publicInputType } = argumentType;
203
+
204
+ const inputFields =
205
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
206
+ publicInputType?.toFields(argument.publicInput as any) ?? [];
207
+
208
+ const outputFields =
209
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
210
+ publicOutputType?.toFields(argument.publicOutput as any) ?? [];
211
+
212
+ let auxiliary = "";
213
+
214
+ // Has to be asProver, because this function will be called by runtimeMethod
215
+ // to transform the args into a Field[] to compute the argsHash
216
+ // In this case, the auxiliary might be empty, but it isn't used by that method anyways
217
+ Provable.asProver(() => {
218
+ const jsonProof = argument.toJSON();
219
+ auxiliary = JSON.stringify({
220
+ proof: jsonProof.proof,
221
+ maxProofsVerified: jsonProof.maxProofsVerified,
222
+ });
223
+ });
224
+
225
+ return {
226
+ fields: [...inputFields, ...outputFields],
227
+ auxiliary,
228
+ };
229
+ }
230
+
231
+ const argumentType = this.types[index] as ToFieldableStatic;
232
+ return {
233
+ fields: argumentType.toFields(argument),
234
+ auxiliary: undefined,
235
+ };
236
+ })
237
+ .reduce<{
238
+ fields: Field[];
239
+ auxiliary: string[];
240
+ }>(
241
+ (a, b) => {
242
+ return {
243
+ fields: [...a.fields, ...b.fields],
244
+ auxiliary:
245
+ b.auxiliary !== undefined
246
+ ? [...a.auxiliary, b.auxiliary]
247
+ : a.auxiliary,
248
+ };
249
+ },
250
+ { fields: [], auxiliary: [] }
251
+ );
252
+ }
253
+
254
+ public fieldSize(): number {
255
+ return this.types
256
+ .map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
257
+ .reduce((a, b) => a + b, 0);
258
+ }
259
+ }
260
+ /* eslint-enable @typescript-eslint/consistent-type-assertions */
@@ -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
+ }