@proto-kit/module 0.1.1-develop.456 → 0.1.1-develop.600

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ export * from "./runtime/RuntimeEnvironment";
5
5
  export * from "./runtime/Runtime";
6
6
  export * from "./state/InMemoryStateService";
7
7
  export * from "./state/decorator";
8
- export * from "./method/MethodParameterDecoder";
8
+ export * from "./method/MethodParameterEncoder";
9
9
  export * from "./runtime/MethodIdResolver";
10
10
  export * from "./factories/MethodIdFactory";
11
11
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -5,6 +5,6 @@ export * from "./runtime/RuntimeEnvironment";
5
5
  export * from "./runtime/Runtime";
6
6
  export * from "./state/InMemoryStateService";
7
7
  export * from "./state/decorator";
8
- export * from "./method/MethodParameterDecoder";
8
+ export * from "./method/MethodParameterEncoder";
9
9
  export * from "./runtime/MethodIdResolver";
10
10
  export * from "./factories/MethodIdFactory";
@@ -0,0 +1,17 @@
1
+ import { Field, FlexibleProvable, ProvableExtended } from "o1js";
2
+ import { ArgumentTypes } from "@proto-kit/common";
3
+ import type { RuntimeModule } from "../runtime/RuntimeModule";
4
+ export declare class MethodParameterEncoder {
5
+ private readonly types;
6
+ static fromMethod(target: RuntimeModule<unknown>, methodName: string): MethodParameterEncoder;
7
+ static fieldSize(type: ProvableExtended<unknown>): number | undefined;
8
+ private constructor();
9
+ decode(argsJSON: string[]): FlexibleProvable<unknown>[];
10
+ decodeFields(fields: Field[]): ArgumentTypes;
11
+ encode(args: ArgumentTypes): {
12
+ argsFields: Field[];
13
+ argsJSON: string[];
14
+ };
15
+ get fieldSize(): number;
16
+ }
17
+ //# sourceMappingURL=MethodParameterEncoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MethodParameterEncoder.d.ts","sourceRoot":"","sources":["../../src/method/MethodParameterEncoder.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAS,gBAAgB,EAAE,MAAM,MAAM,CAAC;AACxE,OAAO,EACL,aAAa,EAKd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAgB9D,qBAAa,sBAAsB;IAuBb,OAAO,CAAC,QAAQ,CAAC,KAAK;WAtB5B,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM;WAiB7D,SAAS,CAAC,IAAI,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS;IAK5E,OAAO;IAEA,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,EAAE;IAsBvD,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,aAAa;IAkB5C,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG;QAClC,UAAU,EAAE,KAAK,EAAE,CAAC;QACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB;IAyCD,IAAW,SAAS,IAAI,MAAM,CAI7B;CACF"}
@@ -0,0 +1,90 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ import { Proof } from "o1js";
3
+ const errors = {
4
+ fieldLengthNotMatching: (expected, actual) => new Error(`Expected ${expected} field elements, got ${actual}`),
5
+ typeNotCompatible: (name, error) => new Error(`Cannot decode type ${name}, it has to be either a Struct, CircuitValue or built-in snarkyjs type.${error !== undefined ? `Caused by: ${error}` : ""}`),
6
+ };
7
+ export class MethodParameterEncoder {
8
+ static fromMethod(target, methodName) {
9
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
10
+ const paramtypes = Reflect.getMetadata("design:paramtypes", target, methodName);
11
+ if (paramtypes === undefined) {
12
+ throw new Error(`Method with name ${methodName} doesn't exist on this module`);
13
+ }
14
+ return new MethodParameterEncoder(paramtypes);
15
+ }
16
+ static fieldSize(type) {
17
+ // as any, since we shouldn't be using this workaround in the first place
18
+ return type.prototype._fields?.length ?? type.sizeInFields?.();
19
+ }
20
+ constructor(types) {
21
+ this.types = types;
22
+ }
23
+ decode(argsJSON) {
24
+ return this.types.map((type, index) => {
25
+ // eslint-disable-next-line @typescript-eslint/init-declarations
26
+ let value;
27
+ try {
28
+ // eslint-disable-next-line max-len
29
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
30
+ value = type.fromJSON(JSON.parse(argsJSON[index]));
31
+ }
32
+ catch (e) {
33
+ if (e instanceof Error) {
34
+ throw errors.typeNotCompatible(type.constructor.name, e.message);
35
+ }
36
+ throw errors.typeNotCompatible(type.constructor.name);
37
+ }
38
+ return value;
39
+ });
40
+ }
41
+ decodeFields(fields) {
42
+ if (fields.length < this.fieldSize) {
43
+ throw errors.fieldLengthNotMatching(this.fieldSize, fields.length);
44
+ }
45
+ let stack = fields.slice();
46
+ return this.types.map((type) => {
47
+ const numberFieldsNeeded = MethodParameterEncoder.fieldSize(type) ?? -1;
48
+ if (numberFieldsNeeded === -1) {
49
+ throw errors.typeNotCompatible(type.constructor.name);
50
+ }
51
+ const structFields = stack.slice(0, numberFieldsNeeded);
52
+ stack = stack.slice(numberFieldsNeeded);
53
+ return type.fromFields(structFields, []);
54
+ });
55
+ }
56
+ encode(args) {
57
+ /**
58
+ * Use the type info obtained previously to convert
59
+ * the args passed to fields
60
+ */
61
+ const argsFields = args.flatMap((argument, index) => {
62
+ if (argument instanceof Proof) {
63
+ const argumentType = this.types[index];
64
+ const publicOutputType = argumentType?.publicOutputType;
65
+ const publicInputType = argumentType?.publicInputType;
66
+ const inputFields = publicInputType?.toFields(argument.publicInput) ?? [];
67
+ const outputFields = publicOutputType?.toFields(argument.publicOutput) ?? [];
68
+ return [...inputFields, ...outputFields];
69
+ }
70
+ const argumentType = this.types[index];
71
+ return argumentType.toFields(argument);
72
+ });
73
+ const argsJSON = args.map((argument, index) => {
74
+ if (argument instanceof Proof) {
75
+ return JSON.stringify(argument.toJSON());
76
+ }
77
+ const argumentType = this.types[index];
78
+ return JSON.stringify(argumentType.toJSON(argument));
79
+ });
80
+ return {
81
+ argsFields,
82
+ argsJSON,
83
+ };
84
+ }
85
+ get fieldSize() {
86
+ return this.types
87
+ .map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
88
+ .reduce((a, b) => a + b, 0);
89
+ }
90
+ }
@@ -3,10 +3,13 @@ import { ArgumentTypes } from "@proto-kit/common";
3
3
  import type { RuntimeModule } from "../runtime/RuntimeModule.js";
4
4
  export declare function toStateTransitionsHash(stateTransitions: StateTransition<any>[]): import("o1js/dist/node/lib/field.js").Field;
5
5
  export type WrappedMethod = (...args: ArgumentTypes) => MethodPublicOutput;
6
- export declare function toWrappedMethod(this: RuntimeModule<unknown>, methodName: string, moduleMethod: (...args: ArgumentTypes) => unknown, methodArguments: ArgumentTypes): WrappedMethod;
6
+ export declare function toWrappedMethod(this: RuntimeModule<unknown>, methodName: string, moduleMethod: (...args: ArgumentTypes) => unknown, methodArguments: ArgumentTypes, options: {
7
+ invocationType: RuntimeMethodInvocationType;
8
+ }): WrappedMethod;
7
9
  export declare function combineMethodName(runtimeModuleName: string, methodName: string): string;
8
10
  export declare const runtimeMethodMetadataKey = "yab-method";
9
11
  export declare const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
12
+ export declare const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
10
13
  /**
11
14
  * Checks the metadata of the provided runtime module and its method,
12
15
  * to see if it has been decorated with @runtimeMethod()
@@ -16,5 +19,7 @@ export declare const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods"
16
19
  * @returns - If the provided method name is a runtime method or not
17
20
  */
18
21
  export declare function isRuntimeMethod(target: RuntimeModule<unknown>, propertyKey: string): boolean;
22
+ export type RuntimeMethodInvocationType = "SIGNATURE" | "INCOMING_MESSAGE";
23
+ export declare function runtimeMessage(): (target: RuntimeModule<unknown>, methodName: string, descriptor: PropertyDescriptor) => void;
19
24
  export declare function runtimeMethod(): (target: RuntimeModule<unknown>, methodName: string, descriptor: PropertyDescriptor) => void;
20
25
  //# sourceMappingURL=runtimeMethod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtimeMethod.d.ts","sourceRoot":"","sources":["../../src/method/runtimeMethod.ts"],"names":[],"mappings":"AASA,OAAO,EACL,eAAe,EAGf,kBAAkB,EAEnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAOL,aAAa,EAGd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAoBjE,wBAAgB,sBAAsB,CAEpC,gBAAgB,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,+CAczC;AAGD,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,EAAE,aAAa,KAAK,kBAAkB,CAAC;AAE3E,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAC5B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,CAAC,GAAG,IAAI,EAAE,aAAa,KAAK,OAAO,EACjD,eAAe,EAAE,aAAa,iBAqG/B;AAED,wBAAgB,iBAAiB,CAC/B,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,UAGnB;AAED,eAAO,MAAM,wBAAwB,eAAe,CAAC;AACrD,eAAO,MAAM,6BAA6B,8BAA8B,CAAC;AAEzE;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,EAC9B,WAAW,EAAE,MAAM,WAKpB;AAED,wBAAgB,aAAa,aAEjB,cAAc,OAAO,CAAC,cAClB,MAAM,cACN,kBAAkB,UAwFjC"}
1
+ {"version":3,"file":"runtimeMethod.d.ts","sourceRoot":"","sources":["../../src/method/runtimeMethod.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,eAAe,EAGf,kBAAkB,EAGnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAOL,aAAa,EAGd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAoBjE,wBAAgB,sBAAsB,CAEpC,gBAAgB,EAAE,eAAe,CAAC,GAAG,CAAC,EAAE,+CAczC;AAGD,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,EAAE,aAAa,KAAK,kBAAkB,CAAC;AAE3E,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,EAC5B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,CAAC,GAAG,IAAI,EAAE,aAAa,KAAK,OAAO,EACjD,eAAe,EAAE,aAAa,EAC9B,OAAO,EAAE;IACP,cAAc,EAAE,2BAA2B,CAAC;CAC7C,iBAiFF;AAED,wBAAgB,iBAAiB,CAC/B,iBAAiB,EAAE,MAAM,EACzB,UAAU,EAAE,MAAM,UAGnB;AAED,eAAO,MAAM,wBAAwB,eAAe,CAAC;AACrD,eAAO,MAAM,6BAA6B,8BAA8B,CAAC;AACzE,eAAO,MAAM,4BAA4B,kCAAkC,CAAC;AAE5E;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,EAC9B,WAAW,EAAE,MAAM,WAKpB;AAED,MAAM,MAAM,2BAA2B,GAAG,WAAW,GAAG,kBAAkB,CAAC;AAwG3E,wBAAgB,cAAc,iGAI7B;AAED,wBAAgB,aAAa,iGAI5B"}
@@ -1,8 +1,9 @@
1
1
  /* eslint-disable max-statements */
2
- import { Field, Poseidon, Proof, } from "o1js";
2
+ import { Bool, Field, Poseidon, } from "o1js";
3
3
  import { container } from "tsyringe";
4
4
  import { DefaultProvableHashList, ProvableStateTransition, MethodPublicOutput, RuntimeMethodExecutionContext, } from "@proto-kit/protocol";
5
5
  import { toProver, } from "@proto-kit/common";
6
+ import { MethodParameterEncoder } from "./MethodParameterEncoder";
6
7
  const errors = {
7
8
  runtimeNotProvided: (name) => new Error(`Runtime was not provided for module: ${name}`),
8
9
  methodInputsNotProvided: () => new Error("Method execution inputs not provided, provide them via context.inputs"),
@@ -18,7 +19,7 @@ stateTransitions) {
18
19
  .reduce((allStateTransitionsHashList, stateTransition) => allStateTransitionsHashList.push(stateTransition), stateTransitionsHashList)
19
20
  .toField();
20
21
  }
21
- export function toWrappedMethod(methodName, moduleMethod, methodArguments) {
22
+ export function toWrappedMethod(methodName, moduleMethod, methodArguments, options) {
22
23
  const executionContext = container.resolve(RuntimeMethodExecutionContext);
23
24
  const wrappedMethod = (...args) => {
24
25
  Reflect.apply(moduleMethod, this, args);
@@ -34,47 +35,35 @@ export function toWrappedMethod(methodName, moduleMethod, methodArguments) {
34
35
  if (runtime === undefined) {
35
36
  throw errors.runtimeNotProvided(name);
36
37
  }
37
- // Assert that the given transaction has the correct methodId
38
+ const { transaction, networkState } = executionContext.witnessInput();
38
39
  const { methodIdResolver } = runtime;
40
+ // Assert that the given transaction has the correct methodId
39
41
  const thisMethodId = Field(methodIdResolver.getMethodId(name, methodName));
40
42
  if (!thisMethodId.isConstant()) {
41
43
  throw errors.fieldNotConstant("methodId");
42
44
  }
43
- input.transaction.methodId.assertEquals(thisMethodId, "Runtimemethod called with wrong methodId on the transaction object");
44
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
45
- const parameterTypes = Reflect.getMetadata("design:paramtypes", this, methodName);
45
+ transaction.methodId.assertEquals(thisMethodId, "Runtimemethod called with wrong methodId on the transaction object");
46
46
  /**
47
47
  * Use the type info obtained previously to convert
48
48
  * the args passed to fields
49
49
  */
50
- const argsFields = args.flatMap((argument, index) => {
51
- if (argument instanceof Proof) {
52
- // eslint-disable-next-line max-len
53
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
54
- const argumentType = parameterTypes[index];
55
- const publicOutputType = argumentType?.publicOutputType;
56
- const publicInputType = argumentType?.publicInputType;
57
- const inputFields = publicInputType?.toFields(argument.publicInput) ?? [];
58
- const outputFields = publicOutputType?.toFields(argument.publicOutput) ?? [];
59
- return [...inputFields, ...outputFields];
60
- }
61
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
62
- const argumentType = parameterTypes[index];
63
- return argumentType.toFields(argument);
64
- });
50
+ const { argsFields } = MethodParameterEncoder.fromMethod(this, methodName).encode(args);
65
51
  // Assert that the argsHash that has been signed matches the given arguments
66
52
  // We can use js-if here, because methodArguments is statically sizes
67
53
  // i.e. the result of the if-statement will be the same for all executions
68
54
  // of this method
69
55
  const argsHash = methodArguments.length > 0 ? Poseidon.hash(argsFields) : Field(0);
70
- input.transaction.argsHash.assertEquals(argsHash, "argsHash and therefore arguments of transaction and runtime call does not match");
71
- const transactionHash = input.transaction.hash();
72
- const networkStateHash = input.networkState.hash();
56
+ transaction.argsHash.assertEquals(argsHash, "argsHash and therefore arguments of transaction and runtime call does not match");
57
+ const isMessage = Bool(options.invocationType === "INCOMING_MESSAGE");
58
+ transaction.assertTransactionType(Bool(isMessage));
59
+ const transactionHash = transaction.hash();
60
+ const networkStateHash = networkState.hash();
73
61
  return new MethodPublicOutput({
74
62
  stateTransitionsHash,
75
63
  status,
76
64
  transactionHash,
77
65
  networkStateHash,
66
+ isMessage,
78
67
  });
79
68
  };
80
69
  Object.defineProperty(wrappedMethod, "name", {
@@ -88,6 +77,7 @@ export function combineMethodName(runtimeModuleName, methodName) {
88
77
  }
89
78
  export const runtimeMethodMetadataKey = "yab-method";
90
79
  export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
80
+ export const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
91
81
  /**
92
82
  * Checks the metadata of the provided runtime module and its method,
93
83
  * to see if it has been decorated with @runtimeMethod()
@@ -99,7 +89,7 @@ export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
99
89
  export function isRuntimeMethod(target, propertyKey) {
100
90
  return Boolean(Reflect.getMetadata(runtimeMethodMetadataKey, target, propertyKey));
101
91
  }
102
- export function runtimeMethod() {
92
+ function runtimeMethodInternal(options) {
103
93
  return (target, methodName, descriptor) => {
104
94
  const executionContext = container.resolve(RuntimeMethodExecutionContext);
105
95
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -112,6 +102,7 @@ export function runtimeMethod() {
112
102
  }
113
103
  Reflect.defineMetadata(runtimeMethodNamesMetadataKey, data, target);
114
104
  Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
105
+ Reflect.defineMetadata(runtimeMethodTypeMetadataKey, options.invocationType, target, methodName);
115
106
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
116
107
  const simulatedMethod = descriptor.value;
117
108
  descriptor.value = function value(...args) {
@@ -127,6 +118,7 @@ export function runtimeMethod() {
127
118
  methodName,
128
119
  simulatedMethod,
129
120
  args,
121
+ options,
130
122
  ]);
131
123
  /**
132
124
  * Before the prover runs, make sure it is operating on the correct
@@ -167,3 +159,13 @@ export function runtimeMethod() {
167
159
  };
168
160
  };
169
161
  }
162
+ export function runtimeMessage() {
163
+ return runtimeMethodInternal({
164
+ invocationType: "INCOMING_MESSAGE",
165
+ });
166
+ }
167
+ export function runtimeMethod() {
168
+ return runtimeMethodInternal({
169
+ invocationType: "SIGNATURE",
170
+ });
171
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"MethodIdResolver.d.ts","sourceRoot":"","sources":["../../src/runtime/MethodIdResolver.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE/D;;;GAGG;AACH,qBACa,gBAAgB;IAMN,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAEpB;gBAG+B,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAoBrE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;IAiBnE,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;CAWnE"}
1
+ {"version":3,"file":"MethodIdResolver.d.ts","sourceRoot":"","sources":["../../src/runtime/MethodIdResolver.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAE/D;;;GAGG;AACH,qBACa,gBAAgB;IAMN,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAEpB;gBAG+B,OAAO,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAkBrE,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS;IAcnE,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;CAQnE"}
@@ -21,9 +21,8 @@ let MethodIdResolver = class MethodIdResolver {
21
21
  constructor(runtime) {
22
22
  this.runtime = runtime;
23
23
  this.dictionary = {};
24
- const { modules } = runtime.definition;
25
24
  this.dictionary = runtime.runtimeModuleNames.reduce((dict, moduleName) => {
26
- this.runtime.assertIsValidModuleName(modules, moduleName);
25
+ this.runtime.assertIsValidModuleName(moduleName);
27
26
  runtime.resolve(moduleName).runtimeMethodNames.forEach((methodName) => {
28
27
  dict[this.getMethodId(moduleName, methodName).toString()] = {
29
28
  moduleName,
@@ -39,11 +38,11 @@ let MethodIdResolver = class MethodIdResolver {
39
38
  return undefined;
40
39
  }
41
40
  const { moduleName, methodName } = methodPath;
42
- this.runtime.assertIsValidModuleName(this.runtime.definition.modules, moduleName);
41
+ this.runtime.assertIsValidModuleName(moduleName);
43
42
  return [moduleName, methodName];
44
43
  }
45
44
  getMethodId(moduleName, methodName) {
46
- this.runtime.assertIsValidModuleName(this.runtime.definition.modules, moduleName);
45
+ this.runtime.assertIsValidModuleName(moduleName);
47
46
  return Poseidon.hash([
48
47
  stringToField(moduleName),
49
48
  stringToField(methodName),
@@ -147,7 +147,7 @@ let Runtime = Runtime_1 = class Runtime extends ModuleContainer {
147
147
  return undefined;
148
148
  }
149
149
  const [moduleName, methodName] = methodDescriptor;
150
- this.assertIsValidModuleName(this.definition.modules, moduleName);
150
+ this.assertIsValidModuleName(moduleName);
151
151
  const module = this.resolve(moduleName);
152
152
  // eslint-disable-next-line max-len
153
153
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-unsafe-member-access
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@proto-kit/module",
3
3
  "license": "MIT",
4
4
  "private": false,
5
- "version": "0.1.1-develop.456+bdb345d",
5
+ "version": "0.1.1-develop.600+699a7df",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "build": "tsc -p tsconfig.json",
@@ -31,5 +31,5 @@
31
31
  "o1js": "0.13.1",
32
32
  "tsyringe": "^4.7.0"
33
33
  },
34
- "gitHead": "bdb345d9e6132387a870c8a4236d8fe295502ce4"
34
+ "gitHead": "699a7dfa3b5d3415ab4500f0cd495d6781365c6a"
35
35
  }
package/src/index.ts CHANGED
@@ -5,6 +5,6 @@ export * from "./runtime/RuntimeEnvironment";
5
5
  export * from "./runtime/Runtime";
6
6
  export * from "./state/InMemoryStateService";
7
7
  export * from "./state/decorator";
8
- export * from "./method/MethodParameterDecoder";
8
+ export * from "./method/MethodParameterEncoder";
9
9
  export * from "./runtime/MethodIdResolver";
10
10
  export * from "./factories/MethodIdFactory";
@@ -0,0 +1,141 @@
1
+ /* eslint-disable no-underscore-dangle */
2
+ import { Field, FlexibleProvable, Proof, ProvableExtended } from "o1js";
3
+ import {
4
+ ArgumentTypes,
5
+ ProofTypes,
6
+ ToFieldable,
7
+ ToFieldableStatic,
8
+ ToJSONableStatic,
9
+ } from "@proto-kit/common";
10
+
11
+ import type { RuntimeModule } from "../runtime/RuntimeModule";
12
+
13
+ const errors = {
14
+ fieldLengthNotMatching: (expected: number, actual: number) =>
15
+ new Error(`Expected ${expected} field elements, got ${actual}`),
16
+
17
+ typeNotCompatible: (name: string, error?: string) =>
18
+ new Error(
19
+ `Cannot decode type ${name}, it has to be either a Struct, CircuitValue or built-in snarkyjs type.${
20
+ error !== undefined ? `Caused by: ${error}` : ""
21
+ }`
22
+ ),
23
+ };
24
+
25
+ type ArgsArray = ProvableExtended<unknown>[];
26
+
27
+ export class MethodParameterEncoder {
28
+ public static fromMethod(target: RuntimeModule<unknown>, methodName: string) {
29
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
30
+ const paramtypes: ArgsArray = Reflect.getMetadata(
31
+ "design:paramtypes",
32
+ target,
33
+ methodName
34
+ );
35
+
36
+ if (paramtypes === undefined) {
37
+ throw new Error(
38
+ `Method with name ${methodName} doesn't exist on this module`
39
+ );
40
+ }
41
+
42
+ return new MethodParameterEncoder(paramtypes);
43
+ }
44
+
45
+ public static fieldSize(type: ProvableExtended<unknown>): number | undefined {
46
+ // as any, since we shouldn't be using this workaround in the first place
47
+ return (type as any).prototype._fields?.length ?? type.sizeInFields?.();
48
+ }
49
+
50
+ private constructor(private readonly types: ArgsArray) {}
51
+
52
+ public decode(argsJSON: string[]): FlexibleProvable<unknown>[] {
53
+ return this.types.map((type, index) => {
54
+ // eslint-disable-next-line @typescript-eslint/init-declarations
55
+ let value: FlexibleProvable<unknown>;
56
+
57
+ try {
58
+ // eslint-disable-next-line max-len
59
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
60
+ value = type.fromJSON(
61
+ JSON.parse(argsJSON[index])
62
+ ) as FlexibleProvable<unknown>;
63
+ } catch (e: unknown) {
64
+ if (e instanceof Error) {
65
+ throw errors.typeNotCompatible(type.constructor.name, e.message);
66
+ }
67
+ throw errors.typeNotCompatible(type.constructor.name);
68
+ }
69
+
70
+ return value;
71
+ });
72
+ }
73
+
74
+ public decodeFields(fields: Field[]): ArgumentTypes {
75
+ if (fields.length < this.fieldSize) {
76
+ throw errors.fieldLengthNotMatching(this.fieldSize, fields.length);
77
+ }
78
+
79
+ let stack = fields.slice();
80
+
81
+ return this.types.map((type) => {
82
+ const numberFieldsNeeded = MethodParameterEncoder.fieldSize(type) ?? -1;
83
+ if (numberFieldsNeeded === -1) {
84
+ throw errors.typeNotCompatible(type.constructor.name);
85
+ }
86
+ const structFields = stack.slice(0, numberFieldsNeeded);
87
+ stack = stack.slice(numberFieldsNeeded);
88
+ return type.fromFields(structFields, []) as ToFieldable;
89
+ });
90
+ }
91
+
92
+ public encode(args: ArgumentTypes): {
93
+ argsFields: Field[];
94
+ argsJSON: string[];
95
+ } {
96
+ /**
97
+ * Use the type info obtained previously to convert
98
+ * the args passed to fields
99
+ */
100
+ const argsFields = args.flatMap((argument, index) => {
101
+ if (argument instanceof Proof) {
102
+ const argumentType = this.types[index] as ProofTypes;
103
+
104
+ const publicOutputType = argumentType?.publicOutputType;
105
+
106
+ const publicInputType = argumentType?.publicInputType;
107
+
108
+ const inputFields =
109
+ publicInputType?.toFields(argument.publicInput) ?? [];
110
+
111
+ const outputFields =
112
+ publicOutputType?.toFields(argument.publicOutput) ?? [];
113
+
114
+ return [...inputFields, ...outputFields];
115
+ }
116
+
117
+ const argumentType = this.types[index] as ToFieldableStatic;
118
+ return argumentType.toFields(argument);
119
+ });
120
+
121
+ const argsJSON = args.map((argument, index) => {
122
+ if (argument instanceof Proof) {
123
+ return JSON.stringify(argument.toJSON());
124
+ }
125
+
126
+ const argumentType = this.types[index] as ToJSONableStatic;
127
+ return JSON.stringify(argumentType.toJSON(argument));
128
+ });
129
+
130
+ return {
131
+ argsFields,
132
+ argsJSON,
133
+ };
134
+ }
135
+
136
+ public get fieldSize(): number {
137
+ return this.types
138
+ .map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
139
+ .reduce((a, b) => a + b, 0);
140
+ }
141
+ }
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable max-statements */
2
2
  import {
3
+ Bool,
3
4
  Field,
4
5
  FlexibleProvable,
5
6
  Poseidon,
@@ -13,6 +14,7 @@ import {
13
14
  ProvableStateTransition,
14
15
  MethodPublicOutput,
15
16
  RuntimeMethodExecutionContext,
17
+ SignedTransaction,
16
18
  } from "@proto-kit/protocol";
17
19
  import {
18
20
  DecoratedMethod,
@@ -27,7 +29,7 @@ import {
27
29
  } from "@proto-kit/common";
28
30
 
29
31
  import type { RuntimeModule } from "../runtime/RuntimeModule.js";
30
- import { MethodIdResolver } from "../runtime/MethodIdResolver";
32
+ import { MethodParameterEncoder } from "./MethodParameterEncoder";
31
33
 
32
34
  const errors = {
33
35
  runtimeNotProvided: (name: string) =>
@@ -71,7 +73,10 @@ export function toWrappedMethod(
71
73
  this: RuntimeModule<unknown>,
72
74
  methodName: string,
73
75
  moduleMethod: (...args: ArgumentTypes) => unknown,
74
- methodArguments: ArgumentTypes
76
+ methodArguments: ArgumentTypes,
77
+ options: {
78
+ invocationType: RuntimeMethodInvocationType;
79
+ }
75
80
  ) {
76
81
  const executionContext = container.resolve<RuntimeMethodExecutionContext>(
77
82
  RuntimeMethodExecutionContext
@@ -99,49 +104,25 @@ export function toWrappedMethod(
99
104
  throw errors.runtimeNotProvided(name);
100
105
  }
101
106
 
102
- // Assert that the given transaction has the correct methodId
107
+ const { transaction, networkState } = executionContext.witnessInput();
103
108
  const { methodIdResolver } = runtime;
109
+
110
+ // Assert that the given transaction has the correct methodId
104
111
  const thisMethodId = Field(methodIdResolver.getMethodId(name, methodName));
105
112
  if (!thisMethodId.isConstant()) {
106
113
  throw errors.fieldNotConstant("methodId");
107
114
  }
108
115
 
109
- input.transaction.methodId.assertEquals(
116
+ transaction.methodId.assertEquals(
110
117
  thisMethodId,
111
118
  "Runtimemethod called with wrong methodId on the transaction object"
112
119
  );
113
120
 
114
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
115
- const parameterTypes: ProofTypes[] | ToFieldableStatic[] =
116
- Reflect.getMetadata("design:paramtypes", this, methodName);
117
-
118
121
  /**
119
122
  * Use the type info obtained previously to convert
120
123
  * the args passed to fields
121
124
  */
122
- const argsFields = args.flatMap((argument, index) => {
123
- if (argument instanceof Proof) {
124
- // eslint-disable-next-line max-len
125
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
126
- const argumentType = parameterTypes[index] as ProofTypes;
127
-
128
- const publicOutputType = argumentType?.publicOutputType;
129
-
130
- const publicInputType = argumentType?.publicInputType;
131
-
132
- const inputFields =
133
- publicInputType?.toFields(argument.publicInput) ?? [];
134
-
135
- const outputFields =
136
- publicOutputType?.toFields(argument.publicOutput) ?? [];
137
-
138
- return [...inputFields, ...outputFields];
139
- }
140
-
141
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
142
- const argumentType = parameterTypes[index] as ToFieldableStatic;
143
- return argumentType.toFields(argument);
144
- });
125
+ const { argsFields } = MethodParameterEncoder.fromMethod(this, methodName).encode(args);
145
126
 
146
127
  // Assert that the argsHash that has been signed matches the given arguments
147
128
  // We can use js-if here, because methodArguments is statically sizes
@@ -150,19 +131,23 @@ export function toWrappedMethod(
150
131
  const argsHash =
151
132
  methodArguments.length > 0 ? Poseidon.hash(argsFields) : Field(0);
152
133
 
153
- input.transaction.argsHash.assertEquals(
134
+ transaction.argsHash.assertEquals(
154
135
  argsHash,
155
136
  "argsHash and therefore arguments of transaction and runtime call does not match"
156
137
  );
157
138
 
158
- const transactionHash = input.transaction.hash();
159
- const networkStateHash = input.networkState.hash();
139
+ const isMessage = Bool(options.invocationType === "INCOMING_MESSAGE");
140
+ transaction.assertTransactionType(Bool(isMessage));
141
+
142
+ const transactionHash = transaction.hash();
143
+ const networkStateHash = networkState.hash();
160
144
 
161
145
  return new MethodPublicOutput({
162
146
  stateTransitionsHash,
163
147
  status,
164
148
  transactionHash,
165
149
  networkStateHash,
150
+ isMessage,
166
151
  });
167
152
  };
168
153
 
@@ -183,6 +168,7 @@ export function combineMethodName(
183
168
 
184
169
  export const runtimeMethodMetadataKey = "yab-method";
185
170
  export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
171
+ export const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
186
172
 
187
173
  /**
188
174
  * Checks the metadata of the provided runtime module and its method,
@@ -201,7 +187,9 @@ export function isRuntimeMethod(
201
187
  );
202
188
  }
203
189
 
204
- export function runtimeMethod() {
190
+ export type RuntimeMethodInvocationType = "SIGNATURE" | "INCOMING_MESSAGE";
191
+
192
+ function runtimeMethodInternal(options: { invocationType: RuntimeMethodInvocationType }) {
205
193
  return (
206
194
  target: RuntimeModule<unknown>,
207
195
  methodName: string,
@@ -225,6 +213,13 @@ export function runtimeMethod() {
225
213
 
226
214
  Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
227
215
 
216
+ Reflect.defineMetadata(
217
+ runtimeMethodTypeMetadataKey,
218
+ options.invocationType,
219
+ target,
220
+ methodName
221
+ );
222
+
228
223
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
229
224
  const simulatedMethod = descriptor.value as DecoratedMethod;
230
225
 
@@ -245,6 +240,7 @@ export function runtimeMethod() {
245
240
  methodName,
246
241
  simulatedMethod,
247
242
  args,
243
+ options,
248
244
  ]);
249
245
 
250
246
  /**
@@ -294,3 +290,15 @@ export function runtimeMethod() {
294
290
  };
295
291
  };
296
292
  }
293
+
294
+ export function runtimeMessage() {
295
+ return runtimeMethodInternal({
296
+ invocationType: "INCOMING_MESSAGE",
297
+ });
298
+ }
299
+
300
+ export function runtimeMethod() {
301
+ return runtimeMethodInternal({
302
+ invocationType: "SIGNATURE",
303
+ });
304
+ }
@@ -17,12 +17,10 @@ export class MethodIdResolver {
17
17
  public constructor(
18
18
  @inject("Runtime") private readonly runtime: Runtime<RuntimeModulesRecord>
19
19
  ) {
20
- const { modules } = runtime.definition;
21
-
22
20
  this.dictionary = runtime.runtimeModuleNames.reduce<
23
21
  Record<string, { moduleName: string; methodName: string }>
24
22
  >((dict, moduleName) => {
25
- this.runtime.assertIsValidModuleName(modules, moduleName);
23
+ this.runtime.assertIsValidModuleName(moduleName);
26
24
 
27
25
  runtime.resolve(moduleName).runtimeMethodNames.forEach((methodName) => {
28
26
  dict[this.getMethodId(moduleName, methodName).toString()] = {
@@ -44,19 +42,13 @@ export class MethodIdResolver {
44
42
 
45
43
  const { moduleName, methodName } = methodPath;
46
44
 
47
- this.runtime.assertIsValidModuleName(
48
- this.runtime.definition.modules,
49
- moduleName
50
- );
45
+ this.runtime.assertIsValidModuleName(moduleName);
51
46
 
52
47
  return [moduleName, methodName];
53
48
  }
54
49
 
55
50
  public getMethodId(moduleName: string, methodName: string): bigint {
56
- this.runtime.assertIsValidModuleName(
57
- this.runtime.definition.modules,
58
- moduleName
59
- );
51
+ this.runtime.assertIsValidModuleName(moduleName);
60
52
 
61
53
  return Poseidon.hash([
62
54
  stringToField(moduleName),
@@ -266,7 +266,7 @@ export class Runtime<Modules extends RuntimeModulesRecord>
266
266
  }
267
267
  const [moduleName, methodName] = methodDescriptor;
268
268
 
269
- this.assertIsValidModuleName(this.definition.modules, moduleName);
269
+ this.assertIsValidModuleName(moduleName);
270
270
  const module = this.resolve(moduleName);
271
271
 
272
272
  // eslint-disable-next-line max-len
@@ -9,7 +9,7 @@ import { container } from "tsyringe";
9
9
  import { AreProofsEnabled, log } from "@proto-kit/common";
10
10
 
11
11
  import { InMemoryStateService, MethodIdResolver, Runtime } from "../src";
12
- import { MethodParameterDecoder } from "../src/method/MethodParameterDecoder";
12
+ import { MethodParameterEncoder } from "../src/method/MethodParameterEncoder";
13
13
 
14
14
  import { Balances } from "./modules/Balances";
15
15
 
@@ -42,7 +42,7 @@ describe("runtimeMethod", () => {
42
42
 
43
43
  const module = runtime.resolve("Balances");
44
44
 
45
- const decoder = MethodParameterDecoder.fromMethod(module, "getBalance");
45
+ const decoder = MethodParameterEncoder.fromMethod(module, "getBalance");
46
46
  const recodedParameters = decoder.fromFields(
47
47
  parameters.flatMap((x) => x.toFields())
48
48
  );
@@ -1,62 +0,0 @@
1
- /* eslint-disable no-underscore-dangle */
2
- import { FlexibleProvable, ProvableExtended } from "o1js";
3
-
4
- import { RuntimeModule } from "../runtime/RuntimeModule";
5
-
6
- const errors = {
7
- typeNotCompatible: (name: string) =>
8
- new Error(
9
- `Cannot decode type ${name}, it has to be either a Struct, CircuitValue or built-in snarkyjs type`
10
- ),
11
- };
12
-
13
- export class MethodParameterDecoder {
14
- public static fromMethod(target: RuntimeModule<unknown>, methodName: string) {
15
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
16
- const paramtypes: ProvableExtended<unknown>[] = Reflect.getMetadata(
17
- "design:paramtypes",
18
- target,
19
- methodName
20
- );
21
-
22
- if (paramtypes === undefined) {
23
- throw new Error(
24
- `Method with name ${methodName} doesn't exist on this module`
25
- );
26
- }
27
-
28
- return new MethodParameterDecoder(paramtypes);
29
- }
30
-
31
- public static fieldSize(type: ProvableExtended<unknown>): number | undefined {
32
- // as any, since we shouldn't be using this workaround in the first place
33
- return (type as any).prototype._fields?.length ?? type.sizeInFields?.();
34
- }
35
-
36
- private constructor(private readonly types: ProvableExtended<unknown>[]) {}
37
-
38
- public fromJSON(argsJSON: string[]): FlexibleProvable<unknown>[] {
39
- return this.types.map((type, index) => {
40
- // eslint-disable-next-line @typescript-eslint/init-declarations
41
- let value: FlexibleProvable<unknown>;
42
-
43
- try {
44
- // eslint-disable-next-line max-len
45
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
46
- value = type.fromJSON(
47
- JSON.parse(argsJSON[index])
48
- ) as FlexibleProvable<unknown>;
49
- } catch {
50
- throw errors.typeNotCompatible(type.constructor.name);
51
- }
52
-
53
- return value;
54
- });
55
- }
56
-
57
- public get fieldSize(): number {
58
- return this.types
59
- .map((type) => MethodParameterDecoder.fieldSize(type) ?? 0)
60
- .reduce((a, b) => a + b, 0);
61
- }
62
- }