@proto-kit/module 0.1.1-develop.0
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 +11 -0
- package/dist/factories/MethodIdFactory.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.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 +33 -0
- package/dist/method/runtimeMethod.d.ts.map +1 -0
- package/dist/method/runtimeMethod.js +169 -0
- package/dist/method/runtimeMethod.js.map +1 -0
- package/dist/module/decorator.d.ts +8 -0
- package/dist/module/decorator.d.ts.map +1 -0
- package/dist/module/decorator.js +16 -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 +72 -0
- package/dist/runtime/Runtime.d.ts.map +1 -0
- package/dist/runtime/Runtime.js +231 -0
- 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 +37 -0
- package/dist/runtime/RuntimeModule.d.ts.map +1 -0
- package/dist/runtime/RuntimeModule.js +80 -0
- package/dist/runtime/RuntimeModule.js.map +1 -0
- package/dist/state/InMemoryStateService.d.ts +15 -0
- package/dist/state/InMemoryStateService.d.ts.map +1 -0
- package/dist/state/InMemoryStateService.js +24 -0
- package/dist/state/InMemoryStateService.js.map +1 -0
- package/dist/state/decorator.d.ts +7 -0
- package/dist/state/decorator.d.ts.map +1 -0
- package/dist/state/decorator.js +40 -0
- package/dist/state/decorator.js.map +1 -0
- package/jest.config.cjs +12 -0
- package/package.json +35 -0
- package/src/factories/MethodIdFactory.ts +13 -0
- package/src/index.ts +10 -0
- package/src/method/MethodParameterEncoder.ts +260 -0
- package/src/method/runtimeMethod.ts +308 -0
- package/src/module/decorator.ts +21 -0
- package/src/runtime/MethodIdResolver.ts +108 -0
- package/src/runtime/Runtime.ts +395 -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 +121 -0
- package/test/method/runtimeMethod-fail.test.ts +50 -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,73 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { assert } from "@proto-kit/protocol";
|
|
3
|
+
import { Field } from "o1js";
|
|
4
|
+
import { beforeAll } from "@jest/globals";
|
|
5
|
+
import { container } from "tsyringe";
|
|
6
|
+
|
|
7
|
+
import { Runtime } from "../../src/runtime/Runtime";
|
|
8
|
+
import { MethodIdResolver } from "../../src/runtime/MethodIdResolver";
|
|
9
|
+
import { runtimeMethod, RuntimeModule, runtimeModule } from "../../src";
|
|
10
|
+
import { createTestingRuntime } from "../TestingRuntime";
|
|
11
|
+
|
|
12
|
+
import { Balances } from "./Balances";
|
|
13
|
+
|
|
14
|
+
interface AdminConfig {}
|
|
15
|
+
|
|
16
|
+
@runtimeModule()
|
|
17
|
+
class Admin extends RuntimeModule<AdminConfig> {
|
|
18
|
+
@runtimeMethod()
|
|
19
|
+
public async isAdminWithAVeryVeryVeryVeryLongName() {
|
|
20
|
+
assert(Field(1).equals(Field(1)));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("methodId", () => {
|
|
25
|
+
let runtime: Runtime<{ Admin: typeof Admin; Balance: typeof Balances }>;
|
|
26
|
+
let resolver: MethodIdResolver;
|
|
27
|
+
|
|
28
|
+
beforeAll(() => {
|
|
29
|
+
container.clearInstances();
|
|
30
|
+
|
|
31
|
+
({ runtime } = createTestingRuntime(
|
|
32
|
+
{
|
|
33
|
+
Admin,
|
|
34
|
+
Balance: Balances,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
Admin: {},
|
|
38
|
+
Balance: {},
|
|
39
|
+
}
|
|
40
|
+
));
|
|
41
|
+
|
|
42
|
+
resolver =
|
|
43
|
+
runtime.dependencyContainer.resolve<MethodIdResolver>("MethodIdResolver");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it.each([
|
|
47
|
+
["Admin", "isAdminWithAVeryVeryVeryVeryLongName"],
|
|
48
|
+
["Balance", "getTotalSupply"],
|
|
49
|
+
["Balance", "getBalance"],
|
|
50
|
+
])("should pass and encode correctly", (givenModuleName, givenMethodName) => {
|
|
51
|
+
expect.assertions(2);
|
|
52
|
+
|
|
53
|
+
const methodId = resolver.getMethodId(givenModuleName, givenMethodName);
|
|
54
|
+
|
|
55
|
+
const [moduleName, methodName] = resolver.getMethodNameFromId(methodId) ?? [
|
|
56
|
+
undefined,
|
|
57
|
+
undefined,
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
expect(moduleName).toBe(givenModuleName);
|
|
61
|
+
expect(methodName).toBe(givenMethodName);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should fail for invalid module name", () => {
|
|
65
|
+
expect.assertions(1);
|
|
66
|
+
|
|
67
|
+
expect(() => {
|
|
68
|
+
resolver.getMethodId("Admin2", "isAdminWithAVeryVeryVeryVeryLongName");
|
|
69
|
+
}).toThrow(
|
|
70
|
+
"Only known module names are allowed, using unknown module name: Admin2"
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import { PublicKey, UInt64 } from "o1js";
|
|
3
|
+
import { container } from "tsyringe";
|
|
4
|
+
import {
|
|
5
|
+
NetworkState,
|
|
6
|
+
Option,
|
|
7
|
+
RuntimeMethodExecutionContext,
|
|
8
|
+
RuntimeTransaction,
|
|
9
|
+
} from "@proto-kit/protocol";
|
|
10
|
+
import { expectDefined } from "@proto-kit/common";
|
|
11
|
+
|
|
12
|
+
import { Runtime } from "../../src";
|
|
13
|
+
import { createTestingRuntime } from "../TestingRuntime";
|
|
14
|
+
|
|
15
|
+
import { Admin } from "./Admin";
|
|
16
|
+
import { Balances } from "./Balances";
|
|
17
|
+
|
|
18
|
+
describe("state", () => {
|
|
19
|
+
let balances: Balances;
|
|
20
|
+
|
|
21
|
+
let runtime: Runtime<{
|
|
22
|
+
Admin: typeof Admin;
|
|
23
|
+
Balances: typeof Balances;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
function createChain() {
|
|
27
|
+
({ runtime } = createTestingRuntime(
|
|
28
|
+
{
|
|
29
|
+
Admin,
|
|
30
|
+
Balances,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
Admin: {
|
|
34
|
+
publicKey: PublicKey.empty<typeof PublicKey>().toBase58(),
|
|
35
|
+
},
|
|
36
|
+
Balances: {},
|
|
37
|
+
}
|
|
38
|
+
));
|
|
39
|
+
|
|
40
|
+
balances = runtime.resolve("Balances");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
createChain();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("state decorator", () => {
|
|
48
|
+
it("should decorate state properties correctly", () => {
|
|
49
|
+
expectDefined(balances.totalSupply.path);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe("transient state", () => {
|
|
54
|
+
it("should track previously set state", async () => {
|
|
55
|
+
expect.assertions(2);
|
|
56
|
+
|
|
57
|
+
const executionContext = container.resolve(RuntimeMethodExecutionContext);
|
|
58
|
+
executionContext.setup({
|
|
59
|
+
networkState: NetworkState.empty(),
|
|
60
|
+
transaction: RuntimeTransaction.dummyTransaction(),
|
|
61
|
+
});
|
|
62
|
+
await balances.transientState();
|
|
63
|
+
|
|
64
|
+
const stateTransitions = executionContext
|
|
65
|
+
.current()
|
|
66
|
+
.result.stateTransitions.map((stateTransition) =>
|
|
67
|
+
stateTransition.toProvable()
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const expectedLastOption = Option.fromValue(
|
|
71
|
+
UInt64.from(200),
|
|
72
|
+
UInt64
|
|
73
|
+
).toProvable();
|
|
74
|
+
|
|
75
|
+
const last = stateTransitions.at(-1);
|
|
76
|
+
|
|
77
|
+
expect(last).toBeDefined();
|
|
78
|
+
expect(last!.to.value).toStrictEqual(expectedLastOption.value);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import "reflect-metadata";
|
|
2
|
+
import {
|
|
3
|
+
PublicKey,
|
|
4
|
+
Struct,
|
|
5
|
+
Bool,
|
|
6
|
+
PrivateKey,
|
|
7
|
+
Field,
|
|
8
|
+
UInt64,
|
|
9
|
+
Poseidon,
|
|
10
|
+
} from "o1js";
|
|
11
|
+
import {
|
|
12
|
+
MethodPublicOutput,
|
|
13
|
+
NetworkState,
|
|
14
|
+
RuntimeMethodExecutionContext,
|
|
15
|
+
RuntimeTransaction,
|
|
16
|
+
} from "@proto-kit/protocol";
|
|
17
|
+
import { container } from "tsyringe";
|
|
18
|
+
import { AreProofsEnabled, log } from "@proto-kit/common";
|
|
19
|
+
|
|
20
|
+
import {
|
|
21
|
+
Runtime,
|
|
22
|
+
MethodParameterEncoder,
|
|
23
|
+
runtimeModule,
|
|
24
|
+
RuntimeModule,
|
|
25
|
+
runtimeMethod,
|
|
26
|
+
toEventsHash,
|
|
27
|
+
RuntimeEvents,
|
|
28
|
+
} from "../src";
|
|
29
|
+
|
|
30
|
+
import { Balances } from "./modules/Balances";
|
|
31
|
+
import { createTestingRuntime } from "./TestingRuntime";
|
|
32
|
+
|
|
33
|
+
export class PrimaryTestEvent extends Struct({
|
|
34
|
+
message: Bool,
|
|
35
|
+
}) {}
|
|
36
|
+
|
|
37
|
+
export class SecondaryTestEvent extends Struct({
|
|
38
|
+
message: Bool,
|
|
39
|
+
}) {}
|
|
40
|
+
|
|
41
|
+
@runtimeModule()
|
|
42
|
+
class EventMaker extends RuntimeModule {
|
|
43
|
+
public constructor() {
|
|
44
|
+
super();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public events = new RuntimeEvents({
|
|
48
|
+
primary: PrimaryTestEvent,
|
|
49
|
+
secondary: SecondaryTestEvent,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
@runtimeMethod()
|
|
53
|
+
public async makeEvent() {
|
|
54
|
+
this.events.emit("primary", new PrimaryTestEvent({ message: Bool(false) }));
|
|
55
|
+
// Should not emit as condition is false.
|
|
56
|
+
this.events.emitIf(
|
|
57
|
+
Bool(false),
|
|
58
|
+
"primary",
|
|
59
|
+
new PrimaryTestEvent({ message: Bool(false) })
|
|
60
|
+
);
|
|
61
|
+
this.events.emit(
|
|
62
|
+
"secondary",
|
|
63
|
+
new SecondaryTestEvent({ message: Bool(true) })
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
describe("runtimeMethod", () => {
|
|
69
|
+
const parameters = [PublicKey.empty<typeof PublicKey>()];
|
|
70
|
+
|
|
71
|
+
let runtime: Runtime<{
|
|
72
|
+
Balances: typeof Balances;
|
|
73
|
+
EventMaker: typeof EventMaker;
|
|
74
|
+
}>;
|
|
75
|
+
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
log.setLevel(log.levels.DEBUG);
|
|
78
|
+
({ runtime } = createTestingRuntime(
|
|
79
|
+
{
|
|
80
|
+
Balances,
|
|
81
|
+
EventMaker,
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
Balances: {},
|
|
85
|
+
EventMaker: {},
|
|
86
|
+
}
|
|
87
|
+
));
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should create correct param types", async () => {
|
|
91
|
+
expect.assertions(1 + parameters.length);
|
|
92
|
+
|
|
93
|
+
const module = runtime.resolve("Balances");
|
|
94
|
+
|
|
95
|
+
const decoder = MethodParameterEncoder.fromMethod(module, "getBalance");
|
|
96
|
+
const recodedParameters = await decoder.decode(
|
|
97
|
+
parameters.flatMap((x) => x.toFields()),
|
|
98
|
+
[]
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
expect(parameters).toHaveLength(recodedParameters.length);
|
|
102
|
+
|
|
103
|
+
parameters.forEach((parameter, index) => {
|
|
104
|
+
expect(parameter).toStrictEqual(recodedParameters[index]);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("should throw on incorrect methodId on tx", async () => {
|
|
109
|
+
expect.assertions(1);
|
|
110
|
+
|
|
111
|
+
const context = container.resolve(RuntimeMethodExecutionContext);
|
|
112
|
+
|
|
113
|
+
runtime.registerValue({
|
|
114
|
+
AppChain: {
|
|
115
|
+
areProofsEnabled: false,
|
|
116
|
+
} as AreProofsEnabled,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
context.setup({
|
|
120
|
+
transaction: RuntimeTransaction.dummyTransaction(),
|
|
121
|
+
networkState: NetworkState.empty(),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const module = runtime.resolve("Balances");
|
|
125
|
+
await module.getBalance(PublicKey.empty<typeof PublicKey>());
|
|
126
|
+
|
|
127
|
+
context.setup({
|
|
128
|
+
transaction: RuntimeTransaction.dummyTransaction(),
|
|
129
|
+
networkState: NetworkState.empty(),
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await expect(context.current().result.prover!()).rejects.toThrow(
|
|
133
|
+
"Runtimemethod called with wrong methodId on the transaction object"
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("should capture event", async () => {
|
|
138
|
+
expect.assertions(5);
|
|
139
|
+
|
|
140
|
+
const context = container.resolve(RuntimeMethodExecutionContext);
|
|
141
|
+
|
|
142
|
+
runtime.registerValue({
|
|
143
|
+
AppChain: {
|
|
144
|
+
areProofsEnabled: false,
|
|
145
|
+
} as AreProofsEnabled,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const eventMakerMethodId = runtime.methodIdResolver.getMethodId(
|
|
149
|
+
"EventMaker",
|
|
150
|
+
"makeEvent"
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const privateKey = PrivateKey.random();
|
|
154
|
+
context.setup({
|
|
155
|
+
transaction: RuntimeTransaction.fromTransaction({
|
|
156
|
+
sender: privateKey.toPublicKey(),
|
|
157
|
+
nonce: UInt64.from(0),
|
|
158
|
+
methodId: Field(eventMakerMethodId),
|
|
159
|
+
argsHash: Poseidon.hash([]),
|
|
160
|
+
}),
|
|
161
|
+
networkState: NetworkState.empty(),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const module = runtime.resolve("EventMaker");
|
|
165
|
+
await module.makeEvent();
|
|
166
|
+
|
|
167
|
+
const firstExpectedEvent = {
|
|
168
|
+
eventType: PrimaryTestEvent,
|
|
169
|
+
event: new PrimaryTestEvent({
|
|
170
|
+
message: Bool(false),
|
|
171
|
+
}),
|
|
172
|
+
eventName: "primary",
|
|
173
|
+
condition: Bool(true),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const secondExpectedEvent = {
|
|
177
|
+
eventType: PrimaryTestEvent,
|
|
178
|
+
event: new PrimaryTestEvent({
|
|
179
|
+
message: Bool(false),
|
|
180
|
+
}),
|
|
181
|
+
eventName: "primary",
|
|
182
|
+
condition: Bool(false),
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const thirdExpectedEvent = {
|
|
186
|
+
eventType: SecondaryTestEvent,
|
|
187
|
+
event: new SecondaryTestEvent({
|
|
188
|
+
message: Bool(true),
|
|
189
|
+
}),
|
|
190
|
+
eventName: "secondary",
|
|
191
|
+
condition: Bool(true),
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const eventsResults = context.current().result.events;
|
|
195
|
+
expect(eventsResults).toHaveLength(3);
|
|
196
|
+
expect(eventsResults[0]).toStrictEqual(firstExpectedEvent);
|
|
197
|
+
expect(eventsResults[1]).toStrictEqual(secondExpectedEvent);
|
|
198
|
+
expect(eventsResults[2]).toStrictEqual(thirdExpectedEvent);
|
|
199
|
+
|
|
200
|
+
context.afterMethod();
|
|
201
|
+
|
|
202
|
+
const proof = await context.current().result.prover!();
|
|
203
|
+
const publicOuput = proof.publicOutput as MethodPublicOutput;
|
|
204
|
+
const { eventsHash } = publicOuput;
|
|
205
|
+
// Note that we omit the second event from below as it was
|
|
206
|
+
// not emitted due to the condition being false.
|
|
207
|
+
expect(eventsHash).toStrictEqual(
|
|
208
|
+
toEventsHash([
|
|
209
|
+
{ ...firstExpectedEvent, condition: Bool(true) },
|
|
210
|
+
{ ...secondExpectedEvent, condition: Bool(false) },
|
|
211
|
+
{ ...thirdExpectedEvent, condition: Bool(true) },
|
|
212
|
+
])
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
});
|