@proto-kit/module 0.1.1-develop.1086
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/LICENSE.md +201 -0
- package/README.md +114 -0
- package/dist/factories/MethodIdFactory.d.ts +10 -0
- package/dist/factories/MethodIdFactory.d.ts.map +1 -0
- package/dist/factories/MethodIdFactory.js +10 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/method/MethodParameterEncoder.d.ts +24 -0
- package/dist/method/MethodParameterEncoder.d.ts.map +1 -0
- package/dist/method/MethodParameterEncoder.js +164 -0
- package/dist/method/runtimeMethod.d.ts +33 -0
- package/dist/method/runtimeMethod.d.ts.map +1 -0
- package/dist/method/runtimeMethod.js +167 -0
- package/dist/module/decorator.d.ts +8 -0
- package/dist/module/decorator.d.ts.map +1 -0
- package/dist/module/decorator.js +15 -0
- package/dist/runtime/MethodIdResolver.d.ts +20 -0
- package/dist/runtime/MethodIdResolver.d.ts.map +1 -0
- package/dist/runtime/MethodIdResolver.js +90 -0
- package/dist/runtime/Runtime.d.ts +71 -0
- package/dist/runtime/Runtime.d.ts.map +1 -0
- package/dist/runtime/Runtime.js +220 -0
- package/dist/runtime/RuntimeEnvironment.d.ts +10 -0
- package/dist/runtime/RuntimeEnvironment.d.ts.map +1 -0
- package/dist/runtime/RuntimeEnvironment.js +1 -0
- package/dist/runtime/RuntimeModule.d.ts +37 -0
- package/dist/runtime/RuntimeModule.d.ts.map +1 -0
- package/dist/runtime/RuntimeModule.js +79 -0
- package/dist/state/InMemoryStateService.d.ts +15 -0
- package/dist/state/InMemoryStateService.d.ts.map +1 -0
- package/dist/state/InMemoryStateService.js +23 -0
- package/dist/state/decorator.d.ts +7 -0
- package/dist/state/decorator.d.ts.map +1 -0
- package/dist/state/decorator.js +39 -0
- package/jest.config.cjs +1 -0
- package/package.json +35 -0
- package/src/factories/MethodIdFactory.ts +13 -0
- package/src/index.ts +10 -0
- package/src/method/MethodParameterEncoder.ts +252 -0
- package/src/method/runtimeMethod.ts +307 -0
- package/src/module/decorator.ts +21 -0
- package/src/runtime/MethodIdResolver.ts +108 -0
- package/src/runtime/Runtime.ts +379 -0
- package/src/runtime/RuntimeEnvironment.ts +16 -0
- package/src/runtime/RuntimeModule.ts +112 -0
- package/src/state/InMemoryStateService.ts +25 -0
- package/src/state/decorator.ts +61 -0
- package/test/Runtime.test.ts +70 -0
- package/test/TestingRuntime.ts +45 -0
- package/test/method/MethodParameterEncoder.test.ts +152 -0
- package/test/method/runtimeMethod.test.ts +46 -0
- package/test/modules/Admin.ts +19 -0
- package/test/modules/Balances.test.ts +337 -0
- package/test/modules/Balances.ts +54 -0
- package/test/modules/MethodIdResolver.test.ts +73 -0
- package/test/modules/State.test.ts +81 -0
- package/test/runtimeMethod.test.ts +215 -0
- package/test/tsconfig.json +7 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +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,EAElB,0BAA0B,EAE3B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAM1D,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;AAE7D,KAAK,aAAa,CAAC,CAAC,SAAS,oBAAoB,CAAC,GAAG,CAAC,IACpD,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AAE1C,qBAAa,aAAa,CAAC,MAAM,SAAS,WAAW;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,MAAM,CAAC,GAAG,SAAS,MAAM,MAAM,EACpC,SAAS,EAAE,IAAI,EACf,SAAS,EAAE,GAAG,EACd,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAgB5B,IAAI,CAAC,GAAG,SAAS,MAAM,MAAM,EAClC,SAAS,EAAE,GAAG,EACd,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;CAIpC;AAED;;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;IAE7B,MAAM,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAa;;IAYxC,SAAS,IAAI,0BAA0B;IAa9C,IAAW,WAAW,IAAI,kBAAkB,CAE3C;IAED,IAAW,OAAO,IAAI,YAAY,CAEjC;CACF"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { ConfigurableModule } from "@proto-kit/common";
|
|
11
|
+
import { container, injectable } from "tsyringe";
|
|
12
|
+
import { RuntimeMethodExecutionContext, RuntimeMethodExecutionDataStruct, } from "@proto-kit/protocol";
|
|
13
|
+
import { Provable, Bool } from "o1js";
|
|
14
|
+
import { runtimeMethodNamesMetadataKey } from "../method/runtimeMethod";
|
|
15
|
+
const errors = {
|
|
16
|
+
inputDataNotSet: () => new Error("Input data for runtime execution not set"),
|
|
17
|
+
};
|
|
18
|
+
export class RuntimeEvents {
|
|
19
|
+
constructor(events) {
|
|
20
|
+
this.events = events;
|
|
21
|
+
}
|
|
22
|
+
emitIf(condition, eventName, event) {
|
|
23
|
+
if (this.events === undefined) {
|
|
24
|
+
throw new Error("'events' property not defined, make sure to define the event types on your runtimemodule");
|
|
25
|
+
}
|
|
26
|
+
const eventType = this.events[eventName];
|
|
27
|
+
if (typeof eventName !== "string") {
|
|
28
|
+
throw new Error("Only string");
|
|
29
|
+
}
|
|
30
|
+
return container
|
|
31
|
+
.resolve(RuntimeMethodExecutionContext)
|
|
32
|
+
.addEvent(eventType, event, eventName, condition);
|
|
33
|
+
}
|
|
34
|
+
emit(eventName, event) {
|
|
35
|
+
this.emitIf(Bool(true), eventName, event);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Base class for runtime modules providing the necessary utilities.
|
|
40
|
+
*/
|
|
41
|
+
export let RuntimeModule = class RuntimeModule extends ConfigurableModule {
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
/**
|
|
45
|
+
* Holds all method names that are callable throw transactions
|
|
46
|
+
*/
|
|
47
|
+
this.runtimeMethodNames = [];
|
|
48
|
+
/**
|
|
49
|
+
* This property exists only to typecheck that the RuntimeModule
|
|
50
|
+
* was extended correctly in e.g. a decorator. We need at least
|
|
51
|
+
* one non-optional property in this class to make the typechecking work.
|
|
52
|
+
*/
|
|
53
|
+
this.isRuntimeModule = true;
|
|
54
|
+
this.events = undefined;
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
56
|
+
const methodNames = Reflect.getMetadata(runtimeMethodNamesMetadataKey, this);
|
|
57
|
+
this.runtimeMethodNames = methodNames ?? [];
|
|
58
|
+
}
|
|
59
|
+
getInputs() {
|
|
60
|
+
return Provable.witness(RuntimeMethodExecutionDataStruct, () => {
|
|
61
|
+
const { input } = container.resolve(RuntimeMethodExecutionContext);
|
|
62
|
+
if (input === undefined) {
|
|
63
|
+
throw errors.inputDataNotSet();
|
|
64
|
+
}
|
|
65
|
+
return input;
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
get transaction() {
|
|
69
|
+
return this.getInputs().transaction;
|
|
70
|
+
}
|
|
71
|
+
get network() {
|
|
72
|
+
return this.getInputs().networkState;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
RuntimeModule.presets = {};
|
|
76
|
+
RuntimeModule = __decorate([
|
|
77
|
+
injectable(),
|
|
78
|
+
__metadata("design:paramtypes", [])
|
|
79
|
+
], RuntimeModule);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Field } from "o1js";
|
|
2
|
+
import { SimpleAsyncStateService } from "@proto-kit/protocol";
|
|
3
|
+
/**
|
|
4
|
+
* Naive implementation of an in-memory variant of the StateService interface
|
|
5
|
+
*/
|
|
6
|
+
export declare class InMemoryStateService implements SimpleAsyncStateService {
|
|
7
|
+
/**
|
|
8
|
+
* This mapping container null values if the specific entry has been deleted.
|
|
9
|
+
* This is used by the CachedState service to keep track of deletions
|
|
10
|
+
*/
|
|
11
|
+
values: Record<string, Field[] | null>;
|
|
12
|
+
get(key: Field): Promise<Field[] | undefined>;
|
|
13
|
+
set(key: Field, value: Field[] | undefined): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=InMemoryStateService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryStateService.d.ts","sourceRoot":"","sources":["../../src/state/InMemoryStateService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;GAEG;AACH,qBAAa,oBAAqB,YAAW,uBAAuB;IAClE;;;OAGG;IACI,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,CAAM;IAEtC,GAAG,CAAC,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,SAAS,CAAC;IAI7C,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,SAAS;CAOxD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Naive implementation of an in-memory variant of the StateService interface
|
|
3
|
+
*/
|
|
4
|
+
export class InMemoryStateService {
|
|
5
|
+
constructor() {
|
|
6
|
+
/**
|
|
7
|
+
* This mapping container null values if the specific entry has been deleted.
|
|
8
|
+
* This is used by the CachedState service to keep track of deletions
|
|
9
|
+
*/
|
|
10
|
+
this.values = {};
|
|
11
|
+
}
|
|
12
|
+
async get(key) {
|
|
13
|
+
return this.values[key.toString()] ?? undefined;
|
|
14
|
+
}
|
|
15
|
+
async set(key, value) {
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
this.values[key.toString()] = null;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this.values[key.toString()] = value;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RuntimeModule } from "../runtime/RuntimeModule.js";
|
|
2
|
+
/**
|
|
3
|
+
* Decorates a runtime module property as state, passing down some
|
|
4
|
+
* underlying values to improve developer experience.
|
|
5
|
+
*/
|
|
6
|
+
export declare function state(): <TargetRuntimeModule extends RuntimeModule<unknown>>(target: TargetRuntimeModule, propertyKey: string) => void;
|
|
7
|
+
//# sourceMappingURL=decorator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorator.d.ts","sourceRoot":"","sources":["../../src/state/decorator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAgBjE;;;GAGG;AACH,wBAAgB,KAAK,mGAGJ,MAAM,UAmCtB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Path } from "@proto-kit/protocol";
|
|
2
|
+
const errors = {
|
|
3
|
+
missingName: (className) => new Error(`Unable to provide a unique identifier for state, ${className} is missing a name.
|
|
4
|
+
Did you forget to extend your runtime module with 'extends RuntimeModule'?`),
|
|
5
|
+
missingRuntime: (className) => new Error(`Unable to provide 'runtime' for state, ${className} is missing a name.
|
|
6
|
+
Did you forget to extend your runtime module with 'extends RuntimeModule'?`),
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Decorates a runtime module property as state, passing down some
|
|
10
|
+
* underlying values to improve developer experience.
|
|
11
|
+
*/
|
|
12
|
+
export function state() {
|
|
13
|
+
return (target, propertyKey) => {
|
|
14
|
+
let value;
|
|
15
|
+
Object.defineProperty(target, propertyKey, {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function get() {
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
19
|
+
const self = this;
|
|
20
|
+
if (self.name === undefined) {
|
|
21
|
+
throw errors.missingName(self.constructor.name);
|
|
22
|
+
}
|
|
23
|
+
if (!self.runtime) {
|
|
24
|
+
throw errors.missingRuntime(self.constructor.name);
|
|
25
|
+
}
|
|
26
|
+
const path = Path.fromProperty(self.name, propertyKey);
|
|
27
|
+
if (value) {
|
|
28
|
+
value.path = path;
|
|
29
|
+
// TODO: why is this complaining about `any`?
|
|
30
|
+
value.stateServiceProvider = self.runtime.stateServiceProvider;
|
|
31
|
+
}
|
|
32
|
+
return value;
|
|
33
|
+
},
|
|
34
|
+
set: (newValue) => {
|
|
35
|
+
value = newValue;
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
}
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("../../jest.config.cjs");
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@proto-kit/module",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"private": false,
|
|
5
|
+
"version": "0.1.1-develop.1086+eeb4563a",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p tsconfig.json",
|
|
9
|
+
"dev": "tsc -p tsconfig.json --watch",
|
|
10
|
+
"lint": "eslint ./src ./test",
|
|
11
|
+
"test:file": "node --experimental-vm-modules --experimental-wasm-modules --experimental-wasm-threads ../../node_modules/jest/bin/jest.js",
|
|
12
|
+
"test": "npm run test:file -- ./test/**",
|
|
13
|
+
"test:watch": "npm run test:file -- ./test/** --watch"
|
|
14
|
+
},
|
|
15
|
+
"main": "dist/index.js",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"lodash": "^4.17.21",
|
|
21
|
+
"loglevel": "^1.8.1",
|
|
22
|
+
"reflect-metadata": "^0.1.13"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@jest/globals": "^29.5.0",
|
|
26
|
+
"@types/lodash": "^4.14.194"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@proto-kit/common": "*",
|
|
30
|
+
"@proto-kit/protocol": "*",
|
|
31
|
+
"o1js": "^1.1.0",
|
|
32
|
+
"tsyringe": "^4.7.0"
|
|
33
|
+
},
|
|
34
|
+
"gitHead": "eeb4563a685b29525358ec7404fa9f0251d258d4"
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DependencyFactory, DependencyRecord } from "@proto-kit/common";
|
|
2
|
+
|
|
3
|
+
import { MethodIdResolver } from "../runtime/MethodIdResolver";
|
|
4
|
+
|
|
5
|
+
export class MethodIdFactory implements DependencyFactory {
|
|
6
|
+
public dependencies() {
|
|
7
|
+
return {
|
|
8
|
+
methodIdResolver: {
|
|
9
|
+
useClass: MethodIdResolver,
|
|
10
|
+
},
|
|
11
|
+
} satisfies DependencyRecord;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./method/runtimeMethod";
|
|
2
|
+
export * from "./module/decorator";
|
|
3
|
+
export * from "./runtime/RuntimeModule";
|
|
4
|
+
export * from "./runtime/RuntimeEnvironment";
|
|
5
|
+
export * from "./runtime/Runtime";
|
|
6
|
+
export * from "./state/InMemoryStateService";
|
|
7
|
+
export * from "./state/decorator";
|
|
8
|
+
export * from "./method/MethodParameterEncoder";
|
|
9
|
+
export * from "./runtime/MethodIdResolver";
|
|
10
|
+
export * from "./factories/MethodIdFactory";
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
2
|
+
import {
|
|
3
|
+
Field,
|
|
4
|
+
Proof,
|
|
5
|
+
Provable,
|
|
6
|
+
DynamicProof,
|
|
7
|
+
FlexibleProvablePure,
|
|
8
|
+
} from "o1js";
|
|
9
|
+
import {
|
|
10
|
+
ArgumentTypes,
|
|
11
|
+
ProofTypes,
|
|
12
|
+
ToFieldableStatic,
|
|
13
|
+
TypedClass,
|
|
14
|
+
filterNonUndefined,
|
|
15
|
+
} from "@proto-kit/common";
|
|
16
|
+
|
|
17
|
+
import type { RuntimeModule } from "../runtime/RuntimeModule";
|
|
18
|
+
|
|
19
|
+
const errors = {
|
|
20
|
+
fieldLengthNotMatching: (expected: number, actual: number) =>
|
|
21
|
+
new Error(`Expected ${expected} field elements, got ${actual}`),
|
|
22
|
+
|
|
23
|
+
typeNotCompatible: (name: string, error?: string) =>
|
|
24
|
+
new Error(
|
|
25
|
+
`Cannot decode type ${name}, it has to be either a Struct, CircuitValue or built-in snarkyjs type.${
|
|
26
|
+
error !== undefined ? `Caused by: ${error}` : ""
|
|
27
|
+
}`
|
|
28
|
+
),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type ArgumentType =
|
|
32
|
+
| FlexibleProvablePure<any>
|
|
33
|
+
| typeof Proof<unknown, unknown>
|
|
34
|
+
| typeof DynamicProof<unknown, unknown>;
|
|
35
|
+
|
|
36
|
+
type ArgTypeArray = ArgumentType[];
|
|
37
|
+
|
|
38
|
+
type ArgArray = ArgumentTypes[];
|
|
39
|
+
|
|
40
|
+
function isProofType(type: unknown): type is typeof Proof {
|
|
41
|
+
return (type as unknown as TypedClass<unknown>).prototype instanceof Proof;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isDynamicProofType(type: unknown): type is typeof DynamicProof {
|
|
45
|
+
return (
|
|
46
|
+
(type as unknown as TypedClass<unknown>).prototype instanceof DynamicProof
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isProofBaseType(
|
|
51
|
+
type: unknown
|
|
52
|
+
): type is typeof Proof | typeof DynamicProof {
|
|
53
|
+
return isProofType(type) || isDynamicProofType(type);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getAllPropertyNamesOfPrototypeChain(type: unknown): string[] {
|
|
57
|
+
if (type === undefined || type === null) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
return Object.getOwnPropertyNames(type).concat(
|
|
61
|
+
...getAllPropertyNamesOfPrototypeChain(Object.getPrototypeOf(type))
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isFlexibleProvablePure(
|
|
66
|
+
type: unknown
|
|
67
|
+
): type is FlexibleProvablePure<unknown> {
|
|
68
|
+
// The required properties are defined on the prototype for Structs and CircuitValues
|
|
69
|
+
// but on the constructor function itself for Field and Bool
|
|
70
|
+
// For aliases like Balance in library, it can even be 2 steps upwards the prototype chain
|
|
71
|
+
const props = getAllPropertyNamesOfPrototypeChain(type);
|
|
72
|
+
const mandatory = ["toFields", "fromFields", "sizeInFields"];
|
|
73
|
+
return mandatory.every((prop) => props.includes(prop));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export class MethodParameterEncoder {
|
|
77
|
+
public static fromMethod(target: RuntimeModule<unknown>, methodName: string) {
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
79
|
+
const paramtypes: ArgTypeArray = Reflect.getMetadata(
|
|
80
|
+
"design:paramtypes",
|
|
81
|
+
target,
|
|
82
|
+
methodName
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
if (paramtypes === undefined) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Method with name ${methodName} doesn't exist on this module`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const indizes = paramtypes
|
|
92
|
+
.map((type, index) => {
|
|
93
|
+
if (isProofBaseType(type) || isFlexibleProvablePure(type)) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return `${index}`;
|
|
97
|
+
})
|
|
98
|
+
.filter(filterNonUndefined);
|
|
99
|
+
if (indizes.length > 0) {
|
|
100
|
+
const indexString = indizes.reduce((a, b) => `${a}, ${b}`);
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Not all arguments of method '${target.name}.${methodName}' are provable types or proofs (indizes: [${indexString}])`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return new MethodParameterEncoder(paramtypes);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public static fieldSize(type: ArgumentType): number | undefined {
|
|
110
|
+
if (isProofBaseType(type)) {
|
|
111
|
+
return (
|
|
112
|
+
(MethodParameterEncoder.fieldSize(type.publicInputType) ?? 0) +
|
|
113
|
+
(MethodParameterEncoder.fieldSize(type.publicOutputType) ?? 0)
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
// as any, since we shouldn't be using this workaround in the first place
|
|
117
|
+
return (type as FlexibleProvablePure<unknown>).sizeInFields();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public constructor(private readonly types: ArgTypeArray) {}
|
|
121
|
+
|
|
122
|
+
public decode(fields: Field[], auxiliary: string[]): Promise<ArgArray> {
|
|
123
|
+
if (fields.length < this.fieldSize()) {
|
|
124
|
+
throw errors.fieldLengthNotMatching(this.fieldSize(), fields.length);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let stack = fields.slice();
|
|
128
|
+
const auxiliaryStack = auxiliary.slice();
|
|
129
|
+
|
|
130
|
+
return Promise.all(
|
|
131
|
+
this.types.map((type) => {
|
|
132
|
+
const numberFieldsNeeded = MethodParameterEncoder.fieldSize(type) ?? -1;
|
|
133
|
+
if (numberFieldsNeeded === -1) {
|
|
134
|
+
throw errors.typeNotCompatible(type.constructor.name);
|
|
135
|
+
}
|
|
136
|
+
const structFields = stack.slice(0, numberFieldsNeeded);
|
|
137
|
+
stack = stack.slice(numberFieldsNeeded);
|
|
138
|
+
|
|
139
|
+
// Decode proof
|
|
140
|
+
if (isProofBaseType(type)) {
|
|
141
|
+
const auxiliaryData = auxiliaryStack.shift();
|
|
142
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
143
|
+
const proofData: { proof: string; maxProofsVerified: 0 | 1 | 2 } =
|
|
144
|
+
JSON.parse(auxiliaryData!);
|
|
145
|
+
|
|
146
|
+
const inputFieldSize = MethodParameterEncoder.fieldSize(
|
|
147
|
+
type.publicInputType
|
|
148
|
+
)!;
|
|
149
|
+
const input = structFields
|
|
150
|
+
.slice(0, inputFieldSize)
|
|
151
|
+
.map((x) => x.toString());
|
|
152
|
+
const output = structFields
|
|
153
|
+
.slice(inputFieldSize)
|
|
154
|
+
.map((x) => x.toString());
|
|
155
|
+
|
|
156
|
+
// fromJSON has incompatible signature for Proof and DynamicProof
|
|
157
|
+
if (isProofType(type)) {
|
|
158
|
+
return type.fromJSON({
|
|
159
|
+
...proofData,
|
|
160
|
+
publicInput: input,
|
|
161
|
+
publicOutput: output,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (isDynamicProofType(type)) {
|
|
165
|
+
return type.fromJSON({
|
|
166
|
+
...proofData,
|
|
167
|
+
publicInput: input,
|
|
168
|
+
publicOutput: output,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return (type as FlexibleProvablePure<unknown>).fromFields(
|
|
174
|
+
structFields
|
|
175
|
+
) as any;
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Variant of encode() for provable code that skips the unprovable
|
|
182
|
+
* json encoding
|
|
183
|
+
*/
|
|
184
|
+
public encode(args: ArgumentTypes) {
|
|
185
|
+
/**
|
|
186
|
+
* Use the type info obtained previously to convert
|
|
187
|
+
* the args passed to fields
|
|
188
|
+
*/
|
|
189
|
+
return args
|
|
190
|
+
.map((argument, index) => {
|
|
191
|
+
if (argument instanceof Proof || argument instanceof DynamicProof) {
|
|
192
|
+
const argumentType = this.types[index] as ProofTypes;
|
|
193
|
+
|
|
194
|
+
const { publicOutputType, publicInputType } = argumentType;
|
|
195
|
+
|
|
196
|
+
const inputFields =
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
198
|
+
publicInputType?.toFields(argument.publicInput as any) ?? [];
|
|
199
|
+
|
|
200
|
+
const outputFields =
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
202
|
+
publicOutputType?.toFields(argument.publicOutput as any) ?? [];
|
|
203
|
+
|
|
204
|
+
let auxiliary = "";
|
|
205
|
+
|
|
206
|
+
// Has to be asProver, because this function will be called by runtimeMethod
|
|
207
|
+
// to transform the args into a Field[] to compute the argsHash
|
|
208
|
+
// In this case, the auxiliary might be empty, but it isn't used by that method anyways
|
|
209
|
+
Provable.asProver(() => {
|
|
210
|
+
const jsonProof = argument.toJSON();
|
|
211
|
+
auxiliary = JSON.stringify({
|
|
212
|
+
proof: jsonProof.proof,
|
|
213
|
+
maxProofsVerified: jsonProof.maxProofsVerified,
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
fields: [...inputFields, ...outputFields],
|
|
219
|
+
auxiliary,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const argumentType = this.types[index] as ToFieldableStatic;
|
|
224
|
+
return {
|
|
225
|
+
fields: argumentType.toFields(argument),
|
|
226
|
+
auxiliary: undefined,
|
|
227
|
+
};
|
|
228
|
+
})
|
|
229
|
+
.reduce<{
|
|
230
|
+
fields: Field[];
|
|
231
|
+
auxiliary: string[];
|
|
232
|
+
}>(
|
|
233
|
+
(a, b) => {
|
|
234
|
+
return {
|
|
235
|
+
fields: [...a.fields, ...b.fields],
|
|
236
|
+
auxiliary:
|
|
237
|
+
b.auxiliary !== undefined
|
|
238
|
+
? [...a.auxiliary, b.auxiliary]
|
|
239
|
+
: a.auxiliary,
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
{ fields: [], auxiliary: [] }
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public fieldSize(): number {
|
|
247
|
+
return this.types
|
|
248
|
+
.map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
|
|
249
|
+
.reduce((a, b) => a + b, 0);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/* eslint-enable @typescript-eslint/consistent-type-assertions */
|