@proto-kit/module 0.1.1-develop.165 → 0.1.1-develop.1665
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factories/MethodIdFactory.d.ts +9 -0
- package/dist/factories/MethodIdFactory.d.ts.map +1 -0
- package/dist/factories/MethodIdFactory.js +12 -0
- package/dist/factories/MethodIdFactory.js.map +1 -0
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -0
- package/dist/messages/OutgoingMessages.d.ts +215 -0
- package/dist/messages/OutgoingMessages.d.ts.map +1 -0
- package/dist/messages/OutgoingMessages.js +66 -0
- package/dist/messages/OutgoingMessages.js.map +1 -0
- package/dist/method/MethodParameterEncoder.d.ts +26 -0
- package/dist/method/MethodParameterEncoder.d.ts.map +1 -0
- package/dist/method/MethodParameterEncoder.js +169 -0
- package/dist/method/MethodParameterEncoder.js.map +1 -0
- package/dist/method/runtimeMethod.d.ts +22 -5
- package/dist/method/runtimeMethod.d.ts.map +1 -1
- package/dist/method/runtimeMethod.js +79 -24
- package/dist/method/runtimeMethod.js.map +1 -0
- package/dist/module/decorator.js +1 -0
- package/dist/module/decorator.js.map +1 -0
- package/dist/runtime/MethodIdResolver.d.ts +20 -0
- package/dist/runtime/MethodIdResolver.d.ts.map +1 -0
- package/dist/runtime/MethodIdResolver.js +91 -0
- package/dist/runtime/MethodIdResolver.js.map +1 -0
- package/dist/runtime/Runtime.d.ts +22 -28
- package/dist/runtime/Runtime.d.ts.map +1 -1
- package/dist/runtime/Runtime.js +116 -70
- package/dist/runtime/Runtime.js.map +1 -0
- package/dist/runtime/RuntimeEnvironment.d.ts +10 -0
- package/dist/runtime/RuntimeEnvironment.d.ts.map +1 -0
- package/dist/runtime/RuntimeEnvironment.js +2 -0
- package/dist/runtime/RuntimeEnvironment.js.map +1 -0
- package/dist/runtime/RuntimeModule.d.ts +23 -14
- package/dist/runtime/RuntimeModule.d.ts.map +1 -1
- package/dist/runtime/RuntimeModule.js +47 -10
- package/dist/runtime/RuntimeModule.js.map +1 -0
- package/dist/state/InMemoryStateService.d.ts +11 -10
- package/dist/state/InMemoryStateService.d.ts.map +1 -1
- package/dist/state/InMemoryStateService.js +11 -8
- package/dist/state/InMemoryStateService.js.map +1 -0
- package/jest.config.cjs +12 -1
- package/package.json +10 -11
- package/src/factories/MethodIdFactory.ts +15 -0
- package/src/index.ts +5 -7
- package/src/messages/OutgoingMessages.ts +122 -0
- package/src/method/MethodParameterEncoder.ts +260 -0
- package/src/method/runtimeMethod.ts +146 -31
- package/src/runtime/MethodIdResolver.ts +108 -0
- package/src/runtime/Runtime.ts +191 -112
- package/src/runtime/RuntimeEnvironment.ts +16 -0
- package/src/runtime/RuntimeModule.ts +77 -27
- package/src/state/InMemoryStateService.ts +14 -18
- package/test/Runtime.test.ts +69 -36
- package/test/TestingRuntime.ts +43 -0
- package/test/messages/message.test.ts +42 -0
- package/test/method/MethodParameterEncoder.test.ts +121 -0
- package/test/method/runtimeMethod-fail.test.ts +50 -0
- package/{src/method/decorator.test.ts → test/method/runtimeMethod.test.ts} +3 -3
- package/test/modules/Admin.ts +4 -4
- package/test/modules/Balances.test.ts +92 -78
- package/test/modules/Balances.ts +19 -16
- package/test/modules/MethodIdResolver.test.ts +73 -0
- package/test/modules/State.test.ts +81 -0
- package/test/runtimeMethod.test.ts +192 -20
- package/test/tsconfig.json +7 -0
- package/tsconfig.json +2 -2
- package/dist/chain/Chain.d.ts +0 -109
- package/dist/chain/Chain.d.ts.map +0 -1
- package/dist/chain/Chain.js +0 -229
- package/dist/method/MethodExecutionContext.d.ts +0 -73
- package/dist/method/MethodExecutionContext.d.ts.map +0 -1
- package/dist/method/MethodExecutionContext.js +0 -112
- package/dist/method/MethodParameterDecoder.d.ts +0 -22
- package/dist/method/MethodParameterDecoder.d.ts.map +0 -1
- package/dist/method/MethodParameterDecoder.js +0 -33
- package/dist/method/RuntimeMethodExecutionContext.d.ts +0 -57
- package/dist/method/RuntimeMethodExecutionContext.d.ts.map +0 -1
- package/dist/method/RuntimeMethodExecutionContext.js +0 -92
- package/dist/method/assert.d.ts +0 -12
- package/dist/method/assert.d.ts.map +0 -1
- package/dist/method/assert.js +0 -23
- package/dist/method/decorator.d.ts +0 -45
- package/dist/method/decorator.d.ts.map +0 -1
- package/dist/method/decorator.js +0 -140
- package/dist/state/State.d.ts +0 -65
- package/dist/state/State.d.ts.map +0 -1
- package/dist/state/State.js +0 -114
- package/dist/state/StateMap.d.ts +0 -37
- package/dist/state/StateMap.d.ts.map +0 -1
- package/dist/state/StateMap.js +0 -56
- package/dist/state/StateServiceProvider.d.ts +0 -10
- package/dist/state/StateServiceProvider.d.ts.map +0 -1
- package/dist/state/StateServiceProvider.js +0 -34
- package/dist/state/decorator.d.ts +0 -7
- package/dist/state/decorator.d.ts.map +0 -1
- package/dist/state/decorator.js +0 -42
- package/src/method/MethodParameterDecoder.ts +0 -68
- package/src/method/RuntimeMethodExecutionContext.ts +0 -111
- package/src/method/assert.test.ts +0 -49
- package/src/method/assert.ts +0 -27
- package/src/state/State.ts +0 -154
- package/src/state/StateMap.ts +0 -69
- package/src/state/StateServiceProvider.ts +0 -24
- package/src/state/decorator.ts +0 -65
- package/test/state/MerkleTree.test.ts +0 -95
- package/test/state/MockAsyncMerkleStore.ts +0 -28
- package/test/transaction.test.ts +0 -82
- package/tsconfig.test.json +0 -9
package/src/index.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
export * from "./method/RuntimeMethodExecutionContext";
|
|
2
|
-
export * from "./method/assert";
|
|
3
1
|
export * from "./method/runtimeMethod";
|
|
4
2
|
export * from "./module/decorator";
|
|
5
3
|
export * from "./runtime/RuntimeModule";
|
|
4
|
+
export * from "./runtime/RuntimeEnvironment";
|
|
6
5
|
export * from "./runtime/Runtime";
|
|
7
6
|
export * from "./state/InMemoryStateService";
|
|
8
|
-
export * from "./
|
|
9
|
-
export * from "./
|
|
10
|
-
export * from "./
|
|
11
|
-
export * from "./
|
|
12
|
-
export * from "./method/MethodParameterDecoder";
|
|
7
|
+
export * from "./method/MethodParameterEncoder";
|
|
8
|
+
export * from "./runtime/MethodIdResolver";
|
|
9
|
+
export * from "./factories/MethodIdFactory";
|
|
10
|
+
export * from "./messages/OutgoingMessages";
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Field,
|
|
3
|
+
FlexibleProvablePure,
|
|
4
|
+
InferProvable,
|
|
5
|
+
Struct,
|
|
6
|
+
TokenId,
|
|
7
|
+
} from "o1js";
|
|
8
|
+
import {
|
|
9
|
+
OutgoingMessageEvent,
|
|
10
|
+
OutgoingMessageKeyStruct,
|
|
11
|
+
PROTOKIT_FIELD_PREFIXES,
|
|
12
|
+
RuntimeMethodExecutionContext,
|
|
13
|
+
state as stateDecorator,
|
|
14
|
+
StateMap,
|
|
15
|
+
WithPath,
|
|
16
|
+
WithStateServiceProvider,
|
|
17
|
+
} from "@proto-kit/protocol";
|
|
18
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
19
|
+
import { Mixin } from "ts-mixer";
|
|
20
|
+
import { prefixToField, StringKeyOf } from "@proto-kit/common";
|
|
21
|
+
import { container } from "tsyringe";
|
|
22
|
+
|
|
23
|
+
export type OutgoingMessagesRecord = Record<string, FlexibleProvablePure<any>>;
|
|
24
|
+
|
|
25
|
+
export const outgoingMessage = stateDecorator;
|
|
26
|
+
|
|
27
|
+
export class OutgoingMessages<
|
|
28
|
+
Messages extends OutgoingMessagesRecord,
|
|
29
|
+
> extends Mixin(WithPath, WithStateServiceProvider) {
|
|
30
|
+
public readonly eventTypes: Record<
|
|
31
|
+
string,
|
|
32
|
+
{
|
|
33
|
+
messageType: FlexibleProvablePure<{ messageType: Field; value: any }>;
|
|
34
|
+
eventType: FlexibleProvablePure<{
|
|
35
|
+
key: OutgoingMessageKeyStruct;
|
|
36
|
+
value: any;
|
|
37
|
+
messageType: Field;
|
|
38
|
+
}>;
|
|
39
|
+
}
|
|
40
|
+
>;
|
|
41
|
+
|
|
42
|
+
public constructor(private readonly messages: Messages) {
|
|
43
|
+
super();
|
|
44
|
+
this.eventTypes = this.computeEventTypes();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private counterState() {
|
|
48
|
+
const state = new StateMap(Field, Field);
|
|
49
|
+
state.path = PROTOKIT_FIELD_PREFIXES.OUTGOING_MESSAGE_COUNTER_PATH;
|
|
50
|
+
state.stateServiceProvider = this.stateServiceProvider;
|
|
51
|
+
return state;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public static getEventName(key: string) {
|
|
55
|
+
return `outgoing-${key}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public computeEventTypes() {
|
|
59
|
+
return Object.fromEntries(
|
|
60
|
+
Object.entries(this.messages).map(([key, type]) => {
|
|
61
|
+
class OutgoingMessageEventStruct extends Struct({
|
|
62
|
+
key: OutgoingMessageKeyStruct,
|
|
63
|
+
value: type,
|
|
64
|
+
messageType: Field,
|
|
65
|
+
}) {}
|
|
66
|
+
|
|
67
|
+
class OutgoingMessageStruct extends Struct({
|
|
68
|
+
value: type,
|
|
69
|
+
messageType: Field,
|
|
70
|
+
}) {}
|
|
71
|
+
|
|
72
|
+
return [
|
|
73
|
+
OutgoingMessages.getEventName(key),
|
|
74
|
+
{
|
|
75
|
+
messageType: OutgoingMessageStruct,
|
|
76
|
+
eventType: OutgoingMessageEventStruct,
|
|
77
|
+
},
|
|
78
|
+
];
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private emitEvent<Key extends StringKeyOf<Messages>>(
|
|
84
|
+
eventName: string,
|
|
85
|
+
value: OutgoingMessageEvent<InferProvable<Messages[Key]>>
|
|
86
|
+
) {
|
|
87
|
+
const outgoingMessageType = this.eventTypes[eventName].eventType;
|
|
88
|
+
|
|
89
|
+
return container
|
|
90
|
+
.resolve(RuntimeMethodExecutionContext)
|
|
91
|
+
.addEvent<
|
|
92
|
+
OutgoingMessageEvent<InferProvable<Messages[Key]>>
|
|
93
|
+
>(outgoingMessageType, value, eventName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public async emitMessage<Key extends StringKeyOf<Messages>>(
|
|
97
|
+
key: Key,
|
|
98
|
+
value: InferProvable<Messages[Key]>,
|
|
99
|
+
tokenId: Field = TokenId.default
|
|
100
|
+
) {
|
|
101
|
+
const eventName = OutgoingMessages.getEventName(key);
|
|
102
|
+
|
|
103
|
+
const stateMap = new StateMap(
|
|
104
|
+
OutgoingMessageKeyStruct,
|
|
105
|
+
this.eventTypes[eventName].messageType
|
|
106
|
+
);
|
|
107
|
+
stateMap.path = PROTOKIT_FIELD_PREFIXES.OUTGOING_MESSAGE_BASE_PATH;
|
|
108
|
+
stateMap.stateServiceProvider = this.stateServiceProvider;
|
|
109
|
+
|
|
110
|
+
const counterState = this.counterState();
|
|
111
|
+
const counterOption = await counterState.get(tokenId);
|
|
112
|
+
const counter = counterOption.orElse(Field(0));
|
|
113
|
+
|
|
114
|
+
const messageKey = { index: counter, tokenId };
|
|
115
|
+
const messageType = prefixToField(key);
|
|
116
|
+
|
|
117
|
+
await counterState.set(tokenId, counter.add(1));
|
|
118
|
+
await stateMap.set(messageKey, { messageType, value });
|
|
119
|
+
|
|
120
|
+
this.emitEvent(eventName, { key: messageKey, value, messageType });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/consistent-type-assertions */
|
|
2
|
+
import {
|
|
3
|
+
Field,
|
|
4
|
+
Proof,
|
|
5
|
+
Provable,
|
|
6
|
+
DynamicProof,
|
|
7
|
+
FlexibleProvablePure,
|
|
8
|
+
} from "o1js";
|
|
9
|
+
import {
|
|
10
|
+
ArgumentTypes,
|
|
11
|
+
ProofTypes,
|
|
12
|
+
ToFieldableStatic,
|
|
13
|
+
TypedClass,
|
|
14
|
+
filterNonUndefined,
|
|
15
|
+
} from "@proto-kit/common";
|
|
16
|
+
|
|
17
|
+
import type { RuntimeModule } from "../runtime/RuntimeModule";
|
|
18
|
+
|
|
19
|
+
const errors = {
|
|
20
|
+
fieldLengthNotMatching: (expected: number, actual: number) =>
|
|
21
|
+
new Error(`Expected ${expected} field elements, got ${actual}`),
|
|
22
|
+
|
|
23
|
+
typeNotCompatible: (name: string, error?: string) =>
|
|
24
|
+
new Error(
|
|
25
|
+
`Cannot decode type ${name}, it has to be either a Struct, CircuitValue or built-in snarkyjs type.${
|
|
26
|
+
error !== undefined ? `Caused by: ${error}` : ""
|
|
27
|
+
}`
|
|
28
|
+
),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type ArgumentType =
|
|
32
|
+
| FlexibleProvablePure<any>
|
|
33
|
+
| typeof Proof<unknown, unknown>
|
|
34
|
+
| typeof DynamicProof<unknown, unknown>;
|
|
35
|
+
|
|
36
|
+
type ArgTypeArray = ArgumentType[];
|
|
37
|
+
|
|
38
|
+
type ArgArray = ArgumentTypes[];
|
|
39
|
+
|
|
40
|
+
function isProofType(type: unknown): type is typeof Proof {
|
|
41
|
+
return (type as unknown as TypedClass<unknown>).prototype instanceof Proof;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isDynamicProofType(type: unknown): type is typeof DynamicProof {
|
|
45
|
+
return (
|
|
46
|
+
(type as unknown as TypedClass<unknown>).prototype instanceof DynamicProof
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isProofBaseType(
|
|
51
|
+
type: unknown
|
|
52
|
+
): type is typeof Proof | typeof DynamicProof {
|
|
53
|
+
return isProofType(type) || isDynamicProofType(type);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getAllPropertyNamesOfPrototypeChain(type: unknown): string[] {
|
|
57
|
+
if (type === undefined || type === null) {
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
return Object.getOwnPropertyNames(type).concat(
|
|
61
|
+
...getAllPropertyNamesOfPrototypeChain(Object.getPrototypeOf(type))
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function isFlexibleProvablePure(
|
|
66
|
+
type: unknown
|
|
67
|
+
): type is FlexibleProvablePure<unknown> {
|
|
68
|
+
// The required properties are defined on the prototype for Structs and CircuitValues
|
|
69
|
+
// but on the constructor function itself for Field and Bool
|
|
70
|
+
// For aliases like Balance in library, it can even be 2 steps upwards the prototype chain
|
|
71
|
+
const props = getAllPropertyNamesOfPrototypeChain(type);
|
|
72
|
+
const mandatory = ["toFields", "fromFields", "sizeInFields"];
|
|
73
|
+
return mandatory.every((prop) => props.includes(prop));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function checkArgsProvable(
|
|
77
|
+
target: RuntimeModule<unknown>,
|
|
78
|
+
methodName: string
|
|
79
|
+
) {
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
81
|
+
const paramtypes: ArgTypeArray = Reflect.getMetadata(
|
|
82
|
+
"design:paramtypes",
|
|
83
|
+
target,
|
|
84
|
+
methodName
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
if (paramtypes === undefined) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Method with name ${methodName} doesn't exist on this module`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const indizes = paramtypes
|
|
94
|
+
.map((type, index) => {
|
|
95
|
+
if (isProofBaseType(type) || isFlexibleProvablePure(type)) {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
return `${index}`;
|
|
99
|
+
})
|
|
100
|
+
.filter(filterNonUndefined);
|
|
101
|
+
if (indizes.length > 0) {
|
|
102
|
+
const indexString = indizes.reduce((a, b) => `${a}, ${b}`);
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Not all arguments of method '${target.name}.${methodName}' are provable types or proofs (indizes: [${indexString}])`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return paramtypes;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export class MethodParameterEncoder {
|
|
111
|
+
public static fromMethod(target: RuntimeModule<unknown>, methodName: string) {
|
|
112
|
+
const paramtypes = checkArgsProvable(target, methodName);
|
|
113
|
+
|
|
114
|
+
return new MethodParameterEncoder(paramtypes);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
public static fieldSize(type: ArgumentType): number | undefined {
|
|
118
|
+
if (isProofBaseType(type)) {
|
|
119
|
+
return (
|
|
120
|
+
(MethodParameterEncoder.fieldSize(type.publicInputType) ?? 0) +
|
|
121
|
+
(MethodParameterEncoder.fieldSize(type.publicOutputType) ?? 0)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
// as any, since we shouldn't be using this workaround in the first place
|
|
125
|
+
return (type as FlexibleProvablePure<unknown>).sizeInFields();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public constructor(private readonly types: ArgTypeArray) {}
|
|
129
|
+
|
|
130
|
+
public decode(fields: Field[], auxiliary: string[]): Promise<ArgArray> {
|
|
131
|
+
if (fields.length < this.fieldSize()) {
|
|
132
|
+
throw errors.fieldLengthNotMatching(this.fieldSize(), fields.length);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let stack = fields.slice();
|
|
136
|
+
const auxiliaryStack = auxiliary.slice();
|
|
137
|
+
|
|
138
|
+
return Promise.all(
|
|
139
|
+
this.types.map((type) => {
|
|
140
|
+
const numberFieldsNeeded = MethodParameterEncoder.fieldSize(type) ?? -1;
|
|
141
|
+
if (numberFieldsNeeded === -1) {
|
|
142
|
+
throw errors.typeNotCompatible(type.constructor.name);
|
|
143
|
+
}
|
|
144
|
+
const structFields = stack.slice(0, numberFieldsNeeded);
|
|
145
|
+
stack = stack.slice(numberFieldsNeeded);
|
|
146
|
+
|
|
147
|
+
// Decode proof
|
|
148
|
+
if (isProofBaseType(type)) {
|
|
149
|
+
const auxiliaryData = auxiliaryStack.shift();
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
151
|
+
const proofData: { proof: string; maxProofsVerified: 0 | 1 | 2 } =
|
|
152
|
+
JSON.parse(auxiliaryData!);
|
|
153
|
+
|
|
154
|
+
const inputFieldSize = MethodParameterEncoder.fieldSize(
|
|
155
|
+
type.publicInputType
|
|
156
|
+
)!;
|
|
157
|
+
const input = structFields
|
|
158
|
+
.slice(0, inputFieldSize)
|
|
159
|
+
.map((x) => x.toString());
|
|
160
|
+
const output = structFields
|
|
161
|
+
.slice(inputFieldSize)
|
|
162
|
+
.map((x) => x.toString());
|
|
163
|
+
|
|
164
|
+
// fromJSON has incompatible signature for Proof and DynamicProof
|
|
165
|
+
if (isProofType(type)) {
|
|
166
|
+
return type.fromJSON({
|
|
167
|
+
...proofData,
|
|
168
|
+
publicInput: input,
|
|
169
|
+
publicOutput: output,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (isDynamicProofType(type)) {
|
|
173
|
+
return type.fromJSON({
|
|
174
|
+
...proofData,
|
|
175
|
+
publicInput: input,
|
|
176
|
+
publicOutput: output,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return (type as FlexibleProvablePure<unknown>).fromFields(
|
|
182
|
+
structFields
|
|
183
|
+
) as any;
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Variant of encode() for provable code that skips the unprovable
|
|
190
|
+
* json encoding
|
|
191
|
+
*/
|
|
192
|
+
public encode(args: ArgumentTypes) {
|
|
193
|
+
/**
|
|
194
|
+
* Use the type info obtained previously to convert
|
|
195
|
+
* the args passed to fields
|
|
196
|
+
*/
|
|
197
|
+
return args
|
|
198
|
+
.map((argument, index) => {
|
|
199
|
+
if (argument instanceof Proof || argument instanceof DynamicProof) {
|
|
200
|
+
const argumentType = this.types[index] as ProofTypes;
|
|
201
|
+
|
|
202
|
+
const { publicOutputType, publicInputType } = argumentType;
|
|
203
|
+
|
|
204
|
+
const inputFields =
|
|
205
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
206
|
+
publicInputType?.toFields(argument.publicInput as any) ?? [];
|
|
207
|
+
|
|
208
|
+
const outputFields =
|
|
209
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
210
|
+
publicOutputType?.toFields(argument.publicOutput as any) ?? [];
|
|
211
|
+
|
|
212
|
+
let auxiliary = "";
|
|
213
|
+
|
|
214
|
+
// Has to be asProver, because this function will be called by runtimeMethod
|
|
215
|
+
// to transform the args into a Field[] to compute the argsHash
|
|
216
|
+
// In this case, the auxiliary might be empty, but it isn't used by that method anyways
|
|
217
|
+
Provable.asProver(() => {
|
|
218
|
+
const jsonProof = argument.toJSON();
|
|
219
|
+
auxiliary = JSON.stringify({
|
|
220
|
+
proof: jsonProof.proof,
|
|
221
|
+
maxProofsVerified: jsonProof.maxProofsVerified,
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return {
|
|
226
|
+
fields: [...inputFields, ...outputFields],
|
|
227
|
+
auxiliary,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const argumentType = this.types[index] as ToFieldableStatic;
|
|
232
|
+
return {
|
|
233
|
+
fields: argumentType.toFields(argument),
|
|
234
|
+
auxiliary: undefined,
|
|
235
|
+
};
|
|
236
|
+
})
|
|
237
|
+
.reduce<{
|
|
238
|
+
fields: Field[];
|
|
239
|
+
auxiliary: string[];
|
|
240
|
+
}>(
|
|
241
|
+
(a, b) => {
|
|
242
|
+
return {
|
|
243
|
+
fields: [...a.fields, ...b.fields],
|
|
244
|
+
auxiliary:
|
|
245
|
+
b.auxiliary !== undefined
|
|
246
|
+
? [...a.auxiliary, b.auxiliary]
|
|
247
|
+
: a.auxiliary,
|
|
248
|
+
};
|
|
249
|
+
},
|
|
250
|
+
{ fields: [], auxiliary: [] }
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public fieldSize(): number {
|
|
255
|
+
return this.types
|
|
256
|
+
.map((type) => MethodParameterEncoder.fieldSize(type) ?? 0)
|
|
257
|
+
.reduce((a, b) => a + b, 0);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/* eslint-enable @typescript-eslint/consistent-type-assertions */
|
|
@@ -1,16 +1,25 @@
|
|
|
1
|
-
import { Bool, Field,
|
|
1
|
+
import { Bool, Field, FlexibleProvablePure, Poseidon } from "o1js";
|
|
2
2
|
import { container } from "tsyringe";
|
|
3
3
|
import {
|
|
4
|
-
StateTransition,
|
|
5
|
-
DefaultProvableHashList,
|
|
6
4
|
ProvableStateTransition,
|
|
7
5
|
MethodPublicOutput,
|
|
6
|
+
RuntimeMethodExecutionContext,
|
|
7
|
+
StateTransitionReductionList,
|
|
8
|
+
DefaultProvableHashList,
|
|
8
9
|
} from "@proto-kit/protocol";
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
DecoratedMethod,
|
|
12
|
+
toProver,
|
|
13
|
+
ZkProgrammable,
|
|
14
|
+
ArgumentTypes,
|
|
15
|
+
} from "@proto-kit/common";
|
|
10
16
|
|
|
11
17
|
import type { RuntimeModule } from "../runtime/RuntimeModule.js";
|
|
12
18
|
|
|
13
|
-
import {
|
|
19
|
+
import {
|
|
20
|
+
MethodParameterEncoder,
|
|
21
|
+
checkArgsProvable,
|
|
22
|
+
} from "./MethodParameterEncoder";
|
|
14
23
|
|
|
15
24
|
const errors = {
|
|
16
25
|
runtimeNotProvided: (name: string) =>
|
|
@@ -20,13 +29,19 @@ const errors = {
|
|
|
20
29
|
new Error(
|
|
21
30
|
"Method execution inputs not provided, provide them via context.inputs"
|
|
22
31
|
),
|
|
32
|
+
|
|
33
|
+
runtimeNameNotSet: () => new Error("Runtime name was not set"),
|
|
34
|
+
|
|
35
|
+
fieldNotConstant: (name: string) =>
|
|
36
|
+
new Error(
|
|
37
|
+
`In-circuit field ${name} not a constant, this is likely a framework bug`
|
|
38
|
+
),
|
|
23
39
|
};
|
|
24
40
|
|
|
25
41
|
export function toStateTransitionsHash(
|
|
26
|
-
|
|
27
|
-
stateTransitions: StateTransition<any>[]
|
|
42
|
+
stateTransitions: { toProvable: () => ProvableStateTransition }[]
|
|
28
43
|
) {
|
|
29
|
-
const stateTransitionsHashList = new
|
|
44
|
+
const stateTransitionsHashList = new StateTransitionReductionList(
|
|
30
45
|
ProvableStateTransition
|
|
31
46
|
);
|
|
32
47
|
|
|
@@ -40,39 +55,102 @@ export function toStateTransitionsHash(
|
|
|
40
55
|
.toField();
|
|
41
56
|
}
|
|
42
57
|
|
|
43
|
-
|
|
44
|
-
|
|
58
|
+
export function toEventsHash(
|
|
59
|
+
events: {
|
|
60
|
+
eventType: FlexibleProvablePure<any>;
|
|
61
|
+
event: any;
|
|
62
|
+
eventName: string;
|
|
63
|
+
condition: Bool;
|
|
64
|
+
}[]
|
|
65
|
+
) {
|
|
66
|
+
return events.reduce((acc, event) => {
|
|
67
|
+
const hashList = new DefaultProvableHashList(event.eventType, acc);
|
|
68
|
+
hashList.pushIf(event.event, event.condition);
|
|
69
|
+
return hashList.commitment;
|
|
70
|
+
}, Field(0));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export type WrappedMethod = (...args: ArgumentTypes) => MethodPublicOutput;
|
|
74
|
+
export type AsyncWrappedMethod = (
|
|
75
|
+
...args: ArgumentTypes
|
|
76
|
+
) => Promise<MethodPublicOutput>;
|
|
45
77
|
|
|
46
78
|
export function toWrappedMethod(
|
|
47
79
|
this: RuntimeModule<unknown>,
|
|
48
80
|
methodName: string,
|
|
49
|
-
moduleMethod: (...args:
|
|
50
|
-
|
|
81
|
+
moduleMethod: (...args: ArgumentTypes) => Promise<any>,
|
|
82
|
+
options: {
|
|
83
|
+
invocationType: RuntimeMethodInvocationType;
|
|
84
|
+
}
|
|
85
|
+
): AsyncWrappedMethod {
|
|
51
86
|
const executionContext = container.resolve<RuntimeMethodExecutionContext>(
|
|
52
87
|
RuntimeMethodExecutionContext
|
|
53
88
|
);
|
|
54
89
|
|
|
55
|
-
const wrappedMethod:
|
|
56
|
-
|
|
90
|
+
const wrappedMethod: AsyncWrappedMethod = async (
|
|
91
|
+
...args
|
|
92
|
+
): Promise<MethodPublicOutput> => {
|
|
93
|
+
await Reflect.apply(moduleMethod, this, args);
|
|
57
94
|
const {
|
|
58
|
-
result: { stateTransitions, status },
|
|
59
|
-
input,
|
|
95
|
+
result: { stateTransitions, status, events },
|
|
60
96
|
} = executionContext.current();
|
|
61
97
|
|
|
62
98
|
const stateTransitionsHash = toStateTransitionsHash(stateTransitions);
|
|
99
|
+
const eventsHash = toEventsHash(events);
|
|
100
|
+
|
|
101
|
+
const { name, parent: runtime } = this;
|
|
102
|
+
|
|
103
|
+
if (name === undefined) {
|
|
104
|
+
throw errors.runtimeNameNotSet();
|
|
105
|
+
}
|
|
106
|
+
if (runtime === undefined) {
|
|
107
|
+
throw errors.runtimeNotProvided(name);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const { transaction, networkState } = executionContext.witnessInput();
|
|
111
|
+
const { methodIdResolver } = runtime;
|
|
63
112
|
|
|
64
|
-
|
|
65
|
-
|
|
113
|
+
// Assert that the given transaction has the correct methodId
|
|
114
|
+
const thisMethodId = Field(methodIdResolver.getMethodId(name, methodName));
|
|
115
|
+
if (!thisMethodId.isConstant()) {
|
|
116
|
+
throw errors.fieldNotConstant("methodId");
|
|
66
117
|
}
|
|
67
118
|
|
|
68
|
-
|
|
69
|
-
|
|
119
|
+
transaction.methodId.assertEquals(
|
|
120
|
+
thisMethodId,
|
|
121
|
+
"Runtimemethod called with wrong methodId on the transaction object"
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Use the type info obtained previously to convert
|
|
126
|
+
* the args passed to fields
|
|
127
|
+
*/
|
|
128
|
+
const { fields } = MethodParameterEncoder.fromMethod(
|
|
129
|
+
this,
|
|
130
|
+
methodName
|
|
131
|
+
).encode(args);
|
|
132
|
+
|
|
133
|
+
// Assert that the argsHash that has been signed matches the given arguments
|
|
134
|
+
const argsHash = Poseidon.hash(fields);
|
|
135
|
+
|
|
136
|
+
transaction.argsHash.assertEquals(
|
|
137
|
+
argsHash,
|
|
138
|
+
"argsHash and therefore arguments of transaction and runtime call does not match"
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const isMessage = Bool(options.invocationType === "INCOMING_MESSAGE");
|
|
142
|
+
transaction.assertTransactionType(Bool(isMessage));
|
|
143
|
+
|
|
144
|
+
const transactionHash = transaction.hash();
|
|
145
|
+
const networkStateHash = networkState.hash();
|
|
70
146
|
|
|
71
147
|
return new MethodPublicOutput({
|
|
72
148
|
stateTransitionsHash,
|
|
73
149
|
status,
|
|
74
150
|
transactionHash,
|
|
75
151
|
networkStateHash,
|
|
152
|
+
isMessage,
|
|
153
|
+
eventsHash,
|
|
76
154
|
});
|
|
77
155
|
};
|
|
78
156
|
|
|
@@ -92,6 +170,8 @@ export function combineMethodName(
|
|
|
92
170
|
}
|
|
93
171
|
|
|
94
172
|
export const runtimeMethodMetadataKey = "yab-method";
|
|
173
|
+
export const runtimeMethodNamesMetadataKey = "proto-kit-runtime-methods";
|
|
174
|
+
export const runtimeMethodTypeMetadataKey = "proto-kit-runtime-method-type";
|
|
95
175
|
|
|
96
176
|
/**
|
|
97
177
|
* Checks the metadata of the provided runtime module and its method,
|
|
@@ -110,26 +190,50 @@ export function isRuntimeMethod(
|
|
|
110
190
|
);
|
|
111
191
|
}
|
|
112
192
|
|
|
113
|
-
export
|
|
193
|
+
export type RuntimeMethodInvocationType = "SIGNATURE" | "INCOMING_MESSAGE";
|
|
194
|
+
|
|
195
|
+
function runtimeMethodInternal(options: {
|
|
196
|
+
invocationType: RuntimeMethodInvocationType;
|
|
197
|
+
}) {
|
|
114
198
|
return (
|
|
115
199
|
target: RuntimeModule<unknown>,
|
|
116
200
|
methodName: string,
|
|
117
|
-
descriptor:
|
|
201
|
+
descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<any>>
|
|
118
202
|
) => {
|
|
203
|
+
checkArgsProvable(target, methodName);
|
|
119
204
|
const executionContext = container.resolve<RuntimeMethodExecutionContext>(
|
|
120
205
|
RuntimeMethodExecutionContext
|
|
121
206
|
);
|
|
122
207
|
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
209
|
+
let data: string[] | undefined = Reflect.getMetadata(
|
|
210
|
+
runtimeMethodNamesMetadataKey,
|
|
211
|
+
target
|
|
212
|
+
);
|
|
213
|
+
if (data !== undefined) {
|
|
214
|
+
data.push(methodName);
|
|
215
|
+
} else {
|
|
216
|
+
data = [methodName];
|
|
217
|
+
}
|
|
218
|
+
Reflect.defineMetadata(runtimeMethodNamesMetadataKey, data, target);
|
|
219
|
+
|
|
123
220
|
Reflect.defineMetadata(runtimeMethodMetadataKey, true, target, methodName);
|
|
124
221
|
|
|
222
|
+
Reflect.defineMetadata(
|
|
223
|
+
runtimeMethodTypeMetadataKey,
|
|
224
|
+
options.invocationType,
|
|
225
|
+
target,
|
|
226
|
+
methodName
|
|
227
|
+
);
|
|
228
|
+
|
|
125
229
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
126
230
|
const simulatedMethod = descriptor.value as DecoratedMethod;
|
|
127
231
|
|
|
128
|
-
descriptor.value = function value(
|
|
232
|
+
descriptor.value = async function value(
|
|
129
233
|
this: RuntimeModule<unknown>,
|
|
130
|
-
...args:
|
|
234
|
+
...args: ArgumentTypes
|
|
131
235
|
) {
|
|
132
|
-
const constructorName = this.
|
|
236
|
+
const constructorName = this.name!;
|
|
133
237
|
|
|
134
238
|
/**
|
|
135
239
|
* If its a top level method call, wrap it into a wrapped method,
|
|
@@ -141,6 +245,7 @@ export function runtimeMethod() {
|
|
|
141
245
|
const simulatedWrappedMethod = Reflect.apply(toWrappedMethod, this, [
|
|
142
246
|
methodName,
|
|
143
247
|
simulatedMethod,
|
|
248
|
+
options,
|
|
144
249
|
]);
|
|
145
250
|
|
|
146
251
|
/**
|
|
@@ -148,7 +253,7 @@ export function runtimeMethod() {
|
|
|
148
253
|
* RuntimeMethodExecutionContext state, meaning it enters and exits
|
|
149
254
|
* the context properly.
|
|
150
255
|
*/
|
|
151
|
-
|
|
256
|
+
|
|
152
257
|
async function prover(this: ZkProgrammable<any, any>) {
|
|
153
258
|
executionContext.beforeMethod(constructorName, methodName, args);
|
|
154
259
|
const innerProver = toProver(
|
|
@@ -157,7 +262,6 @@ export function runtimeMethod() {
|
|
|
157
262
|
false,
|
|
158
263
|
...args
|
|
159
264
|
).bind(this);
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
161
265
|
let result: Awaited<ReturnType<typeof innerProver>>;
|
|
162
266
|
try {
|
|
163
267
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
@@ -172,16 +276,15 @@ export function runtimeMethod() {
|
|
|
172
276
|
executionContext.beforeMethod(constructorName, methodName, args);
|
|
173
277
|
|
|
174
278
|
if (executionContext.isTopLevel) {
|
|
175
|
-
if (!this.
|
|
279
|
+
if (!this.parent) {
|
|
176
280
|
throw errors.runtimeNotProvided(constructorName);
|
|
177
281
|
}
|
|
178
|
-
executionContext.setProver(prover.bind(this.
|
|
282
|
+
executionContext.setProver(prover.bind(this.parent.zkProgrammable));
|
|
179
283
|
}
|
|
180
284
|
|
|
181
|
-
// eslint-disable-next-line @typescript-eslint/init-declarations
|
|
182
285
|
let result: unknown;
|
|
183
286
|
try {
|
|
184
|
-
result = Reflect.apply(simulatedMethod, this, args);
|
|
287
|
+
result = await Reflect.apply(simulatedMethod, this, args);
|
|
185
288
|
} finally {
|
|
186
289
|
executionContext.afterMethod();
|
|
187
290
|
}
|
|
@@ -190,3 +293,15 @@ export function runtimeMethod() {
|
|
|
190
293
|
};
|
|
191
294
|
};
|
|
192
295
|
}
|
|
296
|
+
|
|
297
|
+
export function runtimeMessage() {
|
|
298
|
+
return runtimeMethodInternal({
|
|
299
|
+
invocationType: "INCOMING_MESSAGE",
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function runtimeMethod() {
|
|
304
|
+
return runtimeMethodInternal({
|
|
305
|
+
invocationType: "SIGNATURE",
|
|
306
|
+
});
|
|
307
|
+
}
|