@proto-kit/module 0.1.1-develop.457 → 0.1.1-develop.651
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 +1 -1
- package/dist/index.js +1 -1
- package/dist/method/MethodParameterEncoder.d.ts +17 -0
- package/dist/method/MethodParameterEncoder.d.ts.map +1 -0
- package/dist/method/MethodParameterEncoder.js +93 -0
- package/dist/method/runtimeMethod.d.ts +6 -1
- package/dist/method/runtimeMethod.d.ts.map +1 -1
- package/dist/method/runtimeMethod.js +34 -35
- package/dist/runtime/MethodIdResolver.d.ts +7 -0
- package/dist/runtime/MethodIdResolver.d.ts.map +1 -1
- package/dist/runtime/MethodIdResolver.js +36 -4
- package/dist/runtime/Runtime.d.ts +1 -0
- package/dist/runtime/Runtime.d.ts.map +1 -1
- package/dist/runtime/Runtime.js +18 -4
- package/dist/runtime/RuntimeModule.d.ts +2 -2
- package/dist/runtime/RuntimeModule.d.ts.map +1 -1
- package/dist/runtime/RuntimeModule.js +9 -6
- package/package.json +2 -2
- package/src/index.ts +1 -1
- package/src/method/MethodParameterEncoder.ts +150 -0
- package/src/method/runtimeMethod.ts +55 -51
- package/src/runtime/MethodIdResolver.ts +53 -12
- package/src/runtime/Runtime.ts +26 -5
- package/src/runtime/RuntimeModule.ts +12 -8
- package/test/runtimeMethod.test.ts +2 -2
- package/src/method/MethodParameterDecoder.ts +0 -62
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/
|
|
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/
|
|
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,EACL,KAAK,EACL,gBAAgB,EAGhB,gBAAgB,EACjB,MAAM,MAAM,CAAC;AACd,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;IA4CD,IAAW,SAAS,IAAI,MAAM,CAI7B;CACF"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
import { Proof, Provable, } 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
|
+
let argsJSON = [];
|
|
74
|
+
Provable.asProver(() => {
|
|
75
|
+
argsJSON = args.map((argument, index) => {
|
|
76
|
+
if (argument instanceof Proof) {
|
|
77
|
+
return JSON.stringify(argument.toJSON());
|
|
78
|
+
}
|
|
79
|
+
const argumentType = this.types[index];
|
|
80
|
+
return JSON.stringify(argumentType.toJSON(argument));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
argsFields,
|
|
85
|
+
argsJSON,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
get fieldSize() {
|
|
89
|
+
return this.types
|
|
90
|
+
.map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
|
|
91
|
+
.reduce((a, b) => a + b, 0);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -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,
|
|
6
|
+
export declare function toWrappedMethod(this: RuntimeModule<unknown>, methodName: string, moduleMethod: (...args: ArgumentTypes) => unknown, 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":"
|
|
1
|
+
{"version":3,"file":"runtimeMethod.d.ts","sourceRoot":"","sources":["../../src/method/runtimeMethod.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,eAAe,EAEf,kBAAkB,EAKnB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAOL,aAAa,EAGd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAsBjE,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,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;AAyG3E,wBAAgB,cAAc,iGAI7B;AAED,wBAAgB,aAAa,iGAI5B"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
|
-
import { Field, Poseidon
|
|
2
|
+
import { Bool, Field, Poseidon } from "o1js";
|
|
3
3
|
import { container } from "tsyringe";
|
|
4
|
-
import {
|
|
4
|
+
import { ProvableStateTransition, MethodPublicOutput, RuntimeMethodExecutionContext, StateTransitionReductionList, } 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"),
|
|
@@ -12,21 +13,19 @@ const errors = {
|
|
|
12
13
|
export function toStateTransitionsHash(
|
|
13
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
15
|
stateTransitions) {
|
|
15
|
-
const stateTransitionsHashList = new
|
|
16
|
+
const stateTransitionsHashList = new StateTransitionReductionList(ProvableStateTransition);
|
|
16
17
|
return stateTransitions
|
|
17
18
|
.map((stateTransition) => stateTransition.toProvable())
|
|
18
19
|
.reduce((allStateTransitionsHashList, stateTransition) => allStateTransitionsHashList.push(stateTransition), stateTransitionsHashList)
|
|
19
20
|
.toField();
|
|
20
21
|
}
|
|
21
|
-
export function toWrappedMethod(methodName, moduleMethod,
|
|
22
|
+
export function toWrappedMethod(methodName, moduleMethod, options) {
|
|
22
23
|
const executionContext = container.resolve(RuntimeMethodExecutionContext);
|
|
23
24
|
const wrappedMethod = (...args) => {
|
|
24
25
|
Reflect.apply(moduleMethod, this, args);
|
|
25
|
-
const { result: { stateTransitions, status },
|
|
26
|
+
const { result: { stateTransitions, status }, } = executionContext.current();
|
|
26
27
|
const stateTransitionsHash = toStateTransitionsHash(stateTransitions);
|
|
27
|
-
|
|
28
|
-
throw errors.methodInputsNotProvided();
|
|
29
|
-
}
|
|
28
|
+
const input = this.getInputs();
|
|
30
29
|
const { name, runtime } = this;
|
|
31
30
|
if (name === undefined) {
|
|
32
31
|
throw errors.runtimeNameNotSet();
|
|
@@ -34,47 +33,35 @@ export function toWrappedMethod(methodName, moduleMethod, methodArguments) {
|
|
|
34
33
|
if (runtime === undefined) {
|
|
35
34
|
throw errors.runtimeNotProvided(name);
|
|
36
35
|
}
|
|
37
|
-
|
|
36
|
+
const { transaction, networkState } = executionContext.witnessInput();
|
|
38
37
|
const { methodIdResolver } = runtime;
|
|
38
|
+
// Assert that the given transaction has the correct methodId
|
|
39
39
|
const thisMethodId = Field(methodIdResolver.getMethodId(name, methodName));
|
|
40
40
|
if (!thisMethodId.isConstant()) {
|
|
41
41
|
throw errors.fieldNotConstant("methodId");
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
45
|
-
const parameterTypes = Reflect.getMetadata("design:paramtypes", this, methodName);
|
|
43
|
+
transaction.methodId.assertEquals(thisMethodId, "Runtimemethod called with wrong methodId on the transaction object");
|
|
46
44
|
/**
|
|
47
45
|
* Use the type info obtained previously to convert
|
|
48
46
|
* the args passed to fields
|
|
49
47
|
*/
|
|
50
|
-
const argsFields =
|
|
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
|
-
});
|
|
48
|
+
const { argsFields } = MethodParameterEncoder.fromMethod(this, methodName).encode(args);
|
|
65
49
|
// Assert that the argsHash that has been signed matches the given arguments
|
|
66
|
-
// We can use js-if here, because
|
|
50
|
+
// We can use js-if here, because args are statically sized
|
|
67
51
|
// i.e. the result of the if-statement will be the same for all executions
|
|
68
52
|
// of this method
|
|
69
|
-
const argsHash =
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
53
|
+
const argsHash = (args ?? []).length > 0 ? Poseidon.hash(argsFields) : Field(0);
|
|
54
|
+
transaction.argsHash.assertEquals(argsHash, "argsHash and therefore arguments of transaction and runtime call does not match");
|
|
55
|
+
const isMessage = Bool(options.invocationType === "INCOMING_MESSAGE");
|
|
56
|
+
transaction.assertTransactionType(Bool(isMessage));
|
|
57
|
+
const transactionHash = transaction.hash();
|
|
58
|
+
const networkStateHash = networkState.hash();
|
|
73
59
|
return new MethodPublicOutput({
|
|
74
60
|
stateTransitionsHash,
|
|
75
61
|
status,
|
|
76
62
|
transactionHash,
|
|
77
63
|
networkStateHash,
|
|
64
|
+
isMessage,
|
|
78
65
|
});
|
|
79
66
|
};
|
|
80
67
|
Object.defineProperty(wrappedMethod, "name", {
|
|
@@ -88,6 +75,7 @@ export function combineMethodName(runtimeModuleName, methodName) {
|
|
|
88
75
|
}
|
|
89
76
|
export const runtimeMethodMetadataKey = "yab-method";
|
|
90
77
|
export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
|
|
78
|
+
export const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
|
|
91
79
|
/**
|
|
92
80
|
* Checks the metadata of the provided runtime module and its method,
|
|
93
81
|
* to see if it has been decorated with @runtimeMethod()
|
|
@@ -99,7 +87,7 @@ export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
|
|
|
99
87
|
export function isRuntimeMethod(target, propertyKey) {
|
|
100
88
|
return Boolean(Reflect.getMetadata(runtimeMethodMetadataKey, target, propertyKey));
|
|
101
89
|
}
|
|
102
|
-
|
|
90
|
+
function runtimeMethodInternal(options) {
|
|
103
91
|
return (target, methodName, descriptor) => {
|
|
104
92
|
const executionContext = container.resolve(RuntimeMethodExecutionContext);
|
|
105
93
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
@@ -112,10 +100,11 @@ export function runtimeMethod() {
|
|
|
112
100
|
}
|
|
113
101
|
Reflect.defineMetadata(runtimeMethodNamesMetadataKey, data, target);
|
|
114
102
|
Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
|
|
103
|
+
Reflect.defineMetadata(runtimeMethodTypeMetadataKey, options.invocationType, target, methodName);
|
|
115
104
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
116
105
|
const simulatedMethod = descriptor.value;
|
|
117
106
|
descriptor.value = function value(...args) {
|
|
118
|
-
const constructorName = this.
|
|
107
|
+
const constructorName = this.name;
|
|
119
108
|
/**
|
|
120
109
|
* If its a top level method call, wrap it into a wrapped method,
|
|
121
110
|
* since it'll be turned into a real/mock prover in provableMethod().
|
|
@@ -126,7 +115,7 @@ export function runtimeMethod() {
|
|
|
126
115
|
const simulatedWrappedMethod = Reflect.apply(toWrappedMethod, this, [
|
|
127
116
|
methodName,
|
|
128
117
|
simulatedMethod,
|
|
129
|
-
|
|
118
|
+
options,
|
|
130
119
|
]);
|
|
131
120
|
/**
|
|
132
121
|
* Before the prover runs, make sure it is operating on the correct
|
|
@@ -167,3 +156,13 @@ export function runtimeMethod() {
|
|
|
167
156
|
};
|
|
168
157
|
};
|
|
169
158
|
}
|
|
159
|
+
export function runtimeMessage() {
|
|
160
|
+
return runtimeMethodInternal({
|
|
161
|
+
invocationType: "INCOMING_MESSAGE",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
export function runtimeMethod() {
|
|
165
|
+
return runtimeMethodInternal({
|
|
166
|
+
invocationType: "SIGNATURE",
|
|
167
|
+
});
|
|
168
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RuntimeMethodIdMapping } from "@proto-kit/protocol";
|
|
1
2
|
import type { Runtime, RuntimeModulesRecord } from "./Runtime";
|
|
2
3
|
/**
|
|
3
4
|
* Please see `getMethodId` to learn more about
|
|
@@ -7,6 +8,12 @@ export declare class MethodIdResolver {
|
|
|
7
8
|
private readonly runtime;
|
|
8
9
|
private readonly dictionary;
|
|
9
10
|
constructor(runtime: Runtime<RuntimeModulesRecord>);
|
|
11
|
+
/**
|
|
12
|
+
* The purpose of this method is to provide a dictionary where
|
|
13
|
+
* we can look up properties like methodId and invocationType
|
|
14
|
+
* for each runtimeMethod using their module name and method name
|
|
15
|
+
*/
|
|
16
|
+
methodIdMap(): RuntimeMethodIdMapping;
|
|
10
17
|
getMethodNameFromId(methodId: bigint): [string, string] | undefined;
|
|
11
18
|
getMethodId(moduleName: string, methodName: string): bigint;
|
|
12
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MethodIdResolver.d.ts","sourceRoot":"","sources":["../../src/runtime/MethodIdResolver.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MethodIdResolver.d.ts","sourceRoot":"","sources":["../../src/runtime/MethodIdResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAS5E,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;IAkB5E;;;;OAIG;IACI,WAAW,IAAI,sBAAsB;IAsCrC,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"}
|
|
@@ -10,9 +10,11 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
11
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
12
|
};
|
|
13
|
+
import { filterNonUndefined } from "@proto-kit/common";
|
|
13
14
|
import { stringToField } from "@proto-kit/protocol";
|
|
14
15
|
import { Poseidon } from "o1js";
|
|
15
16
|
import { inject, injectable } from "tsyringe";
|
|
17
|
+
import { runtimeMethodTypeMetadataKey, } from "../method/runtimeMethod";
|
|
16
18
|
/**
|
|
17
19
|
* Please see `getMethodId` to learn more about
|
|
18
20
|
* methodId encoding
|
|
@@ -21,9 +23,8 @@ let MethodIdResolver = class MethodIdResolver {
|
|
|
21
23
|
constructor(runtime) {
|
|
22
24
|
this.runtime = runtime;
|
|
23
25
|
this.dictionary = {};
|
|
24
|
-
const { modules } = runtime.definition;
|
|
25
26
|
this.dictionary = runtime.runtimeModuleNames.reduce((dict, moduleName) => {
|
|
26
|
-
this.runtime.assertIsValidModuleName(
|
|
27
|
+
this.runtime.assertIsValidModuleName(moduleName);
|
|
27
28
|
runtime.resolve(moduleName).runtimeMethodNames.forEach((methodName) => {
|
|
28
29
|
dict[this.getMethodId(moduleName, methodName).toString()] = {
|
|
29
30
|
moduleName,
|
|
@@ -33,17 +34,48 @@ let MethodIdResolver = class MethodIdResolver {
|
|
|
33
34
|
return dict;
|
|
34
35
|
}, {});
|
|
35
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* The purpose of this method is to provide a dictionary where
|
|
39
|
+
* we can look up properties like methodId and invocationType
|
|
40
|
+
* for each runtimeMethod using their module name and method name
|
|
41
|
+
*/
|
|
42
|
+
methodIdMap() {
|
|
43
|
+
const methodIdResolver = this.runtime.dependencyContainer.resolve("MethodIdResolver");
|
|
44
|
+
const rawMappings = this.runtime.moduleNames.flatMap((moduleName) => {
|
|
45
|
+
const module = this.runtime.resolve(moduleName);
|
|
46
|
+
return module.runtimeMethodNames.map((method) => {
|
|
47
|
+
const type = Reflect.getMetadata(runtimeMethodTypeMetadataKey, module, method);
|
|
48
|
+
if (type !== undefined) {
|
|
49
|
+
return {
|
|
50
|
+
name: `${moduleName}.${method}`,
|
|
51
|
+
methodId: methodIdResolver.getMethodId(moduleName, method),
|
|
52
|
+
type,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
return rawMappings
|
|
59
|
+
.filter(filterNonUndefined)
|
|
60
|
+
.reduce((acc, entry) => {
|
|
61
|
+
acc[entry.name] = {
|
|
62
|
+
methodId: entry.methodId,
|
|
63
|
+
type: entry.type,
|
|
64
|
+
};
|
|
65
|
+
return acc;
|
|
66
|
+
}, {});
|
|
67
|
+
}
|
|
36
68
|
getMethodNameFromId(methodId) {
|
|
37
69
|
const methodPath = this.dictionary[methodId.toString()];
|
|
38
70
|
if (methodPath === undefined) {
|
|
39
71
|
return undefined;
|
|
40
72
|
}
|
|
41
73
|
const { moduleName, methodName } = methodPath;
|
|
42
|
-
this.runtime.assertIsValidModuleName(
|
|
74
|
+
this.runtime.assertIsValidModuleName(moduleName);
|
|
43
75
|
return [moduleName, methodName];
|
|
44
76
|
}
|
|
45
77
|
getMethodId(moduleName, methodName) {
|
|
46
|
-
this.runtime.assertIsValidModuleName(
|
|
78
|
+
this.runtime.assertIsValidModuleName(moduleName);
|
|
47
79
|
return Poseidon.hash([
|
|
48
80
|
stringToField(moduleName),
|
|
49
81
|
stringToField(methodName),
|
|
@@ -5,6 +5,7 @@ import { MethodPublicOutput, StateServiceProvider, StateService } from "@proto-k
|
|
|
5
5
|
import { RuntimeModule } from "./RuntimeModule";
|
|
6
6
|
import { MethodIdResolver } from "./MethodIdResolver";
|
|
7
7
|
import { RuntimeEnvironment } from "./RuntimeEnvironment";
|
|
8
|
+
export declare function getAllPropertyNames(obj: any): (string | symbol)[];
|
|
8
9
|
/**
|
|
9
10
|
* Record of modules accepted by the Runtime module container.
|
|
10
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/Runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAc,MAAM,UAAU,CAAC;AAC3D,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,EACd,cAAc,
|
|
1
|
+
{"version":3,"file":"Runtime.d.ts","sourceRoot":"","sources":["../../src/runtime/Runtime.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAc,MAAM,UAAU,CAAC;AAC3D,OAAO,EACL,WAAW,EACX,eAAe,EACf,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,YAAY,EACb,MAAM,qBAAqB,CAAC;AAW7B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,GAAG,uBAW3C;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,aAAa,CAC9C,UAAU,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CACnC,CAAC;AAOF;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,OAAO,SAAS,oBAAoB;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACjC;AAED,qBAAa,qBAAqB,CAChC,OAAO,SAAS,oBAAoB,CACpC,SAAQ,cAAc,CAAC,SAAS,EAAE,kBAAkB,CAAC;IAE3B,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;gBAAzB,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IAInD,IAAW,QAAQ,iCAElB;IAEM,gBAAgB,IAAI,cAAc,CAAC,SAAS,EAAE,kBAAkB,CAAC;CAwHzE;AAED;;;GAGG;AACH,qBACa,OAAO,CAAC,OAAO,SAAS,oBAAoB,CACvD,SAAQ,eAAe,CAAC,OAAO,CAC/B,YAAW,kBAAkB;WAEf,IAAI,CAAC,OAAO,SAAS,oBAAoB,EACrD,UAAU,EAAE,iBAAiB,CAAC,OAAO,CAAC,GACrC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IASxB,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;IAEpD,UAAU,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAEvC,cAAc,EAAE,cAAc,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;IAErE;;;;OAIG;gBACgB,UAAU,EAAE,iBAAiB,CAAC,OAAO,CAAC;IAQlD,MAAM,CAAC,sBAAsB,EAAE,sBAAsB;IAM5D,IAAW,QAAQ,IAAI,gBAAgB,GAAG,SAAS,CAElD;IAED,IAAW,oBAAoB,IAAI,oBAAoB,CAItD;IAED,IAAW,YAAY,IAAI,YAAY,CAEtC;IAED,IAAW,gBAAgB,IAAI,gBAAgB,CAE9C;IAED;;OAEG;IACH,IAAW,mBAAmB,IAAI,mBAAmB,CAEpD;IAED;;;OAGG;IACI,aAAa,CAClB,QAAQ,EAAE,MAAM,GACf,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,GAAG,SAAS;IAuBhD;;;;;;OAMG;IACI,cAAc,CACnB,UAAU,EAAE,WAAW,CAAC,OAAO,CAAC,EAChC,eAAe,EAAE,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC;IAQ9D;;OAEG;IACH,IAAW,kBAAkB,aAE5B;CACF"}
|
package/dist/runtime/Runtime.js
CHANGED
|
@@ -14,8 +14,20 @@ import { Experimental } from "o1js";
|
|
|
14
14
|
import { injectable } from "tsyringe";
|
|
15
15
|
import { ModuleContainer, ZkProgrammable, } from "@proto-kit/common";
|
|
16
16
|
import { MethodPublicOutput, } from "@proto-kit/protocol";
|
|
17
|
-
import { combineMethodName, isRuntimeMethod, toWrappedMethod, } from "../method/runtimeMethod";
|
|
17
|
+
import { combineMethodName, isRuntimeMethod, runtimeMethodTypeMetadataKey, toWrappedMethod, } from "../method/runtimeMethod";
|
|
18
18
|
import { MethodIdFactory } from "../factories/MethodIdFactory";
|
|
19
|
+
export function getAllPropertyNames(obj) {
|
|
20
|
+
let keys = [];
|
|
21
|
+
// if primitive (primitives still have keys) skip the first iteration
|
|
22
|
+
if (!(obj instanceof Object)) {
|
|
23
|
+
obj = Object.getPrototypeOf(obj);
|
|
24
|
+
}
|
|
25
|
+
while (obj) {
|
|
26
|
+
keys = keys.concat(Reflect.ownKeys(obj));
|
|
27
|
+
obj = Object.getPrototypeOf(obj);
|
|
28
|
+
}
|
|
29
|
+
return keys;
|
|
30
|
+
}
|
|
19
31
|
const errors = {
|
|
20
32
|
methodNotFound: (methodKey) => new Error(`Unable to find method with id ${methodKey}`),
|
|
21
33
|
};
|
|
@@ -47,12 +59,13 @@ export class RuntimeZkProgrammable extends ZkProgrammable {
|
|
|
47
59
|
// eslint-disable-next-line max-len
|
|
48
60
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
49
61
|
const modulePrototype = Object.getPrototypeOf(runtimeModule);
|
|
50
|
-
const modulePrototypeMethods =
|
|
62
|
+
const modulePrototypeMethods = getAllPropertyNames(runtimeModule).map((method) => method.toString());
|
|
51
63
|
const moduleMethods = modulePrototypeMethods.reduce((allModuleMethods, methodName) => {
|
|
52
64
|
if (isRuntimeMethod(runtimeModule, methodName)) {
|
|
53
65
|
const combinedMethodName = combineMethodName(runtimeModuleName, methodName);
|
|
54
66
|
const method = modulePrototype[methodName];
|
|
55
|
-
const
|
|
67
|
+
const invocationType = Reflect.getMetadata(runtimeMethodTypeMetadataKey, runtimeModule, methodName);
|
|
68
|
+
const wrappedMethod = Reflect.apply(toWrappedMethod, runtimeModule, [methodName, method, { invocationType }]);
|
|
56
69
|
// eslint-disable-next-line no-warning-comments
|
|
57
70
|
// TODO: find out how to import the Tuple type
|
|
58
71
|
const privateInputs = Reflect.getMetadata("design:paramtypes", runtimeModule, methodName);
|
|
@@ -86,6 +99,7 @@ export class RuntimeZkProgrammable extends ZkProgrammable {
|
|
|
86
99
|
return {
|
|
87
100
|
compile: program.compile.bind(program),
|
|
88
101
|
verify: program.verify.bind(program),
|
|
102
|
+
analyzeMethods: program.analyzeMethods.bind(program),
|
|
89
103
|
Proof: SelfProof,
|
|
90
104
|
methods,
|
|
91
105
|
};
|
|
@@ -147,7 +161,7 @@ let Runtime = Runtime_1 = class Runtime extends ModuleContainer {
|
|
|
147
161
|
return undefined;
|
|
148
162
|
}
|
|
149
163
|
const [moduleName, methodName] = methodDescriptor;
|
|
150
|
-
this.assertIsValidModuleName(
|
|
164
|
+
this.assertIsValidModuleName(moduleName);
|
|
151
165
|
const module = this.resolve(moduleName);
|
|
152
166
|
// eslint-disable-next-line max-len
|
|
153
167
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions,@typescript-eslint/no-unsafe-member-access
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConfigurableModule, NoConfig, Presets } from "@proto-kit/common";
|
|
2
|
-
import { NetworkState, RuntimeTransaction } from "@proto-kit/protocol";
|
|
2
|
+
import { NetworkState, RuntimeTransaction, RuntimeMethodExecutionData } from "@proto-kit/protocol";
|
|
3
3
|
import { RuntimeEnvironment } from "./RuntimeEnvironment";
|
|
4
4
|
/**
|
|
5
5
|
* Base class for runtime modules providing the necessary utilities.
|
|
@@ -19,7 +19,7 @@ export declare class RuntimeModule<Config = NoConfig> extends ConfigurableModule
|
|
|
19
19
|
name?: string;
|
|
20
20
|
runtime?: RuntimeEnvironment;
|
|
21
21
|
constructor();
|
|
22
|
-
|
|
22
|
+
getInputs(): RuntimeMethodExecutionData;
|
|
23
23
|
get transaction(): RuntimeTransaction;
|
|
24
24
|
get network(): NetworkState;
|
|
25
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RuntimeModule.d.ts","sourceRoot":"","sources":["../../src/runtime/RuntimeModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,EACL,YAAY,EACZ,kBAAkB,
|
|
1
|
+
{"version":3,"file":"RuntimeModule.d.ts","sourceRoot":"","sources":["../../src/runtime/RuntimeModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE1E,OAAO,EACL,YAAY,EACZ,kBAAkB,EAGlB,0BAA0B,EAE3B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAO1D;;GAEG;AACH,qBACa,aAAa,CACxB,MAAM,GAAG,QAAQ,CACjB,SAAQ,kBAAkB,CAAC,MAAM,CAAC;IAClC,OAAc,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAM;IAE7C;;OAEG;IACH,SAAgB,kBAAkB,EAAE,MAAM,EAAE,CAAM;IAElD;;;;OAIG;IACI,eAAe,UAAQ;IAEvB,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,OAAO,CAAC,EAAE,kBAAkB,CAAC;;IAY7B,SAAS,IAAI,0BAA0B;IAa9C,IAAW,WAAW,IAAI,kBAAkB,CAE3C;IAED,IAAW,OAAO,IAAI,YAAY,CAEjC;CACF"}
|
|
@@ -9,8 +9,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
import { ConfigurableModule } from "@proto-kit/common";
|
|
11
11
|
import { container, injectable } from "tsyringe";
|
|
12
|
-
import { RuntimeMethodExecutionContext, } from "@proto-kit/protocol";
|
|
12
|
+
import { RuntimeMethodExecutionContext, RuntimeMethodExecutionDataStruct, } from "@proto-kit/protocol";
|
|
13
13
|
import { runtimeMethodNamesMetadataKey } from "../method/runtimeMethod";
|
|
14
|
+
import { Provable } from "o1js";
|
|
14
15
|
const errors = {
|
|
15
16
|
inputDataNotSet: () => new Error("Input data for runtime execution not set"),
|
|
16
17
|
};
|
|
@@ -35,11 +36,13 @@ let RuntimeModule = class RuntimeModule extends ConfigurableModule {
|
|
|
35
36
|
this.runtimeMethodNames = methodNames ?? [];
|
|
36
37
|
}
|
|
37
38
|
getInputs() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
return Provable.witness(RuntimeMethodExecutionDataStruct, () => {
|
|
40
|
+
const { input } = container.resolve(RuntimeMethodExecutionContext);
|
|
41
|
+
if (input === undefined) {
|
|
42
|
+
throw errors.inputDataNotSet();
|
|
43
|
+
}
|
|
44
|
+
return input;
|
|
45
|
+
});
|
|
43
46
|
}
|
|
44
47
|
get transaction() {
|
|
45
48
|
return this.getInputs().transaction;
|
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.
|
|
5
|
+
"version": "0.1.1-develop.651+7591cb6",
|
|
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": "
|
|
34
|
+
"gitHead": "7591cb6bdf58a6cd525a10902c25bc292efcfc6b"
|
|
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/
|
|
8
|
+
export * from "./method/MethodParameterEncoder";
|
|
9
9
|
export * from "./runtime/MethodIdResolver";
|
|
10
10
|
export * from "./factories/MethodIdFactory";
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* eslint-disable no-underscore-dangle */
|
|
2
|
+
import {
|
|
3
|
+
Field,
|
|
4
|
+
FlexibleProvable,
|
|
5
|
+
Proof,
|
|
6
|
+
Provable,
|
|
7
|
+
ProvableExtended,
|
|
8
|
+
} from "o1js";
|
|
9
|
+
import {
|
|
10
|
+
ArgumentTypes,
|
|
11
|
+
ProofTypes,
|
|
12
|
+
ToFieldable,
|
|
13
|
+
ToFieldableStatic,
|
|
14
|
+
ToJSONableStatic,
|
|
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 ArgsArray = ProvableExtended<unknown>[];
|
|
32
|
+
|
|
33
|
+
export class MethodParameterEncoder {
|
|
34
|
+
public static fromMethod(target: RuntimeModule<unknown>, methodName: string) {
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
36
|
+
const paramtypes: ArgsArray = Reflect.getMetadata(
|
|
37
|
+
"design:paramtypes",
|
|
38
|
+
target,
|
|
39
|
+
methodName
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (paramtypes === undefined) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Method with name ${methodName} doesn't exist on this module`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return new MethodParameterEncoder(paramtypes);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public static fieldSize(type: ProvableExtended<unknown>): number | undefined {
|
|
52
|
+
// as any, since we shouldn't be using this workaround in the first place
|
|
53
|
+
return (type as any).prototype._fields?.length ?? type.sizeInFields?.();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private constructor(private readonly types: ArgsArray) {}
|
|
57
|
+
|
|
58
|
+
public decode(argsJSON: string[]): FlexibleProvable<unknown>[] {
|
|
59
|
+
return this.types.map((type, index) => {
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
61
|
+
let value: FlexibleProvable<unknown>;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
// eslint-disable-next-line max-len
|
|
65
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
66
|
+
value = type.fromJSON(
|
|
67
|
+
JSON.parse(argsJSON[index])
|
|
68
|
+
) as FlexibleProvable<unknown>;
|
|
69
|
+
} catch (e: unknown) {
|
|
70
|
+
if (e instanceof Error) {
|
|
71
|
+
throw errors.typeNotCompatible(type.constructor.name, e.message);
|
|
72
|
+
}
|
|
73
|
+
throw errors.typeNotCompatible(type.constructor.name);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return value;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public decodeFields(fields: Field[]): ArgumentTypes {
|
|
81
|
+
if (fields.length < this.fieldSize) {
|
|
82
|
+
throw errors.fieldLengthNotMatching(this.fieldSize, fields.length);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let stack = fields.slice();
|
|
86
|
+
|
|
87
|
+
return this.types.map((type) => {
|
|
88
|
+
const numberFieldsNeeded = MethodParameterEncoder.fieldSize(type) ?? -1;
|
|
89
|
+
if (numberFieldsNeeded === -1) {
|
|
90
|
+
throw errors.typeNotCompatible(type.constructor.name);
|
|
91
|
+
}
|
|
92
|
+
const structFields = stack.slice(0, numberFieldsNeeded);
|
|
93
|
+
stack = stack.slice(numberFieldsNeeded);
|
|
94
|
+
return type.fromFields(structFields, []) as ToFieldable;
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public encode(args: ArgumentTypes): {
|
|
99
|
+
argsFields: Field[];
|
|
100
|
+
argsJSON: string[];
|
|
101
|
+
} {
|
|
102
|
+
/**
|
|
103
|
+
* Use the type info obtained previously to convert
|
|
104
|
+
* the args passed to fields
|
|
105
|
+
*/
|
|
106
|
+
const argsFields = args.flatMap((argument, index) => {
|
|
107
|
+
if (argument instanceof Proof) {
|
|
108
|
+
const argumentType = this.types[index] as ProofTypes;
|
|
109
|
+
|
|
110
|
+
const publicOutputType = argumentType?.publicOutputType;
|
|
111
|
+
|
|
112
|
+
const publicInputType = argumentType?.publicInputType;
|
|
113
|
+
|
|
114
|
+
const inputFields =
|
|
115
|
+
publicInputType?.toFields(argument.publicInput) ?? [];
|
|
116
|
+
|
|
117
|
+
const outputFields =
|
|
118
|
+
publicOutputType?.toFields(argument.publicOutput) ?? [];
|
|
119
|
+
|
|
120
|
+
return [...inputFields, ...outputFields];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const argumentType = this.types[index] as ToFieldableStatic;
|
|
124
|
+
return argumentType.toFields(argument);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
let argsJSON: string[] = [];
|
|
128
|
+
Provable.asProver(() => {
|
|
129
|
+
argsJSON = args.map((argument, index) => {
|
|
130
|
+
if (argument instanceof Proof) {
|
|
131
|
+
return JSON.stringify(argument.toJSON());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const argumentType = this.types[index] as ToJSONableStatic;
|
|
135
|
+
return JSON.stringify(argumentType.toJSON(argument));
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
argsFields,
|
|
141
|
+
argsJSON,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public get fieldSize(): number {
|
|
146
|
+
return this.types
|
|
147
|
+
.map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
|
|
148
|
+
.reduce((a, b) => a + b, 0);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
/* eslint-disable max-statements */
|
|
2
|
-
import {
|
|
3
|
-
Field,
|
|
4
|
-
FlexibleProvable,
|
|
5
|
-
Poseidon,
|
|
6
|
-
Proof,
|
|
7
|
-
ProvableExtended,
|
|
8
|
-
} from "o1js";
|
|
2
|
+
import { Bool, Field, Poseidon } from "o1js";
|
|
9
3
|
import { container } from "tsyringe";
|
|
10
4
|
import {
|
|
11
5
|
StateTransition,
|
|
12
|
-
DefaultProvableHashList,
|
|
13
6
|
ProvableStateTransition,
|
|
14
7
|
MethodPublicOutput,
|
|
15
8
|
RuntimeMethodExecutionContext,
|
|
9
|
+
RuntimeMethodExecutionDataStruct,
|
|
10
|
+
SignedTransaction,
|
|
11
|
+
StateTransitionReductionList,
|
|
16
12
|
} from "@proto-kit/protocol";
|
|
17
13
|
import {
|
|
18
14
|
DecoratedMethod,
|
|
@@ -28,6 +24,8 @@ import {
|
|
|
28
24
|
|
|
29
25
|
import type { RuntimeModule } from "../runtime/RuntimeModule.js";
|
|
30
26
|
import { MethodIdResolver } from "../runtime/MethodIdResolver";
|
|
27
|
+
import { state } from "../state/decorator.js";
|
|
28
|
+
import { MethodParameterEncoder } from "./MethodParameterEncoder";
|
|
31
29
|
|
|
32
30
|
const errors = {
|
|
33
31
|
runtimeNotProvided: (name: string) =>
|
|
@@ -50,7 +48,7 @@ export function toStateTransitionsHash(
|
|
|
50
48
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
49
|
stateTransitions: StateTransition<any>[]
|
|
52
50
|
) {
|
|
53
|
-
const stateTransitionsHashList = new
|
|
51
|
+
const stateTransitionsHashList = new StateTransitionReductionList(
|
|
54
52
|
ProvableStateTransition
|
|
55
53
|
);
|
|
56
54
|
|
|
@@ -71,7 +69,9 @@ export function toWrappedMethod(
|
|
|
71
69
|
this: RuntimeModule<unknown>,
|
|
72
70
|
methodName: string,
|
|
73
71
|
moduleMethod: (...args: ArgumentTypes) => unknown,
|
|
74
|
-
|
|
72
|
+
options: {
|
|
73
|
+
invocationType: RuntimeMethodInvocationType;
|
|
74
|
+
}
|
|
75
75
|
) {
|
|
76
76
|
const executionContext = container.resolve<RuntimeMethodExecutionContext>(
|
|
77
77
|
RuntimeMethodExecutionContext
|
|
@@ -81,14 +81,11 @@ export function toWrappedMethod(
|
|
|
81
81
|
Reflect.apply(moduleMethod, this, args);
|
|
82
82
|
const {
|
|
83
83
|
result: { stateTransitions, status },
|
|
84
|
-
input,
|
|
85
84
|
} = executionContext.current();
|
|
86
85
|
|
|
87
86
|
const stateTransitionsHash = toStateTransitionsHash(stateTransitions);
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
throw errors.methodInputsNotProvided();
|
|
91
|
-
}
|
|
88
|
+
const input = this.getInputs();
|
|
92
89
|
|
|
93
90
|
const { name, runtime } = this;
|
|
94
91
|
|
|
@@ -99,70 +96,53 @@ export function toWrappedMethod(
|
|
|
99
96
|
throw errors.runtimeNotProvided(name);
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
|
|
99
|
+
const { transaction, networkState } = executionContext.witnessInput();
|
|
103
100
|
const { methodIdResolver } = runtime;
|
|
101
|
+
|
|
102
|
+
// Assert that the given transaction has the correct methodId
|
|
104
103
|
const thisMethodId = Field(methodIdResolver.getMethodId(name, methodName));
|
|
105
104
|
if (!thisMethodId.isConstant()) {
|
|
106
105
|
throw errors.fieldNotConstant("methodId");
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
|
|
108
|
+
transaction.methodId.assertEquals(
|
|
110
109
|
thisMethodId,
|
|
111
110
|
"Runtimemethod called with wrong methodId on the transaction object"
|
|
112
111
|
);
|
|
113
112
|
|
|
114
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
115
|
-
const parameterTypes: ProofTypes[] | ToFieldableStatic[] =
|
|
116
|
-
Reflect.getMetadata("design:paramtypes", this, methodName);
|
|
117
|
-
|
|
118
113
|
/**
|
|
119
114
|
* Use the type info obtained previously to convert
|
|
120
115
|
* the args passed to fields
|
|
121
116
|
*/
|
|
122
|
-
const argsFields =
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
});
|
|
117
|
+
const { argsFields } = MethodParameterEncoder.fromMethod(
|
|
118
|
+
this,
|
|
119
|
+
methodName
|
|
120
|
+
).encode(args);
|
|
145
121
|
|
|
146
122
|
// Assert that the argsHash that has been signed matches the given arguments
|
|
147
|
-
// We can use js-if here, because
|
|
123
|
+
// We can use js-if here, because args are statically sized
|
|
148
124
|
// i.e. the result of the if-statement will be the same for all executions
|
|
149
125
|
// of this method
|
|
150
126
|
const argsHash =
|
|
151
|
-
|
|
127
|
+
(args ?? []).length > 0 ? Poseidon.hash(argsFields) : Field(0);
|
|
152
128
|
|
|
153
|
-
|
|
129
|
+
transaction.argsHash.assertEquals(
|
|
154
130
|
argsHash,
|
|
155
131
|
"argsHash and therefore arguments of transaction and runtime call does not match"
|
|
156
132
|
);
|
|
157
133
|
|
|
158
|
-
const
|
|
159
|
-
|
|
134
|
+
const isMessage = Bool(options.invocationType === "INCOMING_MESSAGE");
|
|
135
|
+
transaction.assertTransactionType(Bool(isMessage));
|
|
136
|
+
|
|
137
|
+
const transactionHash = transaction.hash();
|
|
138
|
+
const networkStateHash = networkState.hash();
|
|
160
139
|
|
|
161
140
|
return new MethodPublicOutput({
|
|
162
141
|
stateTransitionsHash,
|
|
163
142
|
status,
|
|
164
143
|
transactionHash,
|
|
165
144
|
networkStateHash,
|
|
145
|
+
isMessage,
|
|
166
146
|
});
|
|
167
147
|
};
|
|
168
148
|
|
|
@@ -183,6 +163,7 @@ export function combineMethodName(
|
|
|
183
163
|
|
|
184
164
|
export const runtimeMethodMetadataKey = "yab-method";
|
|
185
165
|
export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
|
|
166
|
+
export const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
|
|
186
167
|
|
|
187
168
|
/**
|
|
188
169
|
* Checks the metadata of the provided runtime module and its method,
|
|
@@ -201,7 +182,11 @@ export function isRuntimeMethod(
|
|
|
201
182
|
);
|
|
202
183
|
}
|
|
203
184
|
|
|
204
|
-
export
|
|
185
|
+
export type RuntimeMethodInvocationType = "SIGNATURE" | "INCOMING_MESSAGE";
|
|
186
|
+
|
|
187
|
+
function runtimeMethodInternal(options: {
|
|
188
|
+
invocationType: RuntimeMethodInvocationType;
|
|
189
|
+
}) {
|
|
205
190
|
return (
|
|
206
191
|
target: RuntimeModule<unknown>,
|
|
207
192
|
methodName: string,
|
|
@@ -225,6 +210,13 @@ export function runtimeMethod() {
|
|
|
225
210
|
|
|
226
211
|
Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
|
|
227
212
|
|
|
213
|
+
Reflect.defineMetadata(
|
|
214
|
+
runtimeMethodTypeMetadataKey,
|
|
215
|
+
options.invocationType,
|
|
216
|
+
target,
|
|
217
|
+
methodName
|
|
218
|
+
);
|
|
219
|
+
|
|
228
220
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
229
221
|
const simulatedMethod = descriptor.value as DecoratedMethod;
|
|
230
222
|
|
|
@@ -232,7 +224,7 @@ export function runtimeMethod() {
|
|
|
232
224
|
this: RuntimeModule<unknown>,
|
|
233
225
|
...args: ArgumentTypes
|
|
234
226
|
) {
|
|
235
|
-
const constructorName = this.
|
|
227
|
+
const constructorName = this.name!;
|
|
236
228
|
|
|
237
229
|
/**
|
|
238
230
|
* If its a top level method call, wrap it into a wrapped method,
|
|
@@ -244,7 +236,7 @@ export function runtimeMethod() {
|
|
|
244
236
|
const simulatedWrappedMethod = Reflect.apply(toWrappedMethod, this, [
|
|
245
237
|
methodName,
|
|
246
238
|
simulatedMethod,
|
|
247
|
-
|
|
239
|
+
options,
|
|
248
240
|
]);
|
|
249
241
|
|
|
250
242
|
/**
|
|
@@ -294,3 +286,15 @@ export function runtimeMethod() {
|
|
|
294
286
|
};
|
|
295
287
|
};
|
|
296
288
|
}
|
|
289
|
+
|
|
290
|
+
export function runtimeMessage() {
|
|
291
|
+
return runtimeMethodInternal({
|
|
292
|
+
invocationType: "INCOMING_MESSAGE",
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function runtimeMethod() {
|
|
297
|
+
return runtimeMethodInternal({
|
|
298
|
+
invocationType: "SIGNATURE",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { filterNonUndefined } from "@proto-kit/common";
|
|
2
|
+
import { stringToField, RuntimeMethodIdMapping } from "@proto-kit/protocol";
|
|
2
3
|
import { Poseidon } from "o1js";
|
|
3
4
|
import { inject, injectable } from "tsyringe";
|
|
4
5
|
|
|
6
|
+
import {
|
|
7
|
+
RuntimeMethodInvocationType,
|
|
8
|
+
runtimeMethodTypeMetadataKey,
|
|
9
|
+
} from "../method/runtimeMethod";
|
|
10
|
+
|
|
5
11
|
import type { Runtime, RuntimeModulesRecord } from "./Runtime";
|
|
6
12
|
|
|
7
13
|
/**
|
|
@@ -17,12 +23,10 @@ export class MethodIdResolver {
|
|
|
17
23
|
public constructor(
|
|
18
24
|
@inject("Runtime") private readonly runtime: Runtime<RuntimeModulesRecord>
|
|
19
25
|
) {
|
|
20
|
-
const { modules } = runtime.definition;
|
|
21
|
-
|
|
22
26
|
this.dictionary = runtime.runtimeModuleNames.reduce<
|
|
23
27
|
Record<string, { moduleName: string; methodName: string }>
|
|
24
28
|
>((dict, moduleName) => {
|
|
25
|
-
this.runtime.assertIsValidModuleName(
|
|
29
|
+
this.runtime.assertIsValidModuleName(moduleName);
|
|
26
30
|
|
|
27
31
|
runtime.resolve(moduleName).runtimeMethodNames.forEach((methodName) => {
|
|
28
32
|
dict[this.getMethodId(moduleName, methodName).toString()] = {
|
|
@@ -35,6 +39,49 @@ export class MethodIdResolver {
|
|
|
35
39
|
}, {});
|
|
36
40
|
}
|
|
37
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
|
+
const type = Reflect.getMetadata(
|
|
57
|
+
runtimeMethodTypeMetadataKey,
|
|
58
|
+
module,
|
|
59
|
+
method
|
|
60
|
+
) as RuntimeMethodInvocationType | undefined;
|
|
61
|
+
|
|
62
|
+
if (type !== undefined) {
|
|
63
|
+
return {
|
|
64
|
+
name: `${moduleName}.${method}`,
|
|
65
|
+
methodId: methodIdResolver.getMethodId(moduleName, method),
|
|
66
|
+
type,
|
|
67
|
+
} as const;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return undefined;
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return rawMappings
|
|
75
|
+
.filter(filterNonUndefined)
|
|
76
|
+
.reduce<RuntimeMethodIdMapping>((acc, entry) => {
|
|
77
|
+
acc[entry.name] = {
|
|
78
|
+
methodId: entry.methodId,
|
|
79
|
+
type: entry.type,
|
|
80
|
+
};
|
|
81
|
+
return acc;
|
|
82
|
+
}, {});
|
|
83
|
+
}
|
|
84
|
+
|
|
38
85
|
public getMethodNameFromId(methodId: bigint): [string, string] | undefined {
|
|
39
86
|
const methodPath = this.dictionary[methodId.toString()];
|
|
40
87
|
|
|
@@ -44,19 +91,13 @@ export class MethodIdResolver {
|
|
|
44
91
|
|
|
45
92
|
const { moduleName, methodName } = methodPath;
|
|
46
93
|
|
|
47
|
-
this.runtime.assertIsValidModuleName(
|
|
48
|
-
this.runtime.definition.modules,
|
|
49
|
-
moduleName
|
|
50
|
-
);
|
|
94
|
+
this.runtime.assertIsValidModuleName(moduleName);
|
|
51
95
|
|
|
52
96
|
return [moduleName, methodName];
|
|
53
97
|
}
|
|
54
98
|
|
|
55
99
|
public getMethodId(moduleName: string, methodName: string): bigint {
|
|
56
|
-
this.runtime.assertIsValidModuleName(
|
|
57
|
-
this.runtime.definition.modules,
|
|
58
|
-
moduleName
|
|
59
|
-
);
|
|
100
|
+
this.runtime.assertIsValidModuleName(moduleName);
|
|
60
101
|
|
|
61
102
|
return Poseidon.hash([
|
|
62
103
|
stringToField(moduleName),
|
package/src/runtime/Runtime.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
TypedClass,
|
|
11
11
|
ZkProgrammable,
|
|
12
12
|
PlainZkProgram,
|
|
13
|
-
WithZkProgrammable,
|
|
14
13
|
AreProofsEnabled,
|
|
15
14
|
ChildContainerProvider,
|
|
16
15
|
} from "@proto-kit/common";
|
|
@@ -23,6 +22,7 @@ import {
|
|
|
23
22
|
import {
|
|
24
23
|
combineMethodName,
|
|
25
24
|
isRuntimeMethod,
|
|
25
|
+
runtimeMethodTypeMetadataKey,
|
|
26
26
|
toWrappedMethod,
|
|
27
27
|
WrappedMethod,
|
|
28
28
|
} from "../method/runtimeMethod";
|
|
@@ -32,6 +32,19 @@ import { RuntimeModule } from "./RuntimeModule";
|
|
|
32
32
|
import { MethodIdResolver } from "./MethodIdResolver";
|
|
33
33
|
import { RuntimeEnvironment } from "./RuntimeEnvironment";
|
|
34
34
|
|
|
35
|
+
export function getAllPropertyNames(obj: any) {
|
|
36
|
+
let keys: (string | symbol)[] = [];
|
|
37
|
+
// if primitive (primitives still have keys) skip the first iteration
|
|
38
|
+
if (!(obj instanceof Object)) {
|
|
39
|
+
obj = Object.getPrototypeOf(obj);
|
|
40
|
+
}
|
|
41
|
+
while (obj) {
|
|
42
|
+
keys = keys.concat(Reflect.ownKeys(obj));
|
|
43
|
+
obj = Object.getPrototypeOf(obj);
|
|
44
|
+
}
|
|
45
|
+
return keys;
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
/**
|
|
36
49
|
* Record of modules accepted by the Runtime module container.
|
|
37
50
|
*
|
|
@@ -104,8 +117,9 @@ export class RuntimeZkProgrammable<
|
|
|
104
117
|
(...args: unknown[]) => unknown
|
|
105
118
|
>;
|
|
106
119
|
|
|
107
|
-
const modulePrototypeMethods =
|
|
108
|
-
|
|
120
|
+
const modulePrototypeMethods = getAllPropertyNames(runtimeModule).map(
|
|
121
|
+
(method) => method.toString()
|
|
122
|
+
);
|
|
109
123
|
|
|
110
124
|
const moduleMethods = modulePrototypeMethods.reduce<Methods>(
|
|
111
125
|
(allModuleMethods, methodName) => {
|
|
@@ -115,10 +129,16 @@ export class RuntimeZkProgrammable<
|
|
|
115
129
|
methodName
|
|
116
130
|
);
|
|
117
131
|
const method = modulePrototype[methodName];
|
|
132
|
+
const invocationType = Reflect.getMetadata(
|
|
133
|
+
runtimeMethodTypeMetadataKey,
|
|
134
|
+
runtimeModule,
|
|
135
|
+
methodName
|
|
136
|
+
);
|
|
137
|
+
|
|
118
138
|
const wrappedMethod = Reflect.apply(
|
|
119
139
|
toWrappedMethod,
|
|
120
140
|
runtimeModule,
|
|
121
|
-
[methodName, method]
|
|
141
|
+
[methodName, method, { invocationType }]
|
|
122
142
|
);
|
|
123
143
|
|
|
124
144
|
// eslint-disable-next-line no-warning-comments
|
|
@@ -175,6 +195,7 @@ export class RuntimeZkProgrammable<
|
|
|
175
195
|
return {
|
|
176
196
|
compile: program.compile.bind(program),
|
|
177
197
|
verify: program.verify.bind(program),
|
|
198
|
+
analyzeMethods: program.analyzeMethods.bind(program),
|
|
178
199
|
Proof: SelfProof,
|
|
179
200
|
methods,
|
|
180
201
|
};
|
|
@@ -266,7 +287,7 @@ export class Runtime<Modules extends RuntimeModulesRecord>
|
|
|
266
287
|
}
|
|
267
288
|
const [moduleName, methodName] = methodDescriptor;
|
|
268
289
|
|
|
269
|
-
this.assertIsValidModuleName(
|
|
290
|
+
this.assertIsValidModuleName(moduleName);
|
|
270
291
|
const module = this.resolve(moduleName);
|
|
271
292
|
|
|
272
293
|
// eslint-disable-next-line max-len
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
StateService,
|
|
7
7
|
RuntimeMethodExecutionContext,
|
|
8
8
|
RuntimeMethodExecutionData,
|
|
9
|
+
RuntimeMethodExecutionDataStruct,
|
|
9
10
|
} from "@proto-kit/protocol";
|
|
10
11
|
|
|
11
12
|
import { runtimeMethodNamesMetadataKey } from "../method/runtimeMethod";
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
RuntimeModulesRecord,
|
|
17
18
|
} from "./Runtime";
|
|
18
19
|
import { RuntimeEnvironment } from "./RuntimeEnvironment";
|
|
20
|
+
import { Provable } from "o1js";
|
|
19
21
|
|
|
20
22
|
const errors = {
|
|
21
23
|
inputDataNotSet: () => new Error("Input data for runtime execution not set"),
|
|
@@ -56,15 +58,17 @@ export class RuntimeModule<
|
|
|
56
58
|
this.runtimeMethodNames = methodNames ?? [];
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
RuntimeMethodExecutionContext
|
|
62
|
-
|
|
61
|
+
public getInputs(): RuntimeMethodExecutionData {
|
|
62
|
+
return Provable.witness(RuntimeMethodExecutionDataStruct, () => {
|
|
63
|
+
const { input } = container.resolve<RuntimeMethodExecutionContext>(
|
|
64
|
+
RuntimeMethodExecutionContext
|
|
65
|
+
);
|
|
66
|
+
if (input === undefined) {
|
|
67
|
+
throw errors.inputDataNotSet();
|
|
68
|
+
}
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
return input;
|
|
70
|
+
return input;
|
|
71
|
+
});
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
public get transaction(): RuntimeTransaction {
|
|
@@ -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 {
|
|
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 =
|
|
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
|
-
}
|